Cutting service binding and preferences dependencies to the MyTracks singleton.

This commit is contained in:
Rodrigo Damazio
2011-05-31 02:35:05 -03:00
parent 9f3099ef2b
commit 73e4af98cc
6 changed files with 326 additions and 182 deletions
@@ -23,26 +23,23 @@ import com.google.android.apps.mytracks.content.TracksColumns;
import com.google.android.apps.mytracks.content.WaypointCreationRequest;
import com.google.android.apps.mytracks.io.file.TempFileCleaner;
import com.google.android.apps.mytracks.services.ITrackRecordingService;
import com.google.android.apps.mytracks.services.TrackRecordingService;
import com.google.android.apps.mytracks.services.TrackRecordingServiceBinder;
import com.google.android.apps.mytracks.services.tasks.StatusAnnouncerFactory;
import com.google.android.apps.mytracks.util.ApiFeatures;
import com.google.android.apps.mytracks.util.UriUtils;
import com.google.android.apps.mytracks.util.SystemUtils;
import com.google.android.apps.mytracks.util.UriUtils;
import com.google.android.maps.mytracks.R;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.TabActivity;
import android.content.ComponentName;
import android.content.ContentUris;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.net.Uri;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.Menu;
@@ -60,6 +57,7 @@ import android.widget.Toast;
* The super activity that embeds our sub activities.
*
* @author Leif Hendrik Wilden
* @author Rodrigo Damazio
*/
public class MyTracks extends TabActivity implements OnTouchListener {
private TrackDataHub dataHub;
@@ -80,48 +78,12 @@ public class MyTracks extends TabActivity implements OnTouchListener {
*/
private boolean startNewTrackRequested = false;
private ITrackRecordingService trackRecordingService;
/**
* Utilities to deal with the database.
*/
private MyTracksProviderUtils providerUtils;
private SharedPreferences sharedPreferences;
/**
* The connection to the track recording service.
*/
private final ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className, IBinder service) {
Log.d(Constants.TAG, "MyTracks: Service now connected.");
// Delay setting the service until we are done with initialization.
ITrackRecordingService trackRecordingService =
ITrackRecordingService.Stub.asInterface(service);
try {
// TODO: Send a start service intent and broadcast service started
// message to avoid the hack below and a race condition.
if (startNewTrackRequested) {
startNewTrackRequested = false;
startRecordingNewTrack(trackRecordingService);
}
} finally {
MyTracks.this.trackRecordingService = trackRecordingService;
}
}
@Override
public void onServiceDisconnected(ComponentName className) {
Log.d(TAG, "MyTracks: Service now disconnected.");
trackRecordingService = null;
}
};
/**
* Whether {@link #serviceConnection} is bound or not.
*/
private boolean isBound = false;
private TrackRecordingServiceBinder serviceBinder;
/*
* Tabs/View navigation:
@@ -135,6 +97,18 @@ public class MyTracks extends TabActivity implements OnTouchListener {
}
};
private final Runnable serviceBindCallback = new Runnable() {
@Override
public void run() {
synchronized (serviceBinder) {
ITrackRecordingService service = serviceBinder.getServiceIfBound();
if (startNewTrackRequested && service != null) {
startRecordingNewTrack(service);
}
}
}
};
/**
* Checks whether we have a track recording session in progress.
* In some cases, when the service has crashed or has been restarted
@@ -145,6 +119,7 @@ public class MyTracks extends TabActivity implements OnTouchListener {
* based on settings from the shared preferences.
*/
public boolean isRecording() {
ITrackRecordingService trackRecordingService = serviceBinder.getServiceIfBound();
if (trackRecordingService == null) {
// Fall back to alternative check method.
return dataHub.isRecording();
@@ -177,10 +152,10 @@ public class MyTracks extends TabActivity implements OnTouchListener {
}
providerUtils = MyTracksProviderUtils.Factory.get(this);
sharedPreferences = getSharedPreferences(Constants.SETTINGS_NAME, 0);
dataHub = new TrackDataHub(this, sharedPreferences, providerUtils);
dataHub = new TrackDataHub(this, providerUtils);
menuManager = new MenuManager(this);
dialogManager = new DialogManager(this);
serviceBinder = TrackRecordingServiceBinder.getInstance(this);
// The volume we want to control is the Text-To-Speech volume
int volumeStream =
@@ -230,7 +205,6 @@ public class MyTracks extends TabActivity implements OnTouchListener {
dataHub.destroy();
tryUnbindTrackRecordingService();
super.onDestroy();
}
@@ -250,7 +224,7 @@ public class MyTracks extends TabActivity implements OnTouchListener {
// Called when activity is going into the background, but has not (yet) been
// killed. Shouldn't block longer than approx. 2 seconds.
Log.d(TAG, "MyTracks.onPause");
tryUnbindTrackRecordingService();
serviceBinder.unbindService();
super.onPause();
}
@@ -259,7 +233,7 @@ public class MyTracks extends TabActivity implements OnTouchListener {
// Called when the current activity is being displayed or re-displayed
// to the user.
Log.d(TAG, "MyTracks.onResume");
tryBindTrackRecordingService();
serviceBinder.bindService(serviceBindCallback);
super.onResume();
}
@@ -271,8 +245,7 @@ public class MyTracks extends TabActivity implements OnTouchListener {
// Ensure that service is running if we're supposed to be recording
if (dataHub.isRecording()) {
Intent startIntent = new Intent(this, TrackRecordingService.class);
startService(startIntent);
serviceBinder.startService();
}
Intent intent = getIntent();
@@ -445,6 +418,7 @@ public class MyTracks extends TabActivity implements OnTouchListener {
* @throws RemoteException If the call on the service failed.
*/
public long insertWaypoint(WaypointCreationRequest request) throws RemoteException {
ITrackRecordingService trackRecordingService = serviceBinder.getServiceIfBound();
if (trackRecordingService == null) {
throw new IllegalStateException("The recording service is not bound.");
}
@@ -485,14 +459,16 @@ public class MyTracks extends TabActivity implements OnTouchListener {
* Starts the track recording service (if not already running) and binds to
* it. Starts recording a new track.
*/
public void startRecording() {
if (trackRecordingService == null) {
void startRecording() {
synchronized (serviceBinder) {
startNewTrackRequested = true;
Intent startIntent = new Intent(this, TrackRecordingService.class);
startService(startIntent);
tryBindTrackRecordingService();
} else {
startRecordingNewTrack(trackRecordingService);
serviceBinder.startService();
// Binding was already requested before, it either already happened
// (in which case running the callback manually triggers the actual recording start)
// or it will happen in the future
// (in which case running the callback now will have no effect).
serviceBindCallback.run();
}
}
@@ -501,8 +477,10 @@ public class MyTracks extends TabActivity implements OnTouchListener {
* "Stopped recording" and pop up the Track Details activity.
*/
public void stopRecording() {
ITrackRecordingService trackRecordingService = serviceBinder.getServiceIfBound();
if (trackRecordingService != null) {
// Save the track id as the shared preference will overwrite the recording track id.
SharedPreferences sharedPreferences = getSharedPreferences(Constants.SETTINGS_NAME, 0);
long currentTrackId = sharedPreferences.getLong(getString(R.string.recording_track_key), -1);
try {
trackRecordingService.endCurrentTrack();
@@ -519,14 +497,10 @@ public class MyTracks extends TabActivity implements OnTouchListener {
startActivity(intent);
}
}
tryUnbindTrackRecordingService();
try {
stopService(new Intent(MyTracks.this, TrackRecordingService.class));
} catch (SecurityException e) {
Log.e(TAG, "Encountered a security exception when trying to stop service.", e);
}
trackRecordingService = null;
serviceBinder.stopService();
}
void clearSelectedTrack() {
dataHub.unloadCurrentTrack();
}
@@ -535,54 +509,10 @@ public class MyTracks extends TabActivity implements OnTouchListener {
return dataHub.getSelectedTrackId();
}
/**
* Binds to track recording service if it is running.
*/
private void tryBindTrackRecordingService() {
Log.d(TAG,
"MyTracks: Trying to bind to track recording service...");
bindService(new Intent(this, TrackRecordingService.class),
serviceConnection, 0);
Log.d(TAG, "MyTracks: ...bind finished!");
isBound = true;
}
/**
* Tries to unbind the track recording service. Catches exception silently in
* case service is not registered anymore.
*/
private void tryUnbindTrackRecordingService() {
if (isBound) {
Log.d(TAG, "MyTracks: Trying to unbind from track recording service...");
try {
unbindService(serviceConnection);
Log.d(TAG, "MyTracks: ...unbind finished!");
} catch (IllegalArgumentException e) {
Log.d(TAG, "MyTracks: Tried unbinding, but service was not registered.", e);
}
isBound = false;
}
}
public DialogManager getDialogManager() {
return dialogManager;
}
// @VisibleForTesting
long getRecordingTrackId() {
return sharedPreferences.getLong(getString(R.string.recording_track_key), -1);
}
// @VisibleForTesting
SharedPreferences getSharedPreferences() {
return sharedPreferences;
}
// @VisibleForTesting
ITrackRecordingService getTrackRecordingService() {
return trackRecordingService;
}
public TrackDataHub getDataHub() {
return dataHub;
}
@@ -593,8 +523,4 @@ public class MyTracks extends TabActivity implements OnTouchListener {
public static MyTracks getInstance() {
return instance;
}
public static void clearInstance() {
instance = null;
}
}
@@ -18,6 +18,7 @@ package com.google.android.apps.mytracks;
import static com.google.android.apps.mytracks.Constants.TAG;
import com.google.android.apps.mytracks.content.Sensor;
import com.google.android.apps.mytracks.services.ITrackRecordingService;
import com.google.android.apps.mytracks.services.TrackRecordingServiceBinder;
import com.google.android.apps.mytracks.services.sensors.SensorUtils;
import com.google.android.maps.mytracks.R;
import com.google.protobuf.InvalidProtocolBufferException;
@@ -45,6 +46,7 @@ public class SensorStateActivity extends Activity {
private static final long REFRESH_PERIOD_MS = 250;
private final StatsUtilities utils;
private TrackRecordingServiceBinder serviceBinder;
/**
* This timer periodically invokes the refresh timer task.
@@ -79,6 +81,8 @@ public class SensorStateActivity extends Activity {
setContentView(R.layout.sensor_state);
serviceBinder = TrackRecordingServiceBinder.getInstance(this);
serviceBinder.bindService(stateUpdater);
updateState();
}
@@ -97,11 +101,13 @@ public class SensorStateActivity extends Activity {
timer = null;
}
protected void updateState() {
MyTracks mt = MyTracks.getInstance();
@Override
protected void onDestroy() {
serviceBinder.unbindService();
}
ITrackRecordingService service =
mt == null ? null : mt.getTrackRecordingService();
protected void updateState() {
ITrackRecordingService service = serviceBinder.getServiceIfBound();
if (service == null) {
Log.d(Constants.TAG, "Could not get track recording service.");
updateSensorState(Sensor.SensorState.NONE);
@@ -22,6 +22,7 @@ import static com.google.android.apps.mytracks.Constants.MAX_LOCATION_AGE_MS;
import static com.google.android.apps.mytracks.Constants.MAX_NETWORK_AGE_MS;
import static com.google.android.apps.mytracks.Constants.TAG;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.content.DataSourceManager.DataSourceListener;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils.DoubleBufferedLocationFactory;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils.LocationIterator;
@@ -195,10 +196,17 @@ public class TrackDataHub {
/**
* Default constructor.
*/
public TrackDataHub(Context ctx, SharedPreferences preferences,
public TrackDataHub(Context ctx, MyTracksProviderUtils providerUtils) {
this(ctx, ctx.getSharedPreferences(Constants.SETTINGS_NAME, 0), providerUtils);
}
/**
* Intermediate constructor, used only for passing preferences into arguments.
*/
private TrackDataHub(Context ctx, SharedPreferences preferences,
MyTracksProviderUtils providerUtils) {
this(ctx, new DataSourcesWrapperImpl(ctx, preferences), new TrackDataListeners(),
preferences, providerUtils, TARGET_DISPLAYED_TRACK_POINTS);
preferences, providerUtils, TARGET_DISPLAYED_TRACK_POINTS);
}
/**
@@ -785,7 +785,7 @@ public class TrackRecordingService extends Service implements LocationListener {
if (intent != null &&
intent.getBooleanExtra(RESUME_TRACK_EXTRA_NAME, false)) {
Log.d(TAG, "TrackRecordingService: requested resume");
// Make sure that the current track exists and is fresh enough.
if (recordingTrack == null || !shouldResumeTrack(recordingTrack)) {
Log.i(TAG,
@@ -796,7 +796,7 @@ public class TrackRecordingService extends Service implements LocationListener {
stopSelfResult(startId);
return;
}
Log.i(TAG, "TrackRecordingService: resuming");
}
}
@@ -0,0 +1,203 @@
/*
* Copyright 2011 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.services;
import static com.google.android.apps.mytracks.Constants.TAG;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.util.SystemUtils;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.util.Log;
import java.util.WeakHashMap;
/**
* A helper for managing the binding to the track recording service.
* This uses reference counting so multiple callers can share a binding.
*
* @author Rodrigo Damazio
*/
public class TrackRecordingServiceBinder {
/** Singleton instance. */
private static TrackRecordingServiceBinder instance;
private final ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className, IBinder service) {
Log.d(Constants.TAG, "Service now connected.");
// Delay setting the service until we are done with initialization.
ITrackRecordingService trackRecordingService =
ITrackRecordingService.Stub.asInterface(service);
synchronized (TrackRecordingServiceBinder.this) {
try {
for (Runnable callback : pendingBindCallbacks.keySet()) {
if (callback != null) {
callback.run();
}
}
} finally {
pendingBindCallbacks.clear();
TrackRecordingServiceBinder.this.trackRecordingService = trackRecordingService;
}
}
}
@Override
public void onServiceDisconnected(ComponentName className) {
Log.d(TAG, "Service now disconnected.");
synchronized (TrackRecordingServiceBinder.this) {
trackRecordingService = null;
}
}
};
/** Pointer to the service, if bound. */
private ITrackRecordingService trackRecordingService;
/** Count of bindings to the service. */
private int bindCount = 0;
/** Set of callbacks to execute when the service connects. */
private final WeakHashMap<Runnable, Object> pendingBindCallbacks =
new WeakHashMap<Runnable, Object>();
/** Application context. */
private final Context applicationContext;
/**
* Starts the service with the default intent.
*
* This should only be called when the service will be put in recording mode,
* as the service being started means it'll be listening to the GPS.
* Notice that it is perfectly fine to call {@link #bindService} without calling
* this at all.
*/
public void startService() {
Intent intent = new Intent(applicationContext, TrackRecordingService.class);
applicationContext.startService(intent);
}
/**
* Binds to the service, and calls the given callback afterwards.
* Calls to this method should be balanced with calls to {@link #unbindService}.
*
* @param onBindCallback the callback for when the service is connected
*/
public void bindService(Runnable onBindCallback) {
synchronized (this) {
bindCount++;
if (trackRecordingService != null) {
if (onBindCallback != null) {
onBindCallback.run();
}
return;
}
if (onBindCallback != null) {
pendingBindCallbacks.put(onBindCallback, null);
}
if (bindCount == 1) {
Intent intent = new Intent(applicationContext, TrackRecordingService.class);
int flags = SystemUtils.isRelease(applicationContext) ? 0 : Context.BIND_DEBUG_UNBIND;
applicationContext.bindService(intent, serviceConnection, flags);
}
}
}
/**
* Unbinds from the service.
*
* This will unbind from the service, unless another caller is still bound to it.
* Calls to this method should be balanced with calls to {@link #bindService}.
*/
public void unbindService() {
synchronized (this) {
bindCount--;
if (bindCount > 0) {
// Someone else may still be using it.
return;
} else if (bindCount < 0) {
Log.e(TAG, "Unbalanced binding calls.");
return;
}
try {
applicationContext.unbindService(serviceConnection);
} catch (IllegalArgumentException e) {
Log.d(TAG, "Tried unbinding, but service was not registered.", e);
}
}
}
/**
* Stops the service, and consequently its GPS listening.
*/
public void stopService() {
try {
applicationContext.stopService(new Intent(applicationContext, TrackRecordingService.class));
} catch (SecurityException e) {
Log.e(TAG, "Encountered a security exception when trying to stop service.", e);
}
}
@Override
protected void finalize() throws Throwable {
if (bindCount > 0) {
Log.e(TAG, "Leaked bindings: " + bindCount + " bindings left on finalize.");
}
super.finalize();
}
/**
* Returns the connected service instance, or null if not connected.
*/
public ITrackRecordingService getServiceIfBound() {
return trackRecordingService;
}
/**
* Returns the singleton instance of this class.
* Notice that although a context is required, it is safe to call this from
* multiple different contexts to obtain the same instance.
*
* @param context the current context
* @return the singleton instance
*/
public synchronized static TrackRecordingServiceBinder getInstance(Context context) {
if (instance == null) {
Context applicationContext = context.getApplicationContext();
instance = new TrackRecordingServiceBinder(applicationContext);
}
return instance;
}
/**
* Internal constructor.
*
* @param applicationContext the current application (not activity) context
*/
private TrackRecordingServiceBinder(Context applicationContext) {
this.applicationContext = applicationContext;
}
}
@@ -36,56 +36,48 @@ import java.util.concurrent.atomic.AtomicBoolean;
* @author Bartlomiej Niechwiej
*/
public class MyTracksTest extends ActivityInstrumentationTestCase2<MyTracks>{
private SharedPreferences sharedPreferences;
public MyTracksTest() {
super(MyTracks.class);
}
@Override
protected void setUp() throws Exception {
super.setUp();
MyTracks.clearInstance();
assertNull(MyTracks.getInstance());
}
@Override
protected void tearDown() throws Exception {
clearSelectedAndRecordingTracks();
waitForIdle();
super.tearDown();
}
public void testInitialization_mainAction() {
// Make sure we can start MyTracks and the activity doesn't start recording.
assertNotNull(getActivity());
assertNotNull(MyTracks.getInstance());
assertNotNull(getActivity().getSharedPreferences());
assertInitialized();
// Check if not recording.
assertFalse(getActivity().isRecording());
assertEquals(-1, getActivity().getRecordingTrackId());
long selectedTrackId = getActivity().getSharedPreferences().getLong(
assertEquals(-1, getRecordingTrackId());
long selectedTrackId = getSharedPreferences().getLong(
getActivity().getString(R.string.selected_track_key), -1);
assertEquals(selectedTrackId, getActivity().getSelectedTrackId());
}
public void testInitialization_viewActionWithNoData() {
// Simulate start with ACTION_VIEW intent.
Intent startIntent = new Intent();
startIntent.setAction(Intent.ACTION_VIEW);
setActivityIntent(startIntent);
assertNotNull(getActivity());
assertNotNull(MyTracks.getInstance());
assertNotNull(getActivity().getSharedPreferences());
assertInitialized();
// Check if not recording.
assertFalse(getActivity().isRecording());
assertEquals(-1, getActivity().getRecordingTrackId());
long selectedTrackId = getActivity().getSharedPreferences().getLong(
assertEquals(-1, getRecordingTrackId());
long selectedTrackId = getSharedPreferences().getLong(
getActivity().getString(R.string.selected_track_key), -1);
assertEquals(selectedTrackId, getActivity().getSelectedTrackId());
}
public void testInitialization_viewActionWithValidData() throws Exception {
// Simulate start with ACTION_VIEW intent.
Intent startIntent = new Intent();
@@ -93,24 +85,22 @@ public class MyTracksTest extends ActivityInstrumentationTestCase2<MyTracks>{
Uri uri = Uri.fromFile(File.createTempFile("valid", ".gpx"));
// TODO: Add a valid GPX.
startIntent.setData(uri);
setActivityIntent(startIntent);
assertNotNull(getActivity());
assertNotNull(MyTracks.getInstance());
assertNotNull(getActivity().getSharedPreferences());
assertInitialized();
// Check if not recording.
assertFalse(getActivity().isRecording());
assertEquals(-1, getActivity().getRecordingTrackId());
long selectedTrackId = getActivity().getSharedPreferences().getLong(
assertEquals(-1, getRecordingTrackId());
long selectedTrackId = getSharedPreferences().getLong(
getActivity().getString(R.string.selected_track_key), -1);
assertEquals(selectedTrackId, getActivity().getSelectedTrackId());
// TODO: Finish this test.
// TODO: Finish this test.
}
public void testInitialization_viewActionWithInvalidData() throws Exception {
// Simulate start with ACTION_VIEW intent.
Intent startIntent = new Intent();
@@ -118,34 +108,29 @@ public class MyTracksTest extends ActivityInstrumentationTestCase2<MyTracks>{
Uri uri = Uri.fromFile(File.createTempFile("invalid", ".gpx"));
startIntent.setData(uri);
setActivityIntent(startIntent);
assertNotNull(getActivity());
assertNotNull(MyTracks.getInstance());
assertNotNull(getActivity().getSharedPreferences());
assertInitialized();
// Check if not recording.
assertFalse(getActivity().isRecording());
assertEquals(-1, getActivity().getRecordingTrackId());
long selectedTrackId = getActivity().getSharedPreferences().getLong(
assertEquals(-1, getRecordingTrackId());
long selectedTrackId = getSharedPreferences().getLong(
getActivity().getString(R.string.selected_track_key), -1);
assertEquals(selectedTrackId, getActivity().getSelectedTrackId());
// TODO: Finish this test.
}
public void testRecording_startAndStop() throws Exception {
// Make sure we can start MyTracks and the activity doesn't start recording.
assertNotNull(getActivity());
assertNotNull(MyTracks.getInstance());
assertNotNull(getActivity().getSharedPreferences());
assertInitialized();
// Check if not recording.
clearSelectedAndRecordingTracks();
waitForIdle();
assertFalse(getActivity().isRecording());
assertEquals(-1, getActivity().getRecordingTrackId());
long selectedTrackId = getActivity().getSharedPreferences().getLong(
assertEquals(-1, getRecordingTrackId());
long selectedTrackId = getSharedPreferences().getLong(
getActivity().getString(R.string.selected_track_key), -1);
assertEquals(selectedTrackId, getActivity().getSelectedTrackId());
@@ -153,16 +138,16 @@ public class MyTracksTest extends ActivityInstrumentationTestCase2<MyTracks>{
getActivity().startRecording();
long recordingTrackId = awaitRecordingStatus(5000, true);
assertTrue(recordingTrackId >= 0);
// Wait until we are done and make sure that selectedTrack = recordingTrack.
waitForIdle();
assertEquals(recordingTrackId, getActivity().getSharedPreferences().getLong(
assertEquals(recordingTrackId, getSharedPreferences().getLong(
getActivity().getString(R.string.recording_track_key), -1));
selectedTrackId = getActivity().getSharedPreferences().getLong(
selectedTrackId = getSharedPreferences().getLong(
getActivity().getString(R.string.selected_track_key), -1);
assertEquals(recordingTrackId, selectedTrackId);
assertEquals(selectedTrackId, getActivity().getSelectedTrackId());
// Watch for MyTracksDetails activity.
ActivityMonitor monitor = getInstrumentation().addMonitor(
TrackDetails.class.getName(), null, false);
@@ -170,14 +155,14 @@ public class MyTracksTest extends ActivityInstrumentationTestCase2<MyTracks>{
// Now, stop the track and make sure that it is still selected, but
// no longer recording.
getActivity().stopRecording();
// Check if we got back MyTracksDetails activity.
Activity activity = getInstrumentation().waitForMonitor(monitor);
assertTrue(activity instanceof TrackDetails);
// TODO: Update track name and other properties and test if they were
// properly saved.
// Simulate a click on Save button.
Button save = (Button) activity.findViewById(R.id.trackdetails_save);
save.performClick();
@@ -185,13 +170,18 @@ public class MyTracksTest extends ActivityInstrumentationTestCase2<MyTracks>{
// Check the remaining properties.
recordingTrackId = awaitRecordingStatus(5000, false);
assertEquals(-1, recordingTrackId);
assertEquals(recordingTrackId, getActivity().getRecordingTrackId());
assertEquals(recordingTrackId, getActivity().getSharedPreferences().getLong(
assertEquals(recordingTrackId, getRecordingTrackId());
assertEquals(recordingTrackId, getSharedPreferences().getLong(
getActivity().getString(R.string.recording_track_key), -1));
// Make sure this is the same track as the last recording track ID.
assertEquals(selectedTrackId, getActivity().getSelectedTrackId());
}
private void assertInitialized() {
assertNotNull(getActivity());
assertNotNull(MyTracks.getInstance());
}
/**
* Waits until the UI thread becomes idle.
*/
@@ -216,13 +206,13 @@ public class MyTracksTest extends ActivityInstrumentationTestCase2<MyTracks>{
}
/**
* Clears {selected,recording}TrackId in the {@link SharedPreferences}.
* Clears {selected,recording}TrackId in the {@link getSharedPreferences()}.
*/
private void clearSelectedAndRecordingTracks() {
Editor editor = getActivity().getSharedPreferences().edit();
Editor editor = getSharedPreferences().edit();
editor.putLong(getActivity().getString(R.string.selected_track_key), -1);
editor.putLong(getActivity().getString(R.string.recording_track_key), -1);
editor.clear();
editor.commit();
}
@@ -245,6 +235,17 @@ public class MyTracksTest extends ActivityInstrumentationTestCase2<MyTracks>{
}
waitForIdle();
assertEquals(isRecording, getActivity().isRecording());
return getActivity().getRecordingTrackId();
return getRecordingTrackId();
}
private long getRecordingTrackId() {
return getSharedPreferences().getLong(getActivity().getString(R.string.recording_track_key), -1);
}
private SharedPreferences getSharedPreferences() {
if (sharedPreferences == null) {
sharedPreferences = getActivity().getSharedPreferences(Constants.SETTINGS_NAME, 0);
}
return sharedPreferences;
}
}