正在查看: Namma Yatri v3.3.7 应用的 LocationUpdateServiceV2.java JAVA 源代码文件
本页面展示 JAVA 反编译生成的源代码文件,支持语法高亮显示。 仅供安全研究与技术分析使用,严禁用于任何非法用途。请遵守相关法律法规。
正在查看: Namma Yatri v3.3.7 应用的 LocationUpdateServiceV2.java JAVA 源代码文件
本页面展示 JAVA 反编译生成的源代码文件,支持语法高亮显示。 仅供安全研究与技术分析使用,严禁用于任何非法用途。请遵守相关法律法规。
package in.juspay.mobility.app;
import android.app.AlarmManager;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.BitmapFactory;
import android.location.Location;
import android.location.LocationManager;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
import androidx.core.app.m;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationResult;
import com.google.android.gms.tasks.CancellationTokenSource;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.firebase.analytics.FirebaseAnalytics;
import com.google.firebase.crashlytics.FirebaseCrashlytics;
import in.juspay.hypersdk.data.KeyValueStore;
import in.juspay.mobility.app.LocationUpdateServiceV2;
import in.juspay.mobility.app.MyFirebaseMessagingService;
import in.juspay.mobility.app.RemoteConfigs.MobilityRemoteConfigs;
import in.juspay.mobility.common.MobilityCommonBridge;
import in.juspay.mobility.common.services.MobilityAPIResponse;
import in.juspay.mobility.common.services.MobilityCallAPI;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Queue;
import java.util.TimeZone;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.ReentrantLock;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
public class LocationUpdateServiceV2 extends Service {
private static final String CONFIG_WAKE_LOCK = "location_service_wake_lock_config";
private static final String DEFAULT_WAKE_LOCK_CONFIG = "{\"enabled\":false,\"timeout_ms\":30000}";
private static final String DRIVER_MIN_DISPLACEMENT = "DRIVER_MIN_DISPLACEMENT";
private static final String LAST_BATCH_SENT_TIME = "LAST_BATCH_SENT_TIME";
private static final String LAST_LOCATION_FETCH_TIME = "LAST_LOCATION_FETCH_TIME";
private static final String LAST_LOCATION_TIME = "LAST_LOCATION_TIME";
private static final String LOCATION_BATCH_INTERVAL = "LOCATION_BATCH_INTERVAL";
private static final String LOCATION_BATCH_SIZE = "LOCATION_BATCH_SIZE";
private static final String LOCATION_CACHED_BATCH = "LOCATION_CACHED_BATCH";
private static final String LOCATION_CACHE_FILE = "location_cache.json";
private static final String LOCATION_FRESHNESS_THRESHOLD = "LOCATION_FRESHNESS_THRESHOLD";
private static final String LOCATION_MAX_BATCH_AGE_KEY = "LOCATION_MAX_BATCH_AGE";
private static final String LOCATION_MAX_BATCH_SIZE_KEY = "LOCATION_MAX_BATCH_SIZE";
private static final String LOCATION_MAX_TIME_THRESHOLD = "LOCATION_MAX_TIME_THRESHOLD";
private static final String LOCATION_PRIORITY = "LOCATION_PRIORITY";
private static final String LOCATION_RATE_LIMIT_SECONDS = "LOCATION_RATE_LIMIT_SECONDS";
private static final String LOCATION_REQUEST_INTERVAL = "LOCATION_REQUEST_INTERVAL";
private static final String LOCATION_SERVICE_VERSION = "LOCATION_SERVICE_VERSION";
private static final String LOCATION_UPDATE_INTERVAL = "LOCATION_UPDATE_INTERVAL";
private static final int MSG_BATCH_PROCESS = 2;
private static final int MSG_CACHE_FLUSH = 3;
private static final int MSG_LOCATION_UPDATE = 1;
private static final String REGISTRATION_TOKEN_KEY = "REGISTERATION_TOKEN";
private static final String TAG = "LocSvc";
private static final String TAG_API = "LocSvc:API";
private static final String TAG_BATCH = "LocSvc:Batch";
private static final String TAG_CACHE = "LocSvc:Cache";
private static final String TAG_CONFIG = "LocSvc:Config";
private static final String TAG_ERROR = "LocSvc:Error";
private static final String TAG_JSON = "LocSvc:JSON";
private static final String TAG_LOCATION = "LocSvc:Location";
private static final String TAG_TIMER = "LocSvc:Timer";
private ScheduledExecutorService batchScheduler;
private LocalBinder binder;
CancellationTokenSource cancellationTokenSource;
private ConnectivityManager connectivityManager;
private Context context;
private String drMode;
private com.google.android.gms.location.e fusedLocationProviderClient;
private Object hyperServices;
private ExecutorService internetCheckExecutor;
private Location lastCachedLocation;
private double lastLatitudeValue;
private double lastLongitudeValue;
private com.google.android.gms.location.i locationCallback;
public ReactLocationEmitter locationEmitter;
private ScheduledExecutorService locationHeartbeatScheduler;
private String merchantID;
private MessageQueue messageQueue;
private ConnectivityManager.NetworkCallback networkCallback;
private PowerManager powerManager;
private SharedPreferences.OnSharedPreferenceChangeListener prefChangeListener;
MobilityRemoteConfigs remoteConfigs;
private SharedPreferences sharedPrefs;
private String vVariant;
private static final ArrayList<UpdateTimeCallback> updateTimeCallbacks = new ArrayList<>();
public static boolean isLocationUpdating = false;
final int notificationServiceId = 15082022;
final int alertNotificationId = 7102022;
private final String LOCATION_UPDATES = "LOCATION_UPDATES";
private final ReentrantLock batchProcessingLock = new ReentrantLock();
private final AtomicBoolean isBatchProcessing = new AtomicBoolean(false);
private final AtomicBoolean isFlushInProgress = new AtomicBoolean(false);
private final AtomicBoolean isCheckingInternet = new AtomicBoolean(false);
private final AtomicBoolean isLocationRequestInProgress = new AtomicBoolean(false);
private int locationUpdateInterval = 10;
private int locationBatchInterval = 10;
private float locationMinDisplacement = 25.0f;
private int locationBatchSize = 20;
private int locationMaxBatchSize = 100;
private String driverRideStatus = "IDLE";
private String driverId = "empty";
private boolean isSpecialpickup = false;
private int locationFreshnessThresholdMinutes = 5;
private int locationRequestInterval = 10;
private int locationMaxTimeThreshold = 4;
private int locationPriority = 100;
private int locationMaxBatchAgeSeconds = 10;
private boolean useWakeLock = false;
private long wakeLockTimeoutMs = 30000;
private long rateLimitTimeInSeconds = 2;
public class AnonymousClass1 extends ConnectivityManager.NetworkCallback {
public AnonymousClass1() {
}
public void lambda$onAvailable$0() {
LocationUpdateServiceV2.this.isCheckingInternet.set(false);
if (LocationUpdateServiceV2.this.messageQueue != null) {
LocationUpdateServiceV2.this.messageQueue.triggerBatchProcess();
}
if (!MobilityCommonBridge.isServiceRunning(LocationUpdateServiceV2.this.context, GRPCNotificationService.class.getName())) {
Log.i(LocationUpdateServiceV2.TAG, "Starting GRPC service");
LocationUpdateServiceV2.this.context.startService(new Intent(LocationUpdateServiceV2.this.context, (Class<?>) GRPCNotificationService.class));
}
LocationUpdateServiceV2.this.startLocationUpdates();
LocationUpdateServiceV2.this.startLocationHeartbeatTimer();
LocationUpdateServiceV2.this.startBatchScheduler();
}
public void lambda$onAvailable$1() {
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public final void run() {
LocationUpdateServiceV2.AnonymousClass1.this.lambda$onAvailable$0();
}
});
}
@Override
public void onAvailable(Network network) {
if (LocationUpdateServiceV2.this.isCheckingInternet.getAndSet(true)) {
Log.d(LocationUpdateServiceV2.TAG, "Internet check already in progress, skipping");
} else {
LocationUpdateServiceV2.this.checkInternetAccess(network, new OnNetworkAvailable() {
@Override
public final void onSuccess() {
LocationUpdateServiceV2.AnonymousClass1.this.lambda$onAvailable$1();
}
});
Log.i(LocationUpdateServiceV2.TAG, "Network connectivity available");
}
}
@Override
public void onLost(Network network) {
Log.d("NetworkCallback", "No internet connection");
LocationUpdateServiceV2.this.stopLocationUpdates();
LocationUpdateServiceV2.this.stopLocationHeartbeatTimer();
LocationUpdateServiceV2.this.stopBatchScheduler();
}
@Override
public void onUnavailable() {
Log.d("NetworkCallback", "No network available");
LocationUpdateServiceV2.this.stopLocationUpdates();
LocationUpdateServiceV2.this.stopLocationHeartbeatTimer();
LocationUpdateServiceV2.this.stopBatchScheduler();
}
}
public class LocalBinder extends Binder {
public LocalBinder() {
}
public LocationUpdateServiceV2 getService() {
return LocationUpdateServiceV2.this;
}
}
public class MessageQueue {
private final Handler handler;
private final Queue<LocationData> queue = new ConcurrentLinkedQueue();
private final ExecutorService executor = Executors.newSingleThreadScheduledExecutor();
private final ExecutorService flushBatchExecutor = Executors.newSingleThreadScheduledExecutor();
public class AnonymousClass1 extends Handler {
final LocationUpdateServiceV2 val$this$0;
public AnonymousClass1(Looper looper, LocationUpdateServiceV2 locationUpdateServiceV2) {
super(looper);
this.val$this$0 = locationUpdateServiceV2;
}
public void lambda$handleMessage$0() {
MessageQueue.this.saveQueueToCache();
}
public void lambda$handleMessage$1() {
MessageQueue.this.saveQueueToCache();
}
@Override
public void handleMessage(Message message) {
int i = message.what;
if (i != 1) {
if (i == 2) {
MessageQueue.this.processBatch();
return;
} else {
if (i != 3) {
return;
}
MessageQueue.this.executor.execute(new Runnable() {
@Override
public final void run() {
LocationUpdateServiceV2.MessageQueue.AnonymousClass1.this.lambda$handleMessage$1();
}
});
return;
}
}
LocationData locationData = (LocationData) message.obj;
MessageQueue.this.queue.add(locationData);
MessageQueue.this.executor.execute(new Runnable() {
@Override
public final void run() {
LocationUpdateServiceV2.MessageQueue.AnonymousClass1.this.lambda$handleMessage$0();
}
});
MessageQueue messageQueue = MessageQueue.this;
if (LocationUpdateServiceV2.this.locationEmitter != null) {
String buildLocationEmitterPayload = messageQueue.buildLocationEmitterPayload(locationData);
LocationUpdateServiceV2.this.emitReactEvent(buildLocationEmitterPayload);
Log.i(LocationUpdateServiceV2.TAG_LOCATION, "Emitted locationPayload " + buildLocationEmitterPayload);
}
boolean shouldSendBatchDueToTime = MessageQueue.this.shouldSendBatchDueToTime();
if (MessageQueue.this.queue.size() >= LocationUpdateServiceV2.this.locationBatchSize || shouldSendBatchDueToTime) {
LocationUpdateServiceV2 locationUpdateServiceV2 = LocationUpdateServiceV2.this;
if (locationUpdateServiceV2.isNetworkAvailable(locationUpdateServiceV2.context)) {
MessageQueue.this.processBatch();
}
}
}
}
public MessageQueue(Looper looper) {
this.handler = new AnonymousClass1(looper, LocationUpdateServiceV2.this);
}
public String buildLocationEmitterPayload(LocationData locationData) {
try {
return locationData.toJsonObject().toString();
} catch (JSONException e) {
Log.e(LocationUpdateServiceV2.TAG_ERROR, "Can't convert LocationData to JSON: " + e);
return "";
}
}
private List<LocationData> convertJsonArrayToLocationList(JSONArray jSONArray) {
ArrayList arrayList = new ArrayList();
for (int i = 0; i < jSONArray.length(); i++) {
try {
arrayList.add(LocationData.fromJsonObject(jSONArray.getJSONObject(i)));
} catch (JSONException e) {
Log.e(LocationUpdateServiceV2.TAG_JSON, "Error deserializing location data at index " + i, e);
}
}
return arrayList;
}
public void flushToBackend(final int i) {
this.flushBatchExecutor.execute(new Runnable() {
@Override
public final void run() {
LocationUpdateServiceV2.MessageQueue.this.lambda$flushToBackend$1(i);
}
});
}
public static int lambda$addAll$0(LocationData locationData, LocationData locationData2) {
return (int) (locationData.timestamp - locationData2.timestamp);
}
public void lambda$flushToBackend$1(int i) {
List<LocationData> subList;
LocationUpdateServiceV2.this.isFlushInProgress.set(true);
try {
try {
List<LocationData> drainBatch = LocationUpdateServiceV2.this.messageQueue.drainBatch(i);
while (!drainBatch.isEmpty()) {
int min = Math.min(LocationUpdateServiceV2.this.locationMaxBatchSize, drainBatch.size());
try {
try {
List<LocationData> subList2 = drainBatch.subList(0, min);
JSONArray jSONArray = new JSONArray();
Iterator<LocationData> it = subList2.iterator();
while (it.hasNext()) {
jSONArray.put(it.next().toJsonObject());
}
Log.i(LocationUpdateServiceV2.TAG_BATCH, "Sending batch of " + subList2.size() + " locations to server");
MobilityCallAPI mobilityCallAPI = MobilityCallAPI.getInstance(LocationUpdateServiceV2.this.context);
Map<String, String> baseHeaders = MobilityCallAPI.getBaseHeaders(LocationUpdateServiceV2.this.context);
String str = LocationUpdateServiceV2.this.context.getSharedPreferences(LocationUpdateServiceV2.this.context.getString(R.string.preference_file_key), 0).getString("BASE_URL", "null") + "/driver/location";
baseHeaders.put("source", "batch_location_update");
LocationUpdateServiceV2.this.setVehicleAndMerchantHeaders(baseHeaders);
Log.i(LocationUpdateServiceV2.TAG_API, "Sending batch of " + subList2.size() + " locations to server with body | " + jSONArray);
MobilityAPIResponse callAPI = mobilityCallAPI.callAPI(str, baseHeaders, jSONArray.toString());
StringBuilder sb2 = new StringBuilder();
sb2.append("Flush to Backend response code ");
sb2.append(callAPI.getStatusCode());
Log.i(LocationUpdateServiceV2.TAG_API, sb2.toString());
Log.i(LocationUpdateServiceV2.TAG_API, "Flush to Backend response body " + callAPI.getResponseBody());
subList = drainBatch.subList(0, min);
} catch (Exception e) {
Log.e(LocationUpdateServiceV2.TAG_ERROR, "Error preparing batch ", e);
FirebaseCrashlytics.getInstance().recordException(e);
subList = drainBatch.subList(0, min);
}
subList.clear();
} finally {
drainBatch.subList(0, min).clear();
}
}
LocationUpdateServiceV2.this.isFlushInProgress.set(false);
} catch (Exception e2) {
Log.e(LocationUpdateServiceV2.TAG_API, "Error flushing batch " + e2);
}
} finally {
LocationUpdateServiceV2.this.isFlushInProgress.set(false);
}
}
public void processBatch() {
throw new UnsupportedOperationException("Method not decompiled: in.juspay.mobility.app.LocationUpdateServiceV2.MessageQueue.processBatch():void");
}
private void saveLocationsToFile(JSONArray jSONArray) {
try {
FileWriter fileWriter = new FileWriter(new File(LocationUpdateServiceV2.this.context.getFilesDir(), LocationUpdateServiceV2.LOCATION_CACHE_FILE));
fileWriter.write(jSONArray.toString());
fileWriter.close();
Log.d(LocationUpdateServiceV2.TAG_CACHE, "Saved " + jSONArray.length() + " locations to file");
} catch (IOException e) {
Log.e(LocationUpdateServiceV2.TAG_ERROR, "Failed to save locations to file", e);
}
}
public void saveQueueToCache() {
try {
ArrayList arrayList = new ArrayList(this.queue);
JSONArray jSONArray = new JSONArray();
Iterator it = arrayList.iterator();
while (it.hasNext()) {
try {
jSONArray.put(((LocationData) it.next()).toJsonObject());
} catch (JSONException e) {
Log.e(LocationUpdateServiceV2.TAG_JSON, "Error serializing location data", e);
}
}
LocationUpdateServiceV2.this.updateStorage(LocationUpdateServiceV2.LOCATION_CACHED_BATCH, jSONArray.toString());
saveLocationsToFile(jSONArray);
Log.d(LocationUpdateServiceV2.TAG_CACHE, "Saved " + arrayList.size() + " locations to cache");
} catch (Exception e2) {
Log.e(LocationUpdateServiceV2.TAG_ERROR, "Failed to save queue to cache", e2);
FirebaseCrashlytics.getInstance().recordException(e2);
}
}
public boolean shouldSendBatchDueToTime() {
if (this.queue.isEmpty()) {
return false;
}
String valueFromStorage = LocationUpdateServiceV2.this.getValueFromStorage(LocationUpdateServiceV2.LAST_BATCH_SENT_TIME);
if (valueFromStorage == null) {
LocationUpdateServiceV2.this.updateStorage(LocationUpdateServiceV2.LAST_BATCH_SENT_TIME, String.valueOf(System.currentTimeMillis()));
return false;
}
long seconds = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis() - Long.parseLong(valueFromStorage));
boolean z = seconds < 0 || seconds >= ((long) LocationUpdateServiceV2.this.locationMaxBatchAgeSeconds);
if (z) {
Log.d(LocationUpdateServiceV2.TAG_BATCH, "Batch age: " + seconds + "s exceeds max age: " + LocationUpdateServiceV2.this.locationMaxBatchAgeSeconds + "s, triggering send");
}
return z;
}
public void addAll(List<LocationData> list) {
ArrayList arrayList = new ArrayList(this.queue);
arrayList.addAll(list);
arrayList.sort(new Comparator() {
@Override
public final int compare(Object obj, Object obj2) {
int lambda$addAll$0;
lambda$addAll$0 = LocationUpdateServiceV2.MessageQueue.lambda$addAll$0((LocationUpdateServiceV2.LocationData) obj, (LocationUpdateServiceV2.LocationData) obj2);
return lambda$addAll$0;
}
});
this.queue.clear();
this.queue.addAll(arrayList);
this.executor.execute(new Runnable() {
@Override
public final void run() {
LocationUpdateServiceV2.MessageQueue.this.saveQueueToCache();
}
});
}
public List<LocationData> drainBatch(int i) {
ArrayList arrayList = new ArrayList();
int min = Math.min(this.queue.size(), i);
for (int i2 = 0; i2 < min; i2++) {
LocationData poll = this.queue.poll();
if (poll != null) {
arrayList.add(poll);
}
}
return arrayList;
}
public void enqueueLocation(LocationData locationData) {
this.handler.sendMessage(this.handler.obtainMessage(1, locationData));
}
public void flushCache() {
this.handler.sendEmptyMessage(3);
}
public void restoreFromCache() {
String valueFromStorage = LocationUpdateServiceV2.this.getValueFromStorage(LocationUpdateServiceV2.LOCATION_CACHED_BATCH);
if (valueFromStorage != null && !valueFromStorage.isEmpty()) {
try {
List<LocationData> convertJsonArrayToLocationList = convertJsonArrayToLocationList(new JSONArray(valueFromStorage));
if (!convertJsonArrayToLocationList.isEmpty()) {
this.queue.addAll(convertJsonArrayToLocationList);
Log.i(LocationUpdateServiceV2.TAG_CACHE, "Restored " + convertJsonArrayToLocationList.size() + " locations from SharedPreferences");
return;
}
} catch (Exception e) {
Log.e(LocationUpdateServiceV2.TAG_ERROR, "Failed to restore from SharedPreferences", e);
}
}
try {
File file = new File(LocationUpdateServiceV2.this.context.getFilesDir(), LocationUpdateServiceV2.LOCATION_CACHE_FILE);
if (file.exists()) {
BufferedReader bufferedReader = new BufferedReader(new FileReader(file));
StringBuilder sb2 = new StringBuilder();
while (true) {
String readLine = bufferedReader.readLine();
if (readLine == null) {
break;
} else {
sb2.append(readLine);
}
}
bufferedReader.close();
List<LocationData> convertJsonArrayToLocationList2 = convertJsonArrayToLocationList(new JSONArray(sb2.toString()));
if (convertJsonArrayToLocationList2.isEmpty()) {
return;
}
this.queue.addAll(convertJsonArrayToLocationList2);
Log.i(LocationUpdateServiceV2.TAG_CACHE, "Restored " + convertJsonArrayToLocationList2.size() + " locations from file");
}
} catch (Exception e2) {
Log.e(LocationUpdateServiceV2.TAG_ERROR, "Failed to restore from file", e2);
}
}
public int size() {
return this.queue.size();
}
public void triggerBatchProcess() {
this.handler.sendEmptyMessage(2);
}
}
public interface OnNetworkAvailable {
void onSuccess();
}
public interface ReactLocationEmitter {
void emitter(String str);
}
public interface UpdateTimeCallback {
void triggerUpdateTimeCallBack(String str, String str2, String str3, String str4);
}
private PowerManager.WakeLock acquireTemporaryWakeLock(String str, long j) {
PowerManager powerManager;
Log.d(TAG, "acquireTemporaryWakeLock() called with tag=" + str + ", timeoutMs=" + j);
if (!this.useWakeLock || (powerManager = this.powerManager) == null) {
return null;
}
PowerManager.WakeLock newWakeLock = powerManager.newWakeLock(1, "LocationUpdateService::" + str);
newWakeLock.acquire(j > 0 ? j : this.wakeLockTimeoutMs);
StringBuilder sb2 = new StringBuilder();
sb2.append("Acquired temporary wake lock: ");
sb2.append(str);
sb2.append(" for ");
if (j <= 0) {
j = this.wakeLockTimeoutMs;
}
sb2.append(j);
sb2.append("ms");
Log.d(TAG, sb2.toString());
Log.d(TAG, "acquireTemporaryWakeLock() complete");
return newWakeLock;
}
public void checkAndSendLocationHeartbeat() {
Log.d(TAG_TIMER, "checkAndSendLocationHeartbeat() called");
try {
Log.d(TAG_TIMER, "Location heartbeat triggered");
} catch (Exception e) {
Log.e(TAG_ERROR, "Error in location heartbeat", e);
FirebaseCrashlytics.getInstance().recordException(e);
}
if (handleDemoMode()) {
return;
}
if (isLocationStale()) {
Log.d(TAG_TIMER, "Current location is stale, fetching new location");
fetchFreshLocation();
} else if (this.lastCachedLocation != null) {
Log.d(TAG_TIMER, "Sending cached location: lat=" + this.lastCachedLocation.getLatitude() + ", lng=" + this.lastCachedLocation.getLongitude());
Location location = new Location(this.lastCachedLocation);
location.setTime(System.currentTimeMillis());
if (this.messageQueue != null) {
this.messageQueue.enqueueLocation(new LocationData(location, "location_heartbeat"));
} else {
Log.e(TAG_ERROR, "MessageQueue is null, cannot enqueue heartbeat location");
}
} else {
Log.d(TAG_TIMER, "No cached location available, fetching new location");
fetchFreshLocation();
}
Log.d(TAG_TIMER, "checkAndSendLocationHeartbeat() complete");
}
private void checkForTokenIssues(String str) {
String string;
Log.d(TAG, "checkForTokenIssues() called");
if (str == null) {
Log.e(TAG_ERROR, "Response body is null in checkForTokenIssues");
return;
}
try {
if (str.trim().isEmpty()) {
str = "{}";
}
JSONObject jSONObject = new JSONObject(str);
if (jSONObject.has("errorCode") && (string = jSONObject.getString("errorCode")) != null && (string.equals("INVALID_TOKEN") || string.equals("TOKEN_EXPIRED"))) {
Log.w(TAG_API, "Invalid token detected: " + string);
updateStorage(REGISTRATION_TOKEN_KEY, "__failed");
stopWidgetService();
stopSelf();
}
} catch (JSONException e) {
Log.e(TAG_ERROR, "Error checking for token issues", e);
}
Log.d(TAG, "checkForTokenIssues() complete");
}
public void checkInternetAccess(final Network network, final OnNetworkAvailable onNetworkAvailable) {
ExecutorService executorService = this.internetCheckExecutor;
if (executorService == null || executorService.isShutdown()) {
return;
}
this.internetCheckExecutor.execute(new Runnable() {
@Override
public final void run() {
LocationUpdateServiceV2.lambda$checkInternetAccess$0(network, onNetworkAvailable);
}
});
}
private void checkNearByPickupZone(Location location) {
SharedPreferences sharedPreferences;
String valueFromStorage;
String valueFromStorage2;
String string;
StringBuilder sb2 = new StringBuilder();
sb2.append("checkNearByPickupZone() called for lat=");
sb2.append(location != null ? Double.valueOf(location.getLatitude()) : "null");
sb2.append(", lon=");
sb2.append(location != null ? Double.valueOf(location.getLongitude()) : "null");
Log.d(TAG, sb2.toString());
try {
Context context = this.context;
sharedPreferences = context.getSharedPreferences(context.getString(R.string.preference_file_key), 0);
valueFromStorage = getValueFromStorage("IS_RIDE_ACTIVE");
valueFromStorage2 = getValueFromStorage("ENABLE_SPECIAL_PICKUP_WIDGET");
} catch (Exception e) {
Log.e(TAG_ERROR, "Error checking nearby pickup zone", e);
FirebaseCrashlytics.getInstance().recordException(e);
}
if (location == null || valueFromStorage == null || valueFromStorage2 == null || !valueFromStorage.equals("false") || !valueFromStorage2.equals("true") || (string = sharedPreferences.getString("SPECIAL_LOCATION_LIST", null)) == null) {
return;
}
JSONArray jSONArray = new JSONArray(string);
GeoHash geoHash = new GeoHash();
String encode = geoHash.encode(location.getLatitude(), location.getLongitude(), 7);
ArrayList<String> nearbyGeohashes = geoHash.nearbyGeohashes(encode, Double.parseDouble(sharedPreferences.getString("SEARCH_SPECIAL_PICKUP_WITHIN_RADIUS", "150.0")));
nearbyGeohashes.add(encode);
String valueFromStorage3 = getValueFromStorage("CURRENT_ZONE_GEO_HASH");
if (valueFromStorage3 == null) {
updateStorage("CURRENT_ZONE_GEO_HASH", encode);
valueFromStorage3 = encode;
}
int i = 0;
boolean z = false;
while (true) {
if (i >= jSONArray.length()) {
break;
}
String str = (String) ((JSONArray) jSONArray.get(i)).get(0);
boolean contains = nearbyGeohashes.contains(str);
if (!valueFromStorage3.equals(str) && contains) {
this.isSpecialpickup = true;
showWidget(true);
updateStorage("CURRENT_ZONE_GEO_HASH", str);
valueFromStorage3 = str;
}
if (contains) {
this.isSpecialpickup = true;
z = contains;
break;
} else {
i++;
z = contains;
}
}
if (!z && this.isSpecialpickup) {
this.isSpecialpickup = false;
updateStorage("CURRENT_ZONE_GEO_HASH", encode);
showWidget(false);
}
Log.d(TAG, "checkNearByPickupZone() complete");
}
private boolean checkRegistrationTokenExistence() {
Log.d(TAG, "checkRegistrationTokenExistence() called");
String string = this.sharedPrefs.getString(REGISTRATION_TOKEN_KEY, null);
return (string == null || string.equals("__failed") || string.equals("null")) ? false : true;
}
private void checkRegistrationTokenValidity() {
Log.d(TAG, "checkRegistrationTokenValidity() called");
String string = this.sharedPrefs.getString(REGISTRATION_TOKEN_KEY, null);
if (string == null || string.equals("__failed") || string.equals("null")) {
Log.w(TAG, "Registration token is invalid or missing on service start, stopping location service");
stopWidgetService();
stopSelf();
}
Log.d(TAG, "checkRegistrationTokenValidity() complete");
}
private Location createLocation(double d, double d2) {
Location location = new Location("demo_provider");
location.setLatitude(d);
location.setLongitude(d2);
location.setAccuracy(1.0f);
location.setTime(System.currentTimeMillis());
return location;
}
private LocationRequest createLocationRequest() {
int i = this.locationRequestInterval * 1000;
Log.d(TAG_CONFIG, String.format(Locale.US, "Creating location request: interval=%dms, minDisplacement=%.1fm, priority=%d, locationMaxTimeThreshold=%d", Integer.valueOf(i), Float.valueOf(this.locationMinDisplacement), Integer.valueOf(this.locationPriority), Integer.valueOf(this.locationMaxTimeThreshold)));
long j = i;
return new LocationRequest.a(j).d(j).i(i / 2).f(this.locationMaxTimeThreshold).h(this.locationMinDisplacement).k(this.driverRideStatus.equals("ON_RIDE")).j(this.locationPriority).a();
}
private Notification createNotification() {
Log.d(TAG, "createNotification() called");
createNotificationChannel();
return new m.e(this, "LOCATION_UPDATES").l("Updating").k(getString(R.string.your_location_is_being_updated)).x(Utils.getResIdentifier(this.context, Build.VERSION.SDK_INT >= 26 ? "ic_launcher_small_icon" : "ny_ic_launcher", "drawable")).u(-2).t(true).j(PendingIntent.getActivity(this, 10, getPackageManager().getLaunchIntentForPackage(this.context.getPackageName()), 67108864)).b();
}
private void createNotificationChannel() {
Log.d(TAG, "createNotificationChannel() called");
if (Build.VERSION.SDK_INT >= 26) {
NotificationChannel a = k3.k.a("LOCATION_UPDATES", "Location Updates", 1);
k3.w.a(a, "Location Update Service");
k3.x.a(a, "3_services");
k3.o.a((NotificationManager) getSystemService(NotificationManager.class), a);
}
Log.d(TAG, "createNotificationChannel() complete");
}
public static void deRegisterCallback(UpdateTimeCallback updateTimeCallback) {
updateTimeCallbacks.remove(updateTimeCallback);
}
private void enqueueDemoModeLocations() {
Location createLocation;
Log.d(TAG_LOCATION, "enqueueDemoModeLocations() called");
String string = this.sharedPrefs.getString("DEMO_MODE_PASSWORD", "null");
string.hashCode();
switch (string) {
case "1789234":
createLocation = createLocation(12.522069908884921d, 76.89518072273476d);
break;
case "7891567":
createLocation = createLocation(9.869715234892222d, 76.37632251438302d);
break;
case "7891678":
createLocation = createLocation(9.955097514840311d, 76.37173322025349d);
break;
case "7891788":
createLocation = createLocation(24.338294091147212d, 88.1949706368274d);
break;
case "7891789":
createLocation = createLocation(23.06194031948526d, 88.7637073215878d);
break;
case "8917234":
createLocation = createLocation(13.260559676317829d, 76.4785809882692d);
break;
case "9178234":
createLocation = createLocation(13.160550263780683d, 76.66727044721313d);
break;
default:
createLocation = createLocation(13.311895563147432d, 76.93981481869986d);
break;
}
this.lastCachedLocation = createLocation;
this.messageQueue.enqueueLocation(new LocationData(createLocation, "demo_mode"));
Log.d(TAG_LOCATION, "Enqueued demo mode locations");
Log.d(TAG_LOCATION, "enqueueDemoModeLocations() complete");
}
private void fetchFreshLocation() {
Log.d(TAG_TIMER, "fetchFreshLocation() called");
if (this.isLocationRequestInProgress.get()) {
Log.d(TAG_TIMER, "Location request already in progress, skipping new request");
return;
}
PowerManager.WakeLock acquireTemporaryWakeLock = acquireTemporaryWakeLock("FetchFreshLocation", this.wakeLockTimeoutMs);
try {
try {
} catch (Exception e) {
Log.e(TAG_ERROR, "Error fetching fresh location", e);
FirebaseCrashlytics.getInstance().recordException(e);
this.isLocationRequestInProgress.set(false);
Log.d(TAG_TIMER, "Manual location request failed with exception");
}
if (this.isLocationRequestInProgress.get()) {
Log.d(TAG_TIMER, "Location request already in progress, skipping new request");
return;
}
if (androidx.core.content.a.checkSelfPermission(this.context, "android.permission.ACCESS_FINE_LOCATION") != 0 && androidx.core.content.a.checkSelfPermission(this.context, "android.permission.ACCESS_COARSE_LOCATION") != 0) {
Log.e(TAG_ERROR, "No location permissions for manual location fetch");
return;
}
if (isLocationDisabled()) {
Log.e(TAG_ERROR, "Location is disabled for manual location fetch");
return;
}
this.isLocationRequestInProgress.set(true);
Log.d(TAG_TIMER, "Starting manual location request");
com.google.android.gms.location.e eVar = this.fusedLocationProviderClient;
if (eVar == null || this.cancellationTokenSource == null) {
Log.e(TAG_ERROR, "FusedLocationProviderClient or CancellationTokenSource is null");
this.isLocationRequestInProgress.set(false);
} else {
eVar.getCurrentLocation(Utils.getLocationPriority("driver_current_location_priority"), this.cancellationTokenSource.getToken()).addOnSuccessListener(new OnSuccessListener() {
public final void onSuccess(Object obj) {
LocationUpdateServiceV2.this.lambda$fetchFreshLocation$6((Location) obj);
}
}).addOnFailureListener(new OnFailureListener() {
public final void onFailure(Exception exc) {
LocationUpdateServiceV2.this.lambda$fetchFreshLocation$7(exc);
}
});
}
releaseWakeLockIfHeld(acquireTemporaryWakeLock);
Log.d(TAG_TIMER, "fetchFreshLocation() complete");
} finally {
releaseWakeLockIfHeld(acquireTemporaryWakeLock);
}
}
private void fetchProfileAndSetHeaders(Map<String, String> map) {
Log.d(TAG_API, "fetchProfileAndSetHeaders() called");
try {
MobilityCallAPI mobilityCallAPI = MobilityCallAPI.getInstance(this.context);
Context context = this.context;
JSONObject jSONObject = new JSONObject(mobilityCallAPI.callAPI(context.getSharedPreferences(context.getString(R.string.preference_file_key), 0).getString("BASE_URL", "null") + "/driver/profile", map, "{}", "GET").getResponseBody());
if (jSONObject.has("mode")) {
String upperCase = jSONObject.get("mode").toString().toUpperCase();
this.drMode = upperCase;
map.put("dm", upperCase);
}
JSONObject optJSONObject = jSONObject.optJSONObject("organization");
if (optJSONObject != null && optJSONObject.has("id")) {
String string = optJSONObject.getString("id");
this.merchantID = string;
map.put("mId", string);
updateStorage("MERCHANT_ID", this.merchantID);
}
JSONObject optJSONObject2 = jSONObject.optJSONObject("linkedVehicle");
if (optJSONObject2 != null && optJSONObject2.has("variant")) {
String string2 = optJSONObject2.getString("variant");
this.vVariant = string2;
map.put("vt", string2);
updateStorage("VEHICLE_VARIANT", this.vVariant);
}
} catch (Exception e) {
Log.e(TAG_ERROR, "Error fetching profile", e);
Bundle bundle = new Bundle();
bundle.putString("error", e.toString());
FirebaseAnalytics.getInstance(this.context).c("LS_ERROR_GETTING_PROFILE", bundle);
}
Log.d(TAG_API, "fetchProfileAndSetHeaders() complete");
}
public String getValueFromStorage(String str) {
Log.d(TAG_CONFIG, "getValueFromStorage() called for key=" + str);
return KeyValueStore.read(getApplicationContext(), getApplicationContext().getString(R.string.preference_file_key), str, null);
}
private void handleApiError(int i, String str, List<LocationData> list) {
Log.d(TAG_API, "handleApiError() called with respCode=" + i);
try {
if (i < 400 || i >= 500) {
Log.w(TAG_API, "Retryable error " + i + ", re-adding batch to queue");
this.messageQueue.addAll(list);
} else {
Log.e(TAG_API, "Non-retryable error " + i + ", discarding batch");
}
String optString = new JSONObject(str).optString("errorCode", "");
if (i == 403 && optString.equals("DRIVER_BLOCKED")) {
notifyDriverBlocked(optString);
}
} catch (Exception e) {
Log.e(TAG_ERROR, "Error parsing API response", e);
}
FirebaseCrashlytics.getInstance().recordException(new Exception("API Error in batch location update for ID: " + this.driverId + " $ Resp Code: " + i + " $ Error: " + str));
Log.d(TAG_API, "handleApiError() complete");
}
public void handleApiResponse(MobilityAPIResponse mobilityAPIResponse, List<LocationData> list) {
Log.d(TAG_API, "handleApiResponse() called with response code=" + mobilityAPIResponse.getStatusCode());
int statusCode = mobilityAPIResponse.getStatusCode();
String responseBody = mobilityAPIResponse.getResponseBody();
Log.d(TAG_API, "API response: code=" + statusCode + ", body=" + responseBody);
if ((statusCode < 200 || statusCode >= 300) && statusCode != 302) {
handleApiError(statusCode, responseBody, list);
} else {
Log.i(TAG_API, "Batch successfully sent to server");
notifyLocationUpdateSuccess();
}
checkForTokenIssues(responseBody);
this.isBatchProcessing.set(false);
Log.d(TAG_API, "handleApiResponse() complete");
}
public void handleLocationResult(LocationResult locationResult) {
Log.d(TAG_LOCATION, "handleLocationResult() called with " + locationResult.k0().size() + " locations");
List<Location> k0 = locationResult.k0();
if (k0.isEmpty()) {
FirebaseCrashlytics.getInstance().recordException(new Exception("Locations Empty callback"));
Log.d(TAG_LOCATION, "Received empty location result");
return;
}
Log.d(TAG_LOCATION, "Received " + k0.size() + " locations");
if (handleDemoMode()) {
return;
}
k0.sort(new Comparator() {
@Override
public final int compare(Object obj, Object obj2) {
int lambda$handleLocationResult$3;
lambda$handleLocationResult$3 = LocationUpdateServiceV2.lambda$handleLocationResult$3((Location) obj, (Location) obj2);
return lambda$handleLocationResult$3;
}
});
for (final Location location : k0) {
if (location != null) {
this.lastLatitudeValue = location.getLatitude();
this.lastLongitudeValue = location.getLongitude();
this.lastCachedLocation = location;
updateStorage(LAST_LOCATION_FETCH_TIME, String.valueOf(System.currentTimeMillis()));
updateLocationStorage(location);
new Thread(new Runnable() {
@Override
public final void run() {
LocationUpdateServiceV2.this.lambda$handleLocationResult$4(location);
}
}).start();
if (this.messageQueue != null) {
this.messageQueue.enqueueLocation(new LocationData(location, "fused_location_provider"));
} else {
Log.e(TAG_ERROR, "MessageQueue is null, cannot enqueue location");
}
checkNearByPickupZone(location);
}
}
Log.d(TAG_LOCATION, "handleLocationResult() complete");
}
private void initializeLocationComponents() {
if (this.fusedLocationProviderClient == null) {
this.fusedLocationProviderClient = com.google.android.gms.location.k.a(this);
}
if (this.cancellationTokenSource == null) {
this.cancellationTokenSource = new CancellationTokenSource();
}
Log.d(TAG, "Location components initialized");
}
private void initializeMessageQueue() {
if (this.messageQueue == null) {
this.messageQueue = new MessageQueue(Looper.getMainLooper());
}
Log.d(TAG, "Message queue initialized");
}
private boolean isLocationDisabled() {
Log.d(TAG, "isLocationDisabled() called");
LocationManager locationManager = (LocationManager) this.context.getSystemService("location");
return locationManager == null || !androidx.core.location.b.a(locationManager);
}
private boolean isLocationStale() {
boolean z;
Log.d(TAG_TIMER, "isLocationStale() called");
try {
String valueFromStorage = getValueFromStorage(LAST_LOCATION_FETCH_TIME);
if (valueFromStorage == null) {
return true;
}
long parseLong = Long.parseLong(valueFromStorage);
long currentTimeMillis = System.currentTimeMillis();
TimeUnit timeUnit = TimeUnit.MILLISECONDS;
long minutes = timeUnit.toMinutes(currentTimeMillis - parseLong);
long minutes2 = timeUnit.toMinutes(currentTimeMillis - this.lastCachedLocation.getTime());
if (minutes > 0 && minutes2 > 0) {
long j = this.locationFreshnessThresholdMinutes;
if (minutes < j && minutes2 < j) {
z = false;
Log.d(TAG_TIMER, "Location staleness check: elapsed=" + minutes + "m, threshold=" + this.locationFreshnessThresholdMinutes + "m, isStale=" + z);
return z;
}
}
z = true;
Log.d(TAG_TIMER, "Location staleness check: elapsed=" + minutes + "m, threshold=" + this.locationFreshnessThresholdMinutes + "m, isStale=" + z);
return z;
} catch (Exception e) {
Log.e(TAG_ERROR, "Error checking location staleness", e);
return true;
}
}
public boolean isNetworkAvailable(Context context) {
NetworkCapabilities networkCapabilities;
Log.d(TAG, "isNetworkAvailable() called");
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService("connectivity");
Network activeNetwork = connectivityManager.getActiveNetwork();
if (activeNetwork == null || (networkCapabilities = connectivityManager.getNetworkCapabilities(activeNetwork)) == null) {
return false;
}
return networkCapabilities.hasTransport(1) || networkCapabilities.hasTransport(0) || networkCapabilities.hasTransport(3);
}
public static void lambda$checkInternetAccess$0(Network network, OnNetworkAvailable onNetworkAvailable) {
try {
HttpURLConnection httpURLConnection = network == null ? (HttpURLConnection) new URL("https://clients3.google.com/generate_204").openConnection() : (HttpURLConnection) network.openConnection(new URL("https://clients3.google.com/generate_204"));
httpURLConnection.setConnectTimeout(3000);
httpURLConnection.setReadTimeout(3000);
httpURLConnection.connect();
if (httpURLConnection.getResponseCode() == 204) {
try {
onNetworkAvailable.onSuccess();
} catch (Exception e) {
Log.e(TAG_ERROR, "Error in network available callback", e);
FirebaseCrashlytics.getInstance().recordException(e);
}
}
} catch (IOException e2) {
Log.d("InternetCheck", "No actual internet: " + e2.getMessage());
}
}
public void lambda$fetchFreshLocation$6(Location location) {
try {
if (location != null) {
Log.d(TAG_TIMER, "Received fresh location: lat=" + location.getLatitude() + ", lng=" + location.getLongitude());
updateStorage(LAST_LOCATION_FETCH_TIME, String.valueOf(System.currentTimeMillis()));
this.lastCachedLocation = location;
updateLocationStorage(location);
if (this.messageQueue != null) {
this.messageQueue.enqueueLocation(new LocationData(location, "manual_fetch"));
}
} else {
FirebaseCrashlytics.getInstance().recordException(new Exception("Location Null"));
Log.e(TAG_TIMER, "Received null location from manual fetch");
}
this.isLocationRequestInProgress.set(false);
Log.d(TAG_TIMER, "Manual location request completed");
} catch (Throwable th) {
this.isLocationRequestInProgress.set(false);
Log.d(TAG_TIMER, "Manual location request completed");
throw th;
}
}
public void lambda$fetchFreshLocation$7(Exception exc) {
Log.e(TAG_ERROR, "Failed to get current location", exc);
FirebaseCrashlytics.getInstance().recordException(exc);
this.isLocationRequestInProgress.set(false);
Log.d(TAG_TIMER, "Manual location request failed");
}
public static int lambda$handleLocationResult$3(Location location, Location location2) {
TimeUnit timeUnit = TimeUnit.NANOSECONDS;
return (int) (timeUnit.toMillis(location.getElapsedRealtimeNanos()) - timeUnit.toMillis(location2.getElapsedRealtimeNanos()));
}
public void lambda$onStartCommand$2() {
initializeMessageQueue();
initializeLocationComponents();
setupPreferenceChangeListener();
setupInternetReceiver();
startBatchScheduler();
updateConfigVariables();
startLocationHeartbeatTimer();
if (!isLocationUpdating) {
startLocationUpdates();
}
if (!MobilityCommonBridge.isServiceRunning(this.context, GRPCNotificationService.class.getName())) {
this.context.startService(new Intent(this.context, (Class<?>) GRPCNotificationService.class));
}
MessageQueue messageQueue = this.messageQueue;
if (messageQueue == null || messageQueue.size() <= this.locationMaxBatchSize) {
return;
}
MessageQueue messageQueue2 = this.messageQueue;
messageQueue2.flushToBackend(messageQueue2.size() - this.locationBatchSize);
}
public void lambda$setupPreferenceChangeListener$8(SharedPreferences sharedPreferences, String str) {
char c;
int parseInt;
int parseInt2;
int parseInt3;
try {
Log.d(TAG_CONFIG, "SharedPreference changed: " + str);
if (str != null) {
switch (str.hashCode()) {
case -1950043801:
if (str.equals(LOCATION_FRESHNESS_THRESHOLD)) {
c = 7;
break;
}
c = 65535;
break;
case -1702598229:
if (str.equals(LOCATION_MAX_BATCH_SIZE_KEY)) {
c = 3;
break;
}
c = 65535;
break;
case -1645371028:
if (str.equals(REGISTRATION_TOKEN_KEY)) {
c = 0;
break;
}
c = 65535;
break;
case -1593522302:
if (str.equals("DRIVER_RIDE_STATUS")) {
c = '\t';
break;
}
c = 65535;
break;
case -1454056834:
if (str.equals(LOCATION_MAX_TIME_THRESHOLD)) {
c = '\f';
break;
}
c = 65535;
break;
case -1272156808:
if (str.equals(Utils.DRIVER_STATUS)) {
c = 11;
break;
}
c = 65535;
break;
case -604694396:
if (str.equals(LOCATION_SERVICE_VERSION)) {
c = 1;
break;
}
c = 65535;
break;
case -332034571:
if (str.equals(LOCATION_MAX_BATCH_AGE_KEY)) {
c = '\b';
break;
}
c = 65535;
break;
case 148826079:
if (str.equals(LOCATION_REQUEST_INTERVAL)) {
c = 14;
break;
}
c = 65535;
break;
case 444547643:
if (str.equals(DRIVER_MIN_DISPLACEMENT)) {
c = 5;
break;
}
c = 65535;
break;
case 811329262:
if (str.equals(LOCATION_PRIORITY)) {
c = '\r';
break;
}
c = 65535;
break;
case 1081435344:
if (str.equals(LOCATION_BATCH_SIZE)) {
c = 6;
break;
}
c = 65535;
break;
case 1828781414:
if (str.equals(LOCATION_RATE_LIMIT_SECONDS)) {
c = '\n';
break;
}
c = 65535;
break;
case 2032535281:
if (str.equals(LOCATION_UPDATE_INTERVAL)) {
c = 2;
break;
}
c = 65535;
break;
case 2050187796:
if (str.equals(LOCATION_BATCH_INTERVAL)) {
c = 4;
break;
}
c = 65535;
break;
default:
c = 65535;
break;
}
switch (c) {
case 0:
String string = sharedPreferences.getString(REGISTRATION_TOKEN_KEY, null);
if (string == null || string.equals("__failed") || string.equals("null")) {
Log.w(TAG, "Registration token is invalid or missing, stopping location service");
stopWidgetService();
stopSelf();
break;
}
break;
case 1:
String string2 = sharedPreferences.getString(LOCATION_SERVICE_VERSION, null);
if (string2 != null && string2.equals("V1")) {
Log.w(TAG, "Location Service swapped to V1, stopping location service");
stopSelf();
break;
}
break;
case 2:
String string3 = sharedPreferences.getString(str, null);
if (string3 != null && (parseInt = Integer.parseInt(string3)) != this.locationUpdateInterval) {
this.locationUpdateInterval = parseInt;
Log.d(TAG_CONFIG, "Location update interval changed to " + parseInt + "s");
if (isLocationUpdating) {
stopLocationUpdates();
startLocationUpdates();
}
restartLocationHeartbeatTimer();
break;
}
break;
case 3:
String string4 = sharedPreferences.getString(str, null);
if (string4 != null && (parseInt2 = Integer.parseInt(string4)) != this.locationMaxBatchSize) {
this.locationMaxBatchSize = parseInt2;
Log.d(TAG_CONFIG, "Location max batch size changed to " + parseInt2);
break;
}
break;
case 4:
String string5 = sharedPreferences.getString(str, null);
if (string5 != null && (parseInt3 = Integer.parseInt(string5)) != this.locationBatchInterval) {
this.locationBatchInterval = parseInt3;
Log.d(TAG_CONFIG, "Batch interval changed to " + parseInt3 + "s");
restartBatchScheduler();
break;
}
break;
case 5:
String string6 = sharedPreferences.getString(str, null);
if (string6 != null) {
float parseFloat = Float.parseFloat(string6);
if (parseFloat != this.locationMinDisplacement) {
this.locationMinDisplacement = parseFloat;
Log.d(TAG_CONFIG, "Min displacement changed to " + parseFloat + "m");
if (isLocationUpdating) {
stopLocationUpdates();
startLocationUpdates();
break;
}
}
}
break;
case 6:
String string7 = sharedPreferences.getString(str, null);
if (string7 != null) {
this.locationBatchSize = Integer.parseInt(string7);
Log.d(TAG_CONFIG, "Batch size changed to " + this.locationBatchSize);
break;
}
break;
case 7:
String string8 = sharedPreferences.getString(str, null);
if (string8 != null) {
this.locationFreshnessThresholdMinutes = Integer.parseInt(string8);
Log.d(TAG_CONFIG, "Location freshness threshold changed to " + this.locationFreshnessThresholdMinutes + "m");
break;
}
break;
case '\b':
String string9 = sharedPreferences.getString(str, null);
if (string9 != null) {
this.locationMaxBatchAgeSeconds = Integer.parseInt(string9);
Log.d(TAG_CONFIG, "Max batch age changed to " + this.locationMaxBatchAgeSeconds + "s");
break;
}
break;
case '\t':
this.driverRideStatus = sharedPreferences.getString(str, "IDLE");
Log.d(TAG_CONFIG, "Driver ride status changed to " + this.driverRideStatus);
if (isLocationUpdating) {
stopLocationUpdates();
startLocationUpdates();
break;
}
break;
case '\n':
this.rateLimitTimeInSeconds = Long.parseLong(sharedPreferences.getString(str, "2"));
Log.d(TAG_CONFIG, "Rate limiting time updated to " + this.rateLimitTimeInSeconds + " seconds");
break;
case 11:
if (sharedPreferences.getString(str, Utils.DRIVER_STATUS_OFFLINE).equals(Utils.DRIVER_STATUS_OFFLINE)) {
stopWidgetService();
stopSelf();
break;
}
break;
case '\f':
int parseInt4 = Integer.parseInt(sharedPreferences.getString(str, "2"));
Log.i(TAG_CONFIG, "LOCATION_MAX_TIME_THRESHOLD updated " + parseInt4 + "sec");
if (parseInt4 != this.locationMaxTimeThreshold && isLocationUpdating) {
this.locationMaxTimeThreshold = parseInt4;
stopLocationUpdates();
startLocationUpdates();
break;
}
break;
case '\r':
String string10 = sharedPreferences.getString(LOCATION_PRIORITY, "PRIORITY_HIGH_ACCURACY");
int priority = Utils.getPriority(string10);
Log.i(TAG_CONFIG, "LOCATION_PRIORITY updated " + priority + ". which is " + string10);
if (priority != this.locationPriority && isLocationUpdating) {
this.locationPriority = priority;
stopLocationUpdates();
startLocationUpdates();
break;
}
break;
case 14:
int parseInt5 = Integer.parseInt(sharedPreferences.getString(str, "10"));
if (parseInt5 != this.locationRequestInterval) {
this.locationRequestInterval = parseInt5;
stopLocationUpdates();
startLocationUpdates();
break;
}
break;
}
}
} catch (Exception e) {
Log.e(TAG_ERROR, "Error handling SharedPreferences change for key: " + str, e);
FirebaseCrashlytics.getInstance().recordException(e);
}
}
public void lambda$startBatchScheduler$1() {
this.messageQueue.triggerBatchProcess();
}
public void lambda$updateDriverStatus$5(boolean z) {
try {
Context context = this.context;
MobilityCallAPI.getInstance(this.context).callAPI(context.getSharedPreferences(context.getString(R.string.preference_file_key), 0).getString("BASE_URL", "null") + "/driver/setActivity?active=" + z + "&mode=" + (z ? "ONLINE" : "OFFLINE"), MobilityCallAPI.getBaseHeaders(this.context));
if (z) {
return;
}
updateStorage("DRIVER_STATUS", "__failed");
showAlertNotification();
stopWidgetService();
stopSelf();
} catch (Exception e) {
Log.e(TAG_ERROR, "Error updating driver status", e);
FirebaseCrashlytics.getInstance().recordException(e);
}
}
private void loadWakeLockConfig() {
Log.d(TAG_CONFIG, "loadWakeLockConfig() called");
try {
MobilityRemoteConfigs mobilityRemoteConfigs = this.remoteConfigs;
if (mobilityRemoteConfigs != null) {
String string = mobilityRemoteConfigs.getString(CONFIG_WAKE_LOCK);
if (string.isEmpty()) {
string = DEFAULT_WAKE_LOCK_CONFIG;
}
JSONObject jSONObject = new JSONObject(string);
this.useWakeLock = jSONObject.optBoolean("enabled", false);
this.wakeLockTimeoutMs = jSONObject.optLong("timeout_ms", 30000L);
Log.d(TAG_CONFIG, "Wake lock config loaded: enabled=" + this.useWakeLock + ", timeout=" + this.wakeLockTimeoutMs + "ms");
} else {
Log.e(TAG_ERROR, "Remote configs is null, using default wake lock config");
this.useWakeLock = false;
this.wakeLockTimeoutMs = 30000L;
}
} catch (Exception e) {
Log.e(TAG_ERROR, "Error loading wake lock config, defaulting to disabled", e);
this.useWakeLock = false;
this.wakeLockTimeoutMs = 30000L;
}
Log.d(TAG_CONFIG, "loadWakeLockConfig() complete");
}
private void logEventForHealthCheck(Intent intent) {
String stringExtra;
Log.d(TAG, "logEventForHealthCheck() called");
if (intent != null && (stringExtra = intent.getStringExtra("StartingSource")) != null) {
if (stringExtra.equals(MyFirebaseMessagingService.NotificationTypes.TRIGGER_SERVICE)) {
FirebaseAnalytics.getInstance(this).c("service_triggered_by_health_check", new Bundle());
} else if (stringExtra.equals("TRIGGER_SERVICE_INACTIVE")) {
FirebaseAnalytics.getInstance(this).c("service_by_health_check_inactive", new Bundle());
}
}
Log.d(TAG, "logEventForHealthCheck() complete");
}
public void lambda$handleLocationResult$4(Location location) {
Log.d(TAG_LOCATION, "logLocationUpdate() called for lat=" + location.getLatitude() + ", lon=" + location.getLongitude());
Log.d(TAG_LOCATION, String.format(Locale.US, "Location: lat=%.6f, lng=%.6f, acc=%.1fm, speed=%.1fm/s, time=%d", Double.valueOf(location.getLatitude()), Double.valueOf(location.getLongitude()), Float.valueOf(location.getAccuracy()), Float.valueOf(location.getSpeed()), Long.valueOf(location.getTime())));
Log.i("Location", "Location | Speed => " + location.getSpeed() + " Lat => " + location.getLatitude() + " Lon => " + location.getLongitude() + " Accuracy => " + location.getAccuracy() + " TimeStamp => " + location.getTime());
Log.d(TAG_LOCATION, "logLocationUpdate() complete");
}
private void notifyDriverBlocked(String str) {
Log.d(TAG, "notifyDriverBlocked() called with errorCode=" + str);
ArrayList<UpdateTimeCallback> arrayList = updateTimeCallbacks;
if (arrayList.isEmpty() || str == null) {
return;
}
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US);
simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
String format = simpleDateFormat.format(new Date());
Iterator<UpdateTimeCallback> it = arrayList.iterator();
while (it.hasNext()) {
UpdateTimeCallback next = it.next();
if (next != null) {
next.triggerUpdateTimeCallBack(format, String.valueOf(this.lastLatitudeValue), String.valueOf(this.lastLongitudeValue), str);
}
}
Log.d(TAG, "notifyDriverBlocked() complete");
}
private void notifyLocationUpdateSuccess() {
Log.d(TAG, "notifyLocationUpdateSuccess() called");
ArrayList<UpdateTimeCallback> arrayList = updateTimeCallbacks;
if (arrayList.isEmpty()) {
return;
}
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US);
simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
String format = simpleDateFormat.format(new Date());
updateStorage("DRIVER_LOCATION_TS", format);
Iterator<UpdateTimeCallback> it = arrayList.iterator();
while (it.hasNext()) {
UpdateTimeCallback next = it.next();
if (next != null) {
next.triggerUpdateTimeCallBack(format, String.valueOf(this.lastLatitudeValue), String.valueOf(this.lastLongitudeValue), "SUCCESS");
}
}
Log.d(TAG, "notifyLocationUpdateSuccess() complete");
}
public static void registerCallback(UpdateTimeCallback updateTimeCallback) {
updateTimeCallbacks.add(updateTimeCallback);
}
private void releaseWakeLockIfHeld(PowerManager.WakeLock wakeLock) {
Log.d(TAG, "releaseWakeLockIfHeld() called");
if (wakeLock != null && wakeLock.isHeld()) {
wakeLock.release();
Log.d(TAG, "Released temporary wake lock");
}
Log.d(TAG, "releaseWakeLockIfHeld() complete");
}
private void restartBatchScheduler() {
Log.d(TAG_BATCH, "restartBatchScheduler() called");
ScheduledExecutorService scheduledExecutorService = this.batchScheduler;
if (scheduledExecutorService != null && !scheduledExecutorService.isShutdown()) {
this.batchScheduler.shutdown();
this.batchScheduler = null;
}
startBatchScheduler();
Log.d(TAG_BATCH, "restartBatchScheduler() complete");
}
private void restartLocationHeartbeatTimer() {
Log.d(TAG_TIMER, "restartLocationHeartbeatTimer() called");
ScheduledExecutorService scheduledExecutorService = this.locationHeartbeatScheduler;
if (scheduledExecutorService != null && !scheduledExecutorService.isShutdown()) {
this.locationHeartbeatScheduler.shutdown();
this.locationHeartbeatScheduler = null;
}
startLocationHeartbeatTimer();
Log.d(TAG_TIMER, "restartLocationHeartbeatTimer() complete");
}
public void sendBatchToServer(final List<LocationData> list) {
JSONArray jSONArray;
MobilityCallAPI mobilityCallAPI;
Log.d(TAG_BATCH, "sendBatchToServer() called with batch size=" + list.size());
if (list.isEmpty()) {
this.isBatchProcessing.set(false);
return;
}
String valueFromStorage = getValueFromStorage(Utils.DRIVER_STATUS);
if (valueFromStorage == null || valueFromStorage.equals(Utils.DRIVER_STATUS_OFFLINE)) {
this.isBatchProcessing.set(false);
Log.i(TAG, "Driver status is Offline, stopping services");
stopWidgetService();
stopSelf();
return;
}
PowerManager.WakeLock acquireTemporaryWakeLock = acquireTemporaryWakeLock("SendBatchToServer", this.wakeLockTimeoutMs);
try {
try {
jSONArray = new JSONArray();
for (LocationData locationData : list) {
if (locationData != null) {
jSONArray.put(locationData.toJsonObject());
}
}
Log.i(TAG_BATCH, "Sending batch of " + list.size() + " locations to server");
mobilityCallAPI = MobilityCallAPI.getInstance(this.context);
} catch (Exception e) {
Log.e(TAG_ERROR, "Error preparing batch", e);
FirebaseCrashlytics.getInstance().recordException(e);
MessageQueue messageQueue = this.messageQueue;
if (messageQueue != null) {
messageQueue.addAll(list);
}
this.isBatchProcessing.set(false);
}
if (mobilityCallAPI == null) {
Log.e(TAG_ERROR, "MobilityCallAPI instance is null");
this.messageQueue.addAll(list);
this.isBatchProcessing.set(false);
releaseWakeLockIfHeld(acquireTemporaryWakeLock);
return;
}
Map<String, String> baseHeaders = MobilityCallAPI.getBaseHeaders(this.context);
if (baseHeaders == null) {
Log.e(TAG_ERROR, "Base headers are null");
this.messageQueue.addAll(list);
this.isBatchProcessing.set(false);
releaseWakeLockIfHeld(acquireTemporaryWakeLock);
return;
}
Context context = this.context;
SharedPreferences sharedPreferences = context.getSharedPreferences(context.getString(R.string.preference_file_key), 0);
if (sharedPreferences == null) {
Log.e(TAG_ERROR, "SharedPreferences is null");
this.messageQueue.addAll(list);
this.isBatchProcessing.set(false);
releaseWakeLockIfHeld(acquireTemporaryWakeLock);
return;
}
String string = sharedPreferences.getString("BASE_URL", "null");
if (string.equals("null")) {
Log.e(TAG_ERROR, "Base URL is null");
this.messageQueue.addAll(list);
this.isBatchProcessing.set(false);
releaseWakeLockIfHeld(acquireTemporaryWakeLock);
return;
}
baseHeaders.put("source", "batch_location_update");
setVehicleAndMerchantHeaders(baseHeaders);
Log.i(TAG_API, "Sending batch of " + list.size() + " locations to server with body | " + jSONArray);
mobilityCallAPI.callAPI(string + "/driver/location", baseHeaders, jSONArray.toString(), new MobilityCallAPI.APICallback() {
@Override
public void onError(Exception exc) {
Log.e(LocationUpdateServiceV2.TAG_ERROR, "API call failed", exc);
FirebaseCrashlytics.getInstance().recordException(exc);
if (LocationUpdateServiceV2.this.messageQueue != null) {
LocationUpdateServiceV2.this.messageQueue.addAll(list);
}
LocationUpdateServiceV2.this.isBatchProcessing.set(false);
}
@Override
public void onResponse(MobilityAPIResponse mobilityAPIResponse) {
LocationUpdateServiceV2.this.isBatchProcessing.set(false);
LocationUpdateServiceV2.this.handleApiResponse(mobilityAPIResponse, list);
}
});
releaseWakeLockIfHeld(acquireTemporaryWakeLock);
Log.d(TAG_BATCH, "sendBatchToServer() complete");
} catch (Throwable th) {
releaseWakeLockIfHeld(acquireTemporaryWakeLock);
throw th;
}
}
public void setVehicleAndMerchantHeaders(Map<String, String> map) {
String str;
Log.d(TAG_API, "setVehicleAndMerchantHeaders() called");
String valueFromStorage = getValueFromStorage("MERCHANT_ID");
String valueFromStorage2 = getValueFromStorage("VEHICLE_VARIANT");
String valueFromStorage3 = getValueFromStorage(Utils.DRIVER_STATUS);
if (valueFromStorage != null && valueFromStorage2 != null && valueFromStorage3 != null) {
map.put("mId", valueFromStorage);
map.put("vt", valueFromStorage2);
map.put("dm", valueFromStorage3.toUpperCase());
} else if (this.vVariant == null || this.drMode == null || (str = this.merchantID) == null) {
fetchProfileAndSetHeaders(map);
} else {
map.put("mId", str);
map.put("vt", this.vVariant);
map.put("dm", this.drMode);
}
Log.d(TAG_API, "setVehicleAndMerchantHeaders() complete");
}
private void setupInternetReceiver() {
if (this.connectivityManager == null) {
this.connectivityManager = (ConnectivityManager) this.context.getSystemService("connectivity");
}
if (this.networkCallback == null) {
AnonymousClass1 anonymousClass1 = new AnonymousClass1();
this.networkCallback = anonymousClass1;
try {
this.connectivityManager.registerDefaultNetworkCallback(anonymousClass1);
Log.d(TAG, "Registered network callback for connectivity monitoring");
} catch (Exception e) {
Log.e(TAG_ERROR, "Failed to register network callback", e);
}
}
}
private void setupPreferenceChangeListener() {
Log.d(TAG_CONFIG, "setupPreferenceChangeListener() called");
if (this.prefChangeListener == null) {
SharedPreferences.OnSharedPreferenceChangeListener onSharedPreferenceChangeListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
@Override
public final void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String str) {
LocationUpdateServiceV2.this.lambda$setupPreferenceChangeListener$8(sharedPreferences, str);
}
};
this.prefChangeListener = onSharedPreferenceChangeListener;
this.sharedPrefs.registerOnSharedPreferenceChangeListener(onSharedPreferenceChangeListener);
}
checkRegistrationTokenValidity();
Log.d(TAG_CONFIG, "setupPreferenceChangeListener() complete");
}
private void showAlertNotification() {
Log.d(TAG, "showAlertNotification() called");
Log.i(TAG, "Showing alert notification for disabled location");
try {
PendingIntent activity = PendingIntent.getActivity(this, 7102022, getPackageManager().getLaunchIntentForPackage(this.context.getPackageName()), 67108864);
m.e eVar = new m.e(this.context, "General");
eVar.p(BitmapFactory.decodeResource(getResources(), Utils.getResIdentifier(this.context, "ic_launcher", "drawable"))).l(getString(R.string.we_made_you_offline)).x(Utils.getResIdentifier(this.context, Build.VERSION.SDK_INT >= 26 ? "ic_launcher_small_icon" : "ny_ic_launcher", "drawable")).k(getString(R.string.location_is_turned_off_permission_is_disabled)).e(true).u(2).j(activity);
androidx.core.app.p b = androidx.core.app.p.b(this.context);
if (androidx.core.content.a.checkSelfPermission(this, "android.permission.POST_NOTIFICATIONS") == 0) {
b.d(7102022, eVar.b());
}
startGPSListeningService();
} catch (Exception e) {
Log.e(TAG_ERROR, "Error showing alert notification", e);
}
Log.d(TAG, "showAlertNotification() complete");
}
private void showWidget(boolean z) {
String string;
Log.d(TAG, "showWidget() called with isSpecialPickupZone=" + z);
try {
Context context = this.context;
string = context.getSharedPreferences(context.getString(R.string.preference_file_key), 0).getString("ACTIVITY_STATUS", "null");
} catch (Exception e) {
Log.e(TAG_ERROR, "Error showing widget", e);
FirebaseCrashlytics.getInstance().recordException(e);
}
if (!string.equals("onPause")) {
if (string.equals("onDestroy")) {
}
Log.d(TAG, "showWidget() complete");
}
Intent intent = new Intent(getApplicationContext(), (Class<?>) WidgetService.class);
if (z) {
intent.putExtra("showNearbySpecialPickup", true);
intent.putExtra("specialPickupMessage", getString(R.string.you_are_near_a_special_pickup_zone));
} else {
intent.putExtra("showNearbySpecialPickup", false);
}
startService(intent);
Log.d(TAG, "showWidget() complete");
}
private void startAsForegroundService() {
try {
if (Build.VERSION.SDK_INT >= 29) {
startForeground(15082022, createNotification(), 8);
} else {
startForeground(15082022, createNotification());
}
Log.d(TAG, "Started as foreground service");
} catch (Exception e) {
Log.e(TAG_ERROR, "Error starting foreground service", e);
FirebaseCrashlytics.getInstance().recordException(e);
}
}
public void startBatchScheduler() {
if (this.batchScheduler == null) {
ScheduledExecutorService newSingleThreadScheduledExecutor = Executors.newSingleThreadScheduledExecutor();
this.batchScheduler = newSingleThreadScheduledExecutor;
if (this.messageQueue != null) {
Runnable runnable = new Runnable() {
@Override
public final void run() {
LocationUpdateServiceV2.this.lambda$startBatchScheduler$1();
}
};
long j = this.locationBatchInterval;
newSingleThreadScheduledExecutor.scheduleWithFixedDelay(runnable, j, j, TimeUnit.SECONDS);
}
}
Log.d(TAG_BATCH, "Batch scheduler started with interval: " + this.locationBatchInterval + "s");
}
private void startGPSListeningService() {
Log.d(TAG, "startGPSListeningService() called");
try {
Intent intent = new Intent(this, (Class<?>) GpsListeningService.class);
SharedPreferences sharedPreferences = getApplicationContext().getSharedPreferences(getString(R.string.preference_file_key), 0);
int i = Build.VERSION.SDK_INT;
if (i >= 31 && sharedPreferences.getString("ACTIVITY_STATUS", "null").equals("onPause")) {
((AlarmManager) getSystemService("alarm")).setExact(0, System.currentTimeMillis(), PendingIntent.getBroadcast(this.context, 0, new Intent(this.context, (Class<?>) GPSBroadcastReceiver.class), 67108864));
} else if (i >= 26) {
getApplicationContext().startForegroundService(intent);
} else {
startService(intent);
}
} catch (Exception e) {
Log.e(TAG_ERROR, "Error starting GPS listening service", e);
FirebaseCrashlytics.getInstance().recordException(e);
}
Log.d(TAG, "startGPSListeningService() complete");
}
public void startLocationHeartbeatTimer() {
Log.d(TAG_TIMER, "startLocationHeartbeatTimer() called");
if (this.locationHeartbeatScheduler == null) {
ScheduledExecutorService newScheduledThreadPool = Executors.newScheduledThreadPool(2);
this.locationHeartbeatScheduler = newScheduledThreadPool;
long j = this.locationUpdateInterval * 1000;
newScheduledThreadPool.scheduleWithFixedDelay(new Runnable() {
@Override
public final void run() {
LocationUpdateServiceV2.this.checkAndSendLocationHeartbeat();
}
}, j, j, TimeUnit.MILLISECONDS);
Log.d(TAG_TIMER, "Started location heartbeat scheduler with interval: " + this.locationUpdateInterval + "s");
}
Log.d(TAG_TIMER, "startLocationHeartbeatTimer() complete");
}
public void startLocationUpdates() {
Log.d(TAG_LOCATION, "startLocationUpdates() called");
if (isLocationUpdating) {
Log.d(TAG_LOCATION, "Location updates already running");
return;
}
Log.i(TAG_LOCATION, "Starting location updates");
if (androidx.core.content.a.checkSelfPermission(this.context, "android.permission.ACCESS_FINE_LOCATION") != 0 && androidx.core.content.a.checkSelfPermission(this.context, "android.permission.ACCESS_COARSE_LOCATION") != 0) {
Log.e(TAG_ERROR, "No location permissions");
return;
}
if (isLocationDisabled()) {
Log.e(TAG_ERROR, "Location is disabled");
updateDriverStatus(false);
return;
}
LocationRequest createLocationRequest = createLocationRequest();
com.google.android.gms.location.i iVar = new com.google.android.gms.location.i() {
public void onLocationResult(LocationResult locationResult) {
LocationUpdateServiceV2.this.handleLocationResult(locationResult);
}
};
this.locationCallback = iVar;
try {
com.google.android.gms.location.e eVar = this.fusedLocationProviderClient;
if (eVar != null) {
eVar.requestLocationUpdates(createLocationRequest, iVar, Looper.getMainLooper());
isLocationUpdating = true;
Log.i(TAG_LOCATION, "Location updates started successfully");
} else {
Log.e(TAG_ERROR, "FusedLocationProviderClient is null");
}
} catch (Exception e) {
Log.e(TAG_ERROR, "Failed to start location updates", e);
FirebaseCrashlytics.getInstance().recordException(e);
}
Log.d(TAG_LOCATION, "startLocationUpdates() complete");
}
public void stopBatchScheduler() {
Log.d(TAG_BATCH, "stopBatchScheduler() called");
ScheduledExecutorService scheduledExecutorService = this.batchScheduler;
if (scheduledExecutorService != null && !scheduledExecutorService.isShutdown()) {
this.batchScheduler.shutdown();
this.batchScheduler = null;
}
Log.d(TAG_BATCH, "stopBatchScheduler() complete");
}
public void stopLocationHeartbeatTimer() {
Log.d(TAG_TIMER, "stopLocationHeartbeatTimer() called");
ScheduledExecutorService scheduledExecutorService = this.locationHeartbeatScheduler;
if (scheduledExecutorService != null && !scheduledExecutorService.isShutdown()) {
this.locationHeartbeatScheduler.shutdown();
this.locationHeartbeatScheduler = null;
}
Log.d(TAG_TIMER, "stopLocationHeartbeatTimer() complete");
}
public void stopLocationUpdates() {
com.google.android.gms.location.i iVar;
Log.d(TAG_LOCATION, "stopLocationUpdates() called");
com.google.android.gms.location.e eVar = this.fusedLocationProviderClient;
if (eVar != null && (iVar = this.locationCallback) != null) {
eVar.removeLocationUpdates(iVar);
isLocationUpdating = false;
Log.i(TAG_LOCATION, "Location updates stopped");
}
Log.d(TAG_LOCATION, "stopLocationUpdates() complete");
}
private void stopWidgetService() {
try {
if (MobilityCommonBridge.isServiceRunning(this.context, WidgetService.class.getName())) {
this.context.stopService(new Intent(this.context, (Class<?>) WidgetService.class));
Log.i(TAG, "Stopped widget service");
}
} catch (Exception e) {
Log.e(TAG_ERROR, "Error stopping widget service", e);
FirebaseCrashlytics.getInstance().recordException(e);
}
}
private void updateConfigVariables() {
Log.d(TAG_CONFIG, "updateConfigVariables() called");
try {
this.driverRideStatus = this.sharedPrefs.getString("DRIVER_RIDE_STATUS", "IDLE");
String string = this.sharedPrefs.getString(LOCATION_UPDATE_INTERVAL, null);
this.locationUpdateInterval = string != null ? Integer.parseInt(string) : 10;
String string2 = this.sharedPrefs.getString(LOCATION_BATCH_INTERVAL, null);
this.locationBatchInterval = string2 != null ? Integer.parseInt(string2) : 30;
String string3 = this.sharedPrefs.getString(DRIVER_MIN_DISPLACEMENT, null);
this.locationMinDisplacement = string3 != null ? Float.parseFloat(string3) : 25.0f;
String string4 = this.sharedPrefs.getString(LOCATION_BATCH_SIZE, null);
this.locationBatchSize = string4 != null ? Integer.parseInt(string4) : 20;
String string5 = this.sharedPrefs.getString(LOCATION_FRESHNESS_THRESHOLD, null);
this.locationFreshnessThresholdMinutes = string5 != null ? Integer.parseInt(string5) : 5;
String string6 = this.sharedPrefs.getString(LOCATION_MAX_BATCH_AGE_KEY, null);
this.locationMaxBatchAgeSeconds = string6 != null ? Integer.parseInt(string6) : this.locationMaxBatchAgeSeconds;
String string7 = this.sharedPrefs.getString(LOCATION_REQUEST_INTERVAL, null);
this.locationRequestInterval = string7 != null ? Integer.parseInt(string7) : 10;
String string8 = this.sharedPrefs.getString(LOCATION_MAX_TIME_THRESHOLD, null);
this.locationMaxTimeThreshold = string8 != null ? Integer.parseInt(string8) : 10;
this.locationPriority = Utils.getPriority(this.sharedPrefs.getString(LOCATION_PRIORITY, "PRIORITY_HIGH_ACCURACY"));
loadWakeLockConfig();
Log.d(TAG_CONFIG, String.format(Locale.US, "Config loaded: locationRequestInterval=%ds, updateInterval=%ds, batchInterval=%ds, minDisplacement=%.1fm, batchSize=%d, freshnessThreshold=%dm, maxBatchAge=%ds", Integer.valueOf(this.locationRequestInterval), Integer.valueOf(this.locationUpdateInterval), Integer.valueOf(this.locationBatchInterval), Float.valueOf(this.locationMinDisplacement), Integer.valueOf(this.locationBatchSize), Integer.valueOf(this.locationFreshnessThresholdMinutes), Integer.valueOf(this.locationMaxBatchAgeSeconds)));
this.rateLimitTimeInSeconds = Long.parseLong(this.sharedPrefs.getString(LOCATION_RATE_LIMIT_SECONDS, "2"));
Log.d(TAG_CONFIG, "Rate limiting time set to " + this.rateLimitTimeInSeconds + " seconds");
Log.d(TAG_CONFIG, "Config variables updated: locationUpdateInterval=" + this.locationUpdateInterval + ", locationBatchInterval=" + this.locationBatchInterval + ", locationMinDisplacement=" + this.locationMinDisplacement + ", locationBatchSize=" + this.locationBatchSize + ", locationFreshnessThresholdMinutes=" + this.locationFreshnessThresholdMinutes + ", locationMaxBatchAgeSeconds=" + this.locationMaxBatchAgeSeconds + ", locationRequestInterval=" + this.locationRequestInterval + ", locationMaxTimeThreshold=" + this.locationMaxTimeThreshold + ", locationPriority=" + this.locationPriority + ", rateLimitTimeInSeconds=" + this.rateLimitTimeInSeconds);
} catch (Exception e) {
Log.e(TAG_ERROR, "Error updating configuration in updateConfigVariables", e);
FirebaseCrashlytics.getInstance().recordException(e);
}
Log.d(TAG_CONFIG, "updateConfigVariables() complete");
}
private void updateDriverStatus(final boolean z) {
Log.d(TAG, "updateDriverStatus() called with status=" + z);
new Thread(new Runnable() {
@Override
public final void run() {
LocationUpdateServiceV2.this.lambda$updateDriverStatus$5(z);
}
}).start();
Log.d(TAG, "updateDriverStatus() complete");
}
private void updateLocationStorage(Location location) {
Log.d(TAG_LOCATION, "updateLocationStorage() called for lat=" + location.getLatitude() + ", lon=" + location.getLongitude());
updateStorage("LAST_KNOWN_LAT", String.valueOf(location.getLatitude()));
updateStorage("LAST_KNOWN_LON", String.valueOf(location.getLongitude()));
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US);
simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
updateStorage(LAST_LOCATION_TIME, simpleDateFormat.format(new Date(location.getTime())));
Log.d(TAG_LOCATION, "updateLocationStorage() complete");
}
public void updateStorage(String str, String str2) {
StringBuilder sb2 = new StringBuilder();
sb2.append("updateStorage() called for key=");
sb2.append(str);
sb2.append(", value=");
sb2.append(str.toLowerCase().contains("token") ? "***MASKED***" : str2);
Log.d(TAG_CONFIG, sb2.toString());
Context context = this.context;
SharedPreferences.Editor edit = context.getSharedPreferences(context.getString(R.string.preference_file_key), 0).edit();
edit.putString(str, str2);
edit.apply();
Log.d(TAG_CONFIG, "updateStorage() complete");
}
public void emitReactEvent(String str) {
ReactLocationEmitter reactLocationEmitter = this.locationEmitter;
if (reactLocationEmitter != null) {
reactLocationEmitter.emitter(str);
}
}
public Object getHyperService() {
return this.hyperServices;
}
public boolean handleDemoMode() {
Log.d(TAG_LOCATION, "handleDemoMode() called");
Context context = this.context;
if (!Boolean.parseBoolean(context.getSharedPreferences(context.getString(R.string.preference_file_key), 0).getString("IS_DEMOMODE_ENABLED", "false"))) {
return false;
}
enqueueDemoModeLocations();
updateStorage(LAST_LOCATION_FETCH_TIME, String.valueOf(System.currentTimeMillis()));
return true;
}
@Override
public IBinder onBind(Intent intent) {
if (this.binder == null) {
this.binder = new LocalBinder();
}
return this.binder;
}
@Override
public void onCreate() {
Log.d(TAG, "onCreate() called");
Log.init(getApplicationContext());
super.onCreate();
Log.i(TAG, "Service onCreate()");
this.context = getApplicationContext();
this.internetCheckExecutor = Executors.newCachedThreadPool();
this.sharedPrefs = getApplicationContext().getSharedPreferences(getString(R.string.preference_file_key), 0);
this.powerManager = (PowerManager) this.context.getSystemService("power");
this.remoteConfigs = new MobilityRemoteConfigs(false, false);
updateConfigVariables();
if (!checkRegistrationTokenExistence()) {
Log.w(TAG, "Registration token missing, stopping service");
stopWidgetService();
stopSelf();
return;
}
initializeMessageQueue();
initializeLocationComponents();
startAsForegroundService();
setupPreferenceChangeListener();
setupInternetReceiver();
this.messageQueue.restoreFromCache();
MessageQueue messageQueue = this.messageQueue;
messageQueue.flushToBackend(messageQueue.size());
Log.i(TAG, "Service initialization complete");
Log.d(TAG, "onCreate() complete");
}
@Override
public void onDestroy() {
ConnectivityManager.NetworkCallback networkCallback;
Log.d(TAG, "onDestroy() called");
Log.i(TAG, "Service onDestroy()");
SharedPreferences sharedPreferences = this.sharedPrefs;
if (sharedPreferences != null) {
sharedPreferences.unregisterOnSharedPreferenceChangeListener(this.prefChangeListener);
}
isLocationUpdating = false;
stopLocationUpdates();
stopLocationHeartbeatTimer();
ScheduledExecutorService scheduledExecutorService = this.batchScheduler;
if (scheduledExecutorService != null && !scheduledExecutorService.isShutdown()) {
this.batchScheduler.shutdown();
}
ExecutorService executorService = this.internetCheckExecutor;
if (executorService != null && !executorService.isShutdown()) {
this.internetCheckExecutor.shutdown();
}
MessageQueue messageQueue = this.messageQueue;
if (messageQueue != null) {
messageQueue.flushCache();
}
ConnectivityManager connectivityManager = this.connectivityManager;
if (connectivityManager != null && (networkCallback = this.networkCallback) != null) {
try {
connectivityManager.unregisterNetworkCallback(networkCallback);
Log.d(TAG, "Unregistered network callback");
} catch (Exception e) {
Log.e(TAG_ERROR, "Error unregistering network callback", e);
}
}
if (MobilityCommonBridge.isServiceRunning(this.context, GRPCNotificationService.class.getName())) {
this.context.stopService(new Intent(this.context, (Class<?>) GRPCNotificationService.class));
}
this.binder = null;
super.onDestroy();
Log.d(TAG, "onDestroy() complete");
}
@Override
public int onStartCommand(Intent intent, int i, int i2) {
StringBuilder sb2 = new StringBuilder();
sb2.append("onStartCommand() called with intent=");
sb2.append(intent != null ? intent.toString() : "null");
sb2.append(", flags=");
sb2.append(i);
sb2.append(", startId=");
sb2.append(i2);
Log.d(TAG, sb2.toString());
Log.i(TAG, "Service onStartCommand()");
startAsForegroundService();
SharedPreferences sharedPreferences = getApplicationContext().getSharedPreferences(getString(R.string.preference_file_key), 0);
if (sharedPreferences != null) {
this.driverId = sharedPreferences.getString("DRIVER_ID", "empty");
}
Log.setLogRetentionDays((int) this.remoteConfigs.getLong("log_retention_days"));
logEventForHealthCheck(intent);
checkInternetAccess(null, new OnNetworkAvailable() {
@Override
public final void onSuccess() {
LocationUpdateServiceV2.this.lambda$onStartCommand$2();
}
});
Log.d(TAG, "onStartCommand() complete");
return 1;
}
public void storeHyperService(Object obj) {
this.hyperServices = obj;
}
public void storeReactEmitter(ReactLocationEmitter reactLocationEmitter) {
this.locationEmitter = reactLocationEmitter;
}
public static class LocationData {
float accuracy;
float bearing;
double latitude;
double longitude;
String source;
float speed;
long timestamp;
public LocationData(Location location, String str) {
this.latitude = location.getLatitude();
this.longitude = location.getLongitude();
this.accuracy = location.getAccuracy();
this.bearing = location.hasBearing() ? location.getBearing() : 0.0f;
this.speed = location.hasSpeed() ? location.getSpeed() : 0.0f;
this.timestamp = location.getTime();
this.source = str;
}
public static LocationData fromJsonObject(JSONObject jSONObject) throws JSONException {
LocationData locationData = new LocationData();
JSONObject jSONObject2 = jSONObject.getJSONObject("pt");
locationData.latitude = jSONObject2.getDouble("lat");
locationData.longitude = jSONObject2.getDouble("lon");
locationData.accuracy = (float) jSONObject.optDouble("acc", 0.0d);
locationData.bearing = (float) jSONObject.optDouble("bear", 0.0d);
locationData.speed = (float) jSONObject.optDouble("v", 0.0d);
locationData.source = jSONObject.optString("source", "unknown");
String optString = jSONObject.optString("ts", "");
if (optString.isEmpty()) {
locationData.timestamp = System.currentTimeMillis();
} else {
try {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US);
simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
Date parse = simpleDateFormat.parse(optString);
locationData.timestamp = parse != null ? parse.getTime() : System.currentTimeMillis();
} catch (Exception e) {
Log.e(LocationUpdateServiceV2.TAG_JSON, "Error parsing timestamp: " + optString, e);
locationData.timestamp = System.currentTimeMillis();
}
}
return locationData;
}
public JSONObject toJsonObject() throws JSONException {
JSONObject jSONObject = new JSONObject();
JSONObject jSONObject2 = new JSONObject();
jSONObject2.put("lat", this.latitude);
jSONObject2.put("lon", this.longitude);
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US);
simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
String format = simpleDateFormat.format(new Date(this.timestamp));
jSONObject.put("pt", jSONObject2);
jSONObject.put("ts", format);
jSONObject.put("acc", this.accuracy);
jSONObject.put("bear", this.bearing);
jSONObject.put("source", this.source);
jSONObject.put("v", this.speed);
return jSONObject;
}
public LocationData() {
}
}
}