Merge Matthew's changes.

This commit is contained in:
Sandor Dornbush
2011-02-04 15:35:16 -08:00
9 changed files with 306 additions and 128 deletions
@@ -30,12 +30,13 @@ import com.google.android.apps.mytracks.util.StringUtils;
import com.google.android.apps.mytracks.util.UnitConversions;
import com.google.android.maps.mytracks.R;
import com.google.api.client.googleapis.GoogleHeaders;
import com.google.api.client.googleapis.GoogleTransport;
import com.google.api.client.googleapis.MethodOverrideIntercepter;
import com.google.api.client.http.GenericUrl;
import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.HttpResponse;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.InputStreamContent;
import com.google.api.client.javanet.NetHttpTransport;
import com.google.api.client.util.Strings;
import android.app.Activity;
@@ -82,6 +83,21 @@ public class SendToFusionTables implements Runnable {
private static final int MAX_POINTS_PER_UPLOAD = 2048;
private static final String GDATA_VERSION = "2";
// This class reports upload status to the user as a completion percentage
// using a progress bar. Progress is defined as follows:
//
// 0% Getting track metadata
// 5% Creating Fusion Table (GData to FT server)
// 10%-90% Uploading the track data to Fusion Tables
// 95% Uploading waypoints
// 100% Done
private static final int PROGRESS_INITIALIZATION = 0;
private static final int PROGRESS_FUSION_TABLE_CREATE = 5;
private static final int PROGRESS_UPLOAD_DATA_MIN = 10;
private static final int PROGRESS_UPLOAD_DATA_MAX = 90;
private static final int PROGRESS_UPLOAD_WAYPOINTS = 95;
private static final int PROGRESS_COMPLETE = 100;
private final Activity context;
private final AuthManager auth;
@@ -105,6 +121,12 @@ public class SendToFusionTables implements Runnable {
private static String MARKER_TYPE_END = "large_red";
private static String MARKER_TYPE_WAYPOINT = "large_yellow";
static {
// We manually assign the transport to avoid having HttpTransport try to
// load it via reflection (which breaks due to ProGuard).
HttpTransport.setLowLevelHttpTransport(new NetHttpTransport());
}
public SendToFusionTables(Activity context, AuthManager auth,
long trackId, ProgressIndicator progressIndicator,
OnSendCompletedListener onCompletion) {
@@ -115,10 +137,14 @@ public class SendToFusionTables implements Runnable {
this.onCompletion = onCompletion;
this.stringUtils = new StringUtils(context);
this.providerUtils = MyTracksProviderUtils.Factory.get(context);
transport = GoogleTransport.create();
GoogleHeaders headers = (GoogleHeaders) transport.defaultHeaders;
GoogleHeaders headers = new GoogleHeaders();
headers.setApplicationName("Google-MyTracks-" + MyTracksUtils.getMyTracksVersion(context));
headers.gdataVersion = GDATA_VERSION;
transport = new HttpTransport();
MethodOverrideIntercepter.setAsFirstFor(transport);
transport.defaultHeaders = headers;
}
@Override
@@ -141,7 +167,7 @@ public class SendToFusionTables implements Runnable {
int statusMessageId = R.string.error_sending_to_fusiontables;
boolean success = true;
try {
progressIndicator.setProgressValue(1);
progressIndicator.setProgressValue(PROGRESS_INITIALIZATION);
progressIndicator.setProgressMessage(R.string.progress_message_reading_track);
// Get the track meta-data
@@ -149,25 +175,30 @@ public class SendToFusionTables implements Runnable {
String originalDescription = track.getDescription();
// Create a new table:
progressIndicator.setProgressValue(PROGRESS_FUSION_TABLE_CREATE);
progressIndicator.setProgressMessage(R.string.progress_message_creating_fusiontable);
success = createNewTable(track);
if (success) {
success = makeTableUnlisted(tableId);
if (!createNewTable(track) || !makeTableUnlisted(tableId)) {
return;
}
progressIndicator.setProgressValue(PROGRESS_UPLOAD_DATA_MIN);
progressIndicator.setProgressMessage(R.string.progress_message_sending_fusiontables);
// Upload all of the segments of the track plus start/end markers
if (success) {
success = uploadAllTrackPoints(track, originalDescription);
if (!uploadAllTrackPoints(track, originalDescription)) {
return;
}
progressIndicator.setProgressValue(PROGRESS_UPLOAD_WAYPOINTS);
// Upload all the waypoints.
if (success) {
success = uploadWaypoints(track);
statusMessageId = R.string.status_new_fusiontable_has_been_created;
if (!uploadWaypoints(track)) {
return;
}
statusMessageId = R.string.status_new_fusiontable_has_been_created;
Log.d(MyTracksConstants.TAG, "SendToFusionTables: Done: " + success);
progressIndicator.setProgressValue(100);
progressIndicator.setProgressValue(PROGRESS_COMPLETE);
} finally {
final boolean finalSuccess = success;
@@ -198,7 +229,7 @@ public class SendToFusionTables implements Runnable {
private boolean makeTableUnlisted(String tableId) {
Log.d(MyTracksConstants.TAG, "Setting visibility to unlisted.");
String query = "UPDATE TABLE " + tableId + " SET VISIBILITY = unlisted";
String query = "UPDATE TABLE " + tableId + " SET VISIBILITY = UNLISTED";
return runUpdate(query);
}
@@ -290,11 +321,10 @@ public class SendToFusionTables implements Runnable {
DoubleBuffer elevationBuffer = new DoubleBuffer(MyTracksConstants.ELEVATION_SMOOTHING_FACTOR);
List<Location> locations = new ArrayList<Location>(MAX_POINTS_PER_UPLOAD);
progressIndicator.setProgressMessage(R.string.progress_message_reading_track);
Location lastLocation = null;
do {
if (totalLocationsRead % 100 == 0) {
updateProgress();
updateTrackDataUploadProgress();
}
Location loc = providerUtils.createLocation(locationsCursor);
@@ -406,8 +436,7 @@ public class SendToFusionTables implements Runnable {
}
private boolean prepareAndUploadPoints(Track track, List<Location> locations) {
progressIndicator.setProgressMessage(R.string.progress_message_preparing_track);
updateProgress();
updateTrackDataUploadProgress();
int numLocations = locations.size();
if (numLocations < 2) {
@@ -420,7 +449,6 @@ public class SendToFusionTables implements Runnable {
ArrayList<Track> splitTracks = prepareLocations(track, locations);
// Start uploading them
progressIndicator.setProgressMessage(R.string.progress_message_sending_fusiontables);
for (Track splitTrack : splitTracks) {
if (totalSegmentsUploaded > 1) {
splitTrack.setName(splitTrack.getName() + " "
@@ -444,7 +472,7 @@ public class SendToFusionTables implements Runnable {
locations.clear();
totalLocationsUploaded += numLocations;
updateProgress();
updateTrackDataUploadProgress();
return true;
}
@@ -473,7 +501,7 @@ public class SendToFusionTables implements Runnable {
boolean startNewTrackSegment = false;
for (Location loc : locations) {
if (totalLocationsPrepared % 100 == 0) {
updateProgress();
updateTrackDataUploadProgress();
}
if (loc.getLatitude() > 90) {
startNewTrackSegment = true;
@@ -596,17 +624,18 @@ public class SendToFusionTables implements Runnable {
}
}
/**
* Sets the current upload progress.
*/
private void updateProgress() {
private void updateTrackDataUploadProgress() {
// The percent of the total that represents the completed part of this
// segment.
int totalPercentage =
// segment. We calculate it as an absolute percentage, and then scale it
// to fit the completion percentage range alloted to track data upload.
double totalPercentage =
(totalLocationsRead + totalLocationsPrepared + totalLocationsUploaded)
/ (totalLocations * 3);
totalPercentage = Math.min(99, totalPercentage);
progressIndicator.setProgressValue(totalPercentage);
double scaledPercentage = totalPercentage
* (PROGRESS_UPLOAD_DATA_MAX - PROGRESS_UPLOAD_DATA_MIN) + PROGRESS_UPLOAD_DATA_MIN;
progressIndicator.setProgressValue((int) scaledPercentage);
}
/**
@@ -33,12 +33,7 @@ public class ApiFeatures {
*/
public static final int ANDROID_API_LEVEL = Integer.parseInt(
Build.VERSION.SDK);
private static final String PLATFORM_ADAPTER_GINGERBREAD =
"com.google.android.apps.mytracks.util.GingerbreadPlatformAdapter";
private static final String PLATFORM_ADAPTER_ECLAIR =
"com.google.android.apps.mytracks.util.EclairPlatformAdapter";
private static ApiFeatures instance;
/**
@@ -67,30 +62,18 @@ public class ApiFeatures {
* Allow subclasses for mocking, but no direct instantiation.
*/
protected ApiFeatures() {
// It is safe to import unsupported classes as long as we only actually
// load the class when supported.
if (getApiLevel() >= 9) {
apiPlatformAdapter = createPlatformAdapter(PLATFORM_ADAPTER_GINGERBREAD);
apiPlatformAdapter = new GingerbreadPlatformAdapter();
} else if (getApiLevel() >= 5) {
apiPlatformAdapter = createPlatformAdapter(PLATFORM_ADAPTER_ECLAIR);
apiPlatformAdapter = new EclairPlatformAdapter();
} else {
// Cupcake adapter is always supported, so it's safe to do static linkage.
apiPlatformAdapter = new CupcakePlatformAdapter();
}
Log.i(MyTracksConstants.TAG, "Using platform adapter " + apiPlatformAdapter.getClass());
}
private static ApiPlatformAdapter createPlatformAdapter(String className) {
try {
Class<?> clazz = Class.forName(className);
return (ApiPlatformAdapter) clazz.newInstance();
} catch (ClassNotFoundException e) {
throw new RuntimeException("ApiFeatures: Unable to find " + className, e);
} catch (InstantiationException e) {
throw new RuntimeException("ApiFeatures: Unable to instantiate " + className, e);
} catch (IllegalAccessException e) {
throw new RuntimeException("ApiFeatures: Unable to access " + className, e);
}
}
public ApiPlatformAdapter getApiPlatformAdapter() {
return apiPlatformAdapter;