From be05945eace01ca3d8f25a23b8d46fad668acbfa Mon Sep 17 00:00:00 2001 From: fkloft Date: Tue, 17 Dec 2013 21:23:47 +0100 Subject: [PATCH] Use native Android API for user-location (WebView causes high cpu load, even when IITC is stopped) Also, move all user-location related functions into new class IITC_UserLocation. --- mobile/plugins/user-location.user.js | 38 ++-- .../com/cradle/iitc_mobile/IITC_Mobile.java | 134 ++++-------- .../iitc_mobile/IITC_NavigationHelper.java | 14 +- .../cradle/iitc_mobile/IITC_UserLocation.java | 196 ++++++++++++++++++ .../com/cradle/iitc_mobile/IITC_WebView.java | 5 +- 5 files changed, 257 insertions(+), 130 deletions(-) create mode 100644 mobile/src/com/cradle/iitc_mobile/IITC_UserLocation.java diff --git a/mobile/plugins/user-location.user.js b/mobile/plugins/user-location.user.js index 4766de51..1ca8dd90 100644 --- a/mobile/plugins/user-location.user.js +++ b/mobile/plugins/user-location.user.js @@ -59,9 +59,6 @@ window.plugin.userLocation.setup = function() { window.plugin.userLocation.circle = circle; window.plugin.userLocation.icon = icon; - if('ondeviceorientation' in window) - window.addEventListener('deviceorientation', window.plugin.userLocation.onDeviceOrientation, false); - window.map.on('zoomend', window.plugin.userLocation.onZoomEnd); window.plugin.userLocation.onZoomEnd(); }; @@ -73,20 +70,25 @@ window.plugin.userLocation.onZoomEnd = function() { window.plugin.userLocation.locationLayer.addLayer(window.plugin.userLocation.circle); }; -window.plugin.userLocation.onDeviceOrientation = function(e) { - var direction, delta, heading; +window.plugin.userLocation.locate = function(lat, lng, accuracy) { + var latlng = new L.LatLng(lat, lng); - if (typeof e.webkitCompassHeading !== 'undefined') { - direction = e.webkitCompassHeading; - if (typeof window.orientation !== 'undefined') { - direction += window.orientation; - } - } - else { - // http://dev.w3.org/geo/api/spec-source-orientation.html#deviceorientation - direction = 360 - e.alpha; - } + var latAccuracy = 180 * accuracy / 40075017; + var lngAccuracy = latAccuracy / Math.cos(L.LatLng.DEG_TO_RAD * lat); + var zoom = window.map.getBoundsZoom(L.latLngBounds( + [lat - latAccuracy, lng - lngAccuracy], + [lat + latAccuracy, lng + lngAccuracy])); + window.map.setView(latlng, zoom); +} + +window.plugin.userLocation.onLocationChange = function(lat, lng) { + var latlng = new L.LatLng(lat, lng); + window.plugin.userLocation.marker.setLatLng(latlng); + window.plugin.userLocation.circle.setLatLng(latlng); +}; + +window.plugin.userLocation.onOrientationChange = function(direction) { $(".container", window.plugin.userLocation.marker._icon) .removeClass("circle") .addClass("arrow") @@ -96,12 +98,6 @@ window.plugin.userLocation.onDeviceOrientation = function(e) { }); } -window.plugin.userLocation.updateLocation = function(lat, lng) { - var latlng = new L.LatLng(lat, lng); - window.plugin.userLocation.marker.setLatLng(latlng); - window.plugin.userLocation.circle.setLatLng(latlng); -}; - var setup = window.plugin.userLocation.setup; // PLUGIN END ////////////////////////////////////////////////////////// diff --git a/mobile/src/com/cradle/iitc_mobile/IITC_Mobile.java b/mobile/src/com/cradle/iitc_mobile/IITC_Mobile.java index ea2b4092..455824e8 100644 --- a/mobile/src/com/cradle/iitc_mobile/IITC_Mobile.java +++ b/mobile/src/com/cradle/iitc_mobile/IITC_Mobile.java @@ -14,8 +14,6 @@ import android.content.SharedPreferences; import android.content.SharedPreferences.OnSharedPreferenceChangeListener; import android.content.res.Configuration; import android.location.Location; -import android.location.LocationListener; -import android.location.LocationManager; import android.net.Uri; import android.os.Bundle; import android.os.Handler; @@ -37,24 +35,28 @@ import java.io.IOException; import java.net.URISyntaxException; import java.util.Stack; -public class IITC_Mobile extends Activity implements OnSharedPreferenceChangeListener, LocationListener { +public class IITC_Mobile extends Activity implements OnSharedPreferenceChangeListener { private static final int REQUEST_LOGIN = 1; + private static final String mIntelUrl = "https://www.ingress.com/intel"; - private IITC_WebView mIitcWebView; - private final String mIntelUrl = "https://www.ingress.com/intel"; - private boolean mIsLocEnabled = false; - private Location mLastLocation = null; - private LocationManager mLocMngr = null; - private IITC_DeviceAccountLogin mLogin; - private MenuItem mSearchMenuItem; - private boolean mDesktopMode = false; - private boolean mAdvancedMenu = false; - private boolean mReloadNeeded = false; - private final Stack mDialogStack = new Stack(); private SharedPreferences mSharedPrefs; + private IITC_WebView mIitcWebView; + private IITC_UserLocation mUserLocation; private IITC_NavigationHelper mNavigationHelper; private IITC_MapSettings mMapSettings; + private IITC_DeviceAccountLogin mLogin; + private boolean mDesktopMode = false; + private boolean mAdvancedMenu = false; + private MenuItem mSearchMenuItem; + private boolean mReloadNeeded = false; + private boolean mIsLoading = true; + private final Stack mDialogStack = new Stack(); + + // Used for custom back stack handling + private final Stack mBackStack = new Stack(); + private Pane mCurrentPane = Pane.MAP; + private boolean mBackButtonPressed = false; private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { @Override @@ -63,11 +65,6 @@ public class IITC_Mobile extends Activity implements OnSharedPreferenceChangeLis } }; - // Used for custom back stack handling - private final Stack mBackStack = new Stack(); - private Pane mCurrentPane = Pane.MAP; - private boolean mBackButtonPressed = false; - @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -91,26 +88,14 @@ public class IITC_Mobile extends Activity implements OnSharedPreferenceChangeLis // get fullscreen status from settings mIitcWebView.updateFullscreenStatus(); - // Acquire a reference to the system Location Manager - mLocMngr = (LocationManager) this - .getSystemService(Context.LOCATION_SERVICE); - - mIsLocEnabled = mSharedPrefs.getBoolean("pref_user_loc", false); - if (mIsLocEnabled) { - // Register the mSharedPrefChangeListener with the Location Manager to receive - // location updates - mLocMngr.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, - 0, 0, this); - mLocMngr.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, - this); - } + mUserLocation = new IITC_UserLocation(this); + mUserLocation.setEnabled(mSharedPrefs.getBoolean("pref_user_loc", false)); // pass ActionBar to helper because we deprecated getActionBar mNavigationHelper = new IITC_NavigationHelper(this, super.getActionBar()); mMapSettings = new IITC_MapSettings(this); - // Clear the back stack mBackStack.clear(); @@ -121,14 +106,13 @@ public class IITC_Mobile extends Activity implements OnSharedPreferenceChangeLis handleIntent(getIntent(), true); } - // --------------------- onSharedPreferenceListener ----------------------- @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { if (key.equals("pref_force_desktop")) { mDesktopMode = sharedPreferences.getBoolean("pref_force_desktop", false); mNavigationHelper.onPrefChanged(); } else if (key.equals("pref_user_loc")) { - mIsLocEnabled = sharedPreferences.getBoolean("pref_user_loc", false); + mUserLocation.setEnabled(sharedPreferences.getBoolean("pref_user_loc", false)); } else if (key.equals("pref_fullscreen")) { mIitcWebView.updateFullscreenStatus(); mNavigationHelper.onPrefChanged(); @@ -154,33 +138,6 @@ public class IITC_Mobile extends Activity implements OnSharedPreferenceChangeLis mReloadNeeded = true; } - // ------------------------------------------------------------------------ - - // ------------------------ LocationListener ------------------------------ - @Override - public void onLocationChanged(Location location) { - // Called when a new location is found by the network location - // provider. - drawMarker(location); - mLastLocation = location; - } - - @Override - public void onStatusChanged(String provider, int status, Bundle extras) { - - } - - @Override - public void onProviderEnabled(String provider) { - - } - - @Override - public void onProviderDisabled(String provider) { - - } - // ------------------------------------------------------------------------ - @Override protected void onNewIntent(Intent intent) { @@ -287,19 +244,14 @@ public class IITC_Mobile extends Activity implements OnSharedPreferenceChangeLis } @Override - protected void onResume() { - super.onResume(); + protected void onStart() { + super.onStart(); // enough idle...let's do some work Log.d("iitcm", "resuming...reset idleTimer"); mIitcWebView.updateCaching(false); - if (mIsLocEnabled) { - // Register the mSharedPrefChangeListener with the Location Manager to receive - // location updates - mLocMngr.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, this); - mLocMngr.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this); - } + mUserLocation.onStart(); if (mReloadNeeded) { Log.d("iitcm", "preference had changed...reload needed"); @@ -317,9 +269,7 @@ public class IITC_Mobile extends Activity implements OnSharedPreferenceChangeLis Log.d("iitcm", "stopping iitcm"); mIitcWebView.loadUrl("javascript: window.idleSet();"); - if (mIsLocEnabled) { - mLocMngr.removeUpdates(this); - } + mUserLocation.onStop(); super.onStop(); } @@ -481,17 +431,13 @@ public class IITC_Mobile extends Activity implements OnSharedPreferenceChangeLis return true; case R.id.locate: // get the users current location and focus it on map switchToPane(Pane.MAP); - // get location from network by default - if (!mIsLocEnabled) { - mIitcWebView.loadUrl("javascript: " + - "window.map.locate({setView : true, maxZoom: 15});"); + + if (mUserLocation.hasCurrentLocation()) { // if gps location is displayed we can use a better location without any costs + mUserLocation.locate(); } else { - if (mLastLocation != null) { - mIitcWebView.loadUrl("javascript: window.map.setView(new L.LatLng(" + - mLastLocation.getLatitude() + "," + - mLastLocation.getLongitude() + "), 15);"); - } + // get location from network by default + mIitcWebView.loadUrl("javascript: window.map.locate({setView : true});"); } return true; case R.id.action_settings: // start settings activity @@ -552,20 +498,6 @@ public class IITC_Mobile extends Activity implements OnSharedPreferenceChangeLis mIitcWebView.loadUrl(url); } - // update the user location marker on the map - public void drawMarker(Location loc) { - // throw away all positions with accuracy > 100 meters - // should avoid gps glitches - if (loc.getAccuracy() < 100) { - // do not touch the javascript while iitc boots - if (findViewById(R.id.imageLoading).getVisibility() == View.GONE) { - mIitcWebView.loadUrl("javascript: " - + "window.plugin.userLocation.updateLocation( " - + loc.getLatitude() + ", " + loc.getLongitude() + ");"); - } - } - } - public IITC_WebView getWebView() { return this.mIitcWebView; } @@ -594,7 +526,7 @@ public class IITC_Mobile extends Activity implements OnSharedPreferenceChangeLis * called by IITC_WebViewClient when the Google login form is opened. */ public void onReceivedLoginRequest(IITC_WebViewClient client, WebView view, - String realm, String account, String args) { + String realm, String account, String args) { mLogin = new IITC_DeviceAccountLogin(this, view, client); mLogin.startLogin(realm, account, args); } @@ -629,7 +561,9 @@ public class IITC_Mobile extends Activity implements OnSharedPreferenceChangeLis } public void setLoadingState(boolean isLoading) { - mNavigationHelper.setLoadingState(isLoading); + mIsLoading = isLoading; + + mNavigationHelper.onLoadingStateChanged(); if (isLoading && !mSharedPrefs.getBoolean("pref_disable_splash", false)) { findViewById(R.id.iitc_webview).setVisibility(View.GONE); @@ -668,6 +602,10 @@ public class IITC_Mobile extends Activity implements OnSharedPreferenceChangeLis finish(); } + public boolean isLoading() { + return mIsLoading; + } + /** * @see getNavigationHelper() * @deprecated ActionBar related stuff should be handled by IITC_NavigationHelper diff --git a/mobile/src/com/cradle/iitc_mobile/IITC_NavigationHelper.java b/mobile/src/com/cradle/iitc_mobile/IITC_NavigationHelper.java index 62254373..9c4df290 100644 --- a/mobile/src/com/cradle/iitc_mobile/IITC_NavigationHelper.java +++ b/mobile/src/com/cradle/iitc_mobile/IITC_NavigationHelper.java @@ -51,7 +51,6 @@ public class IITC_NavigationHelper extends ActionBarDrawerToggle implements OnIt private final View mDrawerRight; private boolean mDesktopMode = false; - private boolean mIsLoading; private Pane mPane = Pane.MAP; private String mHighlighter = null; private int mDialogs = 0; @@ -150,7 +149,7 @@ public class IITC_NavigationHelper extends ActionBarDrawerToggle implements OnIt mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED, mDrawerRight); setDrawerIndicatorEnabled(false); } else { - if (mIsLoading) { + if (mIitc.isLoading()) { mActionBar.setDisplayHomeAsUpEnabled(false); // Hide "up" indicator mActionBar.setHomeButtonEnabled(false);// Make icon unclickable mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED); @@ -175,7 +174,7 @@ public class IITC_NavigationHelper extends ActionBarDrawerToggle implements OnIt } boolean mapVisible = mDesktopMode || mPane == Pane.MAP; - if ("No Highlights".equals(mHighlighter) || isDrawerOpened() || mIsLoading || !mapVisible) { + if ("No Highlights".equals(mHighlighter) || isDrawerOpened() || mIitc.isLoading() || !mapVisible) { mActionBar.setSubtitle(null); } else { mActionBar.setSubtitle(mHighlighter); @@ -255,6 +254,10 @@ public class IITC_NavigationHelper extends ActionBarDrawerToggle implements OnIt mDrawerLayout.closeDrawer(mDrawerLeft); } + public void onLoadingStateChanged() { + updateViews(); + } + @Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == android.R.id.home) { @@ -295,11 +298,6 @@ public class IITC_NavigationHelper extends ActionBarDrawerToggle implements OnIt updateViews(); } - public void setLoadingState(boolean isLoading) { - mIsLoading = isLoading; - updateViews(); - } - public void showActionBar() { mActionBar.show(); } diff --git a/mobile/src/com/cradle/iitc_mobile/IITC_UserLocation.java b/mobile/src/com/cradle/iitc_mobile/IITC_UserLocation.java new file mode 100644 index 00000000..6d137450 --- /dev/null +++ b/mobile/src/com/cradle/iitc_mobile/IITC_UserLocation.java @@ -0,0 +1,196 @@ +package com.cradle.iitc_mobile; + +import android.content.Context; +import android.hardware.Sensor; +import android.hardware.SensorEvent; +import android.hardware.SensorEventListener; +import android.hardware.SensorManager; +import android.location.Location; +import android.location.LocationListener; +import android.location.LocationManager; +import android.os.Bundle; +import android.view.Surface; + +public class IITC_UserLocation implements LocationListener, SensorEventListener { + private boolean mEnabled = false; + private IITC_Mobile mIitc; + private Location mLastLocation = null; + private LocationManager mLocationManager; + private boolean mRegistered = false; + private boolean mRunning = false; + private Sensor mSensorAccelerometer, mSensorMagnetometer; + private SensorManager mSensorManager = null; + float[] mValuesGravity = null, mValuesGeomagnetic = null; + + public IITC_UserLocation(IITC_Mobile iitc) { + mIitc = iitc; + + // Acquire a reference to the Location Manager and Sensor Manager + mLocationManager = (LocationManager) iitc.getSystemService(Context.LOCATION_SERVICE); + mSensorManager = (SensorManager) iitc.getSystemService(Context.SENSOR_SERVICE); + mSensorAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); + mSensorMagnetometer = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD); + } + + private void registerListeners() { + if (mRegistered) return; + mRegistered = true; + + try { + mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, this); + } catch (IllegalArgumentException e) { + // if the given provider doesn't exist + e.printStackTrace(); + } + try { + mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this); + } catch (IllegalArgumentException e) { + // if the given provider doesn't exist + e.printStackTrace(); + } + + if (mSensorAccelerometer != null && mSensorMagnetometer != null) { + mSensorManager.registerListener(this, mSensorAccelerometer, SensorManager.SENSOR_DELAY_UI); + mSensorManager.registerListener(this, mSensorMagnetometer, SensorManager.SENSOR_DELAY_UI); + } + } + + private void unregisterListeners() { + if (!mRegistered) return; + mRegistered = false; + + mLocationManager.removeUpdates(this); + + if (mSensorAccelerometer != null && mSensorMagnetometer != null) { + mSensorManager.unregisterListener(this, mSensorAccelerometer); + mSensorManager.unregisterListener(this, mSensorMagnetometer); + } + + } + + private void updateListeners() { + if (mRunning && mEnabled) + registerListeners(); + else + unregisterListeners(); + } + + public boolean hasCurrentLocation() { + if (!mRegistered) return false; + return mLastLocation != null; + } + + public void locate() { + // do not touch the javascript while iitc boots + if (mIitc.isLoading()) return; + + Location location = mLastLocation; + if (location == null) return; + + mIitc.getWebView().loadJS("if(window.plugin && window.plugin.userLocation)" + + "window.plugin.userLocation.locate(" + + location.getLatitude() + ", " + location.getLongitude() + ", " + location.getAccuracy() + ");"); + } + + public void onStart() { + mRunning = true; + updateListeners(); + } + + public void onStop() { + mRunning = false; + updateListeners(); + } + + public void setEnabled(boolean enabled) { + if (enabled == mEnabled) return; + + mEnabled = enabled; + updateListeners(); + } + + // ------------------------------------------------------------------------ + + // + + @Override + public void onLocationChanged(Location location) { + mLastLocation = location; + + // throw away all positions with accuracy > 100 meters should avoid gps glitches + if (location.getAccuracy() > 100) return; + + // do not touch the javascript while iitc boots + if (mIitc.isLoading()) return; + + mIitc.getWebView().loadJS("if(window.plugin && window.plugin.userLocation)" + + "window.plugin.userLocation.onLocationChange(" + + location.getLatitude() + ", " + location.getLongitude() + ");"); + } + + @Override + public void onProviderDisabled(String provider) { + + } + + @Override + public void onProviderEnabled(String provider) { + + } + + @Override + public void onStatusChanged(String provider, int status, Bundle extras) { + + } + + // + + // ------------------------------------------------------------------------ + + // + + @Override + public void onAccuracyChanged(Sensor sensor, int accuracy) { + } + + @Override + public void onSensorChanged(SensorEvent event) { + if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) + mValuesGravity = event.values; + if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) + mValuesGeomagnetic = event.values; + + // do not touch the javascript while iitc boots + if (mIitc.isLoading()) return; + + // wait until both sensors have given us an event + if (mValuesGravity == null || mValuesGeomagnetic == null) return; + + float R[] = new float[9]; + float I[] = new float[9]; + float orientation[] = new float[3]; + + if (!SensorManager.getRotationMatrix(R, I, mValuesGravity, mValuesGeomagnetic)) return; + SensorManager.getOrientation(R, orientation); + + double direction = orientation[0] / Math.PI * 180; + + int rotation = mIitc.getWindowManager().getDefaultDisplay().getRotation(); + switch (rotation) { + case Surface.ROTATION_90: + direction += 90; + break; + case Surface.ROTATION_180: + direction += 180; + break; + case Surface.ROTATION_270: + direction += 270; + break; + } + + mIitc.getWebView().loadJS("if(window.plugin && window.plugin.userLocation)" + + "window.plugin.userLocation.onOrientationChange(" + direction + ");"); + } + + // +} \ No newline at end of file diff --git a/mobile/src/com/cradle/iitc_mobile/IITC_WebView.java b/mobile/src/com/cradle/iitc_mobile/IITC_WebView.java index f00cad8d..206513d6 100644 --- a/mobile/src/com/cradle/iitc_mobile/IITC_WebView.java +++ b/mobile/src/com/cradle/iitc_mobile/IITC_WebView.java @@ -12,11 +12,9 @@ import android.preference.PreferenceManager; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; -import android.view.View; import android.view.WindowManager; import android.webkit.ConsoleMessage; import android.webkit.GeolocationPermissions; -import android.webkit.ValueCallback; import android.webkit.WebChromeClient; import android.webkit.WebSettings; import android.webkit.WebView; @@ -92,7 +90,7 @@ public class IITC_WebView extends WebView { */ @Override public void onGeolocationPermissionsShowPrompt(String origin, - GeolocationPermissions.Callback callback) { + GeolocationPermissions.Callback callback) { callback.invoke(origin, true, false); } @@ -171,6 +169,7 @@ public class IITC_WebView extends WebView { } } + @TargetApi(19) public void loadJS(String js) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { evaluateJavascript(js, null);