Merge heads

This commit is contained in:
youtaol
2012-09-03 14:17:09 +08:00
16 changed files with 509 additions and 376 deletions
+54
View File
@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<merge xmlns:android="http://schemas.android.com/apk/res/android" >
<ImageButton
android:background="@android:color/transparent"
android:contentDescription="@string/menu_record_track"
android:id="@+id/track_controller_record"
android:layout_height="100dp"
android:layout_width="wrap_content"
android:scaleType="centerInside" />
<RelativeLayout
android:layout_height="100dp"
android:layout_marginLeft="-32dp"
android:layout_width="wrap_content" >
<TextView
android:id="@+id/track_controller_total_time"
android:layout_centerInParent="true"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:paddingLeft="24dp"
android:paddingRight="8dp"
android:textColor="@android:color/white"
style="@style/TextSmall" />
<TextView
android:id="@+id/track_controller_status"
android:layout_above="@id/track_controller_total_time"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:paddingBottom="12dp"
style="@style/TextSmall" />
</RelativeLayout>
<ImageButton
android:background="@android:color/transparent"
android:contentDescription="@string/menu_stop_recording"
android:id="@+id/track_controller_stop"
android:layout_height="100dp"
android:layout_width="wrap_content"
android:scaleType="centerInside"
android:src="@drawable/btn_stop_1" />
</merge>
+34 -23
View File
@@ -14,29 +14,40 @@ 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.
-->
<TabHost xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/tabhost"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="fill_parent"
android:layout_width="fill_parent" >
<LinearLayout
android:layout_height="fill_parent"
android:layout_width="fill_parent"
android:orientation="vertical" >
<TabWidget
android:id="@android:id/tabs"
android:layout_height="wrap_content"
android:layout_weight="0"
android:layout_width="fill_parent"
android:orientation="vertical" >
<TabHost
android:id="@android:id/tabhost"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_width="fill_parent" >
<LinearLayout
android:layout_height="fill_parent"
android:layout_width="fill_parent"
android:orientation="horizontal" />
<FrameLayout
android:id="@android:id/tabcontent"
android:layout_height="0dp"
android:layout_weight="0"
android:layout_width="0dp" />
<FrameLayout
android:id="@+id/realtabcontent"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_width="fill_parent" />
android:orientation="vertical" >
<TabWidget
android:id="@android:id/tabs"
android:layout_height="wrap_content"
android:layout_weight="0"
android:layout_width="fill_parent"
android:orientation="horizontal" />
<FrameLayout
android:id="@android:id/tabcontent"
android:layout_height="0dp"
android:layout_weight="0"
android:layout_width="0dp" />
<FrameLayout
android:id="@+id/realtabcontent"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_width="fill_parent" />
</LinearLayout>
</TabHost>
<LinearLayout
android:id="@+id/track_controler_container"
style="@style/TrackControllerContainer" >
<include layout="@layout/track_controller" />
</LinearLayout>
</TabHost>
</LinearLayout>
+3 -38
View File
@@ -33,43 +33,8 @@ limitations under the License.
style="@style/ListEmptyTextView" >
</TextView>
<LinearLayout
android:layout_gravity="center"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:orientation="horizontal" >
<ImageButton
android:background="@android:color/transparent"
android:id="@+id/track_list_record_track_button"
android:layout_height="100dp"
android:layout_width="wrap_content"
android:scaleType="centerInside" />
<RelativeLayout
android:layout_height="100dp"
android:layout_marginLeft="-32dp"
android:layout_width="wrap_content" >
<TextView
android:id="@+id/track_list_record_time"
android:layout_centerInParent="true"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:paddingLeft="24dp"
android:paddingRight="8dp"
android:textColor="@android:color/white"
style="@style/TextSmall" />
<TextView
android:id="@+id/track_list_record_state"
android:layout_above="@id/track_list_record_time"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:paddingBottom="12dp"
style="@style/TextSmall" />
</RelativeLayout>
<ImageButton
android:background="@android:color/transparent"
android:contentDescription="@string/menu_stop_recording"
android:id="@+id/track_list_stop_recording_button"
android:layout_height="100dp"
android:layout_width="wrap_content"
android:scaleType="centerInside" />
android:id="@+id/track_controler_container"
style="@style/TrackControllerContainer" >
<include layout="@layout/track_controller" />
</LinearLayout>
</LinearLayout>
+2 -1
View File
@@ -18,5 +18,6 @@ limitations under the License.
<item
android:icon="@drawable/menu_satellite_mode"
android:id="@+id/map_satellite_mode"
android:orderInCategory="6"/>
android:orderInCategory="5"
android:showAsAction="ifRoom"/>
</menu>
+1 -1
View File
@@ -24,6 +24,6 @@ limitations under the License.
android:actionViewClass="android.widget.SearchView"
android:icon="@drawable/menu_search"
android:id="@+id/marker_list_search"
android:showAsAction="always|collapseActionView"
android:showAsAction="ifRoom|collapseActionView"
android:title="@string/menu_search"/>
</menu>
+1 -1
View File
@@ -19,6 +19,6 @@ limitations under the License.
android:actionViewClass="android.widget.SearchView"
android:icon="@drawable/menu_search"
android:id="@+id/search_list_search"
android:showAsAction="always|collapseActionView"
android:showAsAction="ifRoom|collapseActionView"
android:title="@string/menu_search"/>
</menu>
+22 -38
View File
@@ -15,67 +15,41 @@ See the License for the specific language governing permissions and
limitations under the License.
-->
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:icon="@drawable/menu_record_track"
android:id="@+id/track_detail_record_track"
android:showAsAction="ifRoom"
android:title="@string/menu_record_track"/>
<item
android:icon="@drawable/menu_pause_track"
android:id="@+id/track_detail_pause_track"
android:showAsAction="ifRoom"
android:title="@string/menu_pause_track"/>
<item
android:icon="@drawable/menu_stop_recording"
android:id="@+id/track_detail_stop_recording"
android:orderInCategory="1"
android:showAsAction="ifRoom"
android:title="@string/menu_stop_recording"/>
<item
android:icon="@drawable/menu_insert_marker"
android:id="@+id/track_detail_insert_marker"
android:orderInCategory="2"
android:orderInCategory="1"
android:showAsAction="ifRoom"
android:title="@string/menu_insert_marker"/>
<item
android:icon="@drawable/menu_play"
android:id="@+id/track_detail_play"
android:orderInCategory="3"
android:orderInCategory="2"
android:showAsAction="ifRoom"
android:title="@string/menu_play"/>
<item
android:icon="@drawable/menu_share"
android:id="@+id/track_detail_share"
android:orderInCategory="4"
android:orderInCategory="3"
android:showAsAction="ifRoom"
android:title="@string/menu_share">
</item>
<item
android:icon="@drawable/menu_markers"
android:id="@+id/track_detail_markers"
android:orderInCategory="5"
android:orderInCategory="4"
android:showAsAction="ifRoom"
android:title="@string/menu_markers"/>
<!-- android:orderInCategory="6" is in map.xml -->
<item
android:icon="@drawable/menu_voice_frequency"
android:id="@+id/track_detail_voice_frequency"
android:orderInCategory="7"
android:title="@string/menu_voice_frequency"/>
<item
android:icon="@drawable/menu_split_frequency"
android:id="@+id/track_detail_split_frequency"
android:orderInCategory="8"
android:title="@string/menu_split_frequency"/>
<!-- android:orderInCategory="5" is in map.xml -->
<item
android:icon="@drawable/menu_send_google"
android:id="@+id/track_detail_send_google"
android:orderInCategory="9"
android:orderInCategory="6"
android:title="@string/menu_send_google"/>
<item
android:icon="@drawable/menu_save"
android:id="@+id/track_detail_save"
android:orderInCategory="10"
android:orderInCategory="7"
android:title="@string/menu_save">
<menu>
<item android:id="@+id/track_detail_save_gpx"/>
@@ -87,26 +61,36 @@ limitations under the License.
<item
android:icon="@drawable/menu_edit"
android:id="@+id/track_detail_edit"
android:orderInCategory="11"
android:orderInCategory="8"
android:title="@string/menu_edit"/>
<item
android:icon="@drawable/menu_delete"
android:id="@+id/track_detail_delete"
android:orderInCategory="12"
android:orderInCategory="9"
android:title="@string/menu_delete"/>
<item
android:icon="@drawable/menu_voice_frequency"
android:id="@+id/track_detail_voice_frequency"
android:orderInCategory="10"
android:title="@string/menu_voice_frequency"/>
<item
android:icon="@drawable/menu_split_frequency"
android:id="@+id/track_detail_split_frequency"
android:orderInCategory="11"
android:title="@string/menu_split_frequency"/>
<item
android:icon="@drawable/menu_sensor_state"
android:id="@+id/track_detail_sensor_state"
android:orderInCategory="13"
android:orderInCategory="12"
android:title="@string/menu_sensor_state"/>
<item
android:icon="@drawable/menu_settings"
android:id="@+id/track_detail_settings"
android:orderInCategory="14"
android:orderInCategory="13"
android:title="@string/menu_settings"/>
<item
android:icon="@drawable/menu_help"
android:id="@+id/track_detail_help"
android:orderInCategory="15"
android:orderInCategory="14"
android:title="@string/menu_help"/>
</menu>
+7
View File
@@ -180,6 +180,13 @@ limitations under the License.
</style>
<!-- Theme selector -->
<style name="ThemeSelector" parent="android:Theme" />
<!-- The style for the track controller container -->
<style name="TrackControllerContainer">
<item name="android:layout_gravity">center</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_width">wrap_content</item>
<item name="android:orientation">horizontal</item>
</style>
<!-- The style for the track widget button -->
<style name="TrackWidgetButton">
<item name="android:layout_gravity">center_horizontal</item>
@@ -0,0 +1,140 @@
/*
* 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;
import com.google.android.apps.mytracks.services.ITrackRecordingService;
import com.google.android.apps.mytracks.services.TrackRecordingServiceConnection;
import com.google.android.apps.mytracks.util.StringUtils;
import com.google.android.maps.mytracks.R;
import android.app.Activity;
import android.os.Handler;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageButton;
import android.widget.TextView;
/**
* Track controller for record, pause, resume, and stop.
*
* @author Jimmy Shih
*/
public class TrackController {
private static final String TAG = TrackController.class.getSimpleName();
private static final int ONE_SECOND = 1000;
private final Activity activity;
private final TrackRecordingServiceConnection trackRecordingServiceConnection;
private final Handler handler;
private final View containerView;
private final TextView statusTextView;
private final TextView totalTimeTextView;
private final ImageButton recordImageButton;
private final ImageButton stopImageButton;
private final boolean alwaysShow;
private boolean isRecording;
private boolean isPaused;
private long totalTime = 0;
// the timestamp for the toal time
private long totalTimeTimestamp = 0;
// A runnable to update the total time.
private final Runnable updateTotalTimeRunnable = new Runnable() {
public void run() {
if (isRecording && !isPaused) {
totalTimeTextView.setText(StringUtils.formatElapsedTimeWithHour(
System.currentTimeMillis() - totalTimeTimestamp + totalTime));
handler.postDelayed(this, ONE_SECOND);
}
}
};
public TrackController(Activity activity,
TrackRecordingServiceConnection trackRecordingServiceConnection, boolean alwaysShow,
OnClickListener recordListener, OnClickListener stopListener) {
this.activity = activity;
this.trackRecordingServiceConnection = trackRecordingServiceConnection;
this.alwaysShow = alwaysShow;
handler = new Handler();
containerView = (View) activity.findViewById(R.id.track_controler_container);
statusTextView = (TextView) activity.findViewById(R.id.track_controller_status);
totalTimeTextView = (TextView) activity.findViewById(R.id.track_controller_total_time);
recordImageButton = (ImageButton) activity.findViewById(R.id.track_controller_record);
recordImageButton.setOnClickListener(recordListener);
stopImageButton = (ImageButton) activity.findViewById(R.id.track_controller_stop);
stopImageButton.setOnClickListener(stopListener);
}
public void update(boolean recording, boolean paused) {
isRecording = recording;
isPaused = paused;
containerView.setVisibility(alwaysShow || isRecording ? View.VISIBLE : View.GONE);
if (!alwaysShow && !isRecording) {
stop();
return;
}
recordImageButton.setImageResource(
isRecording && !isPaused ? R.drawable.btn_pause : R.drawable.btn_record);
recordImageButton.setContentDescription(activity.getString(
isRecording && !isPaused ? R.string.menu_pause_track : R.string.menu_record_track));
stopImageButton.setImageResource(isRecording ? R.drawable.btn_stop_1 : R.drawable.btn_stop_0);
stopImageButton.setEnabled(isRecording);
statusTextView.setVisibility(isRecording ? View.VISIBLE : View.INVISIBLE);
if (isRecording) {
statusTextView.setTextColor(
activity.getResources().getColor(isPaused ? android.R.color.white : R.color.red));
statusTextView.setText(isPaused ? R.string.generic_paused : R.string.generic_recording);
}
stop();
totalTime = isRecording ? getTotalTime() : 0L;
totalTimeTextView.setText(StringUtils.formatElapsedTimeWithHour(totalTime));
if (isRecording && !isPaused) {
totalTimeTimestamp = System.currentTimeMillis();
handler.postDelayed(updateTotalTimeRunnable, ONE_SECOND);
}
}
/**
* Stops the timer.
*/
public void stop() {
handler.removeCallbacks(updateTotalTimeRunnable);
}
/**
* Gets the total time for the current recording track.
*/
private long getTotalTime() {
ITrackRecordingService trackRecordingService = trackRecordingServiceConnection
.getServiceIfBound();
try {
return trackRecordingService != null ? trackRecordingService.getTotalTime() : 0L;
} catch (RemoteException e) {
Log.e(TAG, "exception", e);
return 0L;
}
}
}
@@ -55,6 +55,7 @@ import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.TabHost;
import android.widget.TabHost.TabSpec;
@@ -74,25 +75,41 @@ public class TrackDetailActivity extends AbstractMyTracksActivity implements Del
private static final String TAG = TrackDetailActivity.class.getSimpleName();
private static final String CURRENT_TAG_KEY = "tab";
private TrackDataHub trackDataHub;
// The following are set in onCreate
private TrackRecordingServiceConnection trackRecordingServiceConnection;
private TrackDataHub trackDataHub;
private View mapViewContainer;
private TabHost tabHost;
private TabManager tabManager;
private TrackController trackController;
// From intent
private long trackId;
private long markerId;
// Preferences
private long recordingTrackId;
private boolean recordingTrackPaused;
private MenuItem recordTrackMenuItem;
private MenuItem pauseTrackMenuItem;
private MenuItem stopRecordingMenuItem;
private MenuItem insertMarkerMenuItem;
private MenuItem playMenuItem;
private MenuItem shareMenuItem;
private MenuItem sendGoogleMenuItem;
private MenuItem saveMenuItem;
private View mapViewContainer;
private final Runnable bindChangedCallback = new Runnable() {
@Override
public void run() {
// After binding changes (is available), update the total time in
// trackController.
runOnUiThread(new Runnable() {
@Override
public void run() {
trackController.update(trackId == recordingTrackId, recordingTrackPaused);
}
});
}
};
/*
* Note that sharedPreferenceChangeListener cannot be an anonymous inner
@@ -107,10 +124,6 @@ public class TrackDetailActivity extends AbstractMyTracksActivity implements Del
PreferencesUtils.getKey(TrackDetailActivity.this, R.string.recording_track_id_key))) {
recordingTrackId = PreferencesUtils.getLong(
TrackDetailActivity.this, R.string.recording_track_id_key);
if (key != null) {
updateMenuItems(trackId == recordingTrackId, recordingTrackPaused);
return;
}
}
if (key == null || key.equals(PreferencesUtils.getKey(
TrackDetailActivity.this, R.string.recording_track_paused_key))) {
@@ -118,9 +131,43 @@ public class TrackDetailActivity extends AbstractMyTracksActivity implements Del
R.string.recording_track_paused_key,
PreferencesUtils.RECORDING_TRACK_PAUSED_DEFAULT);
}
if (key != null) {
boolean isRecording = trackId == recordingTrackId;
updateMenuItems(isRecording, recordingTrackPaused);
trackController.update(isRecording, recordingTrackPaused);
}
}
};
private final OnClickListener recordListener = new OnClickListener() {
@Override
public void onClick(View v) {
if (recordingTrackPaused) {
// Paused -> Resume
AnalyticsUtils.sendPageViews(TrackDetailActivity.this, "/action/resume_track");
updateMenuItems(true, false);
TrackRecordingServiceConnectionUtils.resumeTrack(trackRecordingServiceConnection);
trackController.update(true, false);
} else {
// Recording -> Paused
AnalyticsUtils.sendPageViews(TrackDetailActivity.this, "/action/pause_track");
updateMenuItems(true, true);
TrackRecordingServiceConnectionUtils.pauseTrack(trackRecordingServiceConnection);
trackController.update(true, true);
}
}
};
private final OnClickListener stopListener = new OnClickListener() {
@Override
public void onClick(View v) {
AnalyticsUtils.sendPageViews(TrackDetailActivity.this, "/action/stop_recording");
updateMenuItems(false, true);
TrackRecordingServiceConnectionUtils.stopRecording(
TrackDetailActivity.this, trackRecordingServiceConnection, true);
}
};
/**
* We are not displaying driving directions. Just an arbitrary track that is
* not associated to any licensed mapping data. Therefore it should be okay to
@@ -152,7 +199,7 @@ public class TrackDetailActivity extends AbstractMyTracksActivity implements Del
sharedPreferences.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
sharedPreferenceChangeListener.onSharedPreferenceChanged(sharedPreferences, null);
trackRecordingServiceConnection = new TrackRecordingServiceConnection(this, null);
trackRecordingServiceConnection = new TrackRecordingServiceConnection(this, bindChangedCallback);
trackDataHub = TrackDataHub.newInstance(this);
mapViewContainer = getLayoutInflater().inflate(R.layout.map, null);
@@ -175,13 +222,7 @@ public class TrackDetailActivity extends AbstractMyTracksActivity implements Del
if (savedInstanceState != null) {
tabHost.setCurrentTabByTag(savedInstanceState.getString(CURRENT_TAG_KEY));
}
showMarker();
}
@Override
public void onNewIntent(Intent intent) {
setIntent(intent);
handleIntent(intent);
trackController = new TrackController(this, trackRecordingServiceConnection, false, recordListener, stopListener);
showMarker();
}
@@ -191,12 +232,18 @@ public class TrackDetailActivity extends AbstractMyTracksActivity implements Del
trackDataHub.start();
}
@Override
protected void onPause() {
super.onPause();
trackController.stop();
}
@Override
protected void onResume() {
super.onResume();
trackDataHub.loadTrack(trackId);
TrackRecordingServiceConnectionUtils.resumeConnection(this, trackRecordingServiceConnection);
updateMenuItems(trackId == recordingTrackId, recordingTrackPaused);
trackController.update(trackId == recordingTrackId, recordingTrackPaused);
}
@Override
@@ -217,6 +264,20 @@ public class TrackDetailActivity extends AbstractMyTracksActivity implements Del
trackRecordingServiceConnection.unbind();
}
@Override
protected void onHomeSelected() {
Intent intent = IntentUtils.newIntent(this, TrackListActivity.class);
startActivity(intent);
finish();
}
@Override
public void onNewIntent(Intent intent) {
setIntent(intent);
handleIntent(intent);
showMarker();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.track_detail, menu);
@@ -230,9 +291,6 @@ public class TrackDetailActivity extends AbstractMyTracksActivity implements Del
menu.findItem(R.id.track_detail_save_tcx)
.setTitle(getString(R.string.menu_save_format, fileTypes[3]));
recordTrackMenuItem = menu.findItem(R.id.track_detail_record_track);
pauseTrackMenuItem = menu.findItem(R.id.track_detail_pause_track);
stopRecordingMenuItem = menu.findItem(R.id.track_detail_stop_recording);
insertMarkerMenuItem = menu.findItem(R.id.track_detail_insert_marker);
playMenuItem = menu.findItem(R.id.track_detail_play);
shareMenuItem = menu.findItem(R.id.track_detail_share);
@@ -243,13 +301,6 @@ public class TrackDetailActivity extends AbstractMyTracksActivity implements Del
return true;
}
@Override
protected void onHomeSelected() {
Intent intent = IntentUtils.newIntent(this, TrackListActivity.class);
startActivity(intent);
finish();
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
String sensorTypeValueNone = getString(R.string.sensor_type_value_none);
@@ -263,19 +314,6 @@ public class TrackDetailActivity extends AbstractMyTracksActivity implements Del
public boolean onOptionsItemSelected(MenuItem item) {
Intent intent;
switch (item.getItemId()) {
case R.id.track_detail_record_track:
updateMenuItems(true, false);
TrackRecordingServiceConnectionUtils.resumeTrack(trackRecordingServiceConnection);
return true;
case R.id.track_detail_pause_track:
updateMenuItems(true, true);
TrackRecordingServiceConnectionUtils.pauseTrack(trackRecordingServiceConnection);
return true;
case R.id.track_detail_stop_recording:
updateMenuItems(false, true);
TrackRecordingServiceConnectionUtils.stopRecording(
this, trackRecordingServiceConnection, true);
return true;
case R.id.track_detail_insert_marker:
AnalyticsUtils.sendPageViews(this, "/action/insert_marker");
intent = IntentUtils.newIntent(this, MarkerEditActivity.class)
@@ -372,6 +410,11 @@ public class TrackDetailActivity extends AbstractMyTracksActivity implements Del
return super.onTrackballEvent(event);
}
@Override
public TrackRecordingServiceConnection getTrackRecordingServiceConnection() {
return trackRecordingServiceConnection;
}
/**
* Gets the map view container.
*/
@@ -437,15 +480,6 @@ public class TrackDetailActivity extends AbstractMyTracksActivity implements Del
* @param isRecording true if recording
*/
private void updateMenuItems(boolean isRecording, boolean isPaused) {
if (recordTrackMenuItem != null) {
recordTrackMenuItem.setVisible(isRecording && isPaused);
}
if (pauseTrackMenuItem != null) {
pauseTrackMenuItem.setVisible(isRecording && !isPaused);
}
if (stopRecordingMenuItem != null) {
stopRecordingMenuItem.setVisible(isRecording);
}
if (insertMarkerMenuItem != null) {
insertMarkerMenuItem.setVisible(isRecording && !isPaused);
}
@@ -500,9 +534,4 @@ public class TrackDetailActivity extends AbstractMyTracksActivity implements Del
}
return false;
}
@Override
public TrackRecordingServiceConnection getTrackRecordingServiceConnection() {
return trackRecordingServiceConnection;
}
}
@@ -16,8 +16,6 @@
package com.google.android.apps.mytracks;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.content.TracksColumns;
import com.google.android.apps.mytracks.fragments.CheckUnitsDialogFragment;
import com.google.android.apps.mytracks.fragments.DeleteAllTrackDialogFragment;
@@ -47,7 +45,6 @@ import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.database.Cursor;
import android.os.Bundle;
import android.os.Handler;
import android.os.Parcelable;
import android.speech.tts.TextToSpeech;
import android.support.v4.app.Fragment;
@@ -63,12 +60,11 @@ import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
/**
@@ -80,9 +76,6 @@ public class TrackListActivity extends FragmentActivity implements DeleteOneTrac
private static final String TAG = TrackListActivity.class.getSimpleName();
// One second in milliseconds
private static final int ONE_SECOND = 1000;
private static final String[] PROJECTION = new String[] { TracksColumns._ID, TracksColumns.NAME,
TracksColumns.DESCRIPTION, TracksColumns.CATEGORY, TracksColumns.STARTTIME,
TracksColumns.TOTALDISTANCE, TracksColumns.TOTALTIME, TracksColumns.ICON };
@@ -91,6 +84,16 @@ public class TrackListActivity extends FragmentActivity implements DeleteOneTrac
private final Runnable bindChangedCallback = new Runnable() {
@Override
public void run() {
// After binding changes (is available), update the total time in
// trackController.
runOnUiThread(new Runnable() {
@Override
public void run() {
trackController.update(recordingTrackId != PreferencesUtils.RECORDING_TRACK_ID_DEFAULT,
recordingTrackPaused);
}
});
if (!startNewRecording) {
return;
}
@@ -144,7 +147,7 @@ public class TrackListActivity extends FragmentActivity implements DeleteOneTrac
}
updateMenuItems(isRecording);
resourceCursorAdapter.notifyDataSetChanged();
startUpdateRecordTime(isRecording);
trackController.update(isRecording, recordingTrackPaused);
return;
}
}
@@ -154,9 +157,10 @@ public class TrackListActivity extends FragmentActivity implements DeleteOneTrac
R.string.recording_track_paused_key,
PreferencesUtils.RECORDING_TRACK_PAUSED_DEFAULT);
if (key != null) {
updateButtons(recordingTrackId != PreferencesUtils.RECORDING_TRACK_ID_DEFAULT,
recordingTrackPaused);
resourceCursorAdapter.notifyDataSetChanged();
trackController.update(
recordingTrackId != PreferencesUtils.RECORDING_TRACK_ID_DEFAULT,
recordingTrackPaused);
return;
}
}
@@ -164,7 +168,7 @@ public class TrackListActivity extends FragmentActivity implements DeleteOneTrac
};
// Callback when an item is selected in the contextual action mode
private ContextualActionModeCallback
private final ContextualActionModeCallback
contextualActionModeCallback = new ContextualActionModeCallback() {
@Override
public boolean onClick(int itemId, int position, long id) {
@@ -172,25 +176,44 @@ public class TrackListActivity extends FragmentActivity implements DeleteOneTrac
}
};
// A runnable to update the record time.
private final Runnable updateRecordTimeRunnable = new Runnable() {
public void run() {
if (recordingTrackId != PreferencesUtils.RECORDING_TRACK_ID_DEFAULT
&& !recordingTrackPaused) {
recordTimeTextView.setText(StringUtils.formatElapsedTimeWithHour(
System.currentTimeMillis() - lastResumeTime + recordTime));
handler.postDelayed(this, ONE_SECOND);
private final OnClickListener recordListener = new OnClickListener() {
public void onClick(View v) {
if (recordingTrackId == PreferencesUtils.RECORDING_TRACK_ID_DEFAULT) {
// Not recording -> Recording
AnalyticsUtils.sendPageViews(TrackListActivity.this, "/action/record_track");
updateMenuItems(true);
startRecording();
} else {
if (recordingTrackPaused) {
// Paused -> Resume
AnalyticsUtils.sendPageViews(TrackListActivity.this, "/action/resume_track");
updateMenuItems(true);
TrackRecordingServiceConnectionUtils.resumeTrack(trackRecordingServiceConnection);
trackController.update(true, false);
} else {
// Recording -> Paused
AnalyticsUtils.sendPageViews(TrackListActivity.this, "/action/pause_track");
updateMenuItems(true);
TrackRecordingServiceConnectionUtils.pauseTrack(trackRecordingServiceConnection);
trackController.update(true, true);
}
}
}
};
// The following are set in the constructor
private final OnClickListener stopListener = new OnClickListener() {
@Override
public void onClick(View v) {
AnalyticsUtils.sendPageViews(TrackListActivity.this, "/action/stop_recording");
updateMenuItems(false);
TrackRecordingServiceConnectionUtils.stopRecording(
TrackListActivity.this, trackRecordingServiceConnection, true);
}
};
// The following are set in onCreate
private TrackRecordingServiceConnection trackRecordingServiceConnection;
private Handler handler;
private TextView recordStateTextView;
private TextView recordTimeTextView;
private ImageButton recordTrackImageButton;
private ImageButton stopRecordingImageButton;
private TrackController trackController;
private ListView listView;
private ResourceCursorAdapter resourceCursorAdapter;
@@ -204,12 +227,8 @@ public class TrackListActivity extends FragmentActivity implements DeleteOneTrac
private MenuItem importMenuItem;
private MenuItem saveAllMenuItem;
private MenuItem deleteAllMenuItem;
private boolean startNewRecording = false; // true to start a new recording
// For recordTimeTextView
private long recordTime = 0;
private long lastResumeTime = 0;
private boolean startNewRecording = false; // true to start a new recording
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -225,53 +244,9 @@ public class TrackListActivity extends FragmentActivity implements DeleteOneTrac
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
sharedPreferences.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
sharedPreferenceChangeListener.onSharedPreferenceChanged(sharedPreferences, null);
handler = new Handler();
recordStateTextView = (TextView) findViewById(R.id.track_list_record_state);
recordTimeTextView = (TextView) findViewById(R.id.track_list_record_time);
recordTrackImageButton = (ImageButton) findViewById(R.id.track_list_record_track_button);
recordTrackImageButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!(recordingTrackId != PreferencesUtils.RECORDING_TRACK_ID_DEFAULT)) {
// Not recording -> Recording
AnalyticsUtils.sendPageViews(TrackListActivity.this, "/action/record_track");
updateMenuItems(true);
updateButtons(true, false);
startRecording();
} else {
if (recordingTrackPaused) {
// Paused -> Resume
AnalyticsUtils.sendPageViews(TrackListActivity.this, "/action/resume_track");
updateMenuItems(true);
updateButtons(true, false);
TrackRecordingServiceConnectionUtils.resumeTrack(trackRecordingServiceConnection);
startUpdateRecordTime(true);
} else {
// Recording -> Paused
AnalyticsUtils.sendPageViews(TrackListActivity.this, "/action/pause_track");
updateMenuItems(true);
updateButtons(true, true);
TrackRecordingServiceConnectionUtils.pauseTrack(trackRecordingServiceConnection);
stopUpdateRecordTime(true);
}
}
}
});
stopRecordingImageButton = (ImageButton) findViewById(R.id.track_list_stop_recording_button);
stopRecordingImageButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
AnalyticsUtils.sendPageViews(TrackListActivity.this, "/action/stop_recording");
updateMenuItems(false);
updateButtons(false, true);
TrackRecordingServiceConnectionUtils.stopRecording(
TrackListActivity.this, trackRecordingServiceConnection, true);
stopUpdateRecordTime(false);
}
});
updateButtons(
recordingTrackId != PreferencesUtils.RECORDING_TRACK_ID_DEFAULT, recordingTrackPaused);
trackController = new TrackController(
this, trackRecordingServiceConnection, true, recordListener, stopListener);
listView = (ListView) findViewById(R.id.track_list);
listView.setEmptyView(findViewById(R.id.track_list_empty_view));
@@ -349,14 +324,15 @@ public class TrackListActivity extends FragmentActivity implements DeleteOneTrac
@Override
protected void onPause() {
super.onPause();
stopUpdateRecordTime(recordingTrackId != PreferencesUtils.RECORDING_TRACK_ID_DEFAULT);
trackController.stop();
}
@Override
protected void onResume() {
super.onResume();
TrackRecordingServiceConnectionUtils.resumeConnection(this, trackRecordingServiceConnection);
startUpdateRecordTime(recordingTrackId != PreferencesUtils.RECORDING_TRACK_ID_DEFAULT);
trackController.update(
recordingTrackId != PreferencesUtils.RECORDING_TRACK_ID_DEFAULT, recordingTrackPaused);
}
@Override
@@ -513,57 +489,6 @@ public class TrackListActivity extends FragmentActivity implements DeleteOneTrac
}
}
private void updateButtons(boolean isRecording, boolean isPaused) {
recordTrackImageButton.setImageResource(
isRecording && !isPaused ? R.drawable.btn_pause : R.drawable.btn_record);
recordTrackImageButton.setContentDescription(getString(
isRecording && !isPaused ? R.string.menu_pause_track : R.string.menu_record_track));
stopRecordingImageButton.setImageResource(
isRecording ? R.drawable.btn_stop_1 : R.drawable.btn_stop_0);
stopRecordingImageButton.setEnabled(isRecording);
if (isRecording) {
recordStateTextView.setTextColor(
getResources().getColor(isPaused ? android.R.color.white : R.color.red));
recordStateTextView.setText(isPaused ? R.string.generic_paused : R.string.generic_recording);
recordStateTextView.setVisibility(View.VISIBLE);
} else {
recordStateTextView.setVisibility(View.INVISIBLE);
}
}
private void startUpdateRecordTime(boolean isRecording) {
stopUpdateRecordTime(false);
if (isRecording) {
recordTime = getRecordTime();
lastResumeTime = System.currentTimeMillis();
recordTimeTextView.setEnabled(true);
recordTimeTextView.setText(StringUtils.formatElapsedTimeWithHour(recordTime));
handler.postDelayed(updateRecordTimeRunnable, ONE_SECOND);
}
}
private void stopUpdateRecordTime(boolean isRecording) {
handler.removeCallbacks(updateRecordTimeRunnable);
if (isRecording) {
recordTime = getRecordTime();
recordTimeTextView.setEnabled(true);
recordTimeTextView.setText(StringUtils.formatElapsedTimeWithHour(recordTime));
} else {
recordTimeTextView.setEnabled(false);
recordTimeTextView.setText(StringUtils.formatElapsedTimeWithHour(0L));
}
}
/**
* Gets the current record time.
*/
private long getRecordTime() {
MyTracksProviderUtils myTracksProviderUtils = MyTracksProviderUtils.Factory.get(this);
Track track = myTracksProviderUtils.getTrack(recordingTrackId);
return track.getTripStatistics().getTotalTime();
}
/**
* Starts a new recording.
*/
@@ -1088,30 +1088,6 @@ public class TrackRecordingService extends Service {
return true;
}
@Override
public boolean isRecording() {
if (!canAccess()) {
return false;
}
return trackRecordingService.isRecording();
}
@Override
public boolean isPaused() {
if (!canAccess()) {
return false;
}
return trackRecordingService.isPaused();
}
@Override
public long getRecordingTrackId() {
if (!canAccess()) {
return -1L;
}
return trackRecordingService.recordingTrackId;
}
@Override
public long startNewTrack() {
if (!canAccess()) {
@@ -1120,14 +1096,6 @@ public class TrackRecordingService extends Service {
return trackRecordingService.startNewTrack();
}
@Override
public long insertWaypoint(WaypointCreationRequest waypointCreationRequest) {
if (!canAccess()) {
return -1L;
}
return trackRecordingService.insertWaypoint(waypointCreationRequest);
}
@Override
public void pauseCurrentTrack() {
if (!canAccess()) {
@@ -1153,7 +1121,54 @@ public class TrackRecordingService extends Service {
}
@Override
public void recordLocation(Location location) {
public boolean isRecording() {
if (!canAccess()) {
return false;
}
return trackRecordingService.isRecording();
}
@Override
public boolean isPaused() {
if (!canAccess()) {
return false;
}
return trackRecordingService.isPaused();
}
@Override
public long getRecordingTrackId() {
if (!canAccess()) {
return -1L;
}
return trackRecordingService.recordingTrackId;
}
@Override
public long getTotalTime() {
if (!canAccess()) {
return 0;
}
TripStatisticsUpdater updater = trackRecordingService.trackTripStatisticsUpdater;
if (updater == null) {
return 0;
}
if (!trackRecordingService.isPaused()) {
updater.updateTime(System.currentTimeMillis());
}
return updater.getTripStatistics().getTotalTime();
}
@Override
public long insertWaypoint(WaypointCreationRequest waypointCreationRequest) {
if (!canAccess()) {
return -1L;
}
return trackRecordingService.insertWaypoint(waypointCreationRequest);
}
@Override
public void insertTrackPoint(Location location) {
if (!canAccess()) {
return;
}
@@ -26,72 +26,74 @@ interface ITrackRecordingService {
/**
* Starts recording a new track.
*
* @return the track ID of the new track
* @return the track ID of the new track.
*/
long startNewTrack();
/**
* Checks and returns whether we're currently recording a track.
*/
boolean isRecording();
/**
* Checks and returns whether the current recording is paused.
*/
boolean isPaused();
/**
* Returns the track ID of the track currently being recorded, or -1 if none
* is being recorded. This ID can then be used to read track data from the
* content source.
*/
long getRecordingTrackId();
/**
* Inserts a waypoint marker in the track being recorded.
*
* @param request Details for the waypoint to be inserted.
* @return the unique ID of the inserted marker
*/
long insertWaypoint(in WaypointCreationRequest request);
/**
* Inserts a location in the track being recorded.
*
* When recording, locations detected by the GPS are already automatically
* added to the track, so this should be used only for adding special points
* or for testing.
*
* @param loc the location to insert
*/
void recordLocation(in Location loc);
/**
* Pauses the current track recording.
* Pauses the current recording track.
*/
void pauseCurrentTrack();
/**
* Resumes the current track recording.
* Resumes the current recording track.
*/
void resumeCurrentTrack();
/**
* Stops recording the current track.
* Ends the current recording track.
*/
void endCurrentTrack();
/**
* The current sensor data.
* The data is returned as a byte array which is a binary version of a
* Sensor.SensorDataSet object.
* @return the current sensor data or null if there is none.
* Returns true if currently recording a track.
*/
boolean isRecording();
/**
* Returns true if the current recording track is paused. Returns true if not recording.
*/
boolean isPaused();
/**
* Gets the current recording track ID. Returns -1 if not recording.
*/
long getRecordingTrackId();
/**
* Gets the total time for the current recording track. Returns 0 if not recording.
*/
long getTotalTime();
/**
* Inserts a waypoint in the current recording track.
*
* @param request the details of the waypoint to be inserted
* @return the ID of the inserted waypoint
*/
long insertWaypoint(in WaypointCreationRequest request);
/**
* Inserts a track point in the current recording track.
*
* When recording a track, GPS locations are automatically inserted. This is used for
* inserting special track points or for testing.
*
* @param location the track point to be inserted
*/
void insertTrackPoint(in Location location);
/**
* Gets the current sensor data. Returns null if there is no data.
* @return a byte array of the binary version of the Sensor.SensorDataSet object.
*/
byte[] getSensorData();
/**
* The current state of the sensor manager.
* The value is the value of a Sensor.SensorState enum.
* Gets the current sensor manager state.
*
* return a Sensor.SensorState enum value.
*/
int getSensorState();
}
@@ -114,7 +114,7 @@ public class DeleteTest extends ActivityInstrumentationTestCase2<TrackListActivi
EndToEndTestUtils
.getButtonOnScreen(activityMyTracks.getString(R.string.generic_ok), true, true);
instrumentation.waitForIdleSync();
assertFalse(EndToEndTestUtils.SOLO.getCurrentActivity().findViewById(R.id.track_list_stop_recording_button).isEnabled());
assertFalse(EndToEndTestUtils.SOLO.getCurrentActivity().findViewById(R.id.track_controller_stop).isEnabled());
}
@Override
@@ -394,7 +394,7 @@ public class EndToEndTestUtils {
* Starts recoding track.
*/
static void startRecording() {
View startButton = SOLO.getCurrentActivity().findViewById(R.id.track_list_record_track_button);
View startButton = SOLO.getCurrentActivity().findViewById(R.id.track_controller_record);
if(startButton != null && startButton.isShown()) {
SOLO.clickOnView(startButton);
} else if (hasActionBar) {
@@ -427,7 +427,7 @@ public class EndToEndTestUtils {
* Pauses recoding track.
*/
static void pauseRecording() {
View pauseButton = SOLO.getCurrentActivity().findViewById(R.id.track_list_record_track_button);
View pauseButton = SOLO.getCurrentActivity().findViewById(R.id.track_controller_record);
if(pauseButton != null && pauseButton.isShown()) {
SOLO.clickOnView(pauseButton);
} else if (hasActionBar) {
@@ -445,7 +445,7 @@ public class EndToEndTestUtils {
* Resume recoding track.
*/
static void resumeRecording() {
View startButton = SOLO.getCurrentActivity().findViewById(R.id.track_list_record_track_button);
View startButton = SOLO.getCurrentActivity().findViewById(R.id.track_controller_record);
if(startButton != null && startButton.isShown()) {
SOLO.clickOnView(startButton);
} else if (hasActionBar) {
@@ -465,7 +465,7 @@ public class EndToEndTestUtils {
* @return true if it is under recording.
*/
static boolean isUnderRecording() {
View startButton = SOLO.getCurrentActivity().findViewById(R.id.track_list_record_track_button);
View startButton = SOLO.getCurrentActivity().findViewById(R.id.track_controller_record);
if(startButton != null && startButton.isShown()) {
return false;
}
@@ -490,7 +490,7 @@ public class EndToEndTestUtils {
* @param isSave true means should save this track
*/
static void stopRecording(boolean isSave) {
View stopButton = SOLO.getCurrentActivity().findViewById(R.id.track_list_stop_recording_button);
View stopButton = SOLO.getCurrentActivity().findViewById(R.id.track_controller_stop);
if(stopButton != null && stopButton.isShown() ) {
SOLO.clickOnView(stopButton);
} else if (hasActionBar) {
@@ -751,7 +751,7 @@ public class TrackRecordingServiceTest extends ServiceTestCase<TestRecordingServ
loc.setSpeed(10);
loc.setTime(startTime + i * 10000);
loc.setBearing(3.0f);
service.recordLocation(loc);
service.insertTrackPoint(loc);
if (i % 10 == 0) {
service.insertWaypoint(WaypointCreationRequest.DEFAULT_STATISTICS);
@@ -787,7 +787,7 @@ public class TrackRecordingServiceTest extends ServiceTestCase<TestRecordingServ
location.setSpeed(10);
location.setTime(System.currentTimeMillis());
location.setBearing(3.0f);
trackRecordingService.recordLocation(location);
trackRecordingService.insertTrackPoint(location);
Thread.sleep(100);
}
}