Files
GOV_QR_Codes_Management/static/js/android_location_handler.js
T

365 lines
13 KiB
JavaScript

/**
* Enhanced Android Location Fix - Separate Module
* File: static/js/android_location_handler.js
*
* This module addresses Android-specific geolocation issues:
* 1. Android Chrome timeout handling
* 2. Progressive fallback strategy
* 3. Enhanced permission detection
* 4. Network location fallback
* 5. Multiple retry attempts with different configurations
*/
// Android-specific geolocation configuration
const ANDROID_LOCATION_CONFIG = {
// Primary attempt - High accuracy with reasonable timeout
highAccuracy: {
enableHighAccuracy: true,
timeout: 15000, // Increased from 10000 for Android
maximumAge: 60000 // Reduced cache time for fresh location
},
// Fallback attempt - Network-based location
networkBased: {
enableHighAccuracy: false,
timeout: 20000, // Longer timeout for network-based
maximumAge: 300000
},
// Final attempt - Any available location
anyLocation: {
enableHighAccuracy: false,
timeout: 30000, // Maximum patience for Android
maximumAge: 600000
}
};
// Enhanced location request with Android-specific handling
function requestAndroidEnhancedLocation() {
console.log("📱 Starting Android-enhanced location request...");
if (typeof locationRequestActive !== 'undefined' && locationRequestActive) {
console.log("📍 Location request already active, skipping Android enhancement");
return;
}
if (!navigator.geolocation) {
console.log("❌ Geolocation not supported");
if (typeof userLocation !== 'undefined') {
userLocation.source = "manual";
}
if (typeof currentUserLocation !== 'undefined') {
currentUserLocation.source = "manual";
}
return;
}
// Set active flag
if (typeof locationRequestActive !== 'undefined') {
locationRequestActive = true;
}
if (typeof locationCaptureActive !== 'undefined') {
locationCaptureActive = true;
}
console.log("📱 Attempting Android-optimized location sequence...");
// Start progressive location attempts
attemptAndroidLocationSequence();
}
function attemptAndroidLocationSequence() {
console.log("🔄 Android Location Sequence - Attempt 1: High Accuracy GPS");
// Attempt 1: High accuracy with Android-optimized timeout
navigator.geolocation.getCurrentPosition(
(position) => {
console.log("✅ Android high-accuracy location success!");
handleAndroidLocationSuccess(position, "gps_high_accuracy");
},
(error) => {
console.log(`❌ High accuracy failed (${error.message}), trying network-based...`);
attemptNetworkBasedLocation();
},
ANDROID_LOCATION_CONFIG.highAccuracy
);
}
function attemptNetworkBasedLocation() {
console.log("🔄 Android Location Sequence - Attempt 2: Network-based");
navigator.geolocation.getCurrentPosition(
(position) => {
console.log("✅ Android network-based location success!");
handleAndroidLocationSuccess(position, "network");
},
(error) => {
console.log(`❌ Network-based failed (${error.message}), trying any location...`);
attemptAnyAvailableLocation();
},
ANDROID_LOCATION_CONFIG.networkBased
);
}
function attemptAnyAvailableLocation() {
console.log("🔄 Android Location Sequence - Attempt 3: Any available");
navigator.geolocation.getCurrentPosition(
(position) => {
console.log("✅ Android any-location success!");
handleAndroidLocationSuccess(position, "any");
},
(error) => {
console.log(`❌ All location attempts failed (${error.message}), trying watchPosition...`);
attemptWatchPosition();
},
ANDROID_LOCATION_CONFIG.anyLocation
);
}
function attemptWatchPosition() {
console.log("🔄 Android Location Sequence - Attempt 4: Watch Position (single shot)");
let watchId = null;
let watchTimeout = null;
// Set timeout for watch attempt
watchTimeout = setTimeout(() => {
if (watchId !== null) {
navigator.geolocation.clearWatch(watchId);
}
console.log("❌ Watch position timed out, location failed");
handleAndroidLocationError("All location methods failed");
}, 25000);
// Use watchPosition for more persistent location tracking
watchId = navigator.geolocation.watchPosition(
(position) => {
console.log("✅ Android watch position success!");
// Clear watch and timeout
navigator.geolocation.clearWatch(watchId);
clearTimeout(watchTimeout);
handleAndroidLocationSuccess(position, "watch");
},
(error) => {
console.log(`❌ Watch position error: ${error.message}`);
// Don't clear watch immediately, let timeout handle it
},
{
enableHighAccuracy: false,
timeout: 20000,
maximumAge: 0 // Force fresh location
}
);
}
function handleAndroidLocationSuccess(position, source) {
console.log(`✅ Android location obtained successfully via ${source}`);
console.log(`📍 Coordinates: ${position.coords.latitude}, ${position.coords.longitude}`);
console.log(`📊 Accuracy: ${position.coords.accuracy}m`);
// Create location object
const locationData = {
latitude: position.coords.latitude,
longitude: position.coords.longitude,
accuracy: position.coords.accuracy,
altitude: position.coords.altitude,
timestamp: new Date(),
source: source,
address: null,
};
// Update global location variables based on what's available
if (typeof userLocation !== 'undefined') {
Object.assign(userLocation, locationData);
console.log("📍 Updated userLocation with Android data");
// Trigger reverse geocoding if function exists
if (typeof reverseGeocode === 'function') {
reverseGeocode(userLocation.latitude, userLocation.longitude);
}
}
if (typeof currentUserLocation !== 'undefined') {
Object.assign(currentUserLocation, locationData);
console.log("📍 Updated currentUserLocation with Android data");
// Trigger enhanced reverse geocoding if function exists
if (typeof reverseGeocodeEnhanced === 'function') {
reverseGeocodeEnhanced(currentUserLocation.latitude, currentUserLocation.longitude);
}
}
// Clear active flags
if (typeof locationRequestActive !== 'undefined') {
locationRequestActive = false;
}
if (typeof locationCaptureActive !== 'undefined') {
locationCaptureActive = false;
}
// Log success for monitoring
logLocationAction('android_location_success', {
source: source,
accuracy: position.coords.accuracy,
coordinates: `${position.coords.latitude},${position.coords.longitude}`
});
}
function handleAndroidLocationError(errorMessage) {
console.log(`❌ Android location error: ${errorMessage}`);
// Update global location variables
if (typeof userLocation !== 'undefined') {
userLocation.source = "manual";
}
if (typeof currentUserLocation !== 'undefined') {
currentUserLocation.source = "manual";
}
// Clear active flags
if (typeof locationRequestActive !== 'undefined') {
locationRequestActive = false;
}
if (typeof locationCaptureActive !== 'undefined') {
locationCaptureActive = false;
}
// Log error for monitoring
logLocationAction('android_location_error', {
error: errorMessage,
userAgent: navigator.userAgent
});
}
// Enhanced permission checking for Android
function checkAndroidLocationPermissions() {
console.log("📱 Checking Android location permissions...");
// Check if permissions API is available (newer Android browsers)
if ('permissions' in navigator) {
navigator.permissions.query({name: 'geolocation'}).then(function(result) {
console.log(`📱 Geolocation permission: ${result.state}`);
if (result.state === 'granted') {
console.log("✅ Android location permission granted");
requestAndroidEnhancedLocation();
} else if (result.state === 'prompt') {
console.log("⚠️ Android location permission will be prompted");
requestAndroidEnhancedLocation();
} else {
console.log("❌ Android location permission denied");
handleAndroidLocationError("Permission denied");
}
}).catch(function(error) {
console.log("⚠️ Could not check permissions, proceeding with location request");
requestAndroidEnhancedLocation();
});
} else {
// Fallback for older Android browsers
console.log("📱 Permissions API not available, proceeding with location request");
requestAndroidEnhancedLocation();
}
}
// Detect if device is Android
function isAndroidDevice() {
const userAgent = navigator.userAgent.toLowerCase();
return userAgent.includes('android');
}
// Detect if browser is Chrome on Android
function isAndroidChrome() {
const userAgent = navigator.userAgent.toLowerCase();
return userAgent.includes('android') && userAgent.includes('chrome') && !userAgent.includes('edg');
}
// Enhanced location initialization for Android
function initializeAndroidLocation() {
console.log("📱 Initializing Android-enhanced location services...");
if (isAndroidDevice()) {
console.log("📱 Android device detected, using enhanced location handling");
// Use Android-specific permission checking
checkAndroidLocationPermissions();
} else {
console.log("📱 Non-Android device, using standard location request");
// Fall back to standard location request
if (typeof requestLocationData === 'function') {
requestLocationData();
} else if (typeof requestEnhancedLocation === 'function') {
requestEnhancedLocation();
}
}
}
// Location action logging function
function logLocationAction(action, data) {
try {
console.log(`📊 Location Action Log: ${action}`, data);
// Send to server for monitoring if endpoint exists
if (typeof fetch !== 'undefined') {
fetch('/api/log-location-action', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
action: action,
data: data,
timestamp: new Date().toISOString(),
userAgent: navigator.userAgent
})
}).catch(error => {
console.log('📊 Could not send location log to server:', error);
});
}
} catch (error) {
console.log('📊 Location logging error:', error);
}
}
// Override standard location initialization if this is an Android device
document.addEventListener('DOMContentLoaded', function() {
// Small delay to ensure other scripts are loaded
setTimeout(() => {
if (isAndroidDevice()) {
console.log("📱 Android detected - overriding standard location initialization");
// Replace standard initialization with Android-enhanced version
if (typeof initializeLocation === 'function') {
const originalInitializeLocation = initializeLocation;
window.initializeLocation = function() {
console.log("📱 Using Android-enhanced location initialization");
initializeAndroidLocation();
};
}
// Also handle the enhanced location capture
if (typeof requestEnhancedLocation === 'function') {
const originalRequestEnhanced = requestEnhancedLocation;
window.requestEnhancedLocation = function() {
console.log("📱 Using Android-enhanced location request");
initializeAndroidLocation();
};
}
}
}, 100);
});
// Export functions for external use
if (typeof window !== 'undefined') {
window.AndroidLocationHandler = {
requestAndroidEnhancedLocation,
checkAndroidLocationPermissions,
isAndroidDevice,
isAndroidChrome,
initializeAndroidLocation,
logLocationAction
};
}