forked from upstream-mirrors/OpenTracks
merge heads
This commit is contained in:
@@ -1738,13 +1738,6 @@ limitations under the License.
|
|||||||
Screenshot: settings_recording_top.png">
|
Screenshot: settings_recording_top.png">
|
||||||
Voice
|
Voice
|
||||||
</string>
|
</string>
|
||||||
<string name="settings_recording_voice_not_available"
|
|
||||||
translation_description="In the 'Recording' settings, the summary for the 'Voice'
|
|
||||||
explaining that this option is not available on your Android phone.
|
|
||||||
|
|
||||||
Screenshot: settings_recording_voice_not_available.png">
|
|
||||||
Voice announcement is not available on your Android phone.
|
|
||||||
</string>
|
|
||||||
<string name="settings_recording_voice_summary"
|
<string name="settings_recording_voice_summary"
|
||||||
translation_description="In the 'Recording' settings, the summary for the 'Voice'
|
translation_description="In the 'Recording' settings, the summary for the 'Voice'
|
||||||
dropdown option explaining that it configures the time or distance between two voice
|
dropdown option explaining that it configures the time or distance between two voice
|
||||||
|
|||||||
@@ -26,10 +26,9 @@ import com.google.android.apps.mytracks.content.TrackDataHub;
|
|||||||
import com.google.android.apps.mytracks.content.TrackDataHub.ListenerDataType;
|
import com.google.android.apps.mytracks.content.TrackDataHub.ListenerDataType;
|
||||||
import com.google.android.apps.mytracks.content.TrackDataListener;
|
import com.google.android.apps.mytracks.content.TrackDataListener;
|
||||||
import com.google.android.apps.mytracks.content.Waypoint;
|
import com.google.android.apps.mytracks.content.Waypoint;
|
||||||
import com.google.android.apps.mytracks.services.tasks.StatusAnnouncerFactory;
|
import com.google.android.apps.mytracks.services.tasks.StatusAnnouncerTask;
|
||||||
import com.google.android.apps.mytracks.stats.DoubleBuffer;
|
import com.google.android.apps.mytracks.stats.DoubleBuffer;
|
||||||
import com.google.android.apps.mytracks.stats.TripStatisticsBuilder;
|
import com.google.android.apps.mytracks.stats.TripStatisticsBuilder;
|
||||||
import com.google.android.apps.mytracks.util.ApiFeatures;
|
|
||||||
import com.google.android.apps.mytracks.util.LocationUtils;
|
import com.google.android.apps.mytracks.util.LocationUtils;
|
||||||
import com.google.android.apps.mytracks.util.UnitConversions;
|
import com.google.android.apps.mytracks.util.UnitConversions;
|
||||||
import com.google.android.maps.mytracks.R;
|
import com.google.android.maps.mytracks.R;
|
||||||
@@ -40,6 +39,7 @@ import android.content.DialogInterface;
|
|||||||
import android.content.DialogInterface.OnClickListener;
|
import android.content.DialogInterface.OnClickListener;
|
||||||
import android.location.Location;
|
import android.location.Location;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.speech.tts.TextToSpeech;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
@@ -116,9 +116,7 @@ public class ChartActivity extends Activity implements TrackDataListener {
|
|||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
// The volume we want to control is the Text-To-Speech volume
|
// The volume we want to control is the Text-To-Speech volume
|
||||||
int volumeStream =
|
setVolumeControlStream(TextToSpeech.Engine.DEFAULT_STREAM);
|
||||||
new StatusAnnouncerFactory(ApiFeatures.getInstance()).getVolumeStream();
|
|
||||||
setVolumeControlStream(volumeStream);
|
|
||||||
|
|
||||||
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||||
setContentView(R.layout.mytracks_charts);
|
setContentView(R.layout.mytracks_charts);
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
package com.google.android.apps.mytracks;
|
package com.google.android.apps.mytracks;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.util.ApiFeatures;
|
import com.google.android.apps.mytracks.util.ApiAdapterFactory;
|
||||||
import com.google.android.maps.mytracks.R;
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
@@ -63,8 +63,7 @@ class CheckUnits {
|
|||||||
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
|
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
|
||||||
SharedPreferences.Editor editor = useMetricPreferences.edit();
|
SharedPreferences.Editor editor = useMetricPreferences.edit();
|
||||||
String key = context.getString(R.string.metric_units_key);
|
String key = context.getString(R.string.metric_units_key);
|
||||||
ApiFeatures.getInstance().getApiAdapter().applyPreferenceChanges(
|
ApiAdapterFactory.getApiAdapter().applyPreferenceChanges(editor.putBoolean(key, metric));
|
||||||
editor.putBoolean(key, metric));
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
builder.setOnCancelListener(new DialogInterface.OnCancelListener() {
|
builder.setOnCancelListener(new DialogInterface.OnCancelListener() {
|
||||||
@@ -76,7 +75,7 @@ class CheckUnits {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void recordCheckPerformed(SharedPreferences preferences) {
|
private static void recordCheckPerformed(SharedPreferences preferences) {
|
||||||
ApiFeatures.getInstance().getApiAdapter().applyPreferenceChanges(
|
ApiAdapterFactory.getApiAdapter().applyPreferenceChanges(
|
||||||
preferences.edit().putBoolean(CHECK_UNITS_PREFERENCE_KEY, true));
|
preferences.edit().putBoolean(CHECK_UNITS_PREFERENCE_KEY, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
package com.google.android.apps.mytracks;
|
package com.google.android.apps.mytracks;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
||||||
import com.google.android.apps.mytracks.util.ApiFeatures;
|
import com.google.android.apps.mytracks.util.ApiAdapterFactory;
|
||||||
import com.google.android.maps.mytracks.R;
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
@@ -66,7 +66,7 @@ public class DeleteAllTracks extends Handler {
|
|||||||
Editor editor = prefs.edit();
|
Editor editor = prefs.edit();
|
||||||
// TODO: Go through data manager
|
// TODO: Go through data manager
|
||||||
editor.putLong(context.getString(R.string.selected_track_key), -1);
|
editor.putLong(context.getString(R.string.selected_track_key), -1);
|
||||||
ApiFeatures.getInstance().getApiAdapter().applyPreferenceChanges(editor);
|
ApiAdapterFactory.getApiAdapter().applyPreferenceChanges(editor);
|
||||||
if (done != null) {
|
if (done != null) {
|
||||||
Handler h = new Handler();
|
Handler h = new Handler();
|
||||||
h.post(done);
|
h.post(done);
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import static com.google.android.apps.mytracks.Constants.TAG;
|
|||||||
|
|
||||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
||||||
import com.google.android.apps.mytracks.content.TracksColumns;
|
import com.google.android.apps.mytracks.content.TracksColumns;
|
||||||
import com.google.android.apps.mytracks.util.ApiFeatures;
|
import com.google.android.apps.mytracks.util.ApiAdapterFactory;
|
||||||
import com.google.android.apps.mytracks.util.UriUtils;
|
import com.google.android.apps.mytracks.util.UriUtils;
|
||||||
import com.google.android.maps.mytracks.R;
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
@@ -110,7 +110,7 @@ public class DeleteTrack extends Activity
|
|||||||
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
|
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
|
||||||
if (preferences.getLong(selectedKey, -1) == deleteTrackId) {
|
if (preferences.getLong(selectedKey, -1) == deleteTrackId) {
|
||||||
Editor editor = preferences.edit().putLong(selectedKey, -1);
|
Editor editor = preferences.edit().putLong(selectedKey, -1);
|
||||||
ApiFeatures.getInstance().getApiAdapter().applyPreferenceChanges(editor);
|
ApiAdapterFactory.getApiAdapter().applyPreferenceChanges(editor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,9 +27,8 @@ import com.google.android.apps.mytracks.content.Waypoint;
|
|||||||
import com.google.android.apps.mytracks.io.file.SaveActivity;
|
import com.google.android.apps.mytracks.io.file.SaveActivity;
|
||||||
import com.google.android.apps.mytracks.io.sendtogoogle.SendType;
|
import com.google.android.apps.mytracks.io.sendtogoogle.SendType;
|
||||||
import com.google.android.apps.mytracks.io.sendtogoogle.UploadServiceChooserActivity;
|
import com.google.android.apps.mytracks.io.sendtogoogle.UploadServiceChooserActivity;
|
||||||
import com.google.android.apps.mytracks.services.tasks.StatusAnnouncerFactory;
|
import com.google.android.apps.mytracks.services.tasks.StatusAnnouncerTask;
|
||||||
import com.google.android.apps.mytracks.stats.TripStatistics;
|
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||||
import com.google.android.apps.mytracks.util.ApiFeatures;
|
|
||||||
import com.google.android.apps.mytracks.util.GeoRect;
|
import com.google.android.apps.mytracks.util.GeoRect;
|
||||||
import com.google.android.apps.mytracks.util.LocationUtils;
|
import com.google.android.apps.mytracks.util.LocationUtils;
|
||||||
import com.google.android.maps.GeoPoint;
|
import com.google.android.maps.GeoPoint;
|
||||||
@@ -44,6 +43,7 @@ import android.net.Uri;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
|
import android.speech.tts.TextToSpeech;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.ContextMenu;
|
import android.view.ContextMenu;
|
||||||
import android.view.ContextMenu.ContextMenuInfo;
|
import android.view.ContextMenu.ContextMenuInfo;
|
||||||
@@ -153,9 +153,7 @@ public class MapActivity extends com.google.android.maps.MapActivity
|
|||||||
super.onCreate(bundle);
|
super.onCreate(bundle);
|
||||||
|
|
||||||
// The volume we want to control is the Text-To-Speech volume
|
// The volume we want to control is the Text-To-Speech volume
|
||||||
int volumeStream =
|
setVolumeControlStream(TextToSpeech.Engine.DEFAULT_STREAM);
|
||||||
new StatusAnnouncerFactory(ApiFeatures.getInstance()).getVolumeStream();
|
|
||||||
setVolumeControlStream(volumeStream);
|
|
||||||
|
|
||||||
// We don't need a window title bar:
|
// We don't need a window title bar:
|
||||||
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||||
|
|||||||
@@ -28,8 +28,8 @@ import com.google.android.apps.mytracks.io.file.TempFileCleaner;
|
|||||||
import com.google.android.apps.mytracks.services.ITrackRecordingService;
|
import com.google.android.apps.mytracks.services.ITrackRecordingService;
|
||||||
import com.google.android.apps.mytracks.services.ServiceUtils;
|
import com.google.android.apps.mytracks.services.ServiceUtils;
|
||||||
import com.google.android.apps.mytracks.services.TrackRecordingServiceConnection;
|
import com.google.android.apps.mytracks.services.TrackRecordingServiceConnection;
|
||||||
import com.google.android.apps.mytracks.services.tasks.StatusAnnouncerFactory;
|
import com.google.android.apps.mytracks.services.tasks.StatusAnnouncerTask;
|
||||||
import com.google.android.apps.mytracks.util.ApiFeatures;
|
import com.google.android.apps.mytracks.util.ApiAdapterFactory;
|
||||||
import com.google.android.apps.mytracks.util.EulaUtil;
|
import com.google.android.apps.mytracks.util.EulaUtil;
|
||||||
import com.google.android.apps.mytracks.util.SystemUtils;
|
import com.google.android.apps.mytracks.util.SystemUtils;
|
||||||
import com.google.android.apps.mytracks.util.UriUtils;
|
import com.google.android.apps.mytracks.util.UriUtils;
|
||||||
@@ -48,6 +48,7 @@ import android.content.res.Resources;
|
|||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
|
import android.speech.tts.TextToSpeech;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
@@ -141,9 +142,8 @@ public class MyTracks extends TabActivity implements OnTouchListener {
|
|||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
Log.d(TAG, "MyTracks.onCreate");
|
Log.d(TAG, "MyTracks.onCreate");
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
ApiFeatures apiFeatures = ApiFeatures.getInstance();
|
|
||||||
if (!SystemUtils.isRelease(this)) {
|
if (!SystemUtils.isRelease(this)) {
|
||||||
apiFeatures.getApiAdapter().enableStrictMode();
|
ApiAdapterFactory.getApiAdapter().enableStrictMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
tracker = GoogleAnalyticsTracker.getInstance();
|
tracker = GoogleAnalyticsTracker.getInstance();
|
||||||
@@ -159,10 +159,7 @@ public class MyTracks extends TabActivity implements OnTouchListener {
|
|||||||
menuManager = new MenuManager(this);
|
menuManager = new MenuManager(this);
|
||||||
serviceConnection = new TrackRecordingServiceConnection(this, serviceBindCallback);
|
serviceConnection = new TrackRecordingServiceConnection(this, serviceBindCallback);
|
||||||
|
|
||||||
// The volume we want to control is the Text-To-Speech volume
|
setVolumeControlStream(TextToSpeech.Engine.DEFAULT_STREAM);
|
||||||
int volumeStream =
|
|
||||||
new StatusAnnouncerFactory(apiFeatures).getVolumeStream();
|
|
||||||
setVolumeControlStream(volumeStream);
|
|
||||||
|
|
||||||
// We don't need a window title bar:
|
// We don't need a window title bar:
|
||||||
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||||
|
|||||||
@@ -20,13 +20,13 @@ import static com.google.android.apps.mytracks.Constants.TAG;
|
|||||||
import com.google.android.apps.mytracks.io.backup.BackupActivityHelper;
|
import com.google.android.apps.mytracks.io.backup.BackupActivityHelper;
|
||||||
import com.google.android.apps.mytracks.io.backup.BackupPreferencesListener;
|
import com.google.android.apps.mytracks.io.backup.BackupPreferencesListener;
|
||||||
import com.google.android.apps.mytracks.services.sensors.ant.AntUtils;
|
import com.google.android.apps.mytracks.services.sensors.ant.AntUtils;
|
||||||
import com.google.android.apps.mytracks.services.tasks.StatusAnnouncerFactory;
|
import com.google.android.apps.mytracks.util.ApiAdapterFactory;
|
||||||
import com.google.android.apps.mytracks.util.ApiFeatures;
|
|
||||||
import com.google.android.apps.mytracks.util.BluetoothDeviceUtils;
|
import com.google.android.apps.mytracks.util.BluetoothDeviceUtils;
|
||||||
import com.google.android.apps.mytracks.util.UnitConversions;
|
import com.google.android.apps.mytracks.util.UnitConversions;
|
||||||
import com.google.android.maps.mytracks.R;
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
|
import android.bluetooth.BluetoothAdapter;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.DialogInterface.OnClickListener;
|
import android.content.DialogInterface.OnClickListener;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
@@ -44,6 +44,7 @@ import android.preference.PreferenceCategory;
|
|||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.preference.PreferenceScreen;
|
import android.preference.PreferenceScreen;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
|
import android.speech.tts.TextToSpeech;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
@@ -102,10 +103,7 @@ public class SettingsActivity extends PreferenceActivity {
|
|||||||
super.onCreate(icicle);
|
super.onCreate(icicle);
|
||||||
|
|
||||||
// The volume we want to control is the Text-To-Speech volume
|
// The volume we want to control is the Text-To-Speech volume
|
||||||
ApiFeatures apiFeatures = ApiFeatures.getInstance();
|
setVolumeControlStream(TextToSpeech.Engine.DEFAULT_STREAM);
|
||||||
int volumeStream =
|
|
||||||
new StatusAnnouncerFactory(apiFeatures).getVolumeStream();
|
|
||||||
setVolumeControlStream(volumeStream);
|
|
||||||
|
|
||||||
// Tell it where to read/write preferences
|
// Tell it where to read/write preferences
|
||||||
PreferenceManager preferenceManager = getPreferenceManager();
|
PreferenceManager preferenceManager = getPreferenceManager();
|
||||||
@@ -113,23 +111,13 @@ public class SettingsActivity extends PreferenceActivity {
|
|||||||
preferenceManager.setSharedPreferencesMode(0);
|
preferenceManager.setSharedPreferencesMode(0);
|
||||||
|
|
||||||
// Set up automatic preferences backup
|
// Set up automatic preferences backup
|
||||||
backupListener = apiFeatures.getApiAdapter().getBackupPreferencesListener(this);
|
backupListener = ApiAdapterFactory.getApiAdapter().getBackupPreferencesListener(this);
|
||||||
preferences = preferenceManager.getSharedPreferences();
|
preferences = preferenceManager.getSharedPreferences();
|
||||||
preferences.registerOnSharedPreferenceChangeListener(backupListener);
|
preferences.registerOnSharedPreferenceChangeListener(backupListener);
|
||||||
|
|
||||||
// Load the preferences to be displayed
|
// Load the preferences to be displayed
|
||||||
addPreferencesFromResource(R.xml.preferences);
|
addPreferencesFromResource(R.xml.preferences);
|
||||||
|
|
||||||
// Disable voice announcement if not available
|
|
||||||
if (!apiFeatures.hasTextToSpeech()) {
|
|
||||||
IntegerListPreference announcementFrequency =
|
|
||||||
(IntegerListPreference) findPreference(
|
|
||||||
getString(R.string.announcement_frequency_key));
|
|
||||||
announcementFrequency.setEnabled(false);
|
|
||||||
announcementFrequency.setValue(TASK_FREQUENCY_OFF);
|
|
||||||
announcementFrequency.setSummary(R.string.settings_recording_voice_not_available);
|
|
||||||
}
|
|
||||||
|
|
||||||
setRecordingIntervalOptions();
|
setRecordingIntervalOptions();
|
||||||
setAutoResumeTimeoutOptions();
|
setAutoResumeTimeoutOptions();
|
||||||
|
|
||||||
@@ -557,20 +545,17 @@ public class SettingsActivity extends PreferenceActivity {
|
|||||||
* Configures preference actions related to bluetooth.
|
* Configures preference actions related to bluetooth.
|
||||||
*/
|
*/
|
||||||
private void configureBluetoothPreferences() {
|
private void configureBluetoothPreferences() {
|
||||||
if (BluetoothDeviceUtils.isBluetoothMethodSupported()) {
|
// Populate the list of bluetooth devices
|
||||||
// Populate the list of bluetooth devices
|
populateBluetoothDeviceList();
|
||||||
populateBluetoothDeviceList();
|
// Make the pair devices preference go to the system preferences
|
||||||
|
findPreference(getString(R.string.bluetooth_pairing_key)).setOnPreferenceClickListener(
|
||||||
// Make the pair devices preference go to the system preferences
|
new OnPreferenceClickListener() {
|
||||||
findPreference(getString(R.string.bluetooth_pairing_key))
|
public boolean onPreferenceClick(Preference preference) {
|
||||||
.setOnPreferenceClickListener(new OnPreferenceClickListener() {
|
Intent settingsIntent = new Intent(Settings.ACTION_BLUETOOTH_SETTINGS);
|
||||||
public boolean onPreferenceClick(Preference preference) {
|
startActivity(settingsIntent);
|
||||||
Intent settingsIntent = new Intent(Settings.ACTION_BLUETOOTH_SETTINGS);
|
return false;
|
||||||
startActivity(settingsIntent);
|
}
|
||||||
return false;
|
});
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -582,7 +567,10 @@ public class SettingsActivity extends PreferenceActivity {
|
|||||||
List<String> entryValues = new ArrayList<String>();
|
List<String> entryValues = new ArrayList<String>();
|
||||||
|
|
||||||
// The actual devices
|
// The actual devices
|
||||||
BluetoothDeviceUtils.getInstance().populateDeviceLists(entries, entryValues);
|
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
|
||||||
|
if (bluetoothAdapter != null) {
|
||||||
|
BluetoothDeviceUtils.populateDeviceLists(bluetoothAdapter, entries, entryValues);
|
||||||
|
}
|
||||||
|
|
||||||
CharSequence[] entriesArray = entries.toArray(new CharSequence[entries.size()]);
|
CharSequence[] entriesArray = entries.toArray(new CharSequence[entries.size()]);
|
||||||
CharSequence[] entryValuesArray = entryValues.toArray(new CharSequence[entryValues.size()]);
|
CharSequence[] entryValuesArray = entryValues.toArray(new CharSequence[entryValues.size()]);
|
||||||
@@ -685,7 +673,7 @@ public class SettingsActivity extends PreferenceActivity {
|
|||||||
SharedPreferences prefs = getPreferenceManager().getSharedPreferences();
|
SharedPreferences prefs = getPreferenceManager().getSharedPreferences();
|
||||||
Editor editor = prefs.edit();
|
Editor editor = prefs.edit();
|
||||||
editor.putString(getString(id), metricspeed);
|
editor.putString(getString(id), metricspeed);
|
||||||
ApiFeatures.getInstance().getApiAdapter().applyPreferenceChanges(editor);
|
ApiAdapterFactory.getApiAdapter().applyPreferenceChanges(editor);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -23,8 +23,7 @@ import com.google.android.apps.mytracks.content.TrackDataHub.ListenerDataType;
|
|||||||
import com.google.android.apps.mytracks.content.TrackDataListener;
|
import com.google.android.apps.mytracks.content.TrackDataListener;
|
||||||
import com.google.android.apps.mytracks.content.Waypoint;
|
import com.google.android.apps.mytracks.content.Waypoint;
|
||||||
import com.google.android.apps.mytracks.services.ServiceUtils;
|
import com.google.android.apps.mytracks.services.ServiceUtils;
|
||||||
import com.google.android.apps.mytracks.services.tasks.StatusAnnouncerFactory;
|
import com.google.android.apps.mytracks.services.tasks.StatusAnnouncerTask;
|
||||||
import com.google.android.apps.mytracks.util.ApiFeatures;
|
|
||||||
import com.google.android.maps.mytracks.R;
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
@@ -32,6 +31,7 @@ import android.content.Context;
|
|||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.location.Location;
|
import android.location.Location;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.speech.tts.TextToSpeech;
|
||||||
import android.util.DisplayMetrics;
|
import android.util.DisplayMetrics;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.Window;
|
import android.view.Window;
|
||||||
@@ -105,9 +105,7 @@ public class StatsActivity extends Activity implements TrackDataListener {
|
|||||||
utils = new StatsUtilities(this);
|
utils = new StatsUtilities(this);
|
||||||
|
|
||||||
// The volume we want to control is the Text-To-Speech volume
|
// The volume we want to control is the Text-To-Speech volume
|
||||||
int volumeStream =
|
setVolumeControlStream(TextToSpeech.Engine.DEFAULT_STREAM);
|
||||||
new StatusAnnouncerFactory(ApiFeatures.getInstance()).getVolumeStream();
|
|
||||||
setVolumeControlStream(volumeStream);
|
|
||||||
|
|
||||||
// We don't need a window title bar:
|
// We don't need a window title bar:
|
||||||
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||||
|
|||||||
@@ -16,7 +16,6 @@
|
|||||||
package com.google.android.apps.mytracks.content;
|
package com.google.android.apps.mytracks.content;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.Constants;
|
import com.google.android.apps.mytracks.Constants;
|
||||||
import com.google.android.apps.mytracks.util.ApiFeatures;
|
|
||||||
import com.google.android.maps.mytracks.R;
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
import android.content.ContentProvider;
|
import android.content.ContentProvider;
|
||||||
@@ -417,12 +416,9 @@ public class MyTracksProvider extends ContentProvider {
|
|||||||
} else {
|
} else {
|
||||||
throw new IllegalArgumentException("Unknown URL " + url);
|
throw new IllegalArgumentException("Unknown URL " + url);
|
||||||
}
|
}
|
||||||
|
Log.i(Constants.TAG, "Build query: "
|
||||||
|
+ qb.buildQuery(projection, selection, selectionArgs, null, null, sortOrder, null));
|
||||||
|
|
||||||
if (ApiFeatures.getInstance().canReuseSQLiteQueryBuilder()) {
|
|
||||||
Log.i(Constants.TAG,
|
|
||||||
"Build query: " + qb.buildQuery(projection, selection, selectionArgs,
|
|
||||||
null, null, sortOrder, null));
|
|
||||||
}
|
|
||||||
Cursor c = qb.query(db, projection, selection, selectionArgs, null, null,
|
Cursor c = qb.query(db, projection, selection, selectionArgs, null, null,
|
||||||
sortOrder);
|
sortOrder);
|
||||||
c.setNotificationUri(getContext().getContentResolver(), url);
|
c.setNotificationUri(getContext().getContentResolver(), url);
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import com.google.android.apps.mytracks.content.MyTracksProviderUtils.DoubleBuff
|
|||||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils.LocationIterator;
|
import com.google.android.apps.mytracks.content.MyTracksProviderUtils.LocationIterator;
|
||||||
import com.google.android.apps.mytracks.content.TrackDataListener.ProviderState;
|
import com.google.android.apps.mytracks.content.TrackDataListener.ProviderState;
|
||||||
import com.google.android.apps.mytracks.content.TrackDataListeners.ListenerRegistration;
|
import com.google.android.apps.mytracks.content.TrackDataListeners.ListenerRegistration;
|
||||||
import com.google.android.apps.mytracks.util.ApiFeatures;
|
import com.google.android.apps.mytracks.util.ApiAdapterFactory;
|
||||||
import com.google.android.apps.mytracks.util.LocationUtils;
|
import com.google.android.apps.mytracks.util.LocationUtils;
|
||||||
import com.google.android.maps.mytracks.R;
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
@@ -399,7 +399,7 @@ public class TrackDataHub {
|
|||||||
|
|
||||||
// Save the selection to memory and flush.
|
// Save the selection to memory and flush.
|
||||||
selectedTrackId = trackId;
|
selectedTrackId = trackId;
|
||||||
ApiFeatures.getInstance().getApiAdapter().applyPreferenceChanges(
|
ApiAdapterFactory.getApiAdapter().applyPreferenceChanges(
|
||||||
preferences.edit().putLong(SELECTED_TRACK_KEY, trackId));
|
preferences.edit().putLong(SELECTED_TRACK_KEY, trackId));
|
||||||
|
|
||||||
// Force it to reload data from the beginning.
|
// Force it to reload data from the beginning.
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
package com.google.android.apps.mytracks.io.backup;
|
package com.google.android.apps.mytracks.io.backup;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.content.ContentTypeIds;
|
import com.google.android.apps.mytracks.content.ContentTypeIds;
|
||||||
import com.google.android.apps.mytracks.util.ApiFeatures;
|
import com.google.android.apps.mytracks.util.ApiAdapterFactory;
|
||||||
|
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.content.SharedPreferences.Editor;
|
import android.content.SharedPreferences.Editor;
|
||||||
@@ -106,7 +106,7 @@ class PreferenceBackupHelper {
|
|||||||
byte typeId = reader.readByte();
|
byte typeId = reader.readByte();
|
||||||
readAndSetPreference(name, typeId, reader, editor);
|
readAndSetPreference(name, typeId, reader, editor);
|
||||||
}
|
}
|
||||||
ApiFeatures.getInstance().getApiAdapter().applyPreferenceChanges(editor);
|
ApiAdapterFactory.getApiAdapter().applyPreferenceChanges(editor);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+2
-2
@@ -16,7 +16,7 @@
|
|||||||
package com.google.android.apps.mytracks.io.sendtogoogle;
|
package com.google.android.apps.mytracks.io.sendtogoogle;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.Constants;
|
import com.google.android.apps.mytracks.Constants;
|
||||||
import com.google.android.apps.mytracks.util.ApiFeatures;
|
import com.google.android.apps.mytracks.util.ApiAdapterFactory;
|
||||||
import com.google.android.maps.mytracks.R;
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
import android.accounts.Account;
|
import android.accounts.Account;
|
||||||
@@ -153,7 +153,7 @@ public class AccountChooserActivity extends Activity {
|
|||||||
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
|
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
|
||||||
Editor editor = prefs.edit();
|
Editor editor = prefs.edit();
|
||||||
editor.putString(getString(R.string.preferred_account_key), account.name);
|
editor.putString(getString(R.string.preferred_account_key), account.name);
|
||||||
ApiFeatures.getInstance().getApiAdapter().applyPreferenceChanges(editor);
|
ApiAdapterFactory.getApiAdapter().applyPreferenceChanges(editor);
|
||||||
}
|
}
|
||||||
Intent intent = new Intent();
|
Intent intent = new Intent();
|
||||||
intent.putExtra(ACCOUNT, account);
|
intent.putExtra(ACCOUNT, account);
|
||||||
|
|||||||
+2
-2
@@ -7,7 +7,7 @@ import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
|||||||
import com.google.android.apps.mytracks.content.Track;
|
import com.google.android.apps.mytracks.content.Track;
|
||||||
import com.google.android.apps.mytracks.content.Waypoint;
|
import com.google.android.apps.mytracks.content.Waypoint;
|
||||||
import com.google.android.apps.mytracks.stats.DoubleBuffer;
|
import com.google.android.apps.mytracks.stats.DoubleBuffer;
|
||||||
import com.google.android.apps.mytracks.util.ApiFeatures;
|
import com.google.android.apps.mytracks.util.ApiAdapterFactory;
|
||||||
import com.google.android.apps.mytracks.util.LocationUtils;
|
import com.google.android.apps.mytracks.util.LocationUtils;
|
||||||
import com.google.android.apps.mytracks.util.StringUtils;
|
import com.google.android.apps.mytracks.util.StringUtils;
|
||||||
import com.google.android.apps.mytracks.util.SystemUtils;
|
import com.google.android.apps.mytracks.util.SystemUtils;
|
||||||
@@ -108,7 +108,7 @@ public class SendFusionTablesAsyncTask extends AsyncTask<Void, Integer, Boolean>
|
|||||||
|
|
||||||
context = activity.getApplicationContext();
|
context = activity.getApplicationContext();
|
||||||
myTracksProviderUtils = MyTracksProviderUtils.Factory.get(context);
|
myTracksProviderUtils = MyTracksProviderUtils.Factory.get(context);
|
||||||
HttpTransport transport = ApiFeatures.getInstance().getApiAdapter().getHttpTransport();
|
HttpTransport transport = ApiAdapterFactory.getApiAdapter().getHttpTransport();
|
||||||
httpRequestFactory = transport.createRequestFactory(new MethodOverride());
|
httpRequestFactory = transport.createRequestFactory(new MethodOverride());
|
||||||
|
|
||||||
canRetry = true;
|
canRetry = true;
|
||||||
|
|||||||
+2
-2
@@ -16,7 +16,7 @@
|
|||||||
package com.google.android.apps.mytracks.io.sendtogoogle;
|
package com.google.android.apps.mytracks.io.sendtogoogle;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.Constants;
|
import com.google.android.apps.mytracks.Constants;
|
||||||
import com.google.android.apps.mytracks.util.ApiFeatures;
|
import com.google.android.apps.mytracks.util.ApiAdapterFactory;
|
||||||
import com.google.android.maps.mytracks.R;
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
@@ -218,7 +218,7 @@ public class UploadServiceChooserActivity extends Activity {
|
|||||||
editor.putBoolean(getString(R.string.send_to_fusion_tables_key), sendFusionTables());
|
editor.putBoolean(getString(R.string.send_to_fusion_tables_key), sendFusionTables());
|
||||||
editor.putBoolean(getString(R.string.send_to_docs_key), sendDocs());
|
editor.putBoolean(getString(R.string.send_to_docs_key), sendDocs());
|
||||||
}
|
}
|
||||||
ApiFeatures.getInstance().getApiAdapter().applyPreferenceChanges(editor);
|
ApiAdapterFactory.getApiAdapter().applyPreferenceChanges(editor);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
package com.google.android.apps.mytracks.services;
|
package com.google.android.apps.mytracks.services;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.Constants;
|
import com.google.android.apps.mytracks.Constants;
|
||||||
import com.google.android.apps.mytracks.util.ApiFeatures;
|
import com.google.android.apps.mytracks.util.ApiAdapterFactory;
|
||||||
import com.google.android.maps.mytracks.R;
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
@@ -174,19 +174,19 @@ public class PreferenceManager implements OnSharedPreferenceChangeListener {
|
|||||||
public void setAutoResumeTrackCurrentRetry(int retryAttempts) {
|
public void setAutoResumeTrackCurrentRetry(int retryAttempts) {
|
||||||
Editor editor = sharedPreferences.edit();
|
Editor editor = sharedPreferences.edit();
|
||||||
editor.putInt(autoResumeTrackCurrentRetryKey, retryAttempts);
|
editor.putInt(autoResumeTrackCurrentRetryKey, retryAttempts);
|
||||||
ApiFeatures.getInstance().getApiAdapter().applyPreferenceChanges(editor);
|
ApiAdapterFactory.getApiAdapter().applyPreferenceChanges(editor);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRecordingTrack(long id) {
|
public void setRecordingTrack(long id) {
|
||||||
Editor editor = sharedPreferences.edit();
|
Editor editor = sharedPreferences.edit();
|
||||||
editor.putLong(recordingTrackKey, id);
|
editor.putLong(recordingTrackKey, id);
|
||||||
ApiFeatures.getInstance().getApiAdapter().applyPreferenceChanges(editor);
|
ApiAdapterFactory.getApiAdapter().applyPreferenceChanges(editor);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSelectedTrack(long id) {
|
public void setSelectedTrack(long id) {
|
||||||
Editor editor = sharedPreferences.edit();
|
Editor editor = sharedPreferences.edit();
|
||||||
editor.putLong(selectedTrackKey, id);
|
editor.putLong(selectedTrackKey, id);
|
||||||
ApiFeatures.getInstance().getApiAdapter().applyPreferenceChanges(editor);
|
ApiAdapterFactory.getApiAdapter().applyPreferenceChanges(editor);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void shutdown() {
|
public void shutdown() {
|
||||||
|
|||||||
@@ -36,14 +36,12 @@ import com.google.android.apps.mytracks.services.tasks.SplitTask;
|
|||||||
import com.google.android.apps.mytracks.services.tasks.StatusAnnouncerFactory;
|
import com.google.android.apps.mytracks.services.tasks.StatusAnnouncerFactory;
|
||||||
import com.google.android.apps.mytracks.stats.TripStatistics;
|
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||||
import com.google.android.apps.mytracks.stats.TripStatisticsBuilder;
|
import com.google.android.apps.mytracks.stats.TripStatisticsBuilder;
|
||||||
import com.google.android.apps.mytracks.util.ApiFeatures;
|
|
||||||
import com.google.android.apps.mytracks.util.ApiLevelAdapter;
|
|
||||||
import com.google.android.apps.mytracks.util.LocationUtils;
|
import com.google.android.apps.mytracks.util.LocationUtils;
|
||||||
import com.google.android.apps.mytracks.util.StringUtils;
|
import com.google.android.apps.mytracks.util.StringUtils;
|
||||||
import com.google.android.maps.mytracks.R;
|
import com.google.android.maps.mytracks.R;
|
||||||
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
|
||||||
import android.app.Notification;
|
import android.app.Notification;
|
||||||
import android.app.NotificationManager;
|
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.app.Service;
|
import android.app.Service;
|
||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
@@ -80,7 +78,6 @@ public class TrackRecordingService extends Service {
|
|||||||
|
|
||||||
static final int MAX_AUTO_RESUME_TRACK_RETRY_ATTEMPTS = 3;
|
static final int MAX_AUTO_RESUME_TRACK_RETRY_ATTEMPTS = 3;
|
||||||
|
|
||||||
private NotificationManager notificationManager;
|
|
||||||
private LocationManager locationManager;
|
private LocationManager locationManager;
|
||||||
private WakeLock wakeLock;
|
private WakeLock wakeLock;
|
||||||
|
|
||||||
@@ -243,8 +240,6 @@ public class TrackRecordingService extends Service {
|
|||||||
super.onCreate();
|
super.onCreate();
|
||||||
Log.d(TAG, "TrackRecordingService.onCreate");
|
Log.d(TAG, "TrackRecordingService.onCreate");
|
||||||
providerUtils = MyTracksProviderUtils.Factory.get(this);
|
providerUtils = MyTracksProviderUtils.Factory.get(this);
|
||||||
notificationManager =
|
|
||||||
(NotificationManager) getSystemService(NOTIFICATION_SERVICE);
|
|
||||||
locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
|
locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
|
||||||
|
|
||||||
setUpTaskExecutors();
|
setUpTaskExecutors();
|
||||||
@@ -369,7 +364,6 @@ public class TrackRecordingService extends Service {
|
|||||||
|
|
||||||
// Make sure we have no indirect references to this service.
|
// Make sure we have no indirect references to this service.
|
||||||
locationManager = null;
|
locationManager = null;
|
||||||
notificationManager = null;
|
|
||||||
providerUtils = null;
|
providerUtils = null;
|
||||||
binder.detachFromService();
|
binder.detachFromService();
|
||||||
binder = null;
|
binder = null;
|
||||||
@@ -485,8 +479,6 @@ public class TrackRecordingService extends Service {
|
|||||||
* Shows the notification message and icon in the notification bar.
|
* Shows the notification message and icon in the notification bar.
|
||||||
*/
|
*/
|
||||||
private void showNotification() {
|
private void showNotification() {
|
||||||
final ApiLevelAdapter apiLevelAdapter =
|
|
||||||
ApiFeatures.getInstance().getApiAdapter();
|
|
||||||
if (isRecording) {
|
if (isRecording) {
|
||||||
Notification notification = new Notification(
|
Notification notification = new Notification(
|
||||||
R.drawable.arrow_320, null /* tickerText */,
|
R.drawable.arrow_320, null /* tickerText */,
|
||||||
@@ -497,16 +489,24 @@ public class TrackRecordingService extends Service {
|
|||||||
notification.setLatestEventInfo(this, getString(R.string.my_tracks_app_name),
|
notification.setLatestEventInfo(this, getString(R.string.my_tracks_app_name),
|
||||||
getString(R.string.track_record_notification), contentIntent);
|
getString(R.string.track_record_notification), contentIntent);
|
||||||
notification.flags += Notification.FLAG_NO_CLEAR;
|
notification.flags += Notification.FLAG_NO_CLEAR;
|
||||||
apiLevelAdapter.startForeground(this, notificationManager, 1,
|
startForegroundService(notification);
|
||||||
notification);
|
|
||||||
} else {
|
} else {
|
||||||
apiLevelAdapter.stopForeground(this, notificationManager, 1);
|
stopForegroundService();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
protected void startForegroundService(Notification notification) {
|
||||||
|
startForeground(1, notification);
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
protected void stopForegroundService() {
|
||||||
|
stopForeground(true);
|
||||||
|
}
|
||||||
|
|
||||||
private void setUpTaskExecutors() {
|
private void setUpTaskExecutors() {
|
||||||
announcementExecutor = new PeriodicTaskExecutor(
|
announcementExecutor = new PeriodicTaskExecutor(this, new StatusAnnouncerFactory());
|
||||||
this, new StatusAnnouncerFactory(ApiFeatures.getInstance()));
|
|
||||||
splitExecutor = new PeriodicTaskExecutor(this, new SplitTask.Factory());
|
splitExecutor = new PeriodicTaskExecutor(this, new SplitTask.Factory());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+5
-34
@@ -18,7 +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 com.google.android.apps.mytracks.util.ApiAdapterFactory;
|
||||||
|
|
||||||
import android.bluetooth.BluetoothAdapter;
|
import android.bluetooth.BluetoothAdapter;
|
||||||
import android.bluetooth.BluetoothDevice;
|
import android.bluetooth.BluetoothDevice;
|
||||||
@@ -31,8 +31,6 @@ 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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -44,8 +42,9 @@ import java.util.UUID;
|
|||||||
* @author Sandor Dornbush
|
* @author Sandor Dornbush
|
||||||
*/
|
*/
|
||||||
public class BluetoothConnectionManager {
|
public class BluetoothConnectionManager {
|
||||||
// Unique UUID for this application
|
|
||||||
private static final UUID SPP_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
|
// Unique Bluetooth UUID for My Tracks
|
||||||
|
public static final UUID SPP_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
|
||||||
|
|
||||||
private MessageParser parser;
|
private MessageParser parser;
|
||||||
|
|
||||||
@@ -254,41 +253,13 @@ public class BluetoothConnectionManager {
|
|||||||
// Get a BluetoothSocket for a connection with the
|
// Get a BluetoothSocket for a connection with the
|
||||||
// given BluetoothDevice
|
// given BluetoothDevice
|
||||||
try {
|
try {
|
||||||
tmp = getSocket();
|
tmp = ApiAdapterFactory.getApiAdapter().getBluetoothSocket(device);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.e(Constants.TAG, "create() failed", e);
|
Log.e(Constants.TAG, "create() failed", e);
|
||||||
}
|
}
|
||||||
socket = tmp;
|
socket = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
private BluetoothSocket getSocket() throws IOException {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
Log.d(Constants.TAG, "BEGIN mConnectThread");
|
Log.d(Constants.TAG, "BEGIN mConnectThread");
|
||||||
|
|||||||
+2
-3
@@ -16,7 +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 com.google.android.apps.mytracks.util.ApiAdapterFactory;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
@@ -62,8 +62,7 @@ public class ZephyrMessageParser implements MessageParser {
|
|||||||
// 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 = ApiFeatures.getInstance().getApiAdapter()
|
byte[] hardwareFirmwareId = ApiAdapterFactory.getApiAdapter().copyByteArray(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)) {
|
||||||
|
|||||||
+2
-2
@@ -22,7 +22,7 @@ import com.dsi.ant.AntMesg;
|
|||||||
import com.dsi.ant.exception.AntInterfaceException;
|
import com.dsi.ant.exception.AntInterfaceException;
|
||||||
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 com.google.android.apps.mytracks.util.ApiAdapterFactory;
|
||||||
import com.google.android.maps.mytracks.R;
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
@@ -135,7 +135,7 @@ public class AntDirectSensorManager extends AntSensorManager {
|
|||||||
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
|
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
|
||||||
SharedPreferences.Editor editor = prefs.edit();
|
SharedPreferences.Editor editor = prefs.edit();
|
||||||
editor.putInt(context.getString(R.string.ant_heart_rate_sensor_id_key), deviceNumberHRM);
|
editor.putInt(context.getString(R.string.ant_heart_rate_sensor_id_key), deviceNumberHRM);
|
||||||
ApiFeatures.getInstance().getApiAdapter().applyPreferenceChanges(editor);
|
ApiAdapterFactory.getApiAdapter().applyPreferenceChanges(editor);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleMessageResponse(byte[] rawMessage) {
|
private void handleMessageResponse(byte[] rawMessage) {
|
||||||
|
|||||||
+2
-2
@@ -22,7 +22,7 @@ import com.dsi.ant.AntMesg;
|
|||||||
import com.dsi.ant.exception.AntInterfaceException;
|
import com.dsi.ant.exception.AntInterfaceException;
|
||||||
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 com.google.android.apps.mytracks.util.ApiAdapterFactory;
|
||||||
import com.google.android.apps.mytracks.util.SystemUtils;
|
import com.google.android.apps.mytracks.util.SystemUtils;
|
||||||
import com.google.android.maps.mytracks.R;
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
@@ -199,7 +199,7 @@ public class AntSrmBridgeSensorManager extends AntSensorManager {
|
|||||||
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
|
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
|
||||||
SharedPreferences.Editor editor = prefs.edit();
|
SharedPreferences.Editor editor = prefs.edit();
|
||||||
editor.putInt(context.getString(R.string.ant_srm_bridge_sensor_id_key), deviceNumber);
|
editor.putInt(context.getString(R.string.ant_srm_bridge_sensor_id_key), deviceNumber);
|
||||||
ApiFeatures.getInstance().getApiAdapter().applyPreferenceChanges(editor);
|
ApiAdapterFactory.getApiAdapter().applyPreferenceChanges(editor);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleMessageResponse(byte[] rawMessage) {
|
private void handleMessageResponse(byte[] rawMessage) {
|
||||||
|
|||||||
+3
-23
@@ -15,10 +15,9 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.android.apps.mytracks.services.tasks;
|
package com.google.android.apps.mytracks.services.tasks;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.util.ApiFeatures;
|
import com.google.android.apps.mytracks.util.ApiAdapterFactory;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.media.AudioManager;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Factory which wraps construction and setup of text-to-speech announcements in
|
* Factory which wraps construction and setup of text-to-speech announcements in
|
||||||
@@ -28,30 +27,11 @@ import android.media.AudioManager;
|
|||||||
*/
|
*/
|
||||||
public class StatusAnnouncerFactory implements PeriodicTaskFactory {
|
public class StatusAnnouncerFactory implements PeriodicTaskFactory {
|
||||||
|
|
||||||
private final boolean hasTts;
|
public StatusAnnouncerFactory() {
|
||||||
|
|
||||||
public StatusAnnouncerFactory(ApiFeatures apiFeatures) {
|
|
||||||
this.hasTts = apiFeatures.hasTextToSpeech();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PeriodicTask create(Context context) {
|
public PeriodicTask create(Context context) {
|
||||||
if (hasTts) {
|
return ApiAdapterFactory.getApiAdapter().getStatusAnnouncerTask(context);
|
||||||
return ApiFeatures.getInstance().getApiAdapter().getStatusAnnouncerTask(context);
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the appropriate volume stream for controlling announcement
|
|
||||||
* volume.
|
|
||||||
*/
|
|
||||||
public int getVolumeStream() {
|
|
||||||
if (hasTts) {
|
|
||||||
return StatusAnnouncerTask.getVolumeStream();
|
|
||||||
} else {
|
|
||||||
return AudioManager.USE_DEFAULT_STREAM_TYPE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -331,13 +331,6 @@ public class StatusAnnouncerTask implements PeriodicTask {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the volume stream to use for controlling announcement volume.
|
|
||||||
*/
|
|
||||||
public static int getVolumeStream() {
|
|
||||||
return TextToSpeech.Engine.DEFAULT_STREAM;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a string to announce the time.
|
* Gets a string to announce the time.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 Google Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
* use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
* the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations under
|
||||||
|
* the License.
|
||||||
|
*/
|
||||||
|
package com.google.android.apps.mytracks.util;
|
||||||
|
|
||||||
|
import com.google.android.apps.mytracks.Constants;
|
||||||
|
import com.google.android.apps.mytracks.services.sensors.BluetoothConnectionManager;
|
||||||
|
|
||||||
|
import android.bluetooth.BluetoothDevice;
|
||||||
|
import android.bluetooth.BluetoothSocket;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* API level 10 specific implementation of the {@link ApiAdapter}.
|
||||||
|
*
|
||||||
|
* @author Jimmy Shih
|
||||||
|
*/
|
||||||
|
public class Api10Adapter extends Api9Adapter {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BluetoothSocket getBluetoothSocket(BluetoothDevice bluetoothDevice) throws IOException {
|
||||||
|
try {
|
||||||
|
return bluetoothDevice.createInsecureRfcommSocketToServiceRecord(
|
||||||
|
BluetoothConnectionManager.SPP_UUID);
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.d(Constants.TAG, "Unable to create insecure connection", e);
|
||||||
|
}
|
||||||
|
return bluetoothDevice.createRfcommSocketToServiceRecord(BluetoothConnectionManager.SPP_UUID);
|
||||||
|
};
|
||||||
|
}
|
||||||
+28
-43
@@ -15,49 +15,31 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.android.apps.mytracks.util;
|
package com.google.android.apps.mytracks.util;
|
||||||
|
|
||||||
import static com.google.android.apps.mytracks.Constants.TAG;
|
import com.google.android.apps.mytracks.Constants;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.io.backup.BackupPreferencesListener;
|
import com.google.android.apps.mytracks.io.backup.BackupPreferencesListener;
|
||||||
|
import com.google.android.apps.mytracks.services.sensors.BluetoothConnectionManager;
|
||||||
import com.google.android.apps.mytracks.services.tasks.PeriodicTask;
|
import com.google.android.apps.mytracks.services.tasks.PeriodicTask;
|
||||||
import com.google.android.apps.mytracks.services.tasks.StatusAnnouncerTask;
|
import com.google.android.apps.mytracks.services.tasks.StatusAnnouncerTask;
|
||||||
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.apache.ApacheHttpTransport;
|
||||||
|
|
||||||
import android.app.Notification;
|
import android.bluetooth.BluetoothDevice;
|
||||||
import android.app.NotificationManager;
|
import android.bluetooth.BluetoothSocket;
|
||||||
import android.app.Service;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.content.SharedPreferences.Editor;
|
import android.content.SharedPreferences.Editor;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* API level 3 specific implementation of the {@link ApiLevelAdapter}.
|
* API level 7 specific implementation of the {@link ApiAdapter}.
|
||||||
*
|
*
|
||||||
* @author Bartlomiej Niechwiej
|
* @author Bartlomiej Niechwiej
|
||||||
*/
|
*/
|
||||||
public class ApiLevel3Adapter implements ApiLevelAdapter {
|
public class Api7Adapter implements ApiAdapter {
|
||||||
|
|
||||||
@Override
|
|
||||||
public void startForeground(Service service,
|
|
||||||
NotificationManager notificationManager, int id,
|
|
||||||
Notification notification) {
|
|
||||||
setServiceForeground(service, true);
|
|
||||||
|
|
||||||
notificationManager.notify(id, notification);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void stopForeground(Service service,
|
|
||||||
NotificationManager notificationManager, int id) {
|
|
||||||
setServiceForeground(service, false);
|
|
||||||
if (id != -1) {
|
|
||||||
notificationManager.cancel(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PeriodicTask getStatusAnnouncerTask(Context context) {
|
public PeriodicTask getStatusAnnouncerTask(Context context) {
|
||||||
@@ -74,24 +56,6 @@ public class ApiLevel3Adapter implements ApiLevelAdapter {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setServiceForeground(Service service, boolean foreground) {
|
|
||||||
// setForeground has been completely removed in API level 11, so we use reflection.
|
|
||||||
try {
|
|
||||||
Method setForegroundMethod = Service.class.getMethod("setForeground", boolean.class);
|
|
||||||
setForegroundMethod.invoke(service, foreground);
|
|
||||||
} catch (SecurityException e) {
|
|
||||||
Log.e(TAG, "Unable to set service foreground state", e);
|
|
||||||
} catch (NoSuchMethodException e) {
|
|
||||||
Log.e(TAG, "Unable to set service foreground state", e);
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
Log.e(TAG, "Unable to set service foreground state", e);
|
|
||||||
} catch (IllegalAccessException e) {
|
|
||||||
Log.e(TAG, "Unable to set service foreground state", e);
|
|
||||||
} catch (InvocationTargetException e) {
|
|
||||||
Log.e(TAG, "Unable to set service foreground state", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void applyPreferenceChanges(Editor editor) {
|
public void applyPreferenceChanges(Editor editor) {
|
||||||
editor.commit();
|
editor.commit();
|
||||||
@@ -114,4 +78,25 @@ public class ApiLevel3Adapter implements ApiLevelAdapter {
|
|||||||
public HttpTransport getHttpTransport() {
|
public HttpTransport getHttpTransport() {
|
||||||
return new ApacheHttpTransport();
|
return new ApacheHttpTransport();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BluetoothSocket getBluetoothSocket(BluetoothDevice bluetoothDevice) throws IOException {
|
||||||
|
try {
|
||||||
|
Class<? extends BluetoothDevice> c = bluetoothDevice.getClass();
|
||||||
|
Method insecure = c.getMethod("createInsecureRfcommSocket", Integer.class);
|
||||||
|
insecure.setAccessible(true);
|
||||||
|
return (BluetoothSocket) insecure.invoke(bluetoothDevice, 1);
|
||||||
|
} catch (SecurityException e) {
|
||||||
|
Log.d(Constants.TAG, "Unable to create insecure connection", e);
|
||||||
|
} catch (NoSuchMethodException e) {
|
||||||
|
Log.d(Constants.TAG, "Unable to create insecure connection", e);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
Log.d(Constants.TAG, "Unable to create insecure connection", e);
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
Log.d(Constants.TAG, "Unable to create insecure connection", e);
|
||||||
|
} catch (InvocationTargetException e) {
|
||||||
|
Log.d(Constants.TAG, "Unable to create insecure connection", e);
|
||||||
|
}
|
||||||
|
return bluetoothDevice.createRfcommSocketToServiceRecord(BluetoothConnectionManager.SPP_UUID);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+17
-2
@@ -1,3 +1,18 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 Google Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
* use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
* the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations under
|
||||||
|
* the License.
|
||||||
|
*/
|
||||||
package com.google.android.apps.mytracks.util;
|
package com.google.android.apps.mytracks.util;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.io.backup.BackupPreferencesListener;
|
import com.google.android.apps.mytracks.io.backup.BackupPreferencesListener;
|
||||||
@@ -8,11 +23,11 @@ import com.google.android.apps.mytracks.services.tasks.PeriodicTask;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* API level 8 specific implementation of the {@link ApiLevelAdapter}.
|
* API level 8 specific implementation of the {@link ApiAdapter}.
|
||||||
*
|
*
|
||||||
* @author Jimmy Shih
|
* @author Jimmy Shih
|
||||||
*/
|
*/
|
||||||
public class ApiLevel8Adapter extends ApiLevel5Adapter {
|
public class Api8Adapter extends Api7Adapter {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PeriodicTask getStatusAnnouncerTask(Context context) {
|
public PeriodicTask getStatusAnnouncerTask(Context context) {
|
||||||
+17
-2
@@ -1,3 +1,18 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 Google Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
* use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
* the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations under
|
||||||
|
* the License.
|
||||||
|
*/
|
||||||
package com.google.android.apps.mytracks.util;
|
package com.google.android.apps.mytracks.util;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.Constants;
|
import com.google.android.apps.mytracks.Constants;
|
||||||
@@ -11,11 +26,11 @@ import android.util.Log;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* API level 9 specific implementation of the {@link ApiLevelAdapter}.
|
* API level 9 specific implementation of the {@link ApiAdapter}.
|
||||||
*
|
*
|
||||||
* @author Rodrigo Damazio
|
* @author Rodrigo Damazio
|
||||||
*/
|
*/
|
||||||
public class ApiLevel9Adapter extends ApiLevel8Adapter {
|
public class Api9Adapter extends Api8Adapter {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void applyPreferenceChanges(Editor editor) {
|
public void applyPreferenceChanges(Editor editor) {
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010 Google Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
* use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
* the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations under
|
||||||
|
* the License.
|
||||||
|
*/
|
||||||
|
package com.google.android.apps.mytracks.util;
|
||||||
|
|
||||||
|
import com.google.android.apps.mytracks.io.backup.BackupPreferencesListener;
|
||||||
|
import com.google.android.apps.mytracks.services.tasks.PeriodicTask;
|
||||||
|
import com.google.api.client.http.HttpTransport;
|
||||||
|
|
||||||
|
import android.bluetooth.BluetoothDevice;
|
||||||
|
import android.bluetooth.BluetoothSocket;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A set of methods that may be implemented differently depending on the Android
|
||||||
|
* API level.
|
||||||
|
*
|
||||||
|
* @author Bartlomiej Niechwiej
|
||||||
|
*/
|
||||||
|
public interface ApiAdapter {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a status announcer task.
|
||||||
|
* <p>
|
||||||
|
* Due to changes in API level 8.
|
||||||
|
*
|
||||||
|
* @param context the context
|
||||||
|
*/
|
||||||
|
public PeriodicTask getStatusAnnouncerTask(Context context);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a {@link BackupPreferencesListener}.
|
||||||
|
* <p>
|
||||||
|
* Due to changes in API level 8.
|
||||||
|
*
|
||||||
|
* @param context the context
|
||||||
|
*/
|
||||||
|
public BackupPreferencesListener getBackupPreferencesListener(Context context);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies all the changes done to a given preferences editor. Changes may or
|
||||||
|
* may not be applied immediately.
|
||||||
|
* <p>
|
||||||
|
* Due to changes in API level 9.
|
||||||
|
*
|
||||||
|
* @param editor the editor
|
||||||
|
*/
|
||||||
|
public void applyPreferenceChanges(SharedPreferences.Editor editor);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enables strict mode where supported, only if this is a development build.
|
||||||
|
* <p>
|
||||||
|
* Due to changes in API level 9.
|
||||||
|
*/
|
||||||
|
public void enableStrictMode();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies elements from an input byte array into a new byte array, from
|
||||||
|
* indexes start (inclusive) to end (exclusive). The end index must be less
|
||||||
|
* than or equal to the input length.
|
||||||
|
* <p>
|
||||||
|
* Due to changes in API level 9.
|
||||||
|
*
|
||||||
|
* @param input the input byte array
|
||||||
|
* @param start the start index
|
||||||
|
* @param end the end index
|
||||||
|
* @return a new array containing elements from the input byte array.
|
||||||
|
*/
|
||||||
|
public byte[] copyByteArray(byte[] input, int start, int end);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a {@link HttpTransport}.
|
||||||
|
* <p>
|
||||||
|
* Due to changes in API level 9.
|
||||||
|
*/
|
||||||
|
public HttpTransport getHttpTransport();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a {@link BluetoothSocket}.
|
||||||
|
* <p>
|
||||||
|
* Due to changes in API level 10.
|
||||||
|
*
|
||||||
|
* @param bluetoothDevice
|
||||||
|
*/
|
||||||
|
public BluetoothSocket getBluetoothSocket(BluetoothDevice bluetoothDevice) throws IOException;
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010 Google Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
* use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
* the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations under
|
||||||
|
* the License.
|
||||||
|
*/
|
||||||
|
package com.google.android.apps.mytracks.util;
|
||||||
|
|
||||||
|
import android.os.Build;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A factory to get the {@link ApiAdapter} for the current device.
|
||||||
|
*
|
||||||
|
* @author Rodrigo Damazio
|
||||||
|
*/
|
||||||
|
public class ApiAdapterFactory {
|
||||||
|
|
||||||
|
private static ApiAdapter apiAdapter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the {@link ApiAdapter} for the current device.
|
||||||
|
*/
|
||||||
|
public static ApiAdapter getApiAdapter() {
|
||||||
|
if (apiAdapter == null) {
|
||||||
|
if (Build.VERSION.SDK_INT >= 10) {
|
||||||
|
apiAdapter = new Api10Adapter();
|
||||||
|
return apiAdapter;
|
||||||
|
} else if (Build.VERSION.SDK_INT >= 9) {
|
||||||
|
apiAdapter = new Api9Adapter();
|
||||||
|
return apiAdapter;
|
||||||
|
} else if (Build.VERSION.SDK_INT >= 8) {
|
||||||
|
apiAdapter = new Api8Adapter();
|
||||||
|
return apiAdapter;
|
||||||
|
} else {
|
||||||
|
apiAdapter = new Api7Adapter();
|
||||||
|
return apiAdapter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return apiAdapter;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,122 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
|
||||||
* use this file except in compliance with the License. You may obtain a copy of
|
|
||||||
* the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
* License for the specific language governing permissions and limitations under
|
|
||||||
* the License.
|
|
||||||
*/
|
|
||||||
package com.google.android.apps.mytracks.util;
|
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.Constants;
|
|
||||||
|
|
||||||
import android.os.Build;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Utility class for determining if newer-API features are available on the
|
|
||||||
* current device.
|
|
||||||
*
|
|
||||||
* @author Rodrigo Damazio
|
|
||||||
*/
|
|
||||||
public class ApiFeatures {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The API level of the Android version we are being run under.
|
|
||||||
*/
|
|
||||||
private static final int ANDROID_API_LEVEL = Integer.parseInt(
|
|
||||||
Build.VERSION.SDK);
|
|
||||||
|
|
||||||
private static ApiFeatures instance;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The API level adapter for the Android version we are being run under.
|
|
||||||
*/
|
|
||||||
private ApiLevelAdapter apiLevelAdapter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the singleton instance of this class.
|
|
||||||
*/
|
|
||||||
public static ApiFeatures getInstance() {
|
|
||||||
if (instance == null) {
|
|
||||||
instance = new ApiFeatures();
|
|
||||||
}
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Injects a specific singleton instance, to be used for unit tests.
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("hiding")
|
|
||||||
public static void injectInstance(ApiFeatures instance) {
|
|
||||||
ApiFeatures.instance = instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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) {
|
|
||||||
apiLevelAdapter = new ApiLevel9Adapter();
|
|
||||||
} else if (getApiLevel() >= 8) {
|
|
||||||
apiLevelAdapter = new ApiLevel8Adapter();
|
|
||||||
} else if (getApiLevel() >= 5) {
|
|
||||||
apiLevelAdapter = new ApiLevel5Adapter();
|
|
||||||
} else {
|
|
||||||
apiLevelAdapter = new ApiLevel3Adapter();
|
|
||||||
}
|
|
||||||
|
|
||||||
Log.i(Constants.TAG, "Using API level adapter " + apiLevelAdapter.getClass());
|
|
||||||
}
|
|
||||||
|
|
||||||
public ApiLevelAdapter getApiAdapter() {
|
|
||||||
return apiLevelAdapter;
|
|
||||||
}
|
|
||||||
|
|
||||||
// API Level 4 Changes
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns whether text-to-speech is available.
|
|
||||||
*/
|
|
||||||
public boolean hasTextToSpeech() {
|
|
||||||
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
|
|
||||||
* on a given instance (to log the statement for debugging), and then
|
|
||||||
* call query on the same instance to make it actually do the query,
|
|
||||||
* it'll regenerate the query for the second call, and will screw it
|
|
||||||
* up. Specifically, it'll add extra parens which don't belong.
|
|
||||||
*/
|
|
||||||
public boolean canReuseSQLiteQueryBuilder() {
|
|
||||||
return getApiLevel() >= 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
// API Level 10 changes
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if BluetoothDevice.createInsecureRfcommSocketToServiceRecord
|
|
||||||
* is available.
|
|
||||||
*/
|
|
||||||
public boolean hasBluetoothDeviceCreateInsecureRfcommSocketToServiceRecord() {
|
|
||||||
return getApiLevel() >= 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Visible for testing.
|
|
||||||
protected int getApiLevel() {
|
|
||||||
return ANDROID_API_LEVEL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,113 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
|
||||||
* use this file except in compliance with the License. You may obtain a copy of
|
|
||||||
* the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
* License for the specific language governing permissions and limitations under
|
|
||||||
* the License.
|
|
||||||
*/
|
|
||||||
package com.google.android.apps.mytracks.util;
|
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.io.backup.BackupPreferencesListener;
|
|
||||||
import com.google.android.apps.mytracks.services.tasks.PeriodicTask;
|
|
||||||
import com.google.api.client.http.HttpTransport;
|
|
||||||
|
|
||||||
import android.app.Notification;
|
|
||||||
import android.app.NotificationManager;
|
|
||||||
import android.app.Service;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A set of methods that may be implemented differently depending on the Android API level.
|
|
||||||
*
|
|
||||||
* @author Bartlomiej Niechwiej
|
|
||||||
*/
|
|
||||||
public interface ApiLevelAdapter {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Puts the specified service into foreground.
|
|
||||||
*
|
|
||||||
* Due to changes in API level 5.
|
|
||||||
*
|
|
||||||
* @param service the service to be put in foreground.
|
|
||||||
* @param notificationManager the notification manager used to post the given
|
|
||||||
* notification.
|
|
||||||
* @param id the ID of the notification, unique within the application.
|
|
||||||
* @param notification the notification to post.
|
|
||||||
*/
|
|
||||||
void startForeground(Service service, NotificationManager notificationManager,
|
|
||||||
int id, Notification notification);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Puts the given service into background.
|
|
||||||
*
|
|
||||||
* Due to changes in API level 5.
|
|
||||||
*
|
|
||||||
* @param service the service to put into background.
|
|
||||||
* @param notificationManager the notification manager to user when removing
|
|
||||||
* notifications.
|
|
||||||
* @param id the ID of the notification to be remove, or -1 if the
|
|
||||||
* notification shouldn't be removed.
|
|
||||||
*/
|
|
||||||
void stopForeground(Service service, NotificationManager notificationManager,
|
|
||||||
int id);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a status announcer task.
|
|
||||||
*
|
|
||||||
* Due to changes in API level 8.
|
|
||||||
*/
|
|
||||||
PeriodicTask getStatusAnnouncerTask(Context context);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a {@link BackupPreferencesListener}.
|
|
||||||
*
|
|
||||||
* Due to changes in API level 8.
|
|
||||||
*/
|
|
||||||
BackupPreferencesListener getBackupPreferencesListener(Context context);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Applies all changes done to the given preferences editor.
|
|
||||||
* Changes may or may not be applied immediately.
|
|
||||||
*
|
|
||||||
* Due to changes in API level 9.
|
|
||||||
*/
|
|
||||||
void applyPreferenceChanges(SharedPreferences.Editor editor);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enables strict mode where supported, only if this is a development build.
|
|
||||||
*
|
|
||||||
* Due to changes in API level 9.
|
|
||||||
*/
|
|
||||||
void enableStrictMode();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copies elements from the input byte array into a new byte array, from
|
|
||||||
* indexes start (inclusive) to end (exclusive). The end index must be less
|
|
||||||
* than or equal to input.length.
|
|
||||||
*
|
|
||||||
* Due to changes in API level 9.
|
|
||||||
*
|
|
||||||
* @param input the input byte array
|
|
||||||
* @param start the start index
|
|
||||||
* @param end the end index
|
|
||||||
* @return a new array containing elements from the input byte array
|
|
||||||
*/
|
|
||||||
byte[] copyByteArray(byte[] input, int start, int end);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a {@link HttpTransport}.
|
|
||||||
*
|
|
||||||
* Due to changes in API level 9.
|
|
||||||
*/
|
|
||||||
HttpTransport getHttpTransport();
|
|
||||||
}
|
|
||||||
@@ -15,186 +15,49 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.android.apps.mytracks.util;
|
package com.google.android.apps.mytracks.util;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.Constants;
|
|
||||||
|
|
||||||
import android.bluetooth.BluetoothAdapter;
|
import android.bluetooth.BluetoothAdapter;
|
||||||
import android.bluetooth.BluetoothClass;
|
import android.bluetooth.BluetoothClass;
|
||||||
import android.bluetooth.BluetoothDevice;
|
import android.bluetooth.BluetoothDevice;
|
||||||
import android.os.Build;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utilities for dealing with bluetooth devices.
|
* Utilities for dealing with bluetooth devices.
|
||||||
* This can be used safely even in systems that don't support bluetooth,
|
|
||||||
* in which case a dummy implementation will be used.
|
|
||||||
*
|
*
|
||||||
* @author Rodrigo Damazio
|
* @author Rodrigo Damazio
|
||||||
*/
|
*/
|
||||||
public abstract class BluetoothDeviceUtils {
|
public class BluetoothDeviceUtils {
|
||||||
public static final String ANY_DEVICE = "any";
|
|
||||||
private static BluetoothDeviceUtils instance;
|
private BluetoothDeviceUtils() {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dummy implementation, for systems that don't support bluetooth.
|
* Populates the device names and the device addresses with all the suitable
|
||||||
*/
|
|
||||||
private static class DummyImpl extends BluetoothDeviceUtils {
|
|
||||||
@Override
|
|
||||||
public void populateDeviceLists(List<String> deviceNames, List<String> deviceAddresses) {
|
|
||||||
// Do nothing - no devices to add
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BluetoothDevice findDeviceMatching(String targetDeviceAddress) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Real implementation, for systems that DO support bluetooth.
|
|
||||||
*/
|
|
||||||
private static class RealImpl extends BluetoothDeviceUtils {
|
|
||||||
private final BluetoothAdapter bluetoothAdapter;
|
|
||||||
|
|
||||||
public RealImpl() {
|
|
||||||
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
|
|
||||||
|
|
||||||
if (bluetoothAdapter == null) {
|
|
||||||
throw new IllegalStateException("Unable to get bluetooth adapter");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void populateDeviceLists(List<String> deviceNames, List<String> deviceAddresses) {
|
|
||||||
ensureNotDiscovering();
|
|
||||||
|
|
||||||
Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices();
|
|
||||||
for (BluetoothDevice device : pairedDevices) {
|
|
||||||
BluetoothClass bluetoothClass = device.getBluetoothClass();
|
|
||||||
if (bluetoothClass != null) {
|
|
||||||
// Not really sure what we want, but I know what we don't want.
|
|
||||||
switch(bluetoothClass.getMajorDeviceClass()) {
|
|
||||||
case BluetoothClass.Device.Major.COMPUTER:
|
|
||||||
case BluetoothClass.Device.Major.PHONE:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
deviceAddresses.add(device.getAddress());
|
|
||||||
deviceNames.add(device.getName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BluetoothDevice findDeviceMatching(String targetDeviceAddress) {
|
|
||||||
if (targetDeviceAddress.equals(ANY_DEVICE)) {
|
|
||||||
return findAnyDevice();
|
|
||||||
} else {
|
|
||||||
return findDeviceByAddress(targetDeviceAddress);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Finds and returns the first suitable bluetooth sensor.
|
|
||||||
*/
|
|
||||||
private BluetoothDevice findAnyDevice() {
|
|
||||||
ensureNotDiscovering();
|
|
||||||
|
|
||||||
Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices();
|
|
||||||
for (BluetoothDevice device : pairedDevices) {
|
|
||||||
// Look for the first paired computer device
|
|
||||||
if (isSuitableDevice(device)) {
|
|
||||||
return device;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Finds and returns a device with the given address, or null if it's not
|
|
||||||
* a suitable sensor.
|
|
||||||
*/
|
|
||||||
private BluetoothDevice findDeviceByAddress(String targetDeviceAddress) {
|
|
||||||
ensureNotDiscovering();
|
|
||||||
|
|
||||||
BluetoothDevice device = bluetoothAdapter.getRemoteDevice(targetDeviceAddress);
|
|
||||||
if (isSuitableDevice(device)) {
|
|
||||||
return device;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ensures the bluetooth adapter is not in discovery mode.
|
|
||||||
*/
|
|
||||||
private void ensureNotDiscovering() {
|
|
||||||
// If it's in discovery mode, cancel that for now.
|
|
||||||
bluetoothAdapter.cancelDiscovery();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks whether the given device is a suitable sensor.
|
|
||||||
*
|
|
||||||
* @param device the device to check
|
|
||||||
* @return true if it's suitable, false otherwise
|
|
||||||
*/
|
|
||||||
private boolean isSuitableDevice(BluetoothDevice device) {
|
|
||||||
// Check that the device is bonded
|
|
||||||
if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the proper (singleton) instance of this class.
|
|
||||||
*/
|
|
||||||
public static BluetoothDeviceUtils getInstance() {
|
|
||||||
if (instance == null) {
|
|
||||||
if (!isBluetoothMethodSupported()) {
|
|
||||||
Log.d(Constants.TAG, "Using dummy bluetooth utils");
|
|
||||||
instance = new DummyImpl();
|
|
||||||
} else {
|
|
||||||
Log.d(Constants.TAG, "Using real bluetooth utils");
|
|
||||||
try {
|
|
||||||
instance = new RealImpl();
|
|
||||||
} catch (IllegalStateException ise) {
|
|
||||||
Log.w(Constants.TAG, "Oops, I mean, using dummy bluetooth utils", ise);
|
|
||||||
instance = new DummyImpl();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Populates the given lists with the names and addresses of all suitable
|
|
||||||
* bluetooth devices.
|
* bluetooth devices.
|
||||||
*
|
*
|
||||||
* @param deviceNames the list to populate with user-visible names
|
* @param bluetoothAdapter the bluetooth adapter
|
||||||
* @param deviceAddresses the list to populate with device addresses
|
* @param deviceNames list of device names
|
||||||
|
* @param deviceAddresses list of device addresses
|
||||||
*/
|
*/
|
||||||
public abstract void populateDeviceLists(List<String> deviceNames, List<String> deviceAddresses);
|
public static void populateDeviceLists(
|
||||||
|
BluetoothAdapter bluetoothAdapter, List<String> deviceNames, List<String> deviceAddresses) {
|
||||||
|
// Ensure the bluetooth adapter is not in discovery mode.
|
||||||
|
bluetoothAdapter.cancelDiscovery();
|
||||||
|
|
||||||
/**
|
Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices();
|
||||||
* Finds the bluetooth device with the given address.
|
for (BluetoothDevice device : pairedDevices) {
|
||||||
*
|
BluetoothClass bluetoothClass = device.getBluetoothClass();
|
||||||
* @param targetDeviceAddress the address of the device, or
|
if (bluetoothClass != null) {
|
||||||
* {@link #ANY_DEVICE} for using the first suitable device
|
// Not really sure what we want, but I know what we don't want.
|
||||||
* @return the device's descriptor, or null if not found
|
switch (bluetoothClass.getMajorDeviceClass()) {
|
||||||
*/
|
case BluetoothClass.Device.Major.COMPUTER:
|
||||||
public abstract BluetoothDevice findDeviceMatching(String targetDeviceAddress);
|
case BluetoothClass.Device.Major.PHONE:
|
||||||
|
break;
|
||||||
/**
|
default:
|
||||||
* @return whether the bluetooth method is supported on this device
|
deviceAddresses.add(device.getAddress());
|
||||||
*/
|
deviceNames.add(device.getName());
|
||||||
public static boolean isBluetoothMethodSupported() {
|
}
|
||||||
return Integer.parseInt(Build.VERSION.SDK) >= 5;
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ public class EulaUtil {
|
|||||||
EULA_PREFERENCE_FILE, Context.MODE_PRIVATE);
|
EULA_PREFERENCE_FILE, Context.MODE_PRIVATE);
|
||||||
Editor editor = preferences.edit();
|
Editor editor = preferences.edit();
|
||||||
editor.putBoolean(EULA_PREFERENCE_KEY, true);
|
editor.putBoolean(EULA_PREFERENCE_KEY, true);
|
||||||
ApiFeatures.getInstance().getApiAdapter().applyPreferenceChanges(editor);
|
ApiAdapterFactory.getApiAdapter().applyPreferenceChanges(editor);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getEulaMessage(Context context) {
|
public static String getEulaMessage(Context context) {
|
||||||
|
|||||||
@@ -0,0 +1,64 @@
|
|||||||
|
// Copyright 2012 Google Inc. All Rights Reserved.
|
||||||
|
|
||||||
|
package com.google.android.apps.mytracks.services;
|
||||||
|
|
||||||
|
import android.app.Notification;
|
||||||
|
import android.app.Service;
|
||||||
|
import android.test.ServiceTestCase;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link TrackRecordingService} that can be used with {@link ServiceTestCase}.
|
||||||
|
* {@link ServiceTestCase} throws a null pointer exception when the service
|
||||||
|
* calls {@link Service#startForeground(int, android.app.Notification)} and
|
||||||
|
* {@link Service#stopForeground(boolean)}.
|
||||||
|
* <p>
|
||||||
|
* See http://code.google.com/p/android/issues/detail?id=12122
|
||||||
|
* <p>
|
||||||
|
* Wrap these two methods in wrappers and override them.
|
||||||
|
*
|
||||||
|
* @author Jimmy Shih
|
||||||
|
*/
|
||||||
|
public class TestRecordingService extends TrackRecordingService {
|
||||||
|
|
||||||
|
private static final String TAG = TestRecordingService.class.getSimpleName();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void startForegroundService(Notification notification) {
|
||||||
|
try {
|
||||||
|
Method setForegroundMethod = Service.class.getMethod("setForeground", boolean.class);
|
||||||
|
setForegroundMethod.invoke(this, true);
|
||||||
|
} catch (SecurityException e) {
|
||||||
|
Log.e(TAG, "Unable to start a service in foreground", e);
|
||||||
|
} catch (NoSuchMethodException e) {
|
||||||
|
Log.e(TAG, "Unable to start a service in foreground", e);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
Log.e(TAG, "Unable to start a service in foreground", e);
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
Log.e(TAG, "Unable to start a service in foreground", e);
|
||||||
|
} catch (InvocationTargetException e) {
|
||||||
|
Log.e(TAG, "Unable to start a service in foreground", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void stopForegroundService() {
|
||||||
|
try {
|
||||||
|
Method setForegroundMethod = Service.class.getMethod("setForeground", boolean.class);
|
||||||
|
setForegroundMethod.invoke(this, false);
|
||||||
|
} catch (SecurityException e) {
|
||||||
|
Log.e(TAG, "Unable to start a service in foreground", e);
|
||||||
|
} catch (NoSuchMethodException e) {
|
||||||
|
Log.e(TAG, "Unable to start a service in foreground", e);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
Log.e(TAG, "Unable to start a service in foreground", e);
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
Log.e(TAG, "Unable to start a service in foreground", e);
|
||||||
|
} catch (InvocationTargetException e) {
|
||||||
|
Log.e(TAG, "Unable to start a service in foreground", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-19
@@ -24,7 +24,6 @@ import com.google.android.apps.mytracks.content.Track;
|
|||||||
import com.google.android.apps.mytracks.content.Waypoint;
|
import com.google.android.apps.mytracks.content.Waypoint;
|
||||||
import com.google.android.apps.mytracks.content.WaypointCreationRequest;
|
import com.google.android.apps.mytracks.content.WaypointCreationRequest;
|
||||||
import com.google.android.apps.mytracks.stats.TripStatistics;
|
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||||
import com.google.android.apps.mytracks.util.ApiFeatures;
|
|
||||||
import com.google.android.maps.mytracks.R;
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
@@ -57,8 +56,7 @@ import java.util.List;
|
|||||||
* is called, which prevents from testing multiple scenarios in a single
|
* is called, which prevents from testing multiple scenarios in a single
|
||||||
* test (see runFunctionTest for more details).
|
* test (see runFunctionTest for more details).
|
||||||
*/
|
*/
|
||||||
public class TrackRecordingServiceTest
|
public class TrackRecordingServiceTest extends ServiceTestCase<TestRecordingService> {
|
||||||
extends ServiceTestCase<TrackRecordingService> {
|
|
||||||
|
|
||||||
private Context context;
|
private Context context;
|
||||||
private MyTracksProviderUtils providerUtils;
|
private MyTracksProviderUtils providerUtils;
|
||||||
@@ -74,7 +72,7 @@ public class TrackRecordingServiceTest
|
|||||||
private Intent serviceIntent;
|
private Intent serviceIntent;
|
||||||
|
|
||||||
public TrackRecordingServiceTest() {
|
public TrackRecordingServiceTest() {
|
||||||
super(TrackRecordingService.class);
|
super(TestRecordingService.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -96,19 +94,6 @@ public class TrackRecordingServiceTest
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* A mock class that forces API level < 5 to make sure we can workaround a bug
|
|
||||||
* in ServiceTestCase (throwing a NPE).
|
|
||||||
* See http://code.google.com/p/android/issues/detail?id=12122 for more
|
|
||||||
* details.
|
|
||||||
*/
|
|
||||||
private static class MockApiFeatures extends ApiFeatures {
|
|
||||||
@Override
|
|
||||||
protected int getApiLevel() {
|
|
||||||
return 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected IBinder bindService(Intent intent) {
|
protected IBinder bindService(Intent intent) {
|
||||||
if (getService() != null) {
|
if (getService() != null) {
|
||||||
@@ -138,8 +123,6 @@ public class TrackRecordingServiceTest
|
|||||||
protected void setUp() throws Exception {
|
protected void setUp() throws Exception {
|
||||||
super.setUp();
|
super.setUp();
|
||||||
|
|
||||||
ApiFeatures.injectInstance(new MockApiFeatures());
|
|
||||||
|
|
||||||
MockContentResolver mockContentResolver = new MockContentResolver();
|
MockContentResolver mockContentResolver = new MockContentResolver();
|
||||||
RenamingDelegatingContext targetContext = new RenamingDelegatingContext(
|
RenamingDelegatingContext targetContext = new RenamingDelegatingContext(
|
||||||
getContext(), getContext(), "test.");
|
getContext(), getContext(), "test.");
|
||||||
|
|||||||
+1
-61
@@ -15,13 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.android.apps.mytracks.services.tasks;
|
package com.google.android.apps.mytracks.services.tasks;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.services.tasks.PeriodicTask;
|
|
||||||
import com.google.android.apps.mytracks.services.tasks.StatusAnnouncerFactory;
|
|
||||||
import com.google.android.apps.mytracks.services.tasks.StatusAnnouncerTask;
|
|
||||||
import com.google.android.apps.mytracks.util.ApiFeatures;
|
|
||||||
|
|
||||||
import android.media.AudioManager;
|
|
||||||
import android.speech.tts.TextToSpeech;
|
|
||||||
import android.test.AndroidTestCase;
|
import android.test.AndroidTestCase;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -31,62 +24,9 @@ import android.test.AndroidTestCase;
|
|||||||
* @author Rodrigo Damazio
|
* @author Rodrigo Damazio
|
||||||
*/
|
*/
|
||||||
public class StatusAnnouncerFactoryTest extends AndroidTestCase {
|
public class StatusAnnouncerFactoryTest extends AndroidTestCase {
|
||||||
/**
|
|
||||||
* Mock version of the {@link ApiFeatures} class.
|
|
||||||
*/
|
|
||||||
private class MockApiFeatures extends ApiFeatures {
|
|
||||||
private boolean hasTts;
|
|
||||||
|
|
||||||
public void setHasTextToSpeech(boolean hasTts) {
|
|
||||||
this.hasTts = hasTts;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasTextToSpeech() {
|
|
||||||
return hasTts;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private MockApiFeatures apiFeatures;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void setUp() throws Exception {
|
|
||||||
super.setUp();
|
|
||||||
|
|
||||||
apiFeatures = new MockApiFeatures();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testCreate() {
|
public void testCreate() {
|
||||||
apiFeatures.setHasTextToSpeech(true);
|
PeriodicTaskFactory factory = new StatusAnnouncerFactory();
|
||||||
PeriodicTaskFactory factory =
|
|
||||||
new StatusAnnouncerFactory(apiFeatures);
|
|
||||||
PeriodicTask task = factory.create(getContext());
|
PeriodicTask task = factory.create(getContext());
|
||||||
assertTrue(task instanceof StatusAnnouncerTask);
|
assertTrue(task instanceof StatusAnnouncerTask);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testCreate_notAvailable() {
|
|
||||||
apiFeatures.setHasTextToSpeech(false);
|
|
||||||
PeriodicTaskFactory factory =
|
|
||||||
new StatusAnnouncerFactory(apiFeatures);
|
|
||||||
PeriodicTask task = factory.create(getContext());
|
|
||||||
assertNull(task);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testGetVolumeStream() {
|
|
||||||
apiFeatures.setHasTextToSpeech(true);
|
|
||||||
StatusAnnouncerFactory factory =
|
|
||||||
new StatusAnnouncerFactory(apiFeatures);
|
|
||||||
assertEquals(
|
|
||||||
TextToSpeech.Engine.DEFAULT_STREAM,
|
|
||||||
factory.getVolumeStream());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testGetVolumeStream_notAvailable() {
|
|
||||||
apiFeatures.setHasTextToSpeech(false);
|
|
||||||
StatusAnnouncerFactory factory =
|
|
||||||
new StatusAnnouncerFactory(apiFeatures);
|
|
||||||
assertEquals(
|
|
||||||
AudioManager.USE_DEFAULT_STREAM_TYPE,
|
|
||||||
factory.getVolumeStream());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-18
@@ -15,27 +15,15 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.android.apps.mytracks.util;
|
package com.google.android.apps.mytracks.util;
|
||||||
|
|
||||||
import android.app.Notification;
|
import junit.framework.TestCase;
|
||||||
import android.app.NotificationManager;
|
|
||||||
import android.app.Service;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* API level 5 specific implementation of the {@link ApiLevelAdapter}.
|
* Tests {@link ApiAdapterFactory}.
|
||||||
*
|
*
|
||||||
* @author Bartlomiej Niechwiej
|
* @author Rodrigo Damazio
|
||||||
*/
|
*/
|
||||||
public class ApiLevel5Adapter extends ApiLevel3Adapter {
|
public class ApiAdapterFactoryTest extends TestCase {
|
||||||
|
public void testGetApiLevelAdapter() {
|
||||||
@Override
|
assertNotNull(ApiAdapterFactory.getApiAdapter());
|
||||||
public void startForeground(Service service,
|
|
||||||
NotificationManager notificationManager, int id,
|
|
||||||
Notification notification) {
|
|
||||||
service.startForeground(id, notification);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void stopForeground(Service service,
|
|
||||||
NotificationManager notificationManager, int id) {
|
|
||||||
service.stopForeground(id != -1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
|
||||||
* use this file except in compliance with the License. You may obtain a copy of
|
|
||||||
* the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
* License for the specific language governing permissions and limitations under
|
|
||||||
* the License.
|
|
||||||
*/
|
|
||||||
package com.google.android.apps.mytracks.util;
|
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests the API feature detection code in {@link ApiFeatures}.
|
|
||||||
* This test requires Froyo+ to run.
|
|
||||||
*
|
|
||||||
* @author Rodrigo Damazio
|
|
||||||
*/
|
|
||||||
public class ApiFeaturesTest extends TestCase {
|
|
||||||
|
|
||||||
private TestableApiFeatures features;
|
|
||||||
|
|
||||||
private class TestableApiFeatures extends ApiFeatures {
|
|
||||||
private int apiLevel;
|
|
||||||
|
|
||||||
public void setApiLevel(int apiLevel) {
|
|
||||||
this.apiLevel = apiLevel;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected int getApiLevel() {
|
|
||||||
return apiLevel;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void setUp() throws Exception {
|
|
||||||
super.setUp();
|
|
||||||
|
|
||||||
features = new TestableApiFeatures();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testHasTextToSpeech() {
|
|
||||||
features.setApiLevel(3);
|
|
||||||
assertFalse(features.hasTextToSpeech());
|
|
||||||
for (int i = 4; i <= 8; i++) {
|
|
||||||
features.setApiLevel(i);
|
|
||||||
assertTrue(features.hasTextToSpeech());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testGetApiAdapter() {
|
|
||||||
assertNotNull(features.getApiAdapter());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user