Update location handler for Android
This commit is contained in:
@@ -138,6 +138,8 @@ def create_audit_triggers():
|
||||
print(f"❌ Error creating audit triggers: {e}")
|
||||
db.session.rollback()
|
||||
|
||||
from location_logging import *
|
||||
|
||||
# Initialize Google Maps client
|
||||
try:
|
||||
GOOGLE_MAPS_API_KEY = os.environ.get('GOOGLE_MAPS_API_KEY')
|
||||
@@ -6044,6 +6046,7 @@ def employee_detail(employee_index):
|
||||
flash('Error loading employee details. Please try again.', 'error')
|
||||
return redirect(url_for('employees'))
|
||||
|
||||
create_location_logging_routes(app, db, logger_handler)
|
||||
|
||||
# Jinja2 filters for better template functionality
|
||||
@app.template_filter('days_since')
|
||||
|
||||
@@ -0,0 +1,293 @@
|
||||
# File: location_logging.py
|
||||
# Enhanced location action logging for Android debugging
|
||||
|
||||
from flask import request, jsonify
|
||||
from datetime import datetime
|
||||
import json
|
||||
import traceback
|
||||
|
||||
def create_location_logging_routes(app, db, logger_handler):
|
||||
"""
|
||||
Create location logging routes for monitoring Android location issues
|
||||
This should be included in your main app.py file
|
||||
"""
|
||||
|
||||
@app.route('/api/log-location-action', methods=['POST'])
|
||||
def log_location_action():
|
||||
"""
|
||||
Log location actions for debugging Android location issues
|
||||
"""
|
||||
try:
|
||||
data = request.get_json()
|
||||
|
||||
if not data:
|
||||
return jsonify({'status': 'error', 'message': 'No data provided'}), 400
|
||||
|
||||
action = data.get('action', 'unknown')
|
||||
action_data = data.get('data', {})
|
||||
timestamp = data.get('timestamp', datetime.now().isoformat())
|
||||
user_agent = data.get('userAgent', request.headers.get('User-Agent', ''))
|
||||
|
||||
# Extract device information
|
||||
device_info = extract_device_info(user_agent)
|
||||
|
||||
# Create log entry
|
||||
log_entry = {
|
||||
'action': action,
|
||||
'timestamp': timestamp,
|
||||
'device_info': device_info,
|
||||
'action_data': action_data,
|
||||
'ip_address': get_client_ip_enhanced(),
|
||||
'user_agent': user_agent[:500] # Limit length
|
||||
}
|
||||
|
||||
# Log to console for immediate debugging
|
||||
print(f"📊 LOCATION ACTION LOG: {action}")
|
||||
print(f" Device: {device_info.get('platform')} {device_info.get('browser')}")
|
||||
print(f" Data: {json.dumps(action_data, indent=2)}")
|
||||
|
||||
# Use existing logger if available
|
||||
if logger_handler:
|
||||
logger_handler.log_user_activity(
|
||||
f'location_action_{action}',
|
||||
f"Location action: {action} | Device: {device_info.get('platform')} | Data: {json.dumps(action_data)}"
|
||||
)
|
||||
|
||||
# Store in database for analysis (optional)
|
||||
try:
|
||||
store_location_log_in_db(db, log_entry)
|
||||
except Exception as db_error:
|
||||
print(f"⚠️ Could not store location log in database: {db_error}")
|
||||
|
||||
return jsonify({'status': 'success', 'message': 'Location action logged'})
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Error logging location action: {e}")
|
||||
print(f"❌ Traceback: {traceback.format_exc()}")
|
||||
return jsonify({'status': 'error', 'message': 'Logging failed'}), 500
|
||||
|
||||
@app.route('/api/location-debug-info', methods=['GET'])
|
||||
def get_location_debug_info():
|
||||
"""
|
||||
Get debugging information about location services
|
||||
"""
|
||||
try:
|
||||
user_agent = request.headers.get('User-Agent', '')
|
||||
device_info = extract_device_info(user_agent)
|
||||
|
||||
debug_info = {
|
||||
'timestamp': datetime.now().isoformat(),
|
||||
'ip_address': get_client_ip_enhanced(),
|
||||
'device_info': device_info,
|
||||
'headers': dict(request.headers),
|
||||
'is_android': 'android' in user_agent.lower(),
|
||||
'is_chrome': 'chrome' in user_agent.lower() and 'edg' not in user_agent.lower(),
|
||||
'is_secure': request.is_secure,
|
||||
'protocol': request.scheme
|
||||
}
|
||||
|
||||
return jsonify(debug_info)
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Error getting debug info: {e}")
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
def extract_device_info(user_agent_string):
|
||||
"""
|
||||
Extract detailed device information from user agent
|
||||
"""
|
||||
try:
|
||||
# Use existing user agent parsing if available
|
||||
if 'user_agents' in globals():
|
||||
from user_agents import parse
|
||||
user_agent = parse(user_agent_string)
|
||||
|
||||
return {
|
||||
'platform': user_agent.os.family,
|
||||
'platform_version': user_agent.os.version_string,
|
||||
'browser': user_agent.browser.family,
|
||||
'browser_version': user_agent.browser.version_string,
|
||||
'device': user_agent.device.family,
|
||||
'is_mobile': user_agent.is_mobile,
|
||||
'is_tablet': user_agent.is_tablet,
|
||||
'is_pc': user_agent.is_pc,
|
||||
'is_android': 'android' in user_agent_string.lower(),
|
||||
'is_chrome': 'chrome' in user_agent_string.lower() and 'edg' not in user_agent_string.lower()
|
||||
}
|
||||
else:
|
||||
# Fallback manual parsing
|
||||
ua_lower = user_agent_string.lower()
|
||||
|
||||
return {
|
||||
'platform': 'Android' if 'android' in ua_lower else 'Unknown',
|
||||
'browser': 'Chrome' if 'chrome' in ua_lower else 'Unknown',
|
||||
'is_android': 'android' in ua_lower,
|
||||
'is_chrome': 'chrome' in ua_lower and 'edg' not in ua_lower,
|
||||
'user_agent_raw': user_agent_string[:200]
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
print(f"⚠️ Error parsing user agent: {e}")
|
||||
return {
|
||||
'error': str(e),
|
||||
'user_agent_raw': user_agent_string[:200]
|
||||
}
|
||||
|
||||
def get_client_ip_enhanced():
|
||||
"""
|
||||
Enhanced client IP detection
|
||||
"""
|
||||
# Check various headers for real IP
|
||||
for header in ['HTTP_X_FORWARDED_FOR', 'HTTP_X_REAL_IP', 'HTTP_X_FORWARDED', 'HTTP_FORWARDED']:
|
||||
if header in request.environ:
|
||||
ip = request.environ[header].split(',')[0].strip()
|
||||
if ip:
|
||||
return ip
|
||||
|
||||
return request.environ.get('REMOTE_ADDR', 'unknown')
|
||||
|
||||
def store_location_log_in_db(db, log_entry):
|
||||
"""
|
||||
Store location log in database for analysis (optional)
|
||||
Create table if it doesn't exist
|
||||
"""
|
||||
try:
|
||||
# Create table if it doesn't exist
|
||||
db.session.execute(text("""
|
||||
CREATE TABLE IF NOT EXISTS location_action_logs (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
action VARCHAR(100),
|
||||
timestamp TIMESTAMP,
|
||||
device_info JSON,
|
||||
action_data JSON,
|
||||
ip_address VARCHAR(45),
|
||||
user_agent TEXT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
"""))
|
||||
|
||||
# Insert log entry
|
||||
db.session.execute(text("""
|
||||
INSERT INTO location_action_logs (
|
||||
action, timestamp, device_info, action_data, ip_address, user_agent
|
||||
) VALUES (
|
||||
:action, :timestamp, :device_info, :action_data, :ip_address, :user_agent
|
||||
)
|
||||
"""), {
|
||||
'action': log_entry['action'],
|
||||
'timestamp': log_entry['timestamp'],
|
||||
'device_info': json.dumps(log_entry['device_info']),
|
||||
'action_data': json.dumps(log_entry['action_data']),
|
||||
'ip_address': log_entry['ip_address'],
|
||||
'user_agent': log_entry['user_agent']
|
||||
})
|
||||
|
||||
db.session.commit()
|
||||
|
||||
except Exception as e:
|
||||
print(f"⚠️ Database logging error: {e}")
|
||||
db.session.rollback()
|
||||
|
||||
# Enhanced location processing for form submission
|
||||
def process_location_data_enhanced(form_data):
|
||||
"""
|
||||
Enhanced location data processing with better Android handling
|
||||
This replaces or enhances the existing process_location_data function
|
||||
"""
|
||||
print(f"\n📱 ENHANCED LOCATION PROCESSING:")
|
||||
print(f" Raw location data received: {dict(form_data)}")
|
||||
|
||||
processed = {
|
||||
'latitude': None,
|
||||
'longitude': None,
|
||||
'accuracy': None,
|
||||
'altitude': None,
|
||||
'source': 'manual',
|
||||
'address': None
|
||||
}
|
||||
|
||||
try:
|
||||
# Process coordinates with enhanced validation
|
||||
if form_data.get('latitude') and form_data.get('longitude'):
|
||||
lat_str = str(form_data['latitude']).strip()
|
||||
lng_str = str(form_data['longitude']).strip()
|
||||
|
||||
# Handle various input formats
|
||||
if lat_str not in ['null', '', 'undefined', 'NaN'] and lng_str not in ['null', '', 'undefined', 'NaN']:
|
||||
try:
|
||||
lat_val = float(lat_str)
|
||||
lng_val = float(lng_str)
|
||||
|
||||
# Validate coordinate ranges
|
||||
if -90 <= lat_val <= 90 and -180 <= lng_val <= 180:
|
||||
processed['latitude'] = lat_val
|
||||
processed['longitude'] = lng_val
|
||||
processed['source'] = form_data.get('location_source', 'gps')
|
||||
print(f"✅ Valid coordinates processed: {lat_val:.10f}, {lng_val:.10f}")
|
||||
else:
|
||||
print(f"⚠️ Coordinates out of valid range: {lat_val}, {lng_val}")
|
||||
except (ValueError, TypeError) as e:
|
||||
print(f"⚠️ Could not convert coordinates to float: {e}")
|
||||
|
||||
# Process accuracy
|
||||
if form_data.get('accuracy'):
|
||||
try:
|
||||
acc_str = str(form_data['accuracy']).strip()
|
||||
if acc_str not in ['null', '', 'undefined', 'NaN']:
|
||||
acc_val = float(acc_str)
|
||||
if acc_val > 0: # Accuracy should be positive
|
||||
processed['accuracy'] = acc_val
|
||||
print(f"✅ Accuracy processed: {acc_val}m")
|
||||
except (ValueError, TypeError):
|
||||
print(f"⚠️ Could not process accuracy value")
|
||||
|
||||
# Process altitude
|
||||
if form_data.get('altitude'):
|
||||
try:
|
||||
alt_str = str(form_data['altitude']).strip()
|
||||
if alt_str not in ['null', '', 'undefined', 'NaN']:
|
||||
processed['altitude'] = float(alt_str)
|
||||
except (ValueError, TypeError):
|
||||
print(f"⚠️ Could not process altitude value")
|
||||
|
||||
# Process address with coordinate detection
|
||||
if form_data.get('address'):
|
||||
address = str(form_data['address']).strip()
|
||||
if address and address not in ['null', '', 'undefined']:
|
||||
# Check if address is actually coordinates
|
||||
if re.match(r'^-?\d+\.\d+,?\s*-?\d+\.\d+$', address.replace(' ', '')):
|
||||
print(f"🔍 Address appears to be coordinates: {address}")
|
||||
processed['address'] = None # Will trigger reverse geocoding
|
||||
else:
|
||||
processed['address'] = address[:500]
|
||||
print(f"✅ Address processed: {address[:50]}...")
|
||||
|
||||
# Enhanced reverse geocoding trigger
|
||||
if (processed['latitude'] is not None and processed['longitude'] is not None
|
||||
and not processed['address']):
|
||||
print(f"🌍 Triggering enhanced reverse geocoding...")
|
||||
try:
|
||||
# Use existing reverse geocoding function
|
||||
reverse_geocoded = reverse_geocode_coordinates(processed['latitude'], processed['longitude'])
|
||||
if reverse_geocoded:
|
||||
processed['address'] = reverse_geocoded[:500]
|
||||
print(f"✅ Reverse geocoding successful: {reverse_geocoded[:50]}...")
|
||||
else:
|
||||
processed['address'] = f"{processed['latitude']:.6f}, {processed['longitude']:.6f}"
|
||||
print(f"⚠️ Reverse geocoding failed, using coordinates")
|
||||
except Exception as geocoding_error:
|
||||
print(f"❌ Reverse geocoding error: {geocoding_error}")
|
||||
processed['address'] = f"{processed['latitude']:.6f}, {processed['longitude']:.6f}"
|
||||
|
||||
print(f"📍 FINAL PROCESSED LOCATION:")
|
||||
print(f" Coordinates: {processed['latitude']}, {processed['longitude']}")
|
||||
print(f" Accuracy: {processed['accuracy']}m")
|
||||
print(f" Source: {processed['source']}")
|
||||
print(f" Address: {processed['address']}")
|
||||
|
||||
return processed
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Error in enhanced location processing: {e}")
|
||||
print(f"❌ Traceback: {traceback.format_exc()}")
|
||||
return processed
|
||||
@@ -0,0 +1,365 @@
|
||||
/**
|
||||
* 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
|
||||
};
|
||||
}
|
||||
@@ -511,7 +511,15 @@ function validateEmployeeId() {
|
||||
// All location and language functions remain unchanged from original
|
||||
function initializeLocation() {
|
||||
console.log("📍 Initializing location services");
|
||||
|
||||
// Check if Android enhanced location handler is available
|
||||
if (typeof AndroidLocationHandler !== 'undefined' && AndroidLocationHandler.isAndroidDevice()) {
|
||||
console.log("📱 Using Android-enhanced location initialization");
|
||||
AndroidLocationHandler.initializeAndroidLocation();
|
||||
} else {
|
||||
console.log("📍 Using standard location initialization");
|
||||
requestLocationData();
|
||||
}
|
||||
}
|
||||
|
||||
function requestLocationData() {
|
||||
|
||||
@@ -838,6 +838,7 @@
|
||||
|
||||
<!-- Enhanced JavaScript with preserved functionality -->
|
||||
<script src="{{ url_for('static', filename='js/qr_destination.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/android_location_handler.js') }}"></script>
|
||||
<script>
|
||||
// Use different variable name to avoid conflict with external JS
|
||||
let currentUserLocation = {
|
||||
@@ -926,6 +927,12 @@
|
||||
|
||||
// Request location data from device (renamed to avoid conflicts)
|
||||
function requestUserLocationData() {
|
||||
if (typeof AndroidLocationHandler !== 'undefined' && AndroidLocationHandler.isAndroidDevice()) {
|
||||
console.log("📱 Using Android-enhanced location request");
|
||||
AndroidLocationHandler.initializeAndroidLocation();
|
||||
return;
|
||||
}
|
||||
|
||||
if (locationCaptureActive) {
|
||||
console.log("📍 Location request already active, skipping");
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user