- 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:
Jimmy Shih
2011-10-11 14:54:49 -07:00
parent 3f5589b655
commit 5572e07b34
6 changed files with 110 additions and 45 deletions
@@ -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);
}
// Visible for testing
// For use in testing only.
public TrackPathPainter getTrackPathPainter() {
return trackPathPainter;
}
// Visible for testing
// For use in testing only.
public void setTrackPathPainter(TrackPathPainter trackPathPainter) {
this.trackPathPainter = trackPathPainter;
}
@@ -34,6 +34,7 @@ import com.google.wireless.gdata.parser.ParseException;
import com.google.wireless.gdata2.client.AuthenticationException;
import android.content.Context;
import android.text.format.DateFormat;
import android.util.Log;
import java.io.BufferedReader;
@@ -44,7 +45,6 @@ import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.URL;
import java.net.URLConnection;
import java.text.DateFormat;
import java.util.Date;
import java.util.concurrent.atomic.AtomicReference;
@@ -287,13 +287,16 @@ public class DocsHelper {
String elevationUnit = context.getString(metricUnits ?
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.
DocsTagBuilder tagBuilder = new DocsTagBuilder(metricUnits)
.append("name", track.getName())
.append("description", track.getDescription())
.append("date", trackDateFormat.format(new Date(stats.getStartTime())))
.append("date", dateString)
.append("totaltime", StringUtils.formatTimeAlwaysShowingHours(
stats.getTotalTime()))
.append("movingtime", StringUtils.formatTimeAlwaysShowingHours(
@@ -15,6 +15,7 @@
*/
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.UnitConversions;
@@ -45,8 +46,11 @@ import java.util.Locale;
* @author Matthew Simmons
*/
class DocsTagBuilder {
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 =
new DecimalFormat("#,###,###.00", FORMAT_SYMBOLS);
private static final NumberFormat SMALL_UNIT_FORMAT =
@@ -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.content.Sensor;
import com.google.android.apps.mytracks.util.ApiFeatures;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
@@ -30,6 +31,8 @@ import android.util.Log;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.UUID;
/**
@@ -259,10 +262,29 @@ public class BluetoothConnectionManager {
}
private BluetoothSocket getSocket() throws IOException {
try {
return device.createInsecureRfcommSocketToServiceRecord(SPP_UUID);
} catch (IOException e) {
Log.e(Constants.TAG, "Unable to get insecure connect.", e);
if (ApiFeatures.getInstance().hasBluetoothDeviceCreateInsecureRfcommSocketToServiceRecord()) {
try {
return device.createInsecureRfcommSocketToServiceRecord(SPP_UUID);
} 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);
}
@@ -16,6 +16,7 @@
package com.google.android.apps.mytracks.services.sensors;
import com.google.android.apps.mytracks.content.Sensor;
import com.google.android.apps.mytracks.util.ApiFeatures;
import java.util.Arrays;
@@ -23,7 +24,7 @@ import java.util.Arrays;
* An implementation of a Sensor MessageParser for Zephyr.
*
* @author Sandor Dornbush
* @author Dominik Ršttsches
* @author Dominik R�ttsches
*/
public class ZephyrMessageParser implements MessageParser {
@@ -56,13 +57,24 @@ public class ZephyrMessageParser implements MessageParser {
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) {
// Device Firmware ID, Firmware Version, Hardware ID, Hardware Version
// 0x1A00316550003162 produces erroneous values for Cadence and needs
// a workaround based on the stride counter.
// 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();
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.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.util.Log;
import java.text.DecimalFormatSymbols;
import java.util.Arrays;
/**
* Utility class for determining if newer-API features are available on the
* current device.
@@ -32,7 +38,7 @@ public class ApiFeatures {
/**
* 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);
private static ApiFeatures instance;
@@ -81,38 +87,17 @@ public class ApiFeatures {
return apiPlatformAdapter;
}
/**
* Returns whether cloud backup (a.k.a. Froyo backup) is available.
*/
public boolean hasBackup() {
return getApiLevel() >= 8;
}
// API Level 4 Changes
/**
* Returns whether text-to-speech is available.
*/
public boolean hasTextToSpeech() {
if (getApiLevel() < 4) return false;
try {
Class.forName("android.speech.tts.TextToSpeech");
} catch (ClassNotFoundException ex) {
return false;
} catch (LinkageError er) {
return false;
}
return true;
}
public boolean hasStrictMode() {
return getApiLevel() >= 9;
}
public boolean isAudioFocusSupported() {
return getApiLevel() >= 8;
return getApiLevel() >= 4;
}
// API Level 5 Changes
/**
* There's a bug (#1587) in Cupcake and Donut which prevents you from
* using a SQLiteQueryBuilder twice. That is, if you call buildQuery
@@ -122,18 +107,57 @@ public class ApiFeatures {
* up. Specifically, it'll add extra parens which don't belong.
*/
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
* used rather than com.google.api.client.apache.ApacheHttpTransport. See
* {@link HttpTransport} for more info.
* Returns whether cloud backup (a.k.a. Froyo backup) is available.
*/
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() {
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.
protected int getApiLevel() {
return ANDROID_API_LEVEL;