Panagiotis Triantafyllou

steps fixes

...@@ -4,18 +4,18 @@ ...@@ -4,18 +4,18 @@
4 <value> 4 <value>
5 <entry key="app"> 5 <entry key="app">
6 <State> 6 <State>
7 - <targetSelectedWithDropDown> 7 + <runningDeviceTargetSelectedWithDropDown>
8 <Target> 8 <Target>
9 - <type value="QUICK_BOOT_TARGET" /> 9 + <type value="RUNNING_DEVICE_TARGET" />
10 <deviceKey> 10 <deviceKey>
11 <Key> 11 <Key>
12 - <type value="VIRTUAL_DEVICE_PATH" /> 12 + <type value="SERIAL_NUMBER" />
13 - <value value="$USER_HOME$/.android/avd/Pixel_7_v13.avd" /> 13 + <value value="R58M42EM7YT" />
14 </Key> 14 </Key>
15 </deviceKey> 15 </deviceKey>
16 </Target> 16 </Target>
17 - </targetSelectedWithDropDown> 17 + </runningDeviceTargetSelectedWithDropDown>
18 - <timeTargetWasSelectedWithDropDown value="2024-07-09T11:41:15.263632Z" /> 18 + <timeTargetWasSelectedWithDropDown value="2024-07-26T13:26:33.140020Z" />
19 </State> 19 </State>
20 </entry> 20 </entry>
21 </value> 21 </value>
......
...@@ -17,7 +17,8 @@ ...@@ -17,7 +17,8 @@
17 <uses-permission android:name="android.permission.FOREGROUND_SERVICE_HEALTH" /> 17 <uses-permission android:name="android.permission.FOREGROUND_SERVICE_HEALTH" />
18 <uses-permission android:name="android.permission.HIGH_SAMPLING_RATE_SENSORS" /> 18 <uses-permission android:name="android.permission.HIGH_SAMPLING_RATE_SENSORS" />
19 <uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> 19 <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
20 - <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> 20 +<!-- <uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />-->
21 +<!-- <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />-->
21 22
22 <application android:largeHeap="true"> 23 <application android:largeHeap="true">
23 <!-- <meta-data--> 24 <!-- <meta-data-->
...@@ -291,8 +292,8 @@ ...@@ -291,8 +292,8 @@
291 android:name=".receivers.RestartHealthServiceReceiver" 292 android:name=".receivers.RestartHealthServiceReceiver"
292 android:exported="false"> 293 android:exported="false">
293 <intent-filter> 294 <intent-filter>
294 - <action android:name="android.intent.action.BOOT_COMPLETED" /> 295 +<!-- <action android:name="android.intent.action.BOOT_COMPLETED" />-->
295 - <action android:name="android.intent.action.MY_PACKAGE_REPLACED" /> 296 + <action android:name="android.intent.action.RESTART" />
296 </intent-filter> 297 </intent-filter>
297 </receiver> 298 </receiver>
298 299
......
...@@ -28,6 +28,8 @@ package ly.warp.sdk.activities; ...@@ -28,6 +28,8 @@ package ly.warp.sdk.activities;
28 import static ly.warp.sdk.utils.constants.WarpConstants.RANDOM_MAX; 28 import static ly.warp.sdk.utils.constants.WarpConstants.RANDOM_MAX;
29 import static ly.warp.sdk.utils.constants.WarpConstants.RANDOM_MIN; 29 import static ly.warp.sdk.utils.constants.WarpConstants.RANDOM_MIN;
30 30
31 +import android.Manifest;
32 +import android.app.ActivityManager;
31 import android.content.Context; 33 import android.content.Context;
32 import android.content.Intent; 34 import android.content.Intent;
33 import android.content.pm.PackageManager; 35 import android.content.pm.PackageManager;
...@@ -35,6 +37,8 @@ import android.graphics.Color; ...@@ -35,6 +37,8 @@ import android.graphics.Color;
35 import android.os.Build; 37 import android.os.Build;
36 import android.os.Bundle; 38 import android.os.Bundle;
37 import android.os.Handler; 39 import android.os.Handler;
40 +import android.os.PowerManager;
41 +import android.provider.Settings;
38 import android.text.TextUtils; 42 import android.text.TextUtils;
39 import android.view.KeyEvent; 43 import android.view.KeyEvent;
40 import android.view.View; 44 import android.view.View;
...@@ -44,6 +48,8 @@ import android.widget.ProgressBar; ...@@ -44,6 +48,8 @@ import android.widget.ProgressBar;
44 import android.widget.RelativeLayout; 48 import android.widget.RelativeLayout;
45 49
46 import androidx.annotation.NonNull; 50 import androidx.annotation.NonNull;
51 +import androidx.core.app.ActivityCompat;
52 +import androidx.core.content.ContextCompat;
47 import androidx.work.Constraints; 53 import androidx.work.Constraints;
48 import androidx.work.NetworkType; 54 import androidx.work.NetworkType;
49 import androidx.work.OneTimeWorkRequest; 55 import androidx.work.OneTimeWorkRequest;
...@@ -62,11 +68,14 @@ import ly.warp.sdk.Warply; ...@@ -62,11 +68,14 @@ import ly.warp.sdk.Warply;
62 import ly.warp.sdk.db.WarplyDBHelper; 68 import ly.warp.sdk.db.WarplyDBHelper;
63 import ly.warp.sdk.io.callbacks.CallbackReceiver; 69 import ly.warp.sdk.io.callbacks.CallbackReceiver;
64 import ly.warp.sdk.io.models.CouponList; 70 import ly.warp.sdk.io.models.CouponList;
71 +import ly.warp.sdk.io.models.LoyaltySDKFirebaseEventModel;
72 +import ly.warp.sdk.io.models.WarplyPacingEventModel;
65 import ly.warp.sdk.io.models.WarplyWebviewActivityCallbackEventModel; 73 import ly.warp.sdk.io.models.WarplyWebviewActivityCallbackEventModel;
66 import ly.warp.sdk.io.models.WarplyWebviewCallbackEventModel; 74 import ly.warp.sdk.io.models.WarplyWebviewCallbackEventModel;
67 import ly.warp.sdk.services.EventCampaignCouponService; 75 import ly.warp.sdk.services.EventCampaignCouponService;
68 import ly.warp.sdk.services.EventQuestionnaireService; 76 import ly.warp.sdk.services.EventQuestionnaireService;
69 import ly.warp.sdk.services.PushEventsClickedWorkerService; 77 import ly.warp.sdk.services.PushEventsClickedWorkerService;
78 +import ly.warp.sdk.services.WarplyHealthService;
70 import ly.warp.sdk.utils.WarpJSONParser; 79 import ly.warp.sdk.utils.WarpJSONParser;
71 import ly.warp.sdk.utils.WarpUtils; 80 import ly.warp.sdk.utils.WarpUtils;
72 import ly.warp.sdk.utils.WarplyPreferences; 81 import ly.warp.sdk.utils.WarplyPreferences;
...@@ -164,6 +173,24 @@ public class WarpViewActivity extends WarpBaseActivity { ...@@ -164,6 +173,24 @@ public class WarpViewActivity extends WarpBaseActivity {
164 webviewCallbackEventModel.setResponseCode(grantResults[0] == PackageManager.PERMISSION_GRANTED ? "allow" : "deny"); 173 webviewCallbackEventModel.setResponseCode(grantResults[0] == PackageManager.PERMISSION_GRANTED ? "allow" : "deny");
165 EventBus.getDefault().post(new WarplyEventBusManager(webviewCallbackEventModel)); 174 EventBus.getDefault().post(new WarplyEventBusManager(webviewCallbackEventModel));
166 } 175 }
176 + if (requestCode == 5001 && grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
177 + if (!isMyServiceRunning(WarplyHealthService.class)) {
178 + LoyaltySDKFirebaseEventModel analyticsEvent = new LoyaltySDKFirebaseEventModel();
179 + analyticsEvent.setEventName("loyalty_steps_activation");
180 + EventBus.getDefault().post(new WarplyEventBusManager(analyticsEvent));
181 +
182 + Intent stepsServiceIntent = new Intent(this, WarplyHealthService.class);
183 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
184 + startForegroundService(stepsServiceIntent);
185 + } else {
186 + startService(stepsServiceIntent);
187 + }
188 +
189 + WarplyPacingEventModel pacingVisible = new WarplyPacingEventModel();
190 + pacingVisible.setVisible(true);
191 + EventBus.getDefault().post(new WarplyEventBusManager(pacingVisible));
192 + }
193 + }
167 } 194 }
168 195
169 @Override 196 @Override
...@@ -195,6 +222,60 @@ public class WarpViewActivity extends WarpBaseActivity { ...@@ -195,6 +222,60 @@ public class WarpViewActivity extends WarpBaseActivity {
195 // if (event.getPacingService() != null) 222 // if (event.getPacingService() != null)
196 // finish(); 223 // finish();
197 if (event.getPacing() != null && !event.getPacing().isVisible()) finish(); 224 if (event.getPacing() != null && !event.getPacing().isVisible()) finish();
225 + if (event.getHealth() != null) {
226 + if (event.getHealth().isActivated()) {
227 + WarpUtils.setIsStepsManuallyStopped(this, false);
228 +// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
229 +// if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACTIVITY_RECOGNITION) != PackageManager.PERMISSION_GRANTED) {
230 +// ActivityCompat.requestPermissions(this, new String[]{
231 +// Manifest.permission.ACTIVITY_RECOGNITION
232 +// }, 5001);
233 +// } else {
234 +// if (!isMyServiceRunning(WarplyHealthService.class)) {
235 +// LoyaltySDKFirebaseEventModel analyticsEvent = new LoyaltySDKFirebaseEventModel();
236 +// analyticsEvent.setEventName("loyalty_steps_activation");
237 +// EventBus.getDefault().post(new WarplyEventBusManager(analyticsEvent));
238 +//
239 +// Intent stepsServiceIntent = new Intent(this, WarplyHealthService.class);
240 +// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
241 +// startForegroundService(stepsServiceIntent);
242 +// } else {
243 +// startService(stepsServiceIntent);
244 +// }
245 +//
246 +// WarplyPacingEventModel pacingVisible = new WarplyPacingEventModel();
247 +// pacingVisible.setVisible(true);
248 +// EventBus.getDefault().post(new WarplyEventBusManager(pacingVisible));
249 +// }
250 +// }
251 +// } else {
252 + if (!isMyServiceRunning(WarplyHealthService.class)) {
253 + LoyaltySDKFirebaseEventModel analyticsEvent = new LoyaltySDKFirebaseEventModel();
254 + analyticsEvent.setEventName("loyalty_steps_activation");
255 + EventBus.getDefault().post(new WarplyEventBusManager(analyticsEvent));
256 +
257 + Intent stepsServiceIntent = new Intent(this, WarplyHealthService.class);
258 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
259 + startForegroundService(stepsServiceIntent);
260 + } else {
261 + startService(stepsServiceIntent);
262 + }
263 +
264 + WarplyPacingEventModel pacingVisible = new WarplyPacingEventModel();
265 + pacingVisible.setVisible(true);
266 + EventBus.getDefault().post(new WarplyEventBusManager(pacingVisible));
267 + }
268 +// }
269 + } else {
270 + WarpUtils.setIsStepsManuallyStopped(this, true);
271 + Intent stepsServiceIntent = new Intent(this, WarplyHealthService.class);
272 + stopService(stepsServiceIntent);
273 +
274 + WarplyPacingEventModel pacingVisible = new WarplyPacingEventModel();
275 + pacingVisible.setVisible(false);
276 + EventBus.getDefault().post(new WarplyEventBusManager(pacingVisible));
277 + }
278 + }
198 } 279 }
199 280
200 // =========================================================== 281 // ===========================================================
...@@ -251,19 +332,19 @@ public class WarpViewActivity extends WarpBaseActivity { ...@@ -251,19 +332,19 @@ public class WarpViewActivity extends WarpBaseActivity {
251 if (intent.hasExtra("source") && intent.getStringExtra("source").equalsIgnoreCase("from_notification_status")) { 332 if (intent.hasExtra("source") && intent.getStringExtra("source").equalsIgnoreCase("from_notification_status")) {
252 JSONObject params = new JSONObject(); 333 JSONObject params = new JSONObject();
253 try { 334 try {
254 - params.putOpt("web_id", WarpUtils.getWebId(Warply.getWarplyContext())); 335 + params.putOpt("web_id", WarpUtils.getWebId(this));
255 - params.putOpt("app_uuid", WarplyProperty.getAppUuid(Warply.getWarplyContext())); 336 + params.putOpt("app_uuid", WarplyProperty.getAppUuid(this));
256 - params.putOpt("api_key", WarpUtils.getApiKey(Warply.getWarplyContext())); 337 + params.putOpt("api_key", WarpUtils.getApiKey(this));
257 params.putOpt("session_uuid", sessionUUID); 338 params.putOpt("session_uuid", sessionUUID);
258 - params.putOpt("access_token", WarplyDBHelper.getInstance(Warply.getWarplyContext()).getAuthValue("access_token")); 339 + params.putOpt("access_token", WarplyDBHelper.getInstance(this).getAuthValue("access_token"));
259 - params.putOpt("refresh_token", WarplyDBHelper.getInstance(Warply.getWarplyContext()).getAuthValue("refresh_token")); 340 + params.putOpt("refresh_token", WarplyDBHelper.getInstance(this).getAuthValue("refresh_token"));
260 - params.putOpt("client_id", WarplyDBHelper.getInstance(Warply.getWarplyContext()).getClientValue("client_id")); 341 + params.putOpt("client_id", WarplyDBHelper.getInstance(this).getClientValue("client_id"));
261 - params.putOpt("client_secret", WarplyDBHelper.getInstance(Warply.getWarplyContext()).getClientValue("client_secret")); 342 + params.putOpt("client_secret", WarplyDBHelper.getInstance(this).getClientValue("client_secret"));
262 } catch (JSONException e) { 343 } catch (JSONException e) {
263 e.printStackTrace(); 344 e.printStackTrace();
264 } 345 }
265 346
266 - WarpUtils.setWebviewParams(Warply.getWarplyContext(), params); 347 + WarpUtils.setWebviewParams(this, params);
267 348
268 setUpPushEvents(sessionUUID); 349 setUpPushEvents(sessionUUID);
269 } 350 }
...@@ -341,4 +422,24 @@ public class WarpViewActivity extends WarpBaseActivity { ...@@ -341,4 +422,24 @@ public class WarpViewActivity extends WarpBaseActivity {
341 public static void setWebviewSupermarket(boolean isLoaded) { 422 public static void setWebviewSupermarket(boolean isLoaded) {
342 mWebviewSupermarket = isLoaded; 423 mWebviewSupermarket = isLoaded;
343 } 424 }
425 +
426 + private boolean isMyServiceRunning(Class<?> serviceClass) {
427 + ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
428 + for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
429 + if (serviceClass.getName().equals(service.service.getClassName())) {
430 + return true;
431 + }
432 + }
433 + return false;
434 + }
435 +
436 + private void checkBatteryOptimizationForWarplyHealth() {
437 + PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
438 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
439 + if (!pm.isIgnoringBatteryOptimizations(getPackageName())) {
440 + Intent intent = new Intent(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS);
441 + startActivityForResult(intent, 6001);
442 + }
443 + }
444 + }
344 } 445 }
...\ No newline at end of file ...\ No newline at end of file
......
1 +/*
2 + * Copyright 2010-2013 Warply Ltd. All rights reserved.
3 + *
4 + * Redistribution and use in source and binary forms, without modification, are
5 + * permitted provided that the following conditions are met:
6 + *
7 + * 1. Redistributions of source code must retain the above copyright notice,
8 + * this list of conditions and the following disclaimer.
9 + *
10 + * 2. Redistributions in binary form must reproduce the above copyright notice,
11 + * this list of conditions and the following disclaimer in the documentation
12 + * and/or other materials provided with the distribution.
13 + *
14 + * THIS SOFTWARE IS PROVIDED BY THE WARPLY LTD ``AS IS'' AND ANY EXPRESS OR
15 + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
16 + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
17 + * EVENT SHALL WARPLY LTD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
18 + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
19 + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
20 + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
21 + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
22 + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
23 + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 + */
25 +
26 +package ly.warp.sdk.io.models;
27 +
28 +
29 +/**
30 + * Created by Panagiotis Triantafyllou on 25-July-24.
31 + */
32 +
33 +public class WarplyHealthEventModel {
34 + private boolean activated;
35 +
36 + public WarplyHealthEventModel() {
37 + this.activated = true;
38 + }
39 +
40 + public boolean isActivated() {
41 + return activated;
42 + }
43 +
44 + public void setActivated(boolean activated) {
45 + this.activated = activated;
46 + }
47 +}
1 package ly.warp.sdk.receivers; 1 package ly.warp.sdk.receivers;
2 2
3 +import static ly.warp.sdk.services.WarplyHealthService.ACTION_RESTART_SERVICE;
4 +
3 import android.content.BroadcastReceiver; 5 import android.content.BroadcastReceiver;
4 import android.content.Context; 6 import android.content.Context;
5 import android.content.Intent; 7 import android.content.Intent;
6 -import android.os.Build;
7 8
8 -import ly.warp.sdk.services.WarplyHealthService; 9 +import androidx.work.OneTimeWorkRequest;
10 +import androidx.work.WorkManager;
11 +
12 +import java.util.concurrent.TimeUnit;
13 +
14 +import ly.warp.sdk.services.WarplyHealthWorker;
9 15
10 public class RestartHealthServiceReceiver extends BroadcastReceiver { 16 public class RestartHealthServiceReceiver extends BroadcastReceiver {
11 @Override 17 @Override
12 public void onReceive(Context context, Intent intent) { 18 public void onReceive(Context context, Intent intent) {
13 - if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction()) || 19 + if (intent != null && intent.getAction() != null && ACTION_RESTART_SERVICE.equals(intent.getAction())) {
14 - Intent.ACTION_MY_PACKAGE_REPLACED.equals(intent.getAction())) { 20 + scheduleWork(context);
15 - Intent stepsRestartServiceIntent = new Intent(context, WarplyHealthService.class);
16 - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
17 - context.startForegroundService(stepsRestartServiceIntent);
18 - } else {
19 - context.startService(stepsRestartServiceIntent);
20 - }
21 } 21 }
22 } 22 }
23 +
24 + private void scheduleWork(Context context) {
25 + OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(WarplyHealthWorker.class)
26 + .setInitialDelay(2, TimeUnit.SECONDS)
27 + .build();
28 + WorkManager.getInstance(context).enqueue(workRequest);
29 + }
23 } 30 }
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -7,7 +7,6 @@ import android.app.PendingIntent; ...@@ -7,7 +7,6 @@ import android.app.PendingIntent;
7 import android.app.Service; 7 import android.app.Service;
8 import android.content.Context; 8 import android.content.Context;
9 import android.content.Intent; 9 import android.content.Intent;
10 -import android.content.pm.PackageManager;
11 import android.content.pm.ServiceInfo; 10 import android.content.pm.ServiceInfo;
12 import android.hardware.Sensor; 11 import android.hardware.Sensor;
13 import android.hardware.SensorEvent; 12 import android.hardware.SensorEvent;
...@@ -16,6 +15,7 @@ import android.hardware.SensorManager; ...@@ -16,6 +15,7 @@ import android.hardware.SensorManager;
16 import android.os.Build; 15 import android.os.Build;
17 import android.os.Handler; 16 import android.os.Handler;
18 import android.os.IBinder; 17 import android.os.IBinder;
18 +import android.os.Looper;
19 19
20 import androidx.annotation.Nullable; 20 import androidx.annotation.Nullable;
21 import androidx.core.app.NotificationCompat; 21 import androidx.core.app.NotificationCompat;
...@@ -24,6 +24,7 @@ import ly.warp.sdk.R; ...@@ -24,6 +24,7 @@ import ly.warp.sdk.R;
24 import ly.warp.sdk.Warply; 24 import ly.warp.sdk.Warply;
25 import ly.warp.sdk.io.callbacks.CallbackReceiver; 25 import ly.warp.sdk.io.callbacks.CallbackReceiver;
26 import ly.warp.sdk.io.models.PacingDetails; 26 import ly.warp.sdk.io.models.PacingDetails;
27 +import ly.warp.sdk.receivers.RestartHealthServiceReceiver;
27 import ly.warp.sdk.utils.WarpUtils; 28 import ly.warp.sdk.utils.WarpUtils;
28 import ly.warp.sdk.utils.WarplyManagerHelper; 29 import ly.warp.sdk.utils.WarplyManagerHelper;
29 import ly.warp.sdk.utils.managers.WarplyManager; 30 import ly.warp.sdk.utils.managers.WarplyManager;
...@@ -60,6 +61,10 @@ public class WarplyHealthService extends Service implements SensorEventListener ...@@ -60,6 +61,10 @@ public class WarplyHealthService extends Service implements SensorEventListener
60 private float oldVelocityEstimate = 0; 61 private float oldVelocityEstimate = 0;
61 private double eventMeters = 0.0d, pacingMeters = 0.0d; 62 private double eventMeters = 0.0d, pacingMeters = 0.0d;
62 private int sumSteps = 0; 63 private int sumSteps = 0;
64 + private Handler notificationHandler, saveHandler;
65 + private Runnable notificationRunnable, saveRunnable;
66 + private static int mNotificationSteps = 0;
67 + public static final String ACTION_RESTART_SERVICE = "ly.warp.sdk.services.ACTION_RESTART_SERVICE";
63 68
64 // =========================================================== 69 // ===========================================================
65 // Contructors 70 // Contructors
...@@ -95,52 +100,39 @@ public class WarplyHealthService extends Service implements SensorEventListener ...@@ -95,52 +100,39 @@ public class WarplyHealthService extends Service implements SensorEventListener
95 public int onStartCommand(Intent intent, int flags, int startId) { 100 public int onStartCommand(Intent intent, int flags, int startId) {
96 /** 3. We create a sticky notification so the 101 /** 3. We create a sticky notification so the
97 * service can run on background */ 102 * service can run on background */
98 - NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); 103 + createNotificationChannel();
99 - PackageManager pm = getPackageManager(); 104 +
100 - Intent bIntent = pm.getLaunchIntentForPackage(getPackageName()); 105 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
101 - PendingIntent pbIntent = PendingIntent.getActivity(this, 2001, bIntent, PendingIntent.FLAG_IMMUTABLE); 106 + this.startForeground(2001, createNotification(), ServiceInfo.FOREGROUND_SERVICE_TYPE_HEALTH);
102 - 107 + } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
103 - NotificationCompat.Builder b = new NotificationCompat.Builder(this, STEPS_CHANNEL_ID); 108 + this.startForeground(2001, createNotification());
104 - b.setDefaults(Notification.DEFAULT_VIBRATE | Notification.DEFAULT_LIGHTS); 109 + } else {
105 - b.setChannelId(STEPS_CHANNEL_ID); 110 + this.startForeground(2001, createNotification());
106 - b.setContentTitle(getString(R.string.cos_steps_for_good_notification_title)); 111 + }
107 - b.setStyle(new NotificationCompat.BigTextStyle().bigText(getString(R.string.cos_steps_for_good_notification_subtitle)));
108 - b.setContentIntent(pbIntent);
109 - b.setAutoCancel(false); //it was true
110 - b.setOngoing(true);
111 - b.setPriority(NotificationCompat.PRIORITY_HIGH);
112 - b.setSmallIcon(R.drawable.ic_launcher);
113 112
114 - if (notificationManager != null) { 113 + /** We update the notification */
115 - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { 114 + notificationHandler = new Handler(Looper.getMainLooper());
116 - NotificationChannel notificationChannel = new NotificationChannel(STEPS_CHANNEL_ID, "steps_notification_channel", NotificationManager.IMPORTANCE_HIGH); 115 + notificationRunnable = new Runnable() {
117 - notificationManager.createNotificationChannel(notificationChannel); 116 + @Override
118 - Notification notification_build = b.setChannelId(STEPS_CHANNEL_ID).build(); 117 + public void run() {
119 - notification_build.flags = Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR; 118 + Notification notification = createNotification();
120 - this.startForeground(2001, notification_build, ServiceInfo.FOREGROUND_SERVICE_TYPE_HEALTH); 119 + NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
121 - } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { 120 + manager.notify(2001, notification);
122 - NotificationChannel notificationChannel = new NotificationChannel(STEPS_CHANNEL_ID, "steps_notification_channel", NotificationManager.IMPORTANCE_HIGH); 121 + notificationHandler.postDelayed(this, 1000);
123 - notificationManager.createNotificationChannel(notificationChannel);
124 - Notification notification_build = b.setChannelId(STEPS_CHANNEL_ID).build();
125 - notification_build.flags = Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR;
126 - this.startForeground(2001, notification_build);
127 - } else {
128 - Notification notification_build = b.build();
129 - notification_build.flags = Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR;
130 - this.startForeground(2001, notification_build);
131 } 122 }
132 - } 123 + };
124 + notificationHandler.post(notificationRunnable);
133 125
134 /** We save all the steps every 15 minutes */ 126 /** We save all the steps every 15 minutes */
135 - final Handler handler = new Handler(); 127 + saveHandler = new Handler();
136 - Runnable runnable = new Runnable() { 128 + saveRunnable = new Runnable() {
137 @Override 129 @Override
138 public void run() { 130 public void run() {
139 WarplyManager.sendSteps(WarplyHealthService.this); 131 WarplyManager.sendSteps(WarplyHealthService.this);
140 - handler.postDelayed(this, 900000); 132 + saveHandler.postDelayed(this, 900000);
141 } 133 }
142 }; 134 };
143 - handler.post(runnable); 135 + saveHandler.post(saveRunnable);
144 136
145 return Service.START_STICKY; 137 return Service.START_STICKY;
146 } 138 }
...@@ -155,7 +147,29 @@ public class WarplyHealthService extends Service implements SensorEventListener ...@@ -155,7 +147,29 @@ public class WarplyHealthService extends Service implements SensorEventListener
155 eventMeters = 0.0d; 147 eventMeters = 0.0d;
156 pacingMeters = 0.0d; 148 pacingMeters = 0.0d;
157 sumSteps = 0; 149 sumSteps = 0;
150 + mNotificationSteps = 0;
151 + if (notificationHandler != null)
152 + notificationHandler.removeCallbacks(notificationRunnable);
153 + if (saveHandler != null)
154 + saveHandler.removeCallbacks(saveRunnable);
158 WarplyManager.sendSteps(this); 155 WarplyManager.sendSteps(this);
156 +
157 + if (!WarpUtils.getIsStepsManuallyStopped(this)) {
158 + Intent broadcastIntent = new Intent(this, RestartHealthServiceReceiver.class);
159 + broadcastIntent.setAction(ACTION_RESTART_SERVICE);
160 + sendBroadcast(broadcastIntent);
161 + }
162 + }
163 +
164 + @Override
165 + public void onTaskRemoved(Intent rootIntent) {
166 + super.onTaskRemoved(rootIntent);
167 + stopSelf();
168 + if (!WarpUtils.getIsStepsManuallyStopped(this)) {
169 + Intent broadcastIntent = new Intent(this, RestartHealthServiceReceiver.class);
170 + broadcastIntent.setAction(ACTION_RESTART_SERVICE);
171 + sendBroadcast(broadcastIntent);
172 + }
159 } 173 }
160 174
161 @Nullable 175 @Nullable
...@@ -229,6 +243,7 @@ public class WarplyHealthService extends Service implements SensorEventListener ...@@ -229,6 +243,7 @@ public class WarplyHealthService extends Service implements SensorEventListener
229 // WarplyManagerHelper.mSteps++; 243 // WarplyManagerHelper.mSteps++;
230 // WarpUtils.setStepsCounter(this, WarplyManagerHelper.mSteps); 244 // WarpUtils.setStepsCounter(this, WarplyManagerHelper.mSteps);
231 245
246 + mNotificationSteps++;
232 WarplyManagerHelper.mStepsWebview++; 247 WarplyManagerHelper.mStepsWebview++;
233 WarpUtils.log("WEBVIEW_STEPS: " + String.valueOf(WarplyManagerHelper.mStepsWebview)); 248 WarpUtils.log("WEBVIEW_STEPS: " + String.valueOf(WarplyManagerHelper.mStepsWebview));
234 WarplyManagerHelper.mMetersWebview = (WarplyManagerHelper.mStepsWebview * 0.762); 249 WarplyManagerHelper.mMetersWebview = (WarplyManagerHelper.mStepsWebview * 0.762);
...@@ -300,4 +315,76 @@ public class WarplyHealthService extends Service implements SensorEventListener ...@@ -300,4 +315,76 @@ public class WarplyHealthService extends Service implements SensorEventListener
300 315
301 } 316 }
302 }; 317 };
318 +
319 + private void createNotificationChannel() {
320 + NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
321 + if (notificationManager != null) {
322 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
323 + NotificationChannel notificationChannel = new NotificationChannel(STEPS_CHANNEL_ID,
324 + "steps_notification_channel",
325 + NotificationManager.IMPORTANCE_HIGH); //IMPORTANCE_HIGH if we want heads up notification, IMPORTANCE_DEFAULT otherwise
326 + notificationManager.createNotificationChannel(notificationChannel);
327 + } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
328 + NotificationChannel notificationChannel = new NotificationChannel(STEPS_CHANNEL_ID,
329 + "steps_notification_channel",
330 + NotificationManager.IMPORTANCE_HIGH); //IMPORTANCE_HIGH if we want heads up notification, IMPORTANCE_DEFAULT otherwise
331 + notificationManager.createNotificationChannel(notificationChannel);
332 + }
333 + }
334 + }
335 +
336 + private Notification createNotification() {
337 + Intent bIntent = getPackageManager().getLaunchIntentForPackage(getPackageName());
338 + PendingIntent pbIntent = PendingIntent.getActivity(this, 2001, bIntent, PendingIntent.FLAG_IMMUTABLE);
339 +
340 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
341 + NotificationCompat.Builder b = new NotificationCompat.Builder(this, STEPS_CHANNEL_ID);
342 + b.setDefaults(Notification.DEFAULT_VIBRATE | Notification.DEFAULT_LIGHTS);
343 + b.setChannelId(STEPS_CHANNEL_ID);
344 + b.setContentTitle(getString(R.string.cos_steps_for_good_notification_title) + " " + String.valueOf(mNotificationSteps + " /10000"));
345 + b.setContentText(String.valueOf(mNotificationSteps + " βήματα"));
346 + b.setProgress(10000, mNotificationSteps, false);
347 + b.setStyle(new NotificationCompat.BigTextStyle().bigText(getString(R.string.cos_steps_for_good_notification_subtitle)));
348 + b.setContentIntent(pbIntent);
349 + b.setAutoCancel(false); //it was true
350 + b.setOngoing(true);
351 + b.setPriority(NotificationCompat.PRIORITY_HIGH);
352 + b.setSmallIcon(R.drawable.ic_launcher);
353 + Notification notification_build = b.setChannelId(STEPS_CHANNEL_ID).build();
354 + notification_build.flags = Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR;
355 + return notification_build;
356 + } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
357 + NotificationCompat.Builder b = new NotificationCompat.Builder(this, STEPS_CHANNEL_ID);
358 + b.setDefaults(Notification.DEFAULT_VIBRATE | Notification.DEFAULT_LIGHTS);
359 + b.setChannelId(STEPS_CHANNEL_ID);
360 + b.setContentTitle(getString(R.string.cos_steps_for_good_notification_title) + " " + String.valueOf(mNotificationSteps + " /10000"));
361 + b.setContentText(String.valueOf(mNotificationSteps + " βήματα"));
362 + b.setProgress(10000, mNotificationSteps, false);
363 + b.setStyle(new NotificationCompat.BigTextStyle().bigText(getString(R.string.cos_steps_for_good_notification_subtitle)));
364 + b.setContentIntent(pbIntent);
365 + b.setAutoCancel(false); //it was true
366 + b.setOngoing(true);
367 + b.setPriority(NotificationCompat.PRIORITY_HIGH);
368 + b.setSmallIcon(R.drawable.ic_launcher);
369 + Notification notification_build = b.setChannelId(STEPS_CHANNEL_ID).build();
370 + notification_build.flags = Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR;
371 + return notification_build;
372 + } else {
373 + NotificationCompat.Builder b = new NotificationCompat.Builder(this, STEPS_CHANNEL_ID);
374 + b.setDefaults(Notification.DEFAULT_VIBRATE | Notification.DEFAULT_LIGHTS);
375 + b.setChannelId(STEPS_CHANNEL_ID);
376 + b.setContentTitle(getString(R.string.cos_steps_for_good_notification_title) + " " + String.valueOf(mNotificationSteps + " /10000"));
377 + b.setContentText(String.valueOf(mNotificationSteps + " βήματα"));
378 + b.setProgress(10000, mNotificationSteps, false);
379 + b.setStyle(new NotificationCompat.BigTextStyle().bigText(getString(R.string.cos_steps_for_good_notification_subtitle)));
380 + b.setContentIntent(pbIntent);
381 + b.setAutoCancel(false); //it was true
382 + b.setOngoing(true);
383 + b.setPriority(NotificationCompat.PRIORITY_HIGH);
384 + b.setSmallIcon(R.drawable.ic_launcher);
385 + Notification notification_build = b.build();
386 + notification_build.flags = Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR;
387 + return notification_build;
388 + }
389 + }
303 } 390 }
......
1 +package ly.warp.sdk.services;
2 +
3 +import android.content.Context;
4 +import android.content.Intent;
5 +import android.os.Build;
6 +
7 +import androidx.annotation.NonNull;
8 +import androidx.work.Worker;
9 +import androidx.work.WorkerParameters;
10 +
11 +/**
12 + * Created by Panagiotis Triantafyllou on 26/Ιουλ/2024.
13 + */
14 +public class WarplyHealthWorker extends Worker {
15 +
16 + public WarplyHealthWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
17 + super(context, workerParams);
18 + }
19 +
20 + @NonNull
21 + @Override
22 + public Result doWork() {
23 + Context context = getApplicationContext();
24 + Intent stepsRestartServiceIntent = new Intent(context, WarplyHealthService.class);
25 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
26 + context.startForegroundService(stepsRestartServiceIntent);
27 + } else {
28 + context.startService(stepsRestartServiceIntent);
29 + }
30 +
31 + return Result.success();
32 + }
33 +}
...@@ -157,6 +157,8 @@ public class WarpUtils { ...@@ -157,6 +157,8 @@ public class WarpUtils {
157 + "language"; 157 + "language";
158 private static final String PREFERENCES_KEY_STEPS = PREFERENCES_PREFIX 158 private static final String PREFERENCES_KEY_STEPS = PREFERENCES_PREFIX
159 + "steps"; 159 + "steps";
160 + private static final String PREFERENCES_KEY_STEPS_MANUALLY_STOPPED = PREFERENCES_PREFIX
161 + + "steps_manually_stopped";
160 162
161 private static SharedPreferences _prefs; 163 private static SharedPreferences _prefs;
162 164
...@@ -166,9 +168,19 @@ public class WarpUtils { ...@@ -166,9 +168,19 @@ public class WarpUtils {
166 return getPreferences(context).getBoolean(PREFERENCES_KEY_STEPS, false); 168 return getPreferences(context).getBoolean(PREFERENCES_KEY_STEPS, false);
167 } 169 }
168 170
169 - public static void setIsSteps(Context context, boolean isSupermarket) { 171 + public static void setIsSteps(Context context, boolean isSteps) {
170 SharedPreferences.Editor editor = getPreferences(context).edit(); 172 SharedPreferences.Editor editor = getPreferences(context).edit();
171 - editor.putBoolean(PREFERENCES_KEY_STEPS, isSupermarket); 173 + editor.putBoolean(PREFERENCES_KEY_STEPS, isSteps);
174 + editor.apply();
175 + }
176 +
177 + public static boolean getIsStepsManuallyStopped(Context context) {
178 + return getPreferences(context).getBoolean(PREFERENCES_KEY_STEPS_MANUALLY_STOPPED, false);
179 + }
180 +
181 + public static void setIsStepsManuallyStopped(Context context, boolean isManuallyStopped) {
182 + SharedPreferences.Editor editor = getPreferences(context).edit();
183 + editor.putBoolean(PREFERENCES_KEY_STEPS_MANUALLY_STOPPED, isManuallyStopped);
172 editor.apply(); 184 editor.apply();
173 } 185 }
174 186
......
...@@ -27,6 +27,7 @@ import ly.warp.sdk.io.models.WarplyBoxAnalysisEventModel; ...@@ -27,6 +27,7 @@ import ly.warp.sdk.io.models.WarplyBoxAnalysisEventModel;
27 import ly.warp.sdk.io.models.WarplyCCMSEnabledModel; 27 import ly.warp.sdk.io.models.WarplyCCMSEnabledModel;
28 import ly.warp.sdk.io.models.WarplyCouponsChangedEventModel; 28 import ly.warp.sdk.io.models.WarplyCouponsChangedEventModel;
29 import ly.warp.sdk.io.models.WarplyDealsAnalysisEventModel; 29 import ly.warp.sdk.io.models.WarplyDealsAnalysisEventModel;
30 +import ly.warp.sdk.io.models.WarplyHealthEventModel;
30 import ly.warp.sdk.io.models.WarplyNavigateBackEventModel; 31 import ly.warp.sdk.io.models.WarplyNavigateBackEventModel;
31 import ly.warp.sdk.io.models.WarplyPacingCardEventModel; 32 import ly.warp.sdk.io.models.WarplyPacingCardEventModel;
32 import ly.warp.sdk.io.models.WarplyPacingCardServiceEnabledModel; 33 import ly.warp.sdk.io.models.WarplyPacingCardServiceEnabledModel;
...@@ -51,6 +52,7 @@ public class WarplyEventBusManager { ...@@ -51,6 +52,7 @@ public class WarplyEventBusManager {
51 private WarplyCCMSEnabledModel ccmsActivated; 52 private WarplyCCMSEnabledModel ccmsActivated;
52 private LoyaltyGiftsForYouOfferClickEvent giftsYou; 53 private LoyaltyGiftsForYouOfferClickEvent giftsYou;
53 private QuestionnaireEventModel questionnaire; 54 private QuestionnaireEventModel questionnaire;
55 + private WarplyHealthEventModel health;
54 private OpenMyRewardsEventModel openRewards; 56 private OpenMyRewardsEventModel openRewards;
55 private RewardsCouponsEventModel rewardsCoupons; 57 private RewardsCouponsEventModel rewardsCoupons;
56 private VouchersActivityEventModel vouchersActivity; 58 private VouchersActivityEventModel vouchersActivity;
...@@ -91,6 +93,10 @@ public class WarplyEventBusManager { ...@@ -91,6 +93,10 @@ public class WarplyEventBusManager {
91 this.questionnaire = questionnaire; 93 this.questionnaire = questionnaire;
92 } 94 }
93 95
96 + public WarplyEventBusManager(WarplyHealthEventModel health) {
97 + this.health = health;
98 + }
99 +
94 public WarplyEventBusManager(OpenMyRewardsEventModel openRewards) { 100 public WarplyEventBusManager(OpenMyRewardsEventModel openRewards) {
95 this.openRewards = openRewards; 101 this.openRewards = openRewards;
96 } 102 }
...@@ -276,6 +282,10 @@ public class WarplyEventBusManager { ...@@ -276,6 +282,10 @@ public class WarplyEventBusManager {
276 return questionnaire; 282 return questionnaire;
277 } 283 }
278 284
285 + public WarplyHealthEventModel getHealth() {
286 + return health;
287 + }
288 +
279 public VouchersActivityEventModel getVouchersActivity() { 289 public VouchersActivityEventModel getVouchersActivity() {
280 return vouchersActivity; 290 return vouchersActivity;
281 } 291 }
......
...@@ -103,6 +103,7 @@ import ly.warp.sdk.io.models.RefreshVouchersEventModel; ...@@ -103,6 +103,7 @@ import ly.warp.sdk.io.models.RefreshVouchersEventModel;
103 import ly.warp.sdk.io.models.UnifiedCoupon; 103 import ly.warp.sdk.io.models.UnifiedCoupon;
104 import ly.warp.sdk.io.models.WarplyCCMSEnabledModel; 104 import ly.warp.sdk.io.models.WarplyCCMSEnabledModel;
105 import ly.warp.sdk.io.models.WarplyCouponsChangedEventModel; 105 import ly.warp.sdk.io.models.WarplyCouponsChangedEventModel;
106 +import ly.warp.sdk.io.models.WarplyHealthEventModel;
106 import ly.warp.sdk.io.models.WarplyPacingCardEventModel; 107 import ly.warp.sdk.io.models.WarplyPacingCardEventModel;
107 import ly.warp.sdk.io.models.WarplyPacingEventModel; 108 import ly.warp.sdk.io.models.WarplyPacingEventModel;
108 import ly.warp.sdk.io.models.WarplyUnifiedActivatedEventModel; 109 import ly.warp.sdk.io.models.WarplyUnifiedActivatedEventModel;
...@@ -543,29 +544,37 @@ public class WarpView extends WebView implements DefaultLifecycleObserver { ...@@ -543,29 +544,37 @@ public class WarpView extends WebView implements DefaultLifecycleObserver {
543 pacingWidgetVisible.setVisible(true); 544 pacingWidgetVisible.setVisible(true);
544 EventBus.getDefault().post(new WarplyEventBusManager(pacingWidgetVisible)); 545 EventBus.getDefault().post(new WarplyEventBusManager(pacingWidgetVisible));
545 } else if (parts[1].equals("steps") && parts[2].equals("shortcutEnabled")) { // This is for the pacing service 546 } else if (parts[1].equals("steps") && parts[2].equals("shortcutEnabled")) { // This is for the pacing service
546 - if (!isMyServiceRunning(WarplyHealthService.class)) { 547 +// if (!isMyServiceRunning(WarplyHealthService.class)) {
547 - LoyaltySDKFirebaseEventModel analyticsEvent = new LoyaltySDKFirebaseEventModel(); 548 +// LoyaltySDKFirebaseEventModel analyticsEvent = new LoyaltySDKFirebaseEventModel();
548 - analyticsEvent.setEventName("loyalty_steps_activation"); 549 +// analyticsEvent.setEventName("loyalty_steps_activation");
549 - EventBus.getDefault().post(new WarplyEventBusManager(analyticsEvent)); 550 +// EventBus.getDefault().post(new WarplyEventBusManager(analyticsEvent));
550 - 551 +//
551 - Intent stepsServiceIntent = new Intent(Warply.getWarplyContext(), WarplyHealthService.class); 552 +// Intent stepsServiceIntent = new Intent(Warply.getWarplyContext(), WarplyHealthService.class);
552 - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { 553 +// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
553 - Warply.getWarplyContext().startForegroundService(stepsServiceIntent); 554 +// Warply.getWarplyContext().startForegroundService(stepsServiceIntent);
554 - } else { 555 +// } else {
555 - Warply.getWarplyContext().startService(stepsServiceIntent); 556 +// Warply.getWarplyContext().startService(stepsServiceIntent);
556 - } 557 +// }
557 - 558 +//
558 - WarplyPacingEventModel pacingVisible = new WarplyPacingEventModel(); 559 +// WarplyPacingEventModel pacingVisible = new WarplyPacingEventModel();
559 - pacingVisible.setVisible(true); 560 +// pacingVisible.setVisible(true);
560 - EventBus.getDefault().post(new WarplyEventBusManager(pacingVisible)); 561 +// EventBus.getDefault().post(new WarplyEventBusManager(pacingVisible));
561 - } 562 +// }
563 +
564 + WarplyHealthEventModel healthActive = new WarplyHealthEventModel();
565 + healthActive.setActivated(true);
566 + EventBus.getDefault().post(new WarplyEventBusManager(healthActive));
562 } else if (parts[1].equals("steps") && parts[2].equals("shortcutDisabled")) { // This is for the pacing service 567 } else if (parts[1].equals("steps") && parts[2].equals("shortcutDisabled")) { // This is for the pacing service
563 - Intent stepsServiceIntent = new Intent(Warply.getWarplyContext(), WarplyHealthService.class); 568 +// Intent stepsServiceIntent = new Intent(Warply.getWarplyContext(), WarplyHealthService.class);
564 - Warply.getWarplyContext().stopService(stepsServiceIntent); 569 +// Warply.getWarplyContext().stopService(stepsServiceIntent);
565 - 570 +//
566 - WarplyPacingEventModel pacingVisible = new WarplyPacingEventModel(); 571 +// WarplyPacingEventModel pacingVisible = new WarplyPacingEventModel();
567 - pacingVisible.setVisible(false); 572 +// pacingVisible.setVisible(false);
568 - EventBus.getDefault().post(new WarplyEventBusManager(pacingVisible)); 573 +// EventBus.getDefault().post(new WarplyEventBusManager(pacingVisible));
574 +
575 + WarplyHealthEventModel healthActive = new WarplyHealthEventModel();
576 + healthActive.setActivated(false);
577 + EventBus.getDefault().post(new WarplyEventBusManager(healthActive));
569 } else if (parts[1].equals("request") || parts[1].equals("response")) { 578 } else if (parts[1].equals("request") || parts[1].equals("response")) {
570 WarpUtils.log("**************** WARPLY Webview Log START *****************"); 579 WarpUtils.log("**************** WARPLY Webview Log START *****************");
571 WarpUtils.log(message); 580 WarpUtils.log(message);
......