2013-09-22 21:46:11 +02:00

611 lines
22 KiB
Java

package com.cradle.iitc_mobile;
import android.app.ActionBar;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.SearchManager;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
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;
import android.preference.PreferenceManager;
import android.support.v4.widget.DrawerLayout;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.webkit.CookieManager;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.widget.ListView;
import android.widget.SearchView;
import android.widget.Toast;
import com.cradle.iitc_mobile.IITC_NavigationHelper.Pane;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.Locale;
import java.util.Stack;
public class IITC_Mobile extends Activity {
private static final int REQUEST_LOGIN = 1;
private IITC_WebView mIitcWebView;
private OnSharedPreferenceChangeListener mSharedPrefChangeListener;
private final String mIntelUrl = "https://www.ingress.com/intel";
private boolean mIsLocEnabled = false;
private Location mLastLocation = null;
private LocationManager mLocMngr = null;
private LocationListener mLocListener = null;
private boolean mFullscreenMode = false;
private IITC_DeviceAccountLogin mLogin;
private MenuItem mSearchMenuItem;
private boolean mDesktopMode = false;
private boolean mAdvancedMenu = false;
private boolean mReloadNeeded = false;
private final Stack<String> mDialogStack = new Stack<String>();
private SharedPreferences mSharedPrefs;
private IITC_NavigationHelper mNavigationHelper;
// Used for custom back stack handling
private final Stack<Pane> mBackStack = new Stack<IITC_NavigationHelper.Pane>();
private boolean mBackStackPush = true;
private Pane mCurrentPane = Pane.MAP;
private boolean mBackButtonPressed = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// enable progress bar above action bar
requestWindowFeature(Window.FEATURE_PROGRESS);
setContentView(R.layout.activity_main);
mIitcWebView = (IITC_WebView) findViewById(R.id.iitc_webview);
// pass ActionBar to helper because we deprecated getActionBar
mNavigationHelper = new IITC_NavigationHelper(this, super.getActionBar(),
(ListView) findViewById(R.id.left_drawer),
(DrawerLayout) findViewById(R.id.drawer_layout));
// do something if user changed something in the settings
mSharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
mSharedPrefChangeListener = new OnSharedPreferenceChangeListener() {
@Override
public void onSharedPreferenceChanged(
SharedPreferences sharedPreferences, String key) {
if (key.equals("pref_force_desktop")) {
mDesktopMode = sharedPreferences.getBoolean("pref_force_desktop", false);
mNavigationHelper.onPrefChanged();
invalidateOptionsMenu();
}
if (key.equals("pref_user_loc"))
mIsLocEnabled = sharedPreferences.getBoolean("pref_user_loc",
false);
if (key.equals("pref_fullscreen_actionbar")) {
mNavigationHelper.onPrefChanged();
return;
}
if (key.equals("pref_advanced_menu")) {
mAdvancedMenu = sharedPreferences.getBoolean("pref_advanced_menu", false);
mNavigationHelper.setDebugMode(mAdvancedMenu);
invalidateOptionsMenu();
// no reload needed
return;
}
// no reload needed
if (key.equals("pref_press_twice_to_exit") || key.equals("pref_share_selected_tab"))
return;
mReloadNeeded = true;
}
};
mSharedPrefs.registerOnSharedPreferenceChangeListener(mSharedPrefChangeListener);
// enable/disable mDesktopMode mode on menu create and url load
mDesktopMode = mSharedPrefs.getBoolean("pref_force_desktop", false);
// enable/disable advance menu
mAdvancedMenu = mSharedPrefs.getBoolean("pref_advanced_menu", false);
// Acquire a reference to the system Location Manager
mLocMngr = (LocationManager) this
.getSystemService(Context.LOCATION_SERVICE);
// Define a mSharedPrefChangeListener that responds to location updates
mLocListener = new LocationListener() {
public void onLocationChanged(Location location) {
// Called when a new location is found by the network location
// provider.
drawMarker(location);
mLastLocation = location;
}
public void onStatusChanged(String provider, int status, Bundle extras) {
}
public void onProviderEnabled(String provider) {
}
public void onProviderDisabled(String provider) {
}
};
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, mLocListener);
mLocMngr.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0,
mLocListener);
}
// Clear the back stack
mBackStack.clear();
handleIntent(getIntent(), true);
}
@Override
protected void onNewIntent(Intent intent) {
setIntent(intent);
handleIntent(intent, false);
}
private void handleIntent(Intent intent, boolean onCreate) {
// load new iitc web view with ingress intel page
String action = intent.getAction();
if (Intent.ACTION_VIEW.equals(action)) {
Uri uri = intent.getData();
Log.d("iitcm", "intent received url: " + uri.toString());
if (uri.getScheme().equals("http") || uri.getScheme().equals("https")) {
if (uri.getHost() != null
&& (uri.getHost().equals("ingress.com") || uri.getHost().endsWith(".ingress.com"))) {
Log.d("iitcm", "loading url...");
this.loadUrl(uri.toString());
return;
}
}
if (uri.getScheme().equals("geo")) {
try {
handleGeoUri(uri);
return;
} catch (URISyntaxException e) {
e.printStackTrace();
new AlertDialog.Builder(this)
.setTitle(R.string.intent_error)
.setMessage(e.getReason())
.setNeutralButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
})
.create()
.show();
}
}
}
if (Intent.ACTION_SEARCH.equals(action)) {
String query = intent.getStringExtra(SearchManager.QUERY);
query = query.replace("'", "''");
final SearchView searchView =
(SearchView) mSearchMenuItem.getActionView();
searchView.setQuery(query, false);
searchView.clearFocus();
switchToPane(Pane.MAP);
mIitcWebView.loadUrl("javascript:search('" + query + "');");
return;
}
if (onCreate) {
this.loadUrl(mIntelUrl);
}
}
private void handleGeoUri(Uri uri) throws URISyntaxException {
String[] parts = uri.getSchemeSpecificPart().split("\\?", 2);
Double lat, lon;
Integer z = null;
// parts[0] may contain an 'uncertainty' parameter, delimited by a semicolon
String[] pos = parts[0].split(";", 2)[0].split(",", 2);
if (pos.length != 2)
throw new URISyntaxException(uri.toString(), "URI does not contain a valid position");
try {
lat = Double.valueOf(pos[0]);
lon = Double.valueOf(pos[1]);
} catch (NumberFormatException e) {
URISyntaxException use = new URISyntaxException(uri.toString(), "position could not be parsed");
use.initCause(e);
throw use;
}
if (parts.length > 1) { // query string present
// search for z=
for (String param : parts[1].split("&")) {
if (param.startsWith("z=")) {
try {
z = Integer.valueOf(param.substring(2));
} catch (NumberFormatException e) {
URISyntaxException use = new URISyntaxException(uri.toString(), "could not parse zoom level");
use.initCause(e);
throw use;
}
break;
}
}
}
String url = "http://www.ingress.com/intel?ll=" + lat + "," + lon;
if (z != null)
url += "&z=" + z;
this.loadUrl(url);
}
@Override
protected void onResume() {
super.onResume();
// enough idle...let's do some work
Log.d("iitcm", "resuming...reset idleTimer");
mIitcWebView.updateCaching();
if (mIsLocEnabled) {
// Register the mSharedPrefChangeListener with the Location Manager to receive
// location updates
mLocMngr.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, mLocListener);
mLocMngr.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, mLocListener);
}
if (mReloadNeeded) {
Log.d("iitcm", "preference had changed...reload needed");
reloadIITC();
}
else {
// iitc is not fully booted...timer will be reset by the script itself
if (findViewById(R.id.imageLoading).getVisibility() == View.GONE) {
mIitcWebView.loadUrl("javascript: window.idleReset();");
}
}
}
@Override
protected void onStop() {
Log.d("iitcm", "stopping iitcm");
mIitcWebView.loadUrl("javascript: window.idleSet();");
if (mIsLocEnabled)
mLocMngr.removeUpdates(mLocListener);
super.onStop();
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
mNavigationHelper.onConfigurationChanged(newConfig);
Log.d("iitcm", "configuration changed...restoring...reset idleTimer");
mIitcWebView.loadUrl("javascript: window.idleTime = 0");
mIitcWebView.loadUrl("javascript: window.renderUpdateStatus()");
}
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
mNavigationHelper.onPostCreate(savedInstanceState);
}
// we want a self defined behavior for the back button
@Override
public void onBackPressed() {
// first kill all open iitc dialogs
if (!mDialogStack.isEmpty()) {
String id = mDialogStack.pop();
mIitcWebView.loadUrl("javascript: " +
"var selector = $(window.DIALOGS['" + id + "']); " +
"selector.dialog('close'); " +
"selector.remove();");
return;
}
// exit fullscreen mode if it is enabled and action bar is disabled
// or the back stack is empty
if (mFullscreenMode && (mBackStack.isEmpty() || mNavigationHelper.hideInFullscreen())) {
this.toggleFullscreen();
} else if (!mBackStack.isEmpty()) {
// Pop last item from backstack and pretend the relevant menu item was clicked
backStackPop();
} else {
if (mBackButtonPressed || !mSharedPrefs.getBoolean("pref_press_twice_to_exit", false))
super.onBackPressed();
else {
mBackButtonPressed = true;
Toast.makeText(this, "Press twice to exit", Toast.LENGTH_SHORT).show();
// reset back button after 2 seconds
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
mBackButtonPressed = false;
}
}, 2000);
}
}
}
public void backStackPop() {
// shouldn't be called when back stack is empty
// catch wrong usage
if (mBackStack.isEmpty()) {
mBackStack.push(Pane.MAP);
}
Pane pane = mBackStack.pop();
mBackStackPush = false;
switchToPane(pane);
}
public void setCurrentPane(Pane pane) {
// ensure no double adds
if (pane == mCurrentPane) return;
if (mBackStackPush)
mBackStack.push(mCurrentPane);
else
mBackStackPush = true;
mCurrentPane = pane;
mNavigationHelper.switchTo(pane);
}
public void switchToPane(Pane pane) {
String name = pane.name().toLowerCase(Locale.getDefault());
mIitcWebView.loadUrl("javascript: window.show('" + name + "');");
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
// Get the SearchView and set the searchable configuration
SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
mSearchMenuItem = menu.findItem(R.id.menu_search);
final SearchView searchView =
(SearchView) mSearchMenuItem.getActionView();
// Assumes current activity is the searchable activity
searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
searchView.setIconifiedByDefault(false); // Do not iconify the widget; expand it by default
// enable/disable mDesktopMode menu
MenuItem item = menu.findItem(R.id.menu_clear_cookies);
item.setVisible(mAdvancedMenu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (mNavigationHelper.onOptionsItemSelected(item))
return true;
// Handle item selection
final int itemId = item.getItemId();
switch (itemId) {
case android.R.id.home:
mBackStack.clear();
mBackStackPush = false;
switchToPane(Pane.MAP);
return true;
case R.id.reload_button:
reloadIITC();
return true;
case R.id.toggle_fullscreen:
toggleFullscreen();
return true;
case R.id.layer_chooser:
// Force map view to handle potential issue with back stack
if (!mBackStack.isEmpty() && mCurrentPane != Pane.MAP)
switchToPane(Pane.MAP);
// the getLayers function calls the setLayers method of IITC_JSInterface
mIitcWebView.loadUrl("javascript: window.layerChooser.getLayers()");
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 gps location is displayed we can use a better location without any costs
} else {
if (mLastLocation != null)
mIitcWebView.loadUrl("javascript: window.map.setView(new L.LatLng(" +
mLastLocation.getLatitude() + "," +
mLastLocation.getLongitude() + "), 15);");
}
return true;
case R.id.action_settings: // start settings activity
Intent intent = new Intent(this, IITC_PreferenceActivity.class);
intent.putExtra("iitc_version", mIitcWebView.getWebViewClient()
.getIITCVersion());
startActivity(intent);
return true;
case R.id.menu_clear_cookies:
CookieManager cm = CookieManager.getInstance();
cm.removeAllCookie();
return true;
default:
return false;
}
}
public void reloadIITC() {
mNavigationHelper.reset();
mBackStack.clear();
mBackStackPush = true;
// iitc starts on map after reload
mCurrentPane = Pane.MAP;
loadUrl(mIntelUrl);
mReloadNeeded = false;
}
private void loadIITC() {
try {
mIitcWebView.getWebViewClient().loadIITC_JS(this);
} catch (IOException e1) {
e1.printStackTrace();
} catch (NullPointerException e2) {
e2.printStackTrace();
}
}
// vp=f enables mDesktopMode mode...vp=m is the defaul mobile view
private String addUrlParam(String url) {
if (mDesktopMode)
return (url + "?vp=f");
else
return (url + "?vp=m");
}
// inject the iitc-script and load the intel url
// plugins are injected onPageFinished
public void loadUrl(String url) {
setLoadingState(true);
url = addUrlParam(url);
loadIITC();
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 void toggleFullscreen() {
mFullscreenMode = !mFullscreenMode;
mNavigationHelper.setFullscreen(mFullscreenMode);
// toggle notification bar
WindowManager.LayoutParams attrs = getWindow().getAttributes();
attrs.flags ^= WindowManager.LayoutParams.FLAG_FULLSCREEN;
this.getWindow().setAttributes(attrs);
}
public IITC_WebView getWebView() {
return this.mIitcWebView;
}
/**
* It can occur that in order to authenticate, an external activity has to be launched.
* (This could for example be a confirmation dialog.)
*/
public void startLoginActivity(Intent launch) {
startActivityForResult(launch, REQUEST_LOGIN); // REQUEST_LOGIN is to recognize the result
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case REQUEST_LOGIN:
// authentication activity has returned. mLogin will continue authentication
mLogin.onActivityResult(resultCode, data);
break;
default:
super.onActivityResult(requestCode, resultCode, data);
}
}
/**
* 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) {
Log.d("iitcm", "logging in...set caching mode to default");
mIitcWebView.getSettings().setCacheMode(WebSettings.LOAD_DEFAULT);
mLogin = new IITC_DeviceAccountLogin(this, view, client);
mLogin.startLogin(realm, account, args);
}
/**
* called after successful login
*/
public void loginSucceeded() {
// garbage collection
mLogin = null;
setLoadingState(true);
}
// remove dialog and add it back again
// to ensure it is the last element of the list
// focused dialogs should be closed first
public void setFocusedDialog(String id) {
Log.d("iitcm", "Dialog " + id + " focused");
mDialogStack.remove(id);
mDialogStack.push(id);
}
// called by the javascript interface
public void dialogOpened(String id, boolean open) {
if (open) {
Log.d("iitcm", "Dialog " + id + " added");
mDialogStack.push(id);
} else {
Log.d("iitcm", "Dialog " + id + " closed");
mDialogStack.remove(id);
}
}
public void setLoadingState(boolean isLoading) {
mNavigationHelper.setLoadingState(isLoading);
if (isLoading && !mSharedPrefs.getBoolean("pref_disable_splash", false)) {
findViewById(R.id.iitc_webview).setVisibility(View.GONE);
findViewById(R.id.imageLoading).setVisibility(View.VISIBLE);
} else {
findViewById(R.id.iitc_webview).setVisibility(View.VISIBLE);
findViewById(R.id.imageLoading).setVisibility(View.GONE);
}
}
/**
* @deprecated ActionBar related stuff should be handled by IITC_NavigationHelper
* @see getNavigationHelper()
*/
@Deprecated
@Override
public ActionBar getActionBar() {
return super.getActionBar();
}
public IITC_NavigationHelper getNavigationHelper() {
return mNavigationHelper;
}
}