Commit 726837b8 authored by kastner's avatar kastner

Attemping to refacotr code to reduce duplication

created common super class for NewsStand activities
parent 45351148
package edu.umd.umiacs.newsstand;
import android.app.Activity;
import android.app.Fragment;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.PointF;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.location.Location;
import android.location.LocationManager;
import android.location.LocationListener;
import android.net.ConnectivityManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
import android.view.Menu;
import android.view.View;
import android.widget.ImageButton;
import android.widget.RelativeLayout;
import android.widget.SeekBar;
import com.google.android.gms.maps.CameraUpdate;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.LatLngBounds;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import com.nostra13.universalimageloader.core.DisplayImageOptions;
import org.xmlpull.v1.XmlPullParserException;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import edu.umd.umiacs.newsstand.cache.DeviceGrid;
import edu.umd.umiacs.newsstand.cache.DeviceGridCell;
import edu.umd.umiacs.newsstand.cache.Prediction;
import edu.umd.umiacs.newsstand.cache.QueryRecord;
import edu.umd.umiacs.newsstand.filters.FiltersActivity;
import edu.umd.umiacs.newsstand.layers.LayersAlertDialogFragment;
import edu.umd.umiacs.newsstand.map.MapMarker;
import edu.umd.umiacs.newsstand.map.MapUpdateRequest;
import edu.umd.umiacs.newsstand.mode.ModeAlertDialogFragment;
import edu.umd.umiacs.newsstand.source.Source;
import edu.umd.umiacs.newsstand.source.update.SourceUpdateRequest;
import io.keen.client.android.KeenClient;
import io.keen.client.android.UploadFinishedCallback;
import io.keen.client.android.exceptions.KeenException;
import static edu.umd.umiacs.newsstand.NewsStandConstants.ALL_SOURCES_FILENAME;
import static edu.umd.umiacs.newsstand.NewsStandConstants.COUNTRY_SOURCES_FILENAME;
import static edu.umd.umiacs.newsstand.NewsStandConstants.FEED_SOURCES_FILENAME;
import static edu.umd.umiacs.newsstand.NewsStandConstants.GENERAL_PREFS;
import static edu.umd.umiacs.newsstand.NewsStandConstants.HOME_LAT_BOT;
import static edu.umd.umiacs.newsstand.NewsStandConstants.HOME_LAT_TOP;
import static edu.umd.umiacs.newsstand.NewsStandConstants.HOME_LON_LEFT;
import static edu.umd.umiacs.newsstand.NewsStandConstants.HOME_LON_RIGHT;
import static edu.umd.umiacs.newsstand.NewsStandConstants.IMAGE_MARKER_SIZE;
import static edu.umd.umiacs.newsstand.NewsStandConstants.LANGUAGE_SOURCES_FILENAME;
import static edu.umd.umiacs.newsstand.NewsStandConstants.MAX_CACHE_SECONDS;
import static edu.umd.umiacs.newsstand.NewsStandConstants.QUERY_RECORDS_FILENAME;
/**
* This class aims to capture the attributes of a generic activity in the NewsStand app.
* Mainly, this includes the top and bottom navigation bars and the map interface.
*/
public abstract class BaseNewsStandActivity extends Activity implements View.OnLongClickListener,
SeekBar.OnSeekBarChangeListener, LocationListener, SensorEventListener{
protected Menu mMenu;
protected Prediction mPrediction;
protected int mCacheSize;
//Accelerometer
protected SensorManager mSensorManager;
protected LocationManager mLocationManager;
// PhotoStand specific
protected ArrayList<String> mImageURLs;
protected int mImageMarkerPixels;
protected float mDensityMultiplier; // Scale pixels according to device
protected int mHandMode;
protected Sensor mAccelerometer;
protected boolean firstCameraChange = true;
protected GoogleMap mMap;
protected Source.SourceType mSelectedSourceType;
protected int mSelectedSourceIndex = 0;
protected ImageButton mZoomInButton;
protected ImageButton mZoomOutButton;
protected ImageButton mRefreshButton;
protected int mLabelColor;
protected int mShadowColor;
protected StandMode mStandMode;
protected ArrayList<DeviceGridCellMarker> mGridCellMarkers;
protected MapLayers mPreviousLayerSelected = MapLayers.ICON;
protected MapLayers mLayerSelected = MapLayers.ICON;
protected String mSearchKey;
protected String mConstraints;
//Grid
protected DeviceGrid portraitGrid;
protected DeviceGrid landscapeGrid;
protected ArrayList<Marker> mMarkers;
protected boolean mZoomToArea; // Must find markers if set (zoom out until)
protected ArrayList<MapMarker> mMapMarkers;
protected AsyncTask<String, Void, String> languageSourceAsyncTask;
protected AsyncTask<String, Void, String> feedSourceAsyncTask;
private ArrayList<QueryRecord> mQueryRecords;
private DisplayImageOptions options;
private boolean mSensorInitialized;
private int mLastHandMode;
private ArrayList<DeviceGridCell> mWindowGridCells;
private ArrayList<DeviceGridCell> mPredictions;
private boolean retrievedCurrentWindow;
private int K = 5;
private double mMapLonLeft;
private double mMapLonRight;
private double mMapLatBot;
private double mMapLatTop;
// Keen Analytics
private int mWindowsSinceUpdate;
/**
* This method check mobile is connected to network.
*
* @param context
* @return true if connected otherwise false.
*/
protected static boolean isNetworkAvailable(Context context) {
ConnectivityManager conMan = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
return conMan.getActiveNetworkInfo() != null && conMan.getActiveNetworkInfo().isConnected();
}
// ================================================================================
// Cache stuff
// ================================================================================
protected void initializeCache() {
mQueryRecords = loadQueryRecordsFromFile();
if (mQueryRecords == null) {
mQueryRecords = new ArrayList<QueryRecord>();
}
mCacheSize = 10;
mPrediction = new Prediction();
}
@SuppressWarnings("unchecked")
private ArrayList<QueryRecord> loadQueryRecordsFromFile() {
ArrayList<QueryRecord> queryRecords = new ArrayList<QueryRecord>();
FileInputStream fis = null;
ObjectInputStream ois = null;
try {
fis = openFileInput(QUERY_RECORDS_FILENAME);
ois = new ObjectInputStream(fis);
queryRecords = (ArrayList<QueryRecord>) ois.readObject();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (fis != null) fis.close();
if (ois != null) ois.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return queryRecords;
}
@Override
protected void onPause() {
//Log.i(TAG, "ON PAUSE CALLED!");
saveGlobalsToFiles();
mSensorManager.unregisterListener(this);
uploadKeen();
super.onPause();
}
private void saveGlobalsToFiles() {
NewsStandApplication applicationState = ((NewsStandApplication) getApplicationContext());
FileOutputStream fosAll = null, fosLang = null, fosFeed = null, fosCountry = null;
ObjectOutputStream oosAll = null, oosLang = null, oosFeed = null, oosCountry = null;
try {
fosAll = openFileOutput(ALL_SOURCES_FILENAME, Context.MODE_PRIVATE);
oosAll = new ObjectOutputStream(fosAll);
oosAll.writeObject(applicationState != null ? applicationState.getAllSources() : null);
fosLang = openFileOutput(LANGUAGE_SOURCES_FILENAME, Context.MODE_PRIVATE);
oosLang = new ObjectOutputStream(fosLang);
oosLang.writeObject(applicationState != null ? applicationState.getLanguageSources() : null);
fosFeed = openFileOutput(FEED_SOURCES_FILENAME, Context.MODE_PRIVATE);
oosFeed = new ObjectOutputStream(fosFeed);
oosFeed.writeObject(applicationState != null ? applicationState.getFeedSources() : null);
fosCountry = openFileOutput(COUNTRY_SOURCES_FILENAME, Context.MODE_PRIVATE);
oosCountry = new ObjectOutputStream(fosCountry);
oosCountry.writeObject(applicationState != null ? applicationState.getCountrySources() : null);
} catch (Exception e) {
Log.e("NewsStand", "failed to write", e);
} finally {
try {
if (oosAll != null) oosAll.close();
if (fosAll != null) fosAll.close();
if (oosLang != null) oosLang.close();
if (fosLang != null) fosLang.close();
if (oosFeed != null) oosFeed.close();
if (fosFeed != null) fosFeed.close();
if (oosCountry != null) oosCountry.close();
if (fosCountry != null) fosCountry.close();
} catch (Exception e) { /* do nothing */ }
}
}
@SuppressWarnings("unchecked")
protected ArrayList<Source> loadSourcesFromFile(String filename) {
ArrayList<Source> sources = new ArrayList<Source>();
FileInputStream fis = null;
ObjectInputStream ois = null;
try {
fis = openFileInput(filename);
ois = new ObjectInputStream(fis);
sources = (ArrayList<Source>) ois.readObject();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (fis != null) fis.close();
if (ois != null) ois.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return sources;
}
protected void homeItemClicked() {
SharedPreferences sharedPreferences = getSharedPreferences(
GENERAL_PREFS, 0);
float homeLatBot = sharedPreferences
.getFloat(HOME_LAT_BOT, (float) 0.0);
float homeLatTop = sharedPreferences
.getFloat(HOME_LAT_TOP, (float) 0.0);
float homeLonLeft = sharedPreferences.getFloat(HOME_LON_LEFT,
(float) 0.0);
float homeLonRight = sharedPreferences.getFloat(HOME_LON_RIGHT,
(float) 0.0);
if (Math.abs(homeLatBot + homeLatTop + homeLonLeft + homeLonRight) < .001)
return;
try {
LatLng addressSouthWest = new LatLng(homeLatBot, homeLonLeft);
LatLng addressNorthEast = new LatLng(homeLatTop, homeLonRight);
LatLngBounds addressBounds = new LatLngBounds(addressSouthWest,
addressNorthEast);
CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngBounds(
addressBounds, 0);
if (!firstCameraChange)
mMap.animateCamera(cameraUpdate);
else
mMap.moveCamera(cameraUpdate);
} catch (IllegalArgumentException e) {
// invalid
}
}
// ================================================================================
// On Long Click Listener
// ================================================================================
public boolean onLongClick(View view) {
switch (view.getId()) {
case R.id.sourceCancelClickableArea:
case R.id.sourceCancelButton:
setAllSourcesMostRecent();
return true;
}
return false;
}
private void setAllSourcesMostRecent() {
NewsStandApplication applicationState = ((NewsStandApplication) getApplicationContext());
ArrayList<Source> allSources = applicationState.getAllSources();
for (Source currentSource : allSources)
currentSource.setSelected(false);
ArrayList<Source> feedSources = applicationState.getFeedSources();
for (Source currentSource : feedSources)
currentSource.setSelected(false);
ArrayList<Source> languageSources = applicationState.getLanguageSources();
for (Source currentSource : languageSources)
currentSource.setSelected(false);
mSelectedSourceIndex = 0;
mSelectedSourceType = Source.SourceType.ALL_SOURCE;
allSources.get(0).setSelected(true);
applicationState.setAllSources(allSources);
applicationState.setFeedSources(feedSources);
applicationState.setLanguageSources(languageSources);
updateSourceText();
}
// ================================================================================
// Sensor Interface -- One Hand Mode
// ================================================================================
public void onAccuracyChanged(Sensor arg0, int arg1) {
// TODO Auto-generated method stub
}
public void onSensorChanged(SensorEvent event) {
float x = event.values[0];
if (x > 2.0) {
mHandMode = 1;
} else if (x < -2.0) {
mHandMode = 2;
}
if (mLastHandMode != mHandMode) updateHandMode();
}
protected void updateHandMode() {
mLastHandMode = mHandMode;
RelativeLayout.LayoutParams zoomInParams = (RelativeLayout.LayoutParams) mZoomInButton.getLayoutParams();
RelativeLayout.LayoutParams zoomOutParams = (RelativeLayout.LayoutParams) mZoomOutButton.getLayoutParams();
RelativeLayout.LayoutParams refreshParams = (RelativeLayout.LayoutParams) mRefreshButton.getLayoutParams();
android.widget.ImageView leftPic = (android.widget.ImageView) findViewById(R.id.infoPic);
android.widget.ImageView rightPic = (android.widget.ImageView) findViewById(R.id.topStoriesPic);
android.widget.TextView leftText = (android.widget.TextView) findViewById(R.id.BottomInfo);
android.widget.TextView rightText = (android.widget.TextView) findViewById(R.id.BottomTopStories);
if (mHandMode == 3) { // Neutral
leftPic.setImageResource(R.drawable.info);
rightPic.setImageResource(R.drawable.rss);
leftText.setText(R.string.bottom_info);
rightText.setText(R.string.bottom_top_stories);
zoomInParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT, 0);
zoomInParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
zoomInParams.rightMargin = (int) getResources().getDimension(R.dimen.neutral_zoom_right);
zoomOutParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT, 0);
zoomOutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
zoomOutParams.rightMargin = (int) getResources().getDimension(R.dimen.neutral_zoom_right);
refreshParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
refreshParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, 0);
refreshParams.leftMargin = (int) getResources().getDimension(R.dimen.neutral_refresh_left);
} else if (mHandMode == 1) { // Left Hand
leftPic.setImageResource(R.drawable.rss);
rightPic.setImageResource(R.drawable.info);
leftText.setText(R.string.bottom_top_stories);
rightText.setText(R.string.bottom_info);
zoomInParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT, 0);
zoomInParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
zoomInParams.rightMargin = (int) getResources().getDimension(R.dimen.leftHand_zoomIn_right);
zoomOutParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT, 0);
zoomOutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
zoomOutParams.rightMargin = (int) getResources().getDimension(R.dimen.leftHand_zoomOut_right);
refreshParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
refreshParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, 0);
refreshParams.leftMargin = (int) getResources().getDimension(R.dimen.leftHand_refresh_left);
} else if (mHandMode == 2) { // Right Hand
leftPic.setImageResource(R.drawable.info);
rightPic.setImageResource(R.drawable.rss);
leftText.setText(R.string.bottom_info);
rightText.setText(R.string.bottom_top_stories);
zoomInParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
zoomInParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, 0);
zoomInParams.leftMargin = (int) getResources().getDimension(R.dimen.rightHand_zoomIn_left);
zoomOutParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
zoomOutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, 0);
zoomOutParams.leftMargin = (int) getResources().getDimension(R.dimen.rightHand_zoomOut_left);
refreshParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT, 0);
refreshParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
refreshParams.rightMargin = (int) getResources().getDimension(R.dimen.rightHand_refresh_right);
}
RelativeLayout mainRelativeLayout = (RelativeLayout) findViewById(R.id.mainRelativeLayout);
mainRelativeLayout.removeView(mZoomInButton);
mainRelativeLayout.removeView(mZoomOutButton);
mainRelativeLayout.removeView(mRefreshButton);
mZoomInButton.setLayoutParams(zoomInParams);
mZoomOutButton.setLayoutParams(zoomOutParams);
mRefreshButton.setLayoutParams(refreshParams);
mainRelativeLayout.addView(mZoomInButton);
mainRelativeLayout.addView(mZoomOutButton);
mainRelativeLayout.addView(mRefreshButton);
}
protected void setUpMapIfNeeded() {
// Do a null check to confirm that we have not already instantiated the
// map.
if (mMap == null) {
//Log.i(TAG, "Setup Map - map is null");
// Try to obtain the map from the SupportMapFragment.
mMap = ((MapFragment) getFragmentManager().findFragmentById(
R.id.miniMap)).getMap();
// Check if we were successful in obtaining the map.
if (mMap != null) {
setUpMap();
Location localLocation = mLocationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if (localLocation == null) {
localLocation = mLocationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
if (localLocation == null)
return; //Should put some type of can not determine location message
}
LatLng localLatLng = new LatLng(localLocation.getLatitude(), localLocation.getLongitude());
CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(localLatLng, 1);
mMap.animateCamera(cameraUpdate);
}
}
mLabelColor = getResources().getColor(R.color.green_label);
mShadowColor = getResources().getColor(R.color.black);
}
protected abstract void setUpMap();
protected double lat2y(double lat) {
return 180 / Math.PI * Math.log(Math.tan(Math.PI / 4 + lat * (Math.PI / 180) / 2));
}
double y2lat(double y) {
return 180 / Math.PI * (2 * Math.atan(Math.exp(y * Math.PI / 180)) - Math.PI / 2);
}
protected PointF convertLatLngToPoint(LatLng latLngPoint) {
float x = (float) latLngPoint.longitude + 180.0f;
float y = (float) lat2y(latLngPoint.latitude) + 180.0f;
return new PointF(x, y);
}
protected PointF getCurrentXYBounds() {
LatLngBounds bounds = mMap.getProjection().getVisibleRegion().latLngBounds;
LatLng southwest = bounds.southwest;
LatLng northeast = bounds.northeast;
if (southwest.latitude > 85.0511)
southwest = new LatLng(85.0511, southwest.longitude);
if (southwest.latitude < -85.0511)
southwest = new LatLng(-85.0511, southwest.longitude);
if (northeast.latitude > 85.0511)
northeast = new LatLng(85.0511, northeast.longitude);
if (northeast.latitude < -85.0511)
northeast = new LatLng(-85.0511, northeast.longitude);
double lowY = lat2y(southwest.latitude);
double highY = lat2y(northeast.latitude);
double lowX = southwest.longitude;
double highX = northeast.longitude;
if (highY < lowY) {
double temp = lowY;
lowY = highY;
highY = temp;
}
float xDif = (float) Math.abs(highX - lowX);
float yDif = (float) Math.abs(highY - lowY);
return new PointF(xDif, yDif);
}
protected void zoomInButtonClicked() {
float zoomTo = mMap.getCameraPosition().zoom + 2;
mMap.animateCamera(CameraUpdateFactory.zoomTo(zoomTo));
}
protected void zoomOutButtonClicked() {
float zoomTo = mMap.getCameraPosition().zoom - 2;
if (zoomTo < 2)
zoomTo = 2.0f;
mMap.animateCamera(CameraUpdateFactory.zoomTo(zoomTo));
}
protected void refreshButtonClicked() {
refreshMap();
}
protected abstract void updateSourceText();
protected void setupLocationManager() {
mLocationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
100000, // 1000-second interval.
100, // 100 meters.
this);
mPrediction = new Prediction();
// mPrediction.learnModel();
}
protected void setupImageMarkers() {
options = new DisplayImageOptions.Builder()
.showStubImage(R.color.white)
.cacheInMemory()
.cacheOnDisc()
.bitmapConfig(Bitmap.Config.RGB_565)
.build();
mImageURLs = new ArrayList<String>();
DisplayMetrics metrics = getResources().getDisplayMetrics();
mImageMarkerPixels = Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, (int) IMAGE_MARKER_SIZE, metrics));
mDensityMultiplier = getBaseContext().getResources().getDisplayMetrics().density;
}
protected void setupAccelerometer() {
mSensorInitialized = false;
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);