mirror of
https://codeberg.org/OpenTracksApp/OpenTracks.git
synced 2026-10-02 09:33:06 +02:00
- 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);
|
||||
}
|
||||
|
||||
// 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 =
|
||||
|
||||
+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.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);
|
||||
}
|
||||
|
||||
+15
-3
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user