diff --git a/MyTracks/AndroidManifest.xml b/MyTracks/AndroidManifest.xml index b46450418..a71fb2728 100755 --- a/MyTracks/AndroidManifest.xml +++ b/MyTracks/AndroidManifest.xml @@ -219,6 +219,7 @@ limitations under the License. + @@ -226,7 +227,6 @@ limitations under the License. - - - - - - - - - + + + + + + - - - - - - - - - - - + android:layout_marginLeft="8dp" + android:layout_marginRight="8dp" + android:layout_width="wrap_content" /> + + android:layout_width="match_parent" + android:shrinkColumns="0" + android:stretchColumns="0" > + + + - - - - - - - \ No newline at end of file + + + + + + + \ No newline at end of file diff --git a/MyTracks/res/values/arrays_do_not_translate.xml b/MyTracks/res/values/arrays_do_not_translate.xml index 25b3e77bb..ab707b088 100644 --- a/MyTracks/res/values/arrays_do_not_translate.xml +++ b/MyTracks/res/values/arrays_do_not_translate.xml @@ -15,7 +15,6 @@ See the License for the specific language governing permissions and limitations under the License. --> - @string/activity_type_airplane @@ -142,6 +141,12 @@ limitations under the License. 900 1800 + + 500 + 1024 + 2048 + -1 + 1 2 @@ -172,7 +177,7 @@ limitations under the License. @string/sensor_type_value_polar @string/sensor_type_value_zephyr @string/sensor_type_value_ant - @string/sensor_type_value_none + @string/sensor_type_value_none @string/settings_sensor_type_polar @@ -195,7 +200,7 @@ limitations under the License. @string/stats_rate_speed @string/stats_rate_pace - + @string/settings_stats_units_metric @string/settings_stats_units_imperial @@ -203,7 +208,7 @@ limitations under the License. @string/stats_units_metric @string/stats_units_imperial - + @string/settings_map_track_color_mode_single @string/settings_map_track_color_mode_fixed @@ -284,5 +289,4 @@ limitations under the License. @string/waypoint_type_water_fountain @string/waypoint_type_waypoint - \ No newline at end of file diff --git a/MyTracks/res/values/keys.xml b/MyTracks/res/values/keys.xml index 4259acde6..7b2707a67 100644 --- a/MyTracks/res/values/keys.xml +++ b/MyTracks/res/values/keys.xml @@ -27,18 +27,19 @@ limitations under the License. defaultActivity exportExternalStorageFormat exportGoogleFusionTablesPublic - exportGoogleMapsPublic + exportGoogleMapsPublic exportType mapType maxRecordingDistance minRecordingInterval + photoSize recordingDistanceInterval recordingGpsAccuracy sensorType shareTrackInvite shareTrackPublic splitFrequency - statsRate + statsRate statsShowCoordinate statsShowGradeElevation statsShowCalorie @@ -70,6 +71,7 @@ limitations under the License. recordingTrackId recordingTrackPaused + settingsAdvanced settingsBackup settingsBackupReset settingsChart @@ -90,6 +92,5 @@ limitations under the License. settingsSensorBluetooth settingsSensorBluetoothPairing settingsSensorRoot - settingsSharing settingsStats \ No newline at end of file diff --git a/MyTracks/res/values/strings.xml b/MyTracks/res/values/strings.xml index bc383f7e3..4d87d1fb9 100644 --- a/MyTracks/res/values/strings.xml +++ b/MyTracks/res/values/strings.xml @@ -777,7 +777,7 @@ limitations under the License. Delete selected? - + Description @@ -1002,7 +1002,7 @@ limitations under the License. - Delete marker? + Delete marker? @@ -1475,6 +1475,29 @@ limitations under the License. Show + + + Advanced + + + Original size + + + Scale photo to %1$s for export. + + + Photo size + + This will write a full copy of all your tracks and settings to ‘%1$s’ on the external storage. @@ -1955,13 +1978,6 @@ limitations under the License. - - Sharing - Calories Setup Activity Type @@ -2238,11 +2254,11 @@ limitations under the License. %1$s Markers - + @@ -2492,12 +2508,11 @@ limitations under the License. %1$d an integer value. E.g., '2'."> %1$d ft (recommended) - - %1$d km + %1$d kB %1$d kg + + %1$d km + %1$d km/h + + %1$d MB + + android:title="@string/settings_advanced" > + + android:title="@string/settings_sharing_allow_access" /> \ No newline at end of file diff --git a/MyTracks/res/xml/settings.xml b/MyTracks/res/xml/settings.xml index b0a0028f0..d820c79e9 100644 --- a/MyTracks/res/xml/settings.xml +++ b/MyTracks/res/xml/settings.xml @@ -36,10 +36,6 @@ limitations under the License. android:key="@string/settings_recording_key" android:persistent="false" android:title="@string/settings_recording" /> - + \ No newline at end of file diff --git a/MyTracks/src/com/google/android/apps/mytracks/fragments/MarkerDetailFragment.java b/MyTracks/src/com/google/android/apps/mytracks/fragments/MarkerDetailFragment.java index c544891fa..31fb7f0bb 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/fragments/MarkerDetailFragment.java +++ b/MyTracks/src/com/google/android/apps/mytracks/fragments/MarkerDetailFragment.java @@ -101,7 +101,7 @@ public class MarkerDetailFragment extends Fragment { inflater.inflate(R.menu.marker_detail, menu); updateWaypoint(false); - + Track track = myTracksProviderUtils.getTrack(waypoint.getTrackId()); boolean isSharedWithMe = track != null ? track.isSharedWithMe() : true; @@ -114,7 +114,7 @@ public class MarkerDetailFragment extends Fragment { long markerId = getArguments().getLong(KEY_MARKER_ID); FragmentActivity fragmentActivity = getActivity(); Intent intent; - + switch (item.getItemId()) { case R.id.marker_detail_show_on_map: intent = IntentUtils.newIntent(fragmentActivity, TrackDetailActivity.class) @@ -153,6 +153,7 @@ public class MarkerDetailFragment extends Fragment { /** * Updates the UI. */ + @SuppressWarnings("deprecation") private void update() { View waypointSection = getView().findViewById(R.id.marker_detail_waypoint_section); View statisticsSection = getView().findViewById(R.id.marker_detail_statistics_section); @@ -168,11 +169,8 @@ public class MarkerDetailFragment extends Fragment { } else { imageView.setVisibility(View.VISIBLE); Display defaultDisplay = getActivity().getWindowManager().getDefaultDisplay(); - @SuppressWarnings("deprecation") - int displayWidth = defaultDisplay.getWidth(); - @SuppressWarnings("deprecation") - int displayHeight = defaultDisplay.getHeight(); - PhotoUtils.setImageVew(imageView, Uri.parse(photoUrl), displayWidth, displayHeight); + PhotoUtils.setImageVew(imageView, Uri.parse(photoUrl), defaultDisplay.getWidth(), + defaultDisplay.getHeight(), true); } TextView name = (TextView) getView().findViewById(R.id.marker_detail_waypoint_name); @@ -193,8 +191,8 @@ public class MarkerDetailFragment extends Fragment { TextView name = (TextView) getView().findViewById(R.id.marker_detail_statistics_name); name.setText(getString(R.string.generic_name_line, waypoint.getName())); - StatsUtils.setTripStatisticsValues(getActivity(), waypoint.getTripStatistics(), - PreferencesUtils.RECORDING_TRACK_ID_DEFAULT); + StatsUtils.setTripStatisticsValues( + getActivity(), waypoint.getTripStatistics(), PreferencesUtils.RECORDING_TRACK_ID_DEFAULT); StatsUtils.setLocationValues(getActivity(), waypoint.getLocation(), false); } } diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/file/exporter/KmzTrackExporter.java b/MyTracks/src/com/google/android/apps/mytracks/io/file/exporter/KmzTrackExporter.java index 732c24e44..8c0ebae85 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/io/file/exporter/KmzTrackExporter.java +++ b/MyTracks/src/com/google/android/apps/mytracks/io/file/exporter/KmzTrackExporter.java @@ -19,14 +19,18 @@ package com.google.android.apps.mytracks.io.file.exporter; import com.google.android.apps.mytracks.content.MyTracksProviderUtils; import com.google.android.apps.mytracks.content.Track; import com.google.android.apps.mytracks.content.Waypoint; +import com.google.android.apps.mytracks.util.PreferencesUtils; +import com.google.android.maps.mytracks.R; +import android.content.Context; import android.database.Cursor; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.net.Uri; import android.util.Log; import java.io.File; import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.IOException; import java.io.OutputStream; import java.util.zip.ZipEntry; @@ -38,7 +42,7 @@ import java.util.zip.ZipOutputStream; * @author Jimmy Shih */ public class KmzTrackExporter implements TrackExporter { - + public static final String KMZ_EXTENSION = "kmz"; public static final String KMZ_IMAGES_DIR = "images"; public static final String KMZ_KML_FILE = "doc.kml"; @@ -49,6 +53,7 @@ public class KmzTrackExporter implements TrackExporter { private final MyTracksProviderUtils myTracksProviderUtils; private final FileTrackExporter fileTrackExporter; private final Track[] tracks; + private final long photoSize; /** * Constructor. @@ -56,12 +61,15 @@ public class KmzTrackExporter implements TrackExporter { * @param myTracksProviderUtils the my tracks provider utils * @param fileTrackExporter the file track exporter * @param tracks the tracks to export + * @param context the context */ public KmzTrackExporter(MyTracksProviderUtils myTracksProviderUtils, - FileTrackExporter fileTrackExporter, Track[] tracks) { + FileTrackExporter fileTrackExporter, Track[] tracks, Context context) { this.myTracksProviderUtils = myTracksProviderUtils; this.fileTrackExporter = fileTrackExporter; this.tracks = tracks; + this.photoSize = PreferencesUtils.getInt( + context, R.string.photo_size_key, PreferencesUtils.PHOTO_SIZE_DEFAULT); } @Override @@ -78,7 +86,7 @@ public class KmzTrackExporter implements TrackExporter { zipOutputStream.closeEntry(); if (!success) { Log.e(TAG, "Unable to write kml in kmz"); - return false; + return false; } // Add photos @@ -95,7 +103,7 @@ public class KmzTrackExporter implements TrackExporter { try { zipOutputStream.close(); } catch (IOException e) { - Log.e(TAG, "Unable to close zip input stream", e);; + Log.e(TAG, "Unable to close zip input stream", e); } } } @@ -132,10 +140,47 @@ public class KmzTrackExporter implements TrackExporter { private void addImage(ZipOutputStream zipOutputStream, String photoUrl) throws IOException { Uri uri = Uri.parse(photoUrl); + File file = new File(uri.getPath()); + if (!file.exists()) { + Log.e(TAG, "file not found " + photoUrl); + return; + } + ZipEntry zipEntry = new ZipEntry( KMZ_IMAGES_DIR + File.separatorChar + uri.getLastPathSegment()); zipOutputStream.putNextEntry(zipEntry); + int sampleSize; + if (photoSize == -1) { + sampleSize = 1; + } else { + long size = file.length(); + // Convert from kilobytes to bytes. + long limit = photoSize * 1024; + sampleSize = size > limit ? (int) Math.ceil(size / limit) : 1; + } + if (sampleSize == 1) { + readFromFile(zipOutputStream, uri); + } else { + readFromScaledBitmap(zipOutputStream, uri, sampleSize); + } + zipOutputStream.closeEntry(); + } + + private void readFromScaledBitmap(ZipOutputStream zipOutputStream, Uri uri, int sampleSize) { + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inJustDecodeBounds = false; + options.inSampleSize = sampleSize; + + Bitmap bitmap = BitmapFactory.decodeFile(uri.getPath(), options); + if (bitmap == null) { + return; + } + bitmap.compress(Bitmap.CompressFormat.JPEG, 100, zipOutputStream); + bitmap.recycle(); + } + + private void readFromFile(ZipOutputStream zipOutputStream, Uri uri) throws IOException { FileInputStream fileInputStream = null; try { fileInputStream = new FileInputStream(new File(uri.getPath())); @@ -143,14 +188,11 @@ public class KmzTrackExporter implements TrackExporter { int byteCount = 0; while ((byteCount = fileInputStream.read(buffer)) != -1) { zipOutputStream.write(buffer, 0, byteCount); - } - } catch (FileNotFoundException e) { - Log.e(TAG, "Unable to add image", e); + } } finally { if (fileInputStream != null) { fileInputStream.close(); } } - zipOutputStream.closeEntry(); } } \ No newline at end of file diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/file/exporter/SaveAsyncTask.java b/MyTracks/src/com/google/android/apps/mytracks/io/file/exporter/SaveAsyncTask.java index 378a740df..c8263774f 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/io/file/exporter/SaveAsyncTask.java +++ b/MyTracks/src/com/google/android/apps/mytracks/io/file/exporter/SaveAsyncTask.java @@ -202,7 +202,8 @@ public class SaveAsyncTask extends AsyncTask { } }); - trackExporter = useKmz ? new KmzTrackExporter(myTracksProviderUtils, fileTrackExporter, tracks) + trackExporter = useKmz ? new KmzTrackExporter( + myTracksProviderUtils, fileTrackExporter, tracks, context) : fileTrackExporter; String fileName = FileUtils.buildUniqueFileName(directory, track.getName(), extension); diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/sync/SyncUtils.java b/MyTracks/src/com/google/android/apps/mytracks/io/sync/SyncUtils.java index b28dd7a33..dd9c26a7e 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/io/sync/SyncUtils.java +++ b/MyTracks/src/com/google/android/apps/mytracks/io/sync/SyncUtils.java @@ -469,7 +469,7 @@ public class SyncUtils { FileTrackExporter fileTrackExporter = new FileTrackExporter( myTracksProviderUtils, tracks, TrackFileFormat.KML.newTrackWriter(context, false), null); TrackExporter trackExporter = useKmz ? new KmzTrackExporter( - myTracksProviderUtils, fileTrackExporter, tracks) + myTracksProviderUtils, fileTrackExporter, tracks, context) : fileTrackExporter; FileOutputStream fileOutputStream = null; diff --git a/MyTracks/src/com/google/android/apps/mytracks/services/tasks/BitmapLoader.java b/MyTracks/src/com/google/android/apps/mytracks/services/tasks/BitmapLoader.java index 2513e4d7b..96f5cca32 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/services/tasks/BitmapLoader.java +++ b/MyTracks/src/com/google/android/apps/mytracks/services/tasks/BitmapLoader.java @@ -40,16 +40,19 @@ public class BitmapLoader extends AsyncTask { private final WeakReference imageViewReference; private final Uri uri; - private final int displayWidth; - private final int displayHeight; + private final int targetWidth; + private final int targetHeight; + private final boolean fitWithin; - public BitmapLoader(ImageView imageView, Uri uri, int displayWidth, int displayHeight) { + public BitmapLoader( + ImageView imageView, Uri uri, int targetWidth, int targetHeight, boolean fitWithin) { // Use a WeakReference to ensure the ImageView can be garbage collected imageViewReference = new WeakReference(imageView); this.uri = uri; - this.displayWidth = displayWidth; - this.displayHeight = displayHeight; + this.targetWidth = targetWidth; + this.targetHeight = targetHeight; + this.fitWithin = fitWithin; } public Uri getUri() { @@ -64,12 +67,9 @@ public class BitmapLoader extends AsyncTask { options.inJustDecodeBounds = true; BitmapFactory.decodeFile(uri.getPath(), options); - - // Set targetWidth and targetHeight - int targetWidth = displayWidth; - int targetHeight = displayHeight; - if (targetHeight == 0) { - targetHeight = (int) (targetWidth * ((float) options.outHeight / (float) options.outWidth)); + + if (options.outWidth == 0 || options.outHeight == 0) { + return null; } // Set imageWidth and imageHeight based on image rotation @@ -87,20 +87,29 @@ public class BitmapLoader extends AsyncTask { // Get a scaled down version of the image options.inJustDecodeBounds = false; - options.inSampleSize = getInSampleSize(imageWidth, imageHeight, targetWidth, targetHeight); + options.inSampleSize = getInSampleSize(imageWidth, imageHeight); options.inPurgeable = true; Bitmap scaledBitmap = BitmapFactory.decodeFile(uri.getPath(), options); - + if (scaledBitmap == null) { + return null; + } + // Get the final bitmap after rotating the scaled down image Bitmap bitmap; - if (rotation == 0) { + if (rotation == 0 && fitWithin) { bitmap = scaledBitmap; } else { Matrix matrix = new Matrix(); matrix.postRotate(rotation); + int offset = 0; + int height = scaledBitmap.getHeight(); + if (!fitWithin && height > targetHeight) { + offset = (height - targetHeight) / 2; + height = targetHeight; + } bitmap = Bitmap.createBitmap( - scaledBitmap, 0, 0, scaledBitmap.getWidth(), scaledBitmap.getHeight(), matrix, true); + scaledBitmap, 0, offset, scaledBitmap.getWidth(), height, matrix, true); scaledBitmap.recycle(); } return bitmap; @@ -148,10 +157,8 @@ public class BitmapLoader extends AsyncTask { * * @param imageWidth the image width * @param imageHeight the image height - * @param targetWidth the target width - * @param targetHeight the target height */ - private int getInSampleSize(int imageWidth, int imageHeight, int targetWidth, int targetHeight) { + private int getInSampleSize(int imageWidth, int imageHeight) { float widthRatio = 1; if (imageWidth > targetWidth) { widthRatio = (float) imageWidth / (float) targetWidth; @@ -162,11 +169,21 @@ public class BitmapLoader extends AsyncTask { heightRatio = (float) imageHeight / (float) targetHeight; } - /* - * To fit within the target area, return the larger sample ratio so the - * image will not be larger than the target dimensions. Use Math.floor to - * not under sample. - */ - return (int) Math.floor(Math.max(widthRatio, heightRatio)); + double size; + if (fitWithin) { + /* + * To fit within the target area, return the larger sample ratio so the + * image will not be larger than the target dimensions. + */ + size = Math.max(widthRatio, heightRatio); + } else { + /* + * To fill the target area, return the smaller ratio so the image will + * cover both dimensions. + */ + size = Math.min(widthRatio, heightRatio); + } + // Use Math.floor to not under-sample. + return (int) Math.floor(size); } } diff --git a/MyTracks/src/com/google/android/apps/mytracks/settings/SharingSettingsActivity.java b/MyTracks/src/com/google/android/apps/mytracks/settings/AdvancedSettingsActivity.java similarity index 58% rename from MyTracks/src/com/google/android/apps/mytracks/settings/SharingSettingsActivity.java rename to MyTracks/src/com/google/android/apps/mytracks/settings/AdvancedSettingsActivity.java index 044c672cb..170345b23 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/settings/SharingSettingsActivity.java +++ b/MyTracks/src/com/google/android/apps/mytracks/settings/AdvancedSettingsActivity.java @@ -17,21 +17,23 @@ package com.google.android.apps.mytracks.settings; import com.google.android.apps.mytracks.util.DialogUtils; +import com.google.android.apps.mytracks.util.PreferencesUtils; import com.google.android.maps.mytracks.R; import android.app.Dialog; import android.content.DialogInterface; import android.os.Bundle; import android.preference.CheckBoxPreference; +import android.preference.ListPreference; import android.preference.Preference; import android.preference.Preference.OnPreferenceChangeListener; /** - * An activity for accessing the sharing settings. + * An activity for advanced settings. * * @author Jimmy Shih */ -public class SharingSettingsActivity extends AbstractSettingsActivity { +public class AdvancedSettingsActivity extends AbstractSettingsActivity { private static final int DIALOG_CONFIRM_ALLOW_ACCESS_ID = 0; @@ -41,7 +43,7 @@ public class SharingSettingsActivity extends AbstractSettingsActivity { @Override protected void onCreate(Bundle bundle) { super.onCreate(bundle); - addPreferencesFromResource(R.xml.sharing_settings); + addPreferencesFromResource(R.xml.advanced_settings); allowAccessCheckBoxPreference = (CheckBoxPreference) findPreference( getString(R.string.allow_access_key)); @@ -56,6 +58,15 @@ public class SharingSettingsActivity extends AbstractSettingsActivity { } } }); + + ListPreference preference = (ListPreference) findPreference(getString(R.string.photo_size_key)); + int value = PreferencesUtils.getInt( + this, R.string.photo_size_key, PreferencesUtils.PHOTO_SIZE_DEFAULT); + String[] values = getResources().getStringArray(R.array.photo_size_values); + String[] options = new String[values.length]; + String[] summary = new String[values.length]; + setPhotoSizeSummaryAndOptions(summary, options, values); + configureListPreference(preference, summary, options, values, String.valueOf(value), null); } @Override @@ -73,4 +84,21 @@ public class SharingSettingsActivity extends AbstractSettingsActivity { } }); } + + private void setPhotoSizeSummaryAndOptions(String[] summary, String[] options, String[] values) { + for (int i = 0; i < values.length; i++) { + int value = Integer.parseInt(values[i]); + if (value == -1) { + options[i] = getString(R.string.settings_advanced_photo_size_original); + summary[i] = getString(R.string.settings_advanced_photo_size_original); + } else if (value < 1024) { + options[i] = getString(R.string.value_integer_kilobyte, value); + summary[i] = getString(R.string.settings_advanced_photo_size_summary, options[i]); + } else { + int megabyte = value / 1024; + options[i] = getString(R.string.value_integer_megabyte, megabyte); + summary[i] = getString(R.string.settings_advanced_photo_size_summary, options[i]); + } + } + } } diff --git a/MyTracks/src/com/google/android/apps/mytracks/settings/SettingsActivity.java b/MyTracks/src/com/google/android/apps/mytracks/settings/SettingsActivity.java index 9482b31e8..c3df05ace 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/settings/SettingsActivity.java +++ b/MyTracks/src/com/google/android/apps/mytracks/settings/SettingsActivity.java @@ -43,9 +43,9 @@ public class SettingsActivity extends AbstractSettingsActivity { configPreference(R.string.settings_chart_key, ChartSettingsActivity.class); configPreference(R.string.settings_stats_key, StatsSettingsActivity.class); configPreference(R.string.settings_recording_key, RecordingSettingsActivity.class); - configPreference(R.string.settings_sharing_key, SharingSettingsActivity.class); configPreference(R.string.settings_sensor_key, SensorSettingsActivity.class); configPreference(R.string.settings_backup_reset_key, BackupResetSettingsActivity.class); + configPreference(R.string.settings_advanced_key, AdvancedSettingsActivity.class); } /** diff --git a/MyTracks/src/com/google/android/apps/mytracks/util/ListItemUtils.java b/MyTracks/src/com/google/android/apps/mytracks/util/ListItemUtils.java index c4efb3ec1..671ae6390 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/util/ListItemUtils.java +++ b/MyTracks/src/com/google/android/apps/mytracks/util/ListItemUtils.java @@ -20,6 +20,7 @@ import com.google.android.maps.mytracks.R; import android.app.Activity; import android.content.Context; +import android.content.res.TypedArray; import android.net.Uri; import android.text.format.DateUtils; import android.view.Display; @@ -36,6 +37,8 @@ import java.util.Calendar; */ public class ListItemUtils { + private static final int LIST_PREFERRED_ITEM_HEIGHT_DEFAULT = 128; + private ListItemUtils() {} /** @@ -56,6 +59,7 @@ public class ListItemUtils { * @param category the category value * @param description the description value */ + @SuppressWarnings("deprecation") public static void setListItem(Activity activity, View view, boolean isRecording, boolean isPaused, int iconId, int iconContentDescriptionId, String name, String sharedOwner, String totalTime, String totalDistance, String photoUrl, long startTime, String category, @@ -87,17 +91,14 @@ public class ListItemUtils { setTextView(timeDistanceTextView, getTimeDistance(activity, isRecording, isPaused, sharedOwner, totalTime, totalDistance)); - // Set photoUrl - ImageView photo = (ImageView) view.findViewById(R.id.list_item_photo); + ImageView photo = (ImageView) view.findViewById(R.id.list_item_background); if (photoUrl == null || photoUrl.equals("")) { photo.setVisibility(View.GONE); } else { photo.setVisibility(View.VISIBLE); Display defaultDisplay = activity.getWindowManager().getDefaultDisplay(); - // Set the initial width to 33% of the display width. - int width = (int) (defaultDisplay.getWidth() * .33); - int height = 0; - PhotoUtils.setImageVew(photo, Uri.parse(photoUrl), width, height); + PhotoUtils.setImageVew( + photo, Uri.parse(photoUrl), defaultDisplay.getWidth(), getPhotoHeight(activity), false); } // Set date/time @@ -108,6 +109,15 @@ public class ListItemUtils { TextView timeTextView = (TextView) view.findViewById(R.id.list_item_time); setTextView(timeTextView, startTimeDisplay[1]); + /* + * If column0 is GONE, change to INVISIBLE so column1 is placed at the + * correct position. + */ + if (timeTextView.getVisibility() == View.VISIBLE + && timeDistanceTextView.getVisibility() == View.GONE) { + timeDistanceTextView.setVisibility(View.INVISIBLE); + } + // Set category/description TextView descriptionTextView = (TextView) view.findViewById(R.id.list_item_description); setTextView(descriptionTextView, @@ -201,4 +211,17 @@ public class ListItemUtils { textView.setText(value); } } + + /** + * Gets the photo height. + * + * @param context the context + */ + private static int getPhotoHeight(Context context) { + int[] attrs = new int[] { android.R.attr.listPreferredItemHeight }; + TypedArray typeArray = context.obtainStyledAttributes(attrs); + int height = typeArray.getDimensionPixelSize(0, LIST_PREFERRED_ITEM_HEIGHT_DEFAULT); + typeArray.recycle(); + return 2 * height; + } } diff --git a/MyTracks/src/com/google/android/apps/mytracks/util/PhotoUtils.java b/MyTracks/src/com/google/android/apps/mytracks/util/PhotoUtils.java index 80da1d43d..59abcfe6e 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/util/PhotoUtils.java +++ b/MyTracks/src/com/google/android/apps/mytracks/util/PhotoUtils.java @@ -37,13 +37,17 @@ public class PhotoUtils { * * @param imageView the image view * @param uri the image uri - * @param displayWidth the display width - * @param displayHeight the display height + * @param targetWidth the target width + * @param targetHeight the target height + * @param fitWithin true to fit within the target area in order to display the + * entire image (no cropping). False to fill the entire target area. + * (allow cropping). */ public static void setImageVew( - ImageView imageView, Uri uri, int displayWidth, int displayHeight) { + ImageView imageView, Uri uri, int targetWidth, int targetHeight, boolean fitWithin) { if (cancelBitmapLoader(imageView, uri)) { - BitmapLoader bitmapLoader = new BitmapLoader(imageView, uri, displayWidth, displayHeight); + BitmapLoader bitmapLoader = new BitmapLoader( + imageView, uri, targetWidth, targetHeight, fitWithin); WeakReference bitmapLoaderReference = new WeakReference( bitmapLoader); imageView.setTag(bitmapLoaderReference); diff --git a/MyTracks/src/com/google/android/apps/mytracks/util/PreferencesUtils.java b/MyTracks/src/com/google/android/apps/mytracks/util/PreferencesUtils.java index 6f1d6cff4..10b47cb16 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/util/PreferencesUtils.java +++ b/MyTracks/src/com/google/android/apps/mytracks/util/PreferencesUtils.java @@ -82,6 +82,7 @@ public class PreferencesUtils { public static final int MIN_RECORDING_INTERVAL_ADAPT_BATTERY_LIFE = -2; public static final int MIN_RECORDING_INTERVAL_DEFAULT = 0; + public static final int PHOTO_SIZE_DEFAULT = 1024; // 1024 kB public static final int RECORDING_DISTANCE_INTERVAL_DEFAULT = 10; // Values for recording_gps_accuracy diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/fragments/ChartFragmentTest.java b/MyTracksTest/src/com/google/android/apps/mytracks/fragments/ChartFragmentTest.java index 368727cf2..69790b014 100644 --- a/MyTracksTest/src/com/google/android/apps/mytracks/fragments/ChartFragmentTest.java +++ b/MyTracksTest/src/com/google/android/apps/mytracks/fragments/ChartFragmentTest.java @@ -28,7 +28,7 @@ import android.test.AndroidTestCase; /** * Tests {@link ChartFragment}. - * + * * @author Youtao Liu */ public class ChartFragmentTest extends AndroidTestCase { @@ -45,12 +45,12 @@ public class ChartFragmentTest extends AndroidTestCase { } /** - * Tests the logic to get the incorrect values of sensor in - * {@link ChartFragment#fillDataPoint(Location, double[])} + * Tests the logic to get the incorrect values of sensor in {@link ChartFragment#fillDataPoint(Location, + * double[], android.content.Context)} */ public void testFillDataPoint_sensorIncorrect() { MyTracksLocation myTracksLocation = TrackStubUtils.createMyTracksLocation(); - + // No input. double[] point = fillDataPointTestHelper(myTracksLocation); assertEquals(Double.NaN, point[ChartView.HEART_RATE_SERIES + 1]); @@ -69,10 +69,7 @@ public class ChartFragmentTest extends AndroidTestCase { // Creates SensorDataSet. SensorDataSet sensorDataSet = myTracksLocation.getSensorDataSet(); sensorDataSet = sensorDataSet.toBuilder() - .setHeartRate(heartRateData) - .setCadence(cadenceData) - .setPower(powerData) - .build(); + .setHeartRate(heartRateData).setCadence(cadenceData).setPower(powerData).build(); myTracksLocation.setSensorDataSet(sensorDataSet); // Test. point = fillDataPointTestHelper(myTracksLocation); @@ -82,8 +79,8 @@ public class ChartFragmentTest extends AndroidTestCase { } /** - * Tests the logic to get the correct values of sensor in - * {@link ChartFragment#fillDataPoint(Location, double[])}. + * Tests the logic to get the correct values of sensor in {@link ChartFragment#fillDataPoint(Location, + * double[], android.content.Context)}. */ public void testFillDataPoint_sensorCorrect() { MyTracksLocation myTracksLocation = TrackStubUtils.createMyTracksLocation(); @@ -100,14 +97,11 @@ public class ChartFragmentTest extends AndroidTestCase { .setValue(101).setState(Sensor.SensorState.SENDING); Sensor.SensorData.Builder powerData = Sensor.SensorData.newBuilder() .setValue(102).setState(Sensor.SensorState.SENDING); - + // Creates SensorDataSet. SensorDataSet sensorDataSet = myTracksLocation.getSensorDataSet(); sensorDataSet = sensorDataSet.toBuilder() - .setHeartRate(heartRateData) - .setCadence(cadenceData) - .setPower(powerData) - .build(); + .setHeartRate(heartRateData).setCadence(cadenceData).setPower(powerData).build(); myTracksLocation.setSensorDataSet(sensorDataSet); // Test. point = fillDataPointTestHelper(myTracksLocation); @@ -117,8 +111,8 @@ public class ChartFragmentTest extends AndroidTestCase { } /** - * Tests the logic to get the value of metric Distance in - * {@link ChartFragment#fillDataPoint(Location, double[])}. + * Tests the logic to get the value of metric Distance in {@link ChartFragment#fillDataPoint(Location, + * double[], android.content.Context)}. */ public void testFillDataPoint_distanceMetric() { // By distance. @@ -137,7 +131,7 @@ public class ChartFragmentTest extends AndroidTestCase { MyTracksLocation myTracksLocation3 = TrackStubUtils.createMyTracksLocation(); myTracksLocation3.setLatitude(23); point = fillDataPointTestHelper(myTracksLocation3); - + // Computes the distance between Latitude 22 and 23. float[] results = new float[4]; Location.distanceBetween(myTracksLocation2.getLatitude(), myTracksLocation2.getLongitude(), @@ -149,7 +143,7 @@ public class ChartFragmentTest extends AndroidTestCase { MyTracksLocation myTracksLocation4 = TrackStubUtils.createMyTracksLocation(); myTracksLocation4.setLatitude(24); point = fillDataPointTestHelper(myTracksLocation4); - + // Computes the distance between Latitude 23 and 24. Location.distanceBetween(myTracksLocation3.getLatitude(), myTracksLocation3.getLongitude(), myTracksLocation4.getLatitude(), myTracksLocation4.getLongitude(), results); @@ -158,8 +152,8 @@ public class ChartFragmentTest extends AndroidTestCase { } /** - * Tests the logic to get the value of imperial Distance in - * {@link ChartFragment#fillDataPoint(Location, double[])}. + * Tests the logic to get the value of imperial Distance in {@link ChartFragment#fillDataPoint(Location, + * double[], android.content.Context)}. */ public void testFillDataPoint_distanceImperial() { // By distance. @@ -203,8 +197,8 @@ public class ChartFragmentTest extends AndroidTestCase { } /** - * Tests the logic to get the values of time in - * {@link ChartFragment#fillDataPoint(Location, double[])}. + * Tests the logic to get the values of time in {@link ChartFragment#fillDataPoint(Location, + * double[], android.content.Context)}. */ public void testFillDataPoint_time() { // By time @@ -220,9 +214,8 @@ public class ChartFragmentTest extends AndroidTestCase { } /** - * Tests the logic to get the value of elevation in - * {@link ChartFragment#fillDataPoint(Location, double[])} by one and two - * points. + * Tests the logic to get the value of elevation in {@link ChartFragment#fillDataPoint(Location, + * double[], android.content.Context)} by one and two points. */ public void testFillDataPoint_elevation() { MyTracksLocation myTracksLocation1 = TrackStubUtils.createMyTracksLocation(); @@ -246,10 +239,10 @@ public class ChartFragmentTest extends AndroidTestCase { } /** - * Tests the logic to get the value of speed in - * {@link ChartFragment#fillDataPoint(Location, double[])}. In this test, - * firstly remove all points in memory, and then fill in two points one by - * one. The speed values of these points are 129, 130. + * Tests the logic to get the value of speed in {@link ChartFragment#fillDataPoint(Location, + * double[], android.content.Context)}. In this test, firstly remove all + * points in memory, and then fill in two points one by one. The speed values + * of these points are 129, 130. */ public void testFillDataPoint_speed() { /* @@ -283,22 +276,19 @@ public class ChartFragmentTest extends AndroidTestCase { public void testFillDataPoint_speedImperial() { // Setups to use imperial. chartFragment.setMetricUnits(false); - + // First data point is not added to the speed buffer MyTracksLocation myTracksLocation1 = TrackStubUtils.createMyTracksLocation(); myTracksLocation1.setSpeed(100.0f); double[] point = fillDataPointTestHelper(myTracksLocation1); assertEquals(0.0, point[ChartView.SPEED_SERIES + 1]); - + MyTracksLocation myTracksLocation2 = TrackStubUtils.createMyTracksLocation(); - + /* - * Add a time span here to make sure the second point is valid and the speed is valid. - * - * Speed is valid if: - * speedDifference > Constants.MAX_ACCELERATION * timeDifference - * speedDifference = 102 -100 - * timeDifference = 222 + * Add a time span here to make sure the second point is valid and the speed + * is valid. Speed is valid if: speedDifference > Constants.MAX_ACCELERATION + * * timeDifference speedDifference = 102 -100 timeDifference = 222 */ myTracksLocation2.setTime(myTracksLocation2.getTime() + 222); myTracksLocation2.setSpeed(102); @@ -313,22 +303,19 @@ public class ChartFragmentTest extends AndroidTestCase { public void testFillDataPoint_pace_nonZeroSpeed() { // Setups reportSpeed to false. chartFragment.setReportSpeed(false); - + // First data point is not added to the speed buffer MyTracksLocation myTracksLocation1 = TrackStubUtils.createMyTracksLocation(); myTracksLocation1.setSpeed(100.0f); double[] point = fillDataPointTestHelper(myTracksLocation1); assertEquals(0.0, point[ChartView.SPEED_SERIES + 1]); - + MyTracksLocation myTracksLocation2 = TrackStubUtils.createMyTracksLocation(); /* - * Add a time span here to make sure the second point is valid and the speed is valid. - * - * Speed is valid if: - * speedDifference > Constants.MAX_ACCELERATION * timeDifference - * speedDifference = 102 -100 - * timeDifference = 222 + * Add a time span here to make sure the second point is valid and the speed + * is valid. Speed is valid if: speedDifference > Constants.MAX_ACCELERATION + * * timeDifference speedDifference = 102 -100 timeDifference = 222 */ myTracksLocation2.setTime(myTracksLocation2.getTime() + 222); myTracksLocation2.setSpeed(102); @@ -352,7 +339,7 @@ public class ChartFragmentTest extends AndroidTestCase { /** * Helper method to test fillDataPoint. - * + * * @param location location to fill * @return data of this location */ diff --git a/MyTracksTest_E2E/src/com/google/android/apps/mytracks/endtoendtest/common/SettingTest.java b/MyTracksTest_E2E/src/com/google/android/apps/mytracks/endtoendtest/common/SettingTest.java index 7d4a820ca..dc581b60b 100644 --- a/MyTracksTest_E2E/src/com/google/android/apps/mytracks/endtoendtest/common/SettingTest.java +++ b/MyTracksTest_E2E/src/com/google/android/apps/mytracks/endtoendtest/common/SettingTest.java @@ -80,7 +80,7 @@ public class SettingTest extends ActivityInstrumentationTestCase2