forked from upstream-mirrors/OpenTracks
- Use BluetoothDevice createInsecureRfcommSocketToServiceRecord for API level 10 or above.
- Use DecimalFormatSymbols getInstance for API level 9 or above. - Use Arrays copyOfRange for API level 9 or above. - Remove ApiFeatures hasStrictMode. - Fix comment on MapOverlay to indicate that the two methods should only be used during testing. - Use android.text.format.DateFormat to format date and time in DocsHelper. This DateFormat uses the same locale format as the phone configuration. Fix DecimalFormat
This commit is contained in:
@@ -305,12 +305,12 @@ public class MapOverlay extends Overlay implements OnSharedPreferenceChangeListe
|
|||||||
return new Rect(cx - w / 2, cy - h / 2, cx + w / 2, cy + h / 2);
|
return new Rect(cx - w / 2, cy - h / 2, cx + w / 2, cy + h / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Visible for testing
|
// For use in testing only.
|
||||||
public TrackPathPainter getTrackPathPainter() {
|
public TrackPathPainter getTrackPathPainter() {
|
||||||
return trackPathPainter;
|
return trackPathPainter;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Visible for testing
|
// For use in testing only.
|
||||||
public void setTrackPathPainter(TrackPathPainter trackPathPainter) {
|
public void setTrackPathPainter(TrackPathPainter trackPathPainter) {
|
||||||
this.trackPathPainter = trackPathPainter;
|
this.trackPathPainter = trackPathPainter;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ import com.google.wireless.gdata.parser.ParseException;
|
|||||||
import com.google.wireless.gdata2.client.AuthenticationException;
|
import com.google.wireless.gdata2.client.AuthenticationException;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.text.format.DateFormat;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
@@ -44,7 +45,6 @@ import java.io.OutputStream;
|
|||||||
import java.io.OutputStreamWriter;
|
import java.io.OutputStreamWriter;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLConnection;
|
import java.net.URLConnection;
|
||||||
import java.text.DateFormat;
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
@@ -287,13 +287,16 @@ public class DocsHelper {
|
|||||||
String elevationUnit = context.getString(metricUnits ?
|
String elevationUnit = context.getString(metricUnits ?
|
||||||
R.string.meter : R.string.feet);
|
R.string.meter : R.string.feet);
|
||||||
|
|
||||||
DateFormat trackDateFormat = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);
|
java.text.DateFormat dateFormat = DateFormat.getDateFormat(context);
|
||||||
|
java.text.DateFormat timeFormat = DateFormat.getTimeFormat(context);
|
||||||
|
Date startTime = new Date(stats.getStartTime());
|
||||||
|
String dateString = dateFormat.format(startTime) + " " + timeFormat.format(startTime);
|
||||||
|
|
||||||
// Prepare the Post-Text we are going to send.
|
// Prepare the Post-Text we are going to send.
|
||||||
DocsTagBuilder tagBuilder = new DocsTagBuilder(metricUnits)
|
DocsTagBuilder tagBuilder = new DocsTagBuilder(metricUnits)
|
||||||
.append("name", track.getName())
|
.append("name", track.getName())
|
||||||
.append("description", track.getDescription())
|
.append("description", track.getDescription())
|
||||||
.append("date", trackDateFormat.format(new Date(stats.getStartTime())))
|
.append("date", dateString)
|
||||||
.append("totaltime", StringUtils.formatTimeAlwaysShowingHours(
|
.append("totaltime", StringUtils.formatTimeAlwaysShowingHours(
|
||||||
stats.getTotalTime()))
|
stats.getTotalTime()))
|
||||||
.append("movingtime", StringUtils.formatTimeAlwaysShowingHours(
|
.append("movingtime", StringUtils.formatTimeAlwaysShowingHours(
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.android.apps.mytracks.io.docs;
|
package com.google.android.apps.mytracks.io.docs;
|
||||||
|
|
||||||
|
import com.google.android.apps.mytracks.util.ApiFeatures;
|
||||||
import com.google.android.apps.mytracks.util.StringUtils;
|
import com.google.android.apps.mytracks.util.StringUtils;
|
||||||
import com.google.android.apps.mytracks.util.UnitConversions;
|
import com.google.android.apps.mytracks.util.UnitConversions;
|
||||||
|
|
||||||
@@ -45,8 +46,11 @@ import java.util.Locale;
|
|||||||
* @author Matthew Simmons
|
* @author Matthew Simmons
|
||||||
*/
|
*/
|
||||||
class DocsTagBuilder {
|
class DocsTagBuilder {
|
||||||
|
|
||||||
private static final DecimalFormatSymbols FORMAT_SYMBOLS =
|
private static final DecimalFormatSymbols FORMAT_SYMBOLS =
|
||||||
DecimalFormatSymbols.getInstance(Locale.ENGLISH);
|
ApiFeatures.getInstance().hasDecimalFormatSymbolsGetInstance()
|
||||||
|
? DecimalFormatSymbols.getInstance(Locale.ENGLISH)
|
||||||
|
: new DecimalFormatSymbols(Locale.ENGLISH);
|
||||||
private static final NumberFormat LARGE_UNIT_FORMAT =
|
private static final NumberFormat LARGE_UNIT_FORMAT =
|
||||||
new DecimalFormat("#,###,###.00", FORMAT_SYMBOLS);
|
new DecimalFormat("#,###,###.00", FORMAT_SYMBOLS);
|
||||||
private static final NumberFormat SMALL_UNIT_FORMAT =
|
private static final NumberFormat SMALL_UNIT_FORMAT =
|
||||||
|
|||||||
+26
-4
@@ -18,6 +18,7 @@ package com.google.android.apps.mytracks.services.sensors;
|
|||||||
|
|
||||||
import com.google.android.apps.mytracks.Constants;
|
import com.google.android.apps.mytracks.Constants;
|
||||||
import com.google.android.apps.mytracks.content.Sensor;
|
import com.google.android.apps.mytracks.content.Sensor;
|
||||||
|
import com.google.android.apps.mytracks.util.ApiFeatures;
|
||||||
|
|
||||||
import android.bluetooth.BluetoothAdapter;
|
import android.bluetooth.BluetoothAdapter;
|
||||||
import android.bluetooth.BluetoothDevice;
|
import android.bluetooth.BluetoothDevice;
|
||||||
@@ -30,6 +31,8 @@ import android.util.Log;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -259,10 +262,29 @@ public class BluetoothConnectionManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private BluetoothSocket getSocket() throws IOException {
|
private BluetoothSocket getSocket() throws IOException {
|
||||||
try {
|
if (ApiFeatures.getInstance().hasBluetoothDeviceCreateInsecureRfcommSocketToServiceRecord()) {
|
||||||
return device.createInsecureRfcommSocketToServiceRecord(SPP_UUID);
|
try {
|
||||||
} catch (IOException e) {
|
return device.createInsecureRfcommSocketToServiceRecord(SPP_UUID);
|
||||||
Log.e(Constants.TAG, "Unable to get insecure connect.", e);
|
} catch (IOException e) {
|
||||||
|
Log.e(Constants.TAG, "Unable to get insecure connect.", e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
Class<? extends BluetoothDevice> c = device.getClass();
|
||||||
|
Method insecure = c.getMethod("createInsecureRfcommSocket", Integer.class);
|
||||||
|
insecure.setAccessible(true);
|
||||||
|
return (BluetoothSocket) insecure.invoke(device, 1);
|
||||||
|
} catch (SecurityException e) {
|
||||||
|
Log.e(Constants.TAG, "Unable to get insecure connect.", e);
|
||||||
|
} catch (NoSuchMethodException e) {
|
||||||
|
Log.e(Constants.TAG, "Unable to get insecure connect.", e);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
Log.e(Constants.TAG, "Unable to get insecure connect.", e);
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
Log.e(Constants.TAG, "Unable to get insecure connect.", e);
|
||||||
|
} catch (InvocationTargetException e) {
|
||||||
|
Log.e(Constants.TAG, "Unable to get insecure connect.", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return device.createRfcommSocketToServiceRecord(SPP_UUID);
|
return device.createRfcommSocketToServiceRecord(SPP_UUID);
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-3
@@ -16,6 +16,7 @@
|
|||||||
package com.google.android.apps.mytracks.services.sensors;
|
package com.google.android.apps.mytracks.services.sensors;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.content.Sensor;
|
import com.google.android.apps.mytracks.content.Sensor;
|
||||||
|
import com.google.android.apps.mytracks.util.ApiFeatures;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
@@ -23,7 +24,7 @@ import java.util.Arrays;
|
|||||||
* An implementation of a Sensor MessageParser for Zephyr.
|
* An implementation of a Sensor MessageParser for Zephyr.
|
||||||
*
|
*
|
||||||
* @author Sandor Dornbush
|
* @author Sandor Dornbush
|
||||||
* @author Dominik Ršttsches
|
* @author Dominik R�ttsches
|
||||||
*/
|
*/
|
||||||
public class ZephyrMessageParser implements MessageParser {
|
public class ZephyrMessageParser implements MessageParser {
|
||||||
|
|
||||||
@@ -56,13 +57,24 @@ public class ZephyrMessageParser implements MessageParser {
|
|||||||
return sds.build();
|
return sds.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies a byte array. In case Arrays.copyOfRange is not available.
|
||||||
|
*/
|
||||||
|
private byte[] copyByteArray(byte[] input, int from, int to) {
|
||||||
|
int length = to - from;
|
||||||
|
byte[] output = new byte[length];
|
||||||
|
System.arraycopy(input, from, output, 0, length);
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
private void setCadence(Sensor.SensorDataSet.Builder sds, byte[] buffer) {
|
private void setCadence(Sensor.SensorDataSet.Builder sds, byte[] buffer) {
|
||||||
// Device Firmware ID, Firmware Version, Hardware ID, Hardware Version
|
// Device Firmware ID, Firmware Version, Hardware ID, Hardware Version
|
||||||
// 0x1A00316550003162 produces erroneous values for Cadence and needs
|
// 0x1A00316550003162 produces erroneous values for Cadence and needs
|
||||||
// a workaround based on the stride counter.
|
// a workaround based on the stride counter.
|
||||||
// Firmware values range from field 3 to 10 (inclusive) of the byte buffer.
|
// Firmware values range from field 3 to 10 (inclusive) of the byte buffer.
|
||||||
byte[] hardwareFirmwareId = Arrays.copyOfRange(buffer, 3, 11);
|
byte[] hardwareFirmwareId = ApiFeatures.getInstance().hasArraysCopyOfRange()
|
||||||
|
? Arrays.copyOfRange(buffer, 3, 11)
|
||||||
|
: copyByteArray(buffer, 3, 11);
|
||||||
Sensor.SensorData.Builder cadence = Sensor.SensorData.newBuilder();
|
Sensor.SensorData.Builder cadence = Sensor.SensorData.newBuilder();
|
||||||
|
|
||||||
if (Arrays.equals(hardwareFirmwareId, CADENCE_BUG_FW_ID)) {
|
if (Arrays.equals(hardwareFirmwareId, CADENCE_BUG_FW_ID)) {
|
||||||
|
|||||||
@@ -17,10 +17,16 @@ package com.google.android.apps.mytracks.util;
|
|||||||
|
|
||||||
import com.google.android.apps.mytracks.Constants;
|
import com.google.android.apps.mytracks.Constants;
|
||||||
import com.google.api.client.http.HttpTransport;
|
import com.google.api.client.http.HttpTransport;
|
||||||
|
import com.google.api.client.http.apache.ApacheHttpTransport;
|
||||||
|
import com.google.api.client.http.javanet.NetHttpTransport;
|
||||||
|
|
||||||
|
import android.bluetooth.BluetoothDevice;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import java.text.DecimalFormatSymbols;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility class for determining if newer-API features are available on the
|
* Utility class for determining if newer-API features are available on the
|
||||||
* current device.
|
* current device.
|
||||||
@@ -32,7 +38,7 @@ public class ApiFeatures {
|
|||||||
/**
|
/**
|
||||||
* The API level of the Android version we're being run under.
|
* The API level of the Android version we're being run under.
|
||||||
*/
|
*/
|
||||||
public static final int ANDROID_API_LEVEL = Integer.parseInt(
|
private static final int ANDROID_API_LEVEL = Integer.parseInt(
|
||||||
Build.VERSION.SDK);
|
Build.VERSION.SDK);
|
||||||
|
|
||||||
private static ApiFeatures instance;
|
private static ApiFeatures instance;
|
||||||
@@ -81,37 +87,16 @@ public class ApiFeatures {
|
|||||||
return apiPlatformAdapter;
|
return apiPlatformAdapter;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// API Level 4 Changes
|
||||||
* Returns whether cloud backup (a.k.a. Froyo backup) is available.
|
|
||||||
*/
|
|
||||||
public boolean hasBackup() {
|
|
||||||
return getApiLevel() >= 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether text-to-speech is available.
|
* Returns whether text-to-speech is available.
|
||||||
*/
|
*/
|
||||||
public boolean hasTextToSpeech() {
|
public boolean hasTextToSpeech() {
|
||||||
if (getApiLevel() < 4) return false;
|
return getApiLevel() >= 4;
|
||||||
|
|
||||||
try {
|
|
||||||
Class.forName("android.speech.tts.TextToSpeech");
|
|
||||||
} catch (ClassNotFoundException ex) {
|
|
||||||
return false;
|
|
||||||
} catch (LinkageError er) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasStrictMode() {
|
// API Level 5 Changes
|
||||||
return getApiLevel() >= 9;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isAudioFocusSupported() {
|
|
||||||
return getApiLevel() >= 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* There's a bug (#1587) in Cupcake and Donut which prevents you from
|
* There's a bug (#1587) in Cupcake and Donut which prevents you from
|
||||||
@@ -122,18 +107,57 @@ public class ApiFeatures {
|
|||||||
* up. Specifically, it'll add extra parens which don't belong.
|
* up. Specifically, it'll add extra parens which don't belong.
|
||||||
*/
|
*/
|
||||||
public boolean canReuseSQLiteQueryBuilder() {
|
public boolean canReuseSQLiteQueryBuilder() {
|
||||||
return getApiLevel() > 4;
|
return getApiLevel() >= 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
// API Level 8 Changes
|
||||||
|
|
||||||
|
public boolean isAudioFocusSupported() {
|
||||||
|
return getApiLevel() >= 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if com.google.api.client.javanet.NetHttpTransport should be
|
* Returns whether cloud backup (a.k.a. Froyo backup) is available.
|
||||||
* used rather than com.google.api.client.apache.ApacheHttpTransport. See
|
*/
|
||||||
* {@link HttpTransport} for more info.
|
public boolean hasBackup() {
|
||||||
|
return getApiLevel() >= 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
// API Level 9 Changes
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if {@link NetHttpTransport} should be used rather than
|
||||||
|
* {@link ApacheHttpTransport}. See {@link HttpTransport} for more info.
|
||||||
*/
|
*/
|
||||||
public boolean useNetHttpTransport() {
|
public boolean useNetHttpTransport() {
|
||||||
return getApiLevel() >= 9;
|
return getApiLevel() >= 9;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if {@link DecimalFormatSymbols#getInstance} is available.
|
||||||
|
*/
|
||||||
|
public boolean hasDecimalFormatSymbolsGetInstance() {
|
||||||
|
return getApiLevel() >= 9;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if {@link Arrays#copyOfRange} is available.
|
||||||
|
*/
|
||||||
|
public boolean hasArraysCopyOfRange() {
|
||||||
|
return getApiLevel() >= 9;
|
||||||
|
}
|
||||||
|
|
||||||
|
// API Level 10 changes
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if
|
||||||
|
* {@link BluetoothDevice#createInsecureRfcommSocketToServiceRecord} is
|
||||||
|
* available.
|
||||||
|
*/
|
||||||
|
public boolean hasBluetoothDeviceCreateInsecureRfcommSocketToServiceRecord() {
|
||||||
|
return getApiLevel() >= 10;
|
||||||
|
}
|
||||||
|
|
||||||
// Visible for testing.
|
// Visible for testing.
|
||||||
protected int getApiLevel() {
|
protected int getApiLevel() {
|
||||||
return ANDROID_API_LEVEL;
|
return ANDROID_API_LEVEL;
|
||||||
|
|||||||
Reference in New Issue
Block a user