/*
* Copyright (C) 2010 LluĂs Esquerda
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.homelinux.penecoptero.android.citybikes.app;
import java.util.Calendar;
import java.util.List;
import net.homelinux.penecoptero.android.citybikes.utils.CircleHelper;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.location.Location;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.preference.PreferenceManager;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.GestureDetector;
import android.view.Gravity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.widget.LinearLayout.LayoutParams;
import android.widget.RelativeLayout;
import android.widget.Toast;
import android.widget.ToggleButton;
import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;
import com.google.android.maps.Projection;
public class MainActivity extends MapActivity {
private MapView mapView;
public static final int MENU_ITEM_SYNC = Menu.FIRST;
public static final int MENU_ITEM_LOCATION = Menu.FIRST + 1;
public static final int MENU_ITEM_WHATEVER = Menu.FIRST + 2;
public static final int MENU_ITEM_LIST = Menu.FIRST + 3;
public static final int MENU_ITEM_SETTINGS = Menu.FIRST + 4;
public static final int MENU_ITEM_HELP = Menu.FIRST + 5;
public static final int KEY_LAT = 0;
public static final int KEY_LNG = 1;
public static final int SETTINGS_ACTIVITY = 0;
private StationOverlayList stations;
private StationsDBAdapter mDbHelper;
private InfoLayer infoLayer;
private boolean view_all = false;
private HomeOverlay hOverlay;
private ProgressDialog progressDialog;
private StationSlidingDrawer mSlidingDrawer;
private ToggleButton modeButton;
private SharedPreferences settings;
private NetworksDBAdapter mNDBAdapter;
private Handler infoLayerPopulator;
private boolean getBike = true;
private float scale;
private int zoom = -1;
private Locator locator;
private boolean onC2DMTourMode = false;
private int selected_id = -1;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState == null){
selected_id = -1;
} else {
selected_id = savedInstanceState.getInt("c2dm_station_id");
}
if (selected_id == -1){
selected_id = getIntent().getIntExtra("c2dm_station_id", -1);
}
Log.i("CityBikes","I should be centering station "+Integer.toString(selected_id));
setContentView(R.layout.main);
PreferenceManager.setDefaultValues(this, R.xml.preferences, false);
mapView = (MapView) findViewById(R.id.mapview);
mSlidingDrawer = (StationSlidingDrawer) findViewById(R.id.drawer);
infoLayer = (InfoLayer) findViewById(R.id.info_layer);
scale = getResources().getDisplayMetrics().density;
//Log.i("CityBikes","ON CREATEEEEEEEEE!!!!!");
infoLayerPopulator = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == InfoLayer.POPULATE) {
infoLayer.inflateStation(stations.getCurrent());
}
if (msg.what == CityBikes.BOOKMARK_CHANGE){
int id = msg.arg1;
boolean bookmarked;
if (msg.arg2 == 0){
bookmarked = false;
} else{
bookmarked = true;
}
StationOverlay station = stations.getById(id);
try{
BookmarkManager bm = new BookmarkManager(getApplicationContext());
bm.setBookmarked(station.getStation(), !bookmarked);
}catch (Exception e){
Log.i("CityBikes","Error bookmarking station");
e.printStackTrace();
}
if (!view_all) {
view_near();
}
mapView.postInvalidate();
}
}
};
infoLayer.setHandler(infoLayerPopulator);
RelativeLayout.LayoutParams zoomControlsLayoutParams = new RelativeLayout.LayoutParams(
android.view.ViewGroup.LayoutParams.WRAP_CONTENT,
android.view.ViewGroup.LayoutParams.WRAP_CONTENT);
zoomControlsLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP);
zoomControlsLayoutParams.addRule(RelativeLayout.CENTER_HORIZONTAL);
mapView.addView(mapView.getZoomControls(), zoomControlsLayoutParams);
modeButton = (ToggleButton) findViewById(R.id.mode_button);
modeButton.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
changeMode(!getBike);
}
});
applyMapViewLongPressListener(mapView);
settings = getSharedPreferences(CityBikes.PREFERENCES_NAME,0);
List<Overlay> mapOverlays = mapView.getOverlays();
locator = new Locator(this, new Handler(){
@Override
public void handleMessage(Message msg) {
if (msg.what == Locator.LOCATION_CHANGED) {
GeoPoint point = new GeoPoint(msg.arg1, msg.arg2);
hOverlay.moveCenter(point);
mapView.getController().animateTo(point);
mDbHelper.setCenter(point);
// Location has changed
try {
mDbHelper.updateDistances(point);
infoLayer.update();
if (!view_all) {
view_near();
}
} catch (Exception e) {
};
}
}
});
hOverlay = new HomeOverlay(locator.getCurrentGeoPoint(),new Handler(){
@Override
public void handleMessage(Message msg) {
if (msg.what == HomeOverlay.MOTION_CIRCLE_STOP){
Log.i("CityBikes","MOTION CIRCLE STOP");
try {
if (!view_all) {
view_near();
}
mapView.postInvalidate();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
});
stations = new StationOverlayList(mapOverlays, new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == StationOverlay.TOUCHED && msg.arg1 != -1) {
// One station has been touched
stations.setCurrent(msg.arg1, getBike);
infoLayer.inflateStation(stations.getCurrent());
}
}
});
stations.addOverlay(hOverlay);
mNDBAdapter = new NetworksDBAdapter(getApplicationContext());
mDbHelper = new StationsDBAdapter(this, mapView, new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case StationsDBAdapter.FETCH:
break;
case StationsDBAdapter.UPDATE_MAP:
progressDialog.dismiss();
SharedPreferences.Editor editor = settings.edit();
editor.putBoolean("reload_network", false);
editor.commit();
if (selected_id != -1){
selectStation(selected_id, false);
}
StationOverlay current = stations.getCurrent();
if (current == null) {
infoLayer
.inflateMessage(getString(R.string.no_bikes_around));
}
if (current != null) {
current.setSelected(true,getBike);
infoLayer.inflateStation(current);
if (view_all)
view_all();
else
view_near();
} else {
}
mapView.invalidate();
tourC2DM();
break;
case StationsDBAdapter.UPDATE_DATABASE:
////Log.i("openBicing", "Database updated");
break;
case StationsDBAdapter.NETWORK_ERROR:
////Log.i("openBicing", "Network error, last update from " + mDbHelper.getLastUpdated());
Toast toast = Toast.makeText(getApplicationContext(),
getString(R.string.network_error)
+ " " + mDbHelper.getLastUpdated(),
Toast.LENGTH_LONG);
toast.show();
break;
}
}
}, stations);
mDbHelper.setCenter(locator.getCurrentGeoPoint());
mSlidingDrawer.setHandler(new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case StationSlidingDrawer.ITEMCLICKED:
StationOverlay clicked = (StationOverlay) msg.obj;
stations.setCurrent(msg.arg1, getBike);
Message tmp = new Message();
tmp.what = InfoLayer.POPULATE;
tmp.arg1 = msg.arg1;
infoLayerPopulator.dispatchMessage(tmp);
mapView.getController().animateTo(
clicked.getCenter());
}
}
});
if (savedInstanceState != null) {
locator.unlockCenter();
hOverlay.setRadius(
savedInstanceState.getInt("homeRadius"));
this.view_all = savedInstanceState.getBoolean("view_all");
} else {
updateHome();
}
try {
mDbHelper.loadStations();
if (savedInstanceState == null) {
String strUpdated = mDbHelper.getLastUpdated();
Boolean dirty = settings.getBoolean("reload_network",false);
if (strUpdated == null || dirty) {
this.fillData(view_all);
} else {
Toast toast = Toast.makeText(this.getApplicationContext(),
"Last Updated: " + mDbHelper.getLastUpdated(),
Toast.LENGTH_LONG);
toast.show();
Calendar cal = Calendar.getInstance();
long now = cal.getTime().getTime();
if (selected_id != -1){
selectStation(selected_id, true);
}
if (selected_id != -1 || Math.abs(now - mDbHelper.getLastUpdatedTime()) > 60000 * 5)
this.fillData(view_all);
}
}
} catch (Exception e) {
////Log.i("openBicing", "SHIT ... SUCKS");
}
;
if (view_all)
view_all();
else
view_near();
////Log.i("openBicing", "CREATE!");
}
private void showC2DMTour(){
this.onC2DMTourMode = true;
//Toast toastie = Toast.makeText(this,,Toast.LENGTH_LONG);
//toastie.show();
CityBikes.showCustomToast(this.getApplicationContext(), this, getText(R.string.c2dm_tour_start), Toast.LENGTH_LONG, Gravity.TOP | Gravity.CENTER_HORIZONTAL);
infoLayer.setOnC2DMTour(true);
}
private boolean isFirstTimeC2DM(){
SharedPreferences settings = getApplicationContext().getSharedPreferences(CityBikes.PREFERENCES_NAME,0);
boolean firstTime = settings.getBoolean("first_time_c2dm", true);
return firstTime;
}
private void saveFirstTimeC2DM(){
SharedPreferences settings = getApplicationContext().getSharedPreferences(CityBikes.PREFERENCES_NAME,0);
Editor editor = settings.edit();
editor.putBoolean("first_time_c2dm", false);
editor.commit();
}
protected void applyMapViewLongPressListener(MapView mapView) {
final MapView finalMapView = mapView;
final GestureDetector gd = new GestureDetector(new GestureDetector.SimpleOnGestureListener(){
@Override
public void onLongPress(MotionEvent e) {
//Log.i("CityBikes","LONG PRESS!");
Projection astral = finalMapView.getProjection();
GeoPoint center = astral.fromPixels((int) e.getX(),(int) e.getY());
locator.lockCenter(center);
}
@Override
public boolean onDoubleTap(MotionEvent e) {
// TODO Auto-generated method stub
//Log.i("CityBikes","Double tap!");
Projection astral = finalMapView.getProjection();
GeoPoint center = astral.fromPixels((int) e.getX(),(int) e.getY());
locator.lockCenter(center);
return super.onDoubleTap(e);
}
});
mapView.setOnTouchListener(new OnTouchListener(){
@Override
public boolean onTouch(View v, MotionEvent ev) {
return gd.onTouchEvent(ev);
}
});
}
private void showBikeNetworks(){
this.startActivityForResult(new Intent(this,
BikeNetworkActivity.class), SETTINGS_ACTIVITY);
}
private void showAutoNetworkDialog(int method){
AlertDialog alertDialog = new AlertDialog.Builder(this).create();
alertDialog.setIcon(android.R.drawable.ic_dialog_map);
final int mth = method;
try {
mNDBAdapter.update();
final JSONObject network = mNDBAdapter.getAutomaticNetwork(hOverlay.getPoint(),method);
alertDialog.setTitle(R.string.bike_network_alert_success_title);
alertDialog.setMessage(getString(R.string.bike_network_alert_success_text0)+":\n- ("+network.getString("city")+") "+network.getString("name")+"\n"+getString(R.string.bike_network_alert_success_text1));
alertDialog.setButton(AlertDialog.BUTTON_POSITIVE,getString(R.string.sure), new DialogInterface.OnClickListener(){
@Override
public void onClick(DialogInterface dialog, int which) {
try {
mNDBAdapter.setManualNetwork(network.getInt("id"));
fillData(view_all);
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL,getString(R.string.try_again), new DialogInterface.OnClickListener(){
@Override
public void onClick(DialogInterface dialog, int which) {
showAutoNetworkDialog(0);
}
});
alertDialog.setButton(AlertDialog.BUTTON_NEGATIVE,getString(R.string.manual), new DialogInterface.OnClickListener(){
@Override
public void onClick(DialogInterface dialog, int which) {
showBikeNetworks();
}
});
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
alertDialog.setTitle(R.string.bike_network_alert_error_title);
alertDialog.setMessage(getString(R.string.bike_network_alert_error_text));
alertDialog.setButton(AlertDialog.BUTTON_POSITIVE,getString(R.string.try_again), new DialogInterface.OnClickListener(){
@Override
public void onClick(DialogInterface dialog, int which) {
if (mth == 0)
showAutoNetworkDialog(1);
else
showAutoNetworkDialog(0);
}
});
alertDialog.setButton(AlertDialog.BUTTON_NEGATIVE,getString(R.string.manual), new DialogInterface.OnClickListener(){
@Override
public void onClick(DialogInterface dialog, int which) {
showBikeNetworks();
}
});
}
alertDialog.show();
}
private void fillData(boolean all) {
if (mNDBAdapter != null && mNDBAdapter.isConfigured()){
try{
selected_id = stations.getCurrent().getStation().getId();
} catch (Exception e){
}
Bundle data = new Bundle();
if (!all) {
GeoPoint center = locator.getCurrentGeoPoint();
if (center == null){
//Do something..
int nid = settings.getInt("network_id",-1);
//Log.i("CityBikes","Current network is id: "+Integer.toString(nid));
if (nid!=-1){
try{
mNDBAdapter.load();
JSONObject network = mNDBAdapter.getNetworks(nid);
//Log.i("CityBikes",network.toString());
double lat = Integer.parseInt(network.getString("lat"))/1E6;
double lng = Integer.parseInt(network.getString("lng"))/1E6;
Location fallback = new Location("fallback");
fallback.setLatitude(lat);
fallback.setLongitude(lng);
locator.setFallbackLocation(fallback);
locator.unlockCenter();
center = locator.getCurrentGeoPoint();
}catch (Exception e){
//Log.i("CityBikes","We re fucked, that network aint existin");
e.printStackTrace();
}
}else{
//Log.i("CityBikes","We re fucked, why re we here?");
}
}
data.putInt(StationsDBAdapter.CENTER_LAT_KEY, center
.getLatitudeE6());
data.putInt(StationsDBAdapter.CENTER_LNG_KEY, center
.getLongitudeE6());
data.putInt(StationsDBAdapter.RADIUS_KEY, hOverlay.getRadius());
}
progressDialog = new ProgressDialog(this);
progressDialog.setTitle("");
progressDialog.setMessage(getString(R.string.loading));
progressDialog.show();
try {
mDbHelper.sync(all, data);
} catch (Exception e) {
////Log.i("openBicing", "Error Updating?");
e.printStackTrace();
progressDialog.dismiss();
}
;
}else{
//Log.i("CityBikes","First time!!! :D");
try{
mNDBAdapter.update();
AlertDialog alertDialog = new AlertDialog.Builder(this).create();
alertDialog.setIcon(android.R.drawable.ic_dialog_map);
alertDialog.setTitle(R.string.bike_network_alert_title);
alertDialog.setMessage(getString(R.string.bike_network_alert_text));
alertDialog.setButton(getString(R.string.automatic), new DialogInterface.OnClickListener(){
@Override
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
}
});
alertDialog.setButton(AlertDialog.BUTTON_POSITIVE,getString(R.string.automatic), new DialogInterface.OnClickListener(){
@Override
public void onClick(DialogInterface dialog, int which) {
showAutoNetworkDialog(0);
}
});
alertDialog.setButton(AlertDialog.BUTTON_NEGATIVE,getString(R.string.manual), new DialogInterface.OnClickListener(){
@Override
public void onClick(DialogInterface dialog, int which) {
showBikeNetworks();
}
});
alertDialog.show();
}catch (Exception e){
e.printStackTrace();
Toast toast = Toast.makeText(getApplicationContext(),getString(R.string.network_error),Toast.LENGTH_LONG);
toast.show();
}
}
}
public void changeMode(boolean getBike){
this.getBike = getBike;
mDbHelper.changeMode(this.getBike);
this.populateList(this.view_all);
infoLayer.update();
mapView.invalidate();
String text;
if (getBike){
text = getString(R.string.get_bike_mode);
} else {
text = getString(R.string.park_bike_mode);
}
CityBikes.showCustomToast(this.getApplicationContext(), this, text, Toast.LENGTH_SHORT);
}
@Override
protected boolean isRouteDisplayed() {
// TODO Auto-generated method stub
return false;
}
public boolean isOnGetMode(){
return this.getBike;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
menu.add(0, MENU_ITEM_SYNC, 0, R.string.menu_sync).setIcon(
R.drawable.ic_menu_refresh);
menu.add(0, MENU_ITEM_LOCATION, 0, R.string.menu_location).setIcon(
android.R.drawable.ic_menu_mylocation);
menu.add(0, MENU_ITEM_WHATEVER, 0, R.string.menu_view_all).setIcon(
android.R.drawable.checkbox_off_background);
menu.add(0, MENU_ITEM_SETTINGS, 0, R.string.menu_settings).setIcon(
android.R.drawable.ic_menu_preferences);
return true;
}
public void updateHome() {
try {
locator.unlockCenter();
mapView.getController().animateTo(locator.getCurrentGeoPoint());
if (zoom == -1){
zoom = 16;
mapView.getController().setZoom(zoom);
}
} catch (Exception e) {
//Log.i("CityBikes", "center is null..");
}
}
public void selectStation(int id, boolean should_find){
Log.i("CityBikes","Selecting a station automatically! "+Integer.toString(id));
StationOverlay station = stations.getById(id);
if (station != null){
Log.i("CityBikes","Found the station: "+station.getStation().getName());
stations.setCurrent(station.getStation().getId(), getBike);
Message tmp = new Message();
tmp.what = InfoLayer.POPULATE;
tmp.arg1 = station.getStation().getId();
infoLayerPopulator.dispatchMessage(tmp);
} else if (should_find) {
// Check if we are in view near mode (then, we should
// make the radius bigger, or just put the app in
// view all mode to center it. If we are already in
// view all mode, just report the error, or fuck it
station = mDbHelper.getStationFromAll(id);
if (station == null)
Log.i("CityBikes","I don't know about this station, fuck you");
else{
Log.i("CityBikes","Station is not on radius, trying a guess..");
Log.i("CityBikes","It might be at.. "+Integer.toString((int) station.getStation().getMetersDistance())+" m");
hOverlay.setRadius((int) station.getStation().getMetersDistance()+500);
selectStation(id, false);
}
}
}
public void view_all() {
try {
Log.i("CityBikes","Viewing all");
mDbHelper.populateStations();
populateList(true);
} catch (Exception e) {
};
}
public void view_near() {
try {
Log.i("CityBikes","Viewing near");
mDbHelper.populateStations(locator.getCurrentGeoPoint(), hOverlay.getRadius());
populateList(false);
if (!infoLayer.isPopulated()) {
StationOverlay current = stations.getCurrent();
if (current != null) {
infoLayer.inflateStation(current);
current.setSelected(true, this.getBike);
} else {
infoLayer.inflateMessage(getString(R.string.no_bikes_around));
}
}
} catch (Exception e) {
};
}
public void tourC2DM(){
Log.i("CityBikes","Starting new feature showroom!");
if (CityBikes.isC2DMReady(this) && isFirstTimeC2DM()){
saveFirstTimeC2DM();
AlertDialog alertDialog = new AlertDialog.Builder(this).create();
alertDialog.setIcon(android.R.drawable.ic_dialog_alert);
alertDialog.setTitle(this.getString(R.string.new_feature));
alertDialog.setMessage(this.getString(R.string.c2dm_new_feature));
alertDialog.setButton(AlertDialog.BUTTON_POSITIVE,this.getString(R.string.sure), new DialogInterface.OnClickListener(){
@Override
public void onClick(DialogInterface dialog, int which) {
showC2DMTour();
}
});
alertDialog.setButton(AlertDialog.BUTTON_NEGATIVE,this.getString(R.string.nope), new DialogInterface.OnClickListener(){
@Override
public void onClick(DialogInterface dialog, int which) {
Log.i("C2DM","Dismissing this shit!");
}
});
alertDialog.show();
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case MENU_ITEM_SYNC:
try {
this.fillData(view_all);
} catch (Exception e) {
}
;
return true;
case MENU_ITEM_LOCATION:
updateHome();
return true;
case MENU_ITEM_WHATEVER:
if (!view_all) {
item.setIcon(android.R.drawable.checkbox_on_background);
view_all();
} else {
item.setIcon(android.R.drawable.checkbox_off_background);
view_near();
}
view_all = !view_all;
return true;
case MENU_ITEM_SETTINGS:
this
.startActivityForResult(new Intent(this,
SettingsActivity.class), SETTINGS_ACTIVITY);
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
protected void onResume() {
super.onResume();
////Log.i("openBicing", "RESUME!");
}
@Override
protected void onSaveInstanceState(Bundle outState) {
////Log.i("openBicing", "SaveInstanceState!");
outState.putInt("homeRadius", hOverlay.getRadius());
outState.putBoolean("view_all", view_all);
outState.putInt("zoom", mapView.getZoomLevel());
}
@Override
protected void onPause() {
super.onPause();
////Log.i("openBicing", "PAUSE!");
}
@Override
protected void onDestroy() {
super.onDestroy();
////Log.i("openBicing", "DESTROY!");
}
@Override
protected void onStop() {
super.onStop();
////Log.i("openBicing", "STOP!");
locator.stopUpdates();
if (this.isFinishing())
this.finish();
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
//Log.i("CityBikes", "Activity Result");
if (requestCode == SETTINGS_ACTIVITY) {
if (resultCode == RESULT_OK) {
locator.restartUpdates();
}
}
Boolean dirty = settings.getBoolean("reload_network",false);
if (dirty){
this.fillData(view_all);
}
}
public void populateList(boolean all) {
try {
List sts;
if (all) {
sts = mDbHelper.getMemory();
} else {
sts = mDbHelper.getMemory(hOverlay.getRadius());
}
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
int height = dm.heightPixels;
int calc = (sts.size() * CircleHelper.dip2px(50, scale) + CircleHelper.dip2px(45, scale));
if (calc > height - CircleHelper.dip2px(145, scale))
calc = height - CircleHelper.dip2px(145, scale);
else if (sts.size() == 0)
calc = 0;
mSlidingDrawer.setStations(sts);
mSlidingDrawer.setLayoutParams(new LayoutParams(
android.view.ViewGroup.LayoutParams.FILL_PARENT, calc));
} catch (Exception e) {
e.printStackTrace();
}
}
}