aboutsummaryrefslogtreecommitdiffstats
path: root/main/src
diff options
context:
space:
mode:
Diffstat (limited to 'main/src')
-rw-r--r--main/src/android/support/v4/app/FragmentListActivity.java316
-rw-r--r--main/src/cgeo/geocaching/AboutActivity.java80
-rw-r--r--main/src/cgeo/geocaching/AbstractLoggingActivity.java22
-rw-r--r--main/src/cgeo/geocaching/AbstractPopupActivity.java60
-rw-r--r--main/src/cgeo/geocaching/AddressListActivity.java6
-rw-r--r--main/src/cgeo/geocaching/CacheDetailActivity.java619
-rw-r--r--main/src/cgeo/geocaching/CachePopup.java10
-rw-r--r--main/src/cgeo/geocaching/CompassActivity.java (renamed from main/src/cgeo/geocaching/cgeonavigate.java)190
-rw-r--r--main/src/cgeo/geocaching/DirectionProvider.java7
-rw-r--r--main/src/cgeo/geocaching/EditWaypointActivity.java300
-rw-r--r--main/src/cgeo/geocaching/Geocache.java116
-rw-r--r--main/src/cgeo/geocaching/GpxFileListActivity.java7
-rw-r--r--main/src/cgeo/geocaching/ImageSelectActivity.java97
-rw-r--r--main/src/cgeo/geocaching/ImagesActivity.java20
-rw-r--r--main/src/cgeo/geocaching/Intents.java4
-rw-r--r--main/src/cgeo/geocaching/LogCacheActivity.java (renamed from main/src/cgeo/geocaching/VisitCacheActivity.java)259
-rw-r--r--main/src/cgeo/geocaching/LogTrackableActivity.java53
-rw-r--r--main/src/cgeo/geocaching/LogViewHolder.java46
-rw-r--r--main/src/cgeo/geocaching/MainActivity.java (renamed from main/src/cgeo/geocaching/cgeo.java)217
-rw-r--r--main/src/cgeo/geocaching/NavigateAnyPointActivity.java171
-rw-r--r--main/src/cgeo/geocaching/SearchActivity.java113
-rw-r--r--main/src/cgeo/geocaching/SearchResult.java6
-rw-r--r--main/src/cgeo/geocaching/SelectMapfileActivity.java5
-rw-r--r--main/src/cgeo/geocaching/Settings.java121
-rw-r--r--main/src/cgeo/geocaching/SettingsActivity.java47
-rw-r--r--main/src/cgeo/geocaching/StaticMapsActivity.java69
-rw-r--r--main/src/cgeo/geocaching/StaticMapsProvider.java27
-rw-r--r--main/src/cgeo/geocaching/StoredList.java45
-rw-r--r--main/src/cgeo/geocaching/Trackable.java23
-rw-r--r--main/src/cgeo/geocaching/TrackableActivity.java207
-rw-r--r--main/src/cgeo/geocaching/UsefulAppsActivity.java124
-rw-r--r--main/src/cgeo/geocaching/Waypoint.java3
-rw-r--r--main/src/cgeo/geocaching/WaypointPopup.java37
-rw-r--r--main/src/cgeo/geocaching/activity/AbstractActivity.java66
-rw-r--r--main/src/cgeo/geocaching/activity/AbstractListActivity.java34
-rw-r--r--main/src/cgeo/geocaching/activity/AbstractViewPagerActivity.java26
-rw-r--r--main/src/cgeo/geocaching/activity/ActivityMixin.java24
-rw-r--r--main/src/cgeo/geocaching/activity/IAbstractActivity.java2
-rw-r--r--main/src/cgeo/geocaching/apps/AbstractApp.java8
-rw-r--r--main/src/cgeo/geocaching/apps/cache/navi/CompassApp.java8
-rw-r--r--main/src/cgeo/geocaching/apps/cache/navi/GoogleMapsApp.java2
-rw-r--r--main/src/cgeo/geocaching/apps/cache/navi/GoogleMapsDirectionApp.java2
-rw-r--r--main/src/cgeo/geocaching/apps/cache/navi/GoogleNavigationApp.java16
-rw-r--r--main/src/cgeo/geocaching/apps/cache/navi/NavigationAppFactory.java33
-rw-r--r--main/src/cgeo/geocaching/apps/cache/navi/StreetviewApp.java8
-rw-r--r--main/src/cgeo/geocaching/cgData.java52
-rw-r--r--main/src/cgeo/geocaching/cgeoapplication.java4
-rw-r--r--main/src/cgeo/geocaching/cgeocaches.java240
-rw-r--r--main/src/cgeo/geocaching/compatibility/AndroidLevel8Emulation.java4
-rw-r--r--main/src/cgeo/geocaching/connector/AbstractConnector.java54
-rw-r--r--main/src/cgeo/geocaching/connector/ConnectorFactory.java71
-rw-r--r--main/src/cgeo/geocaching/connector/IConnector.java64
-rw-r--r--main/src/cgeo/geocaching/connector/ILoggingManager.java32
-rw-r--r--main/src/cgeo/geocaching/connector/ImageResult.java23
-rw-r--r--main/src/cgeo/geocaching/connector/LogResult.java23
-rw-r--r--main/src/cgeo/geocaching/connector/NoLoggingManager.java46
-rw-r--r--main/src/cgeo/geocaching/connector/UnknownConnector.java3
-rw-r--r--main/src/cgeo/geocaching/connector/WaymarkingConnector.java40
-rw-r--r--main/src/cgeo/geocaching/connector/gc/GCConnector.java58
-rw-r--r--main/src/cgeo/geocaching/connector/gc/GCConstants.java11
-rw-r--r--main/src/cgeo/geocaching/connector/gc/GCLoggingManager.java132
-rw-r--r--main/src/cgeo/geocaching/connector/gc/GCMap.java12
-rw-r--r--main/src/cgeo/geocaching/connector/gc/GCParser.java339
-rw-r--r--main/src/cgeo/geocaching/connector/gc/Login.java76
-rw-r--r--main/src/cgeo/geocaching/connector/gc/SearchHandler.java2
-rw-r--r--main/src/cgeo/geocaching/connector/gc/Tile.java2
-rw-r--r--main/src/cgeo/geocaching/connector/oc/AttributeParser.java327
-rw-r--r--main/src/cgeo/geocaching/connector/oc/OC11XMLParser.java754
-rw-r--r--main/src/cgeo/geocaching/connector/oc/OCApiConnector.java41
-rw-r--r--main/src/cgeo/geocaching/connector/oc/OCApiLiveConnector.java119
-rw-r--r--main/src/cgeo/geocaching/connector/oc/OCAuthorizationActivity.java109
-rw-r--r--main/src/cgeo/geocaching/connector/oc/OCConnector.java9
-rw-r--r--main/src/cgeo/geocaching/connector/oc/OCXMLApiConnector.java67
-rw-r--r--main/src/cgeo/geocaching/connector/oc/OCXMLClient.java115
-rw-r--r--main/src/cgeo/geocaching/connector/oc/OkapiClient.java518
-rw-r--r--main/src/cgeo/geocaching/connector/oc/OkapiLoggingManager.java68
-rw-r--r--main/src/cgeo/geocaching/connector/oc/OkapiService.java21
-rw-r--r--main/src/cgeo/geocaching/connector/trackable/AbstractTrackableConnector.java10
-rw-r--r--main/src/cgeo/geocaching/connector/trackable/GeokretyConnector.java42
-rw-r--r--main/src/cgeo/geocaching/connector/trackable/GeokretyParser.java82
-rw-r--r--main/src/cgeo/geocaching/connector/trackable/TrackableConnector.java19
-rw-r--r--main/src/cgeo/geocaching/connector/trackable/TravelBugConnector.java34
-rw-r--r--main/src/cgeo/geocaching/connector/trackable/UnknownTrackableConnector.java24
-rw-r--r--main/src/cgeo/geocaching/enumerations/CacheAttribute.java30
-rw-r--r--main/src/cgeo/geocaching/enumerations/CacheRealm.java22
-rw-r--r--main/src/cgeo/geocaching/enumerations/CacheType.java14
-rw-r--r--main/src/cgeo/geocaching/enumerations/LogType.java62
-rw-r--r--main/src/cgeo/geocaching/enumerations/WaypointType.java4
-rw-r--r--main/src/cgeo/geocaching/export/AbstractExport.java7
-rw-r--r--main/src/cgeo/geocaching/export/FieldnoteExport.java86
-rw-r--r--main/src/cgeo/geocaching/export/GpxExport.java275
-rw-r--r--main/src/cgeo/geocaching/export/GpxSerializer.java256
-rw-r--r--main/src/cgeo/geocaching/files/AbstractFileListActivity.java6
-rw-r--r--main/src/cgeo/geocaching/files/FileParser.java12
-rw-r--r--main/src/cgeo/geocaching/files/GPXImporter.java948
-rw-r--r--main/src/cgeo/geocaching/files/GPXParser.java71
-rw-r--r--main/src/cgeo/geocaching/files/LocParser.java35
-rw-r--r--main/src/cgeo/geocaching/files/LocalStorage.java19
-rw-r--r--main/src/cgeo/geocaching/files/SimpleDirChooser.java20
-rw-r--r--main/src/cgeo/geocaching/filter/AttributeFilter.java23
-rw-r--r--main/src/cgeo/geocaching/filter/DifficultyFilter.java5
-rw-r--r--main/src/cgeo/geocaching/filter/FilterUserInterface.java9
-rw-r--r--main/src/cgeo/geocaching/filter/IFilterFactory.java4
-rw-r--r--main/src/cgeo/geocaching/filter/ModifiedFilter.java7
-rw-r--r--main/src/cgeo/geocaching/filter/OriginFilter.java5
-rw-r--r--main/src/cgeo/geocaching/filter/SizeFilter.java9
-rw-r--r--main/src/cgeo/geocaching/filter/StateFilter.java31
-rw-r--r--main/src/cgeo/geocaching/filter/TerrainFilter.java8
-rw-r--r--main/src/cgeo/geocaching/filter/TrackablesFilter.java9
-rw-r--r--main/src/cgeo/geocaching/filter/TypeFilter.java9
-rw-r--r--main/src/cgeo/geocaching/gcvote/GCVote.java7
-rw-r--r--main/src/cgeo/geocaching/geopoint/Geopoint.java4
-rw-r--r--main/src/cgeo/geocaching/loaders/CoordsGeocacheListLoader.java6
-rw-r--r--main/src/cgeo/geocaching/loaders/UrlLoader.java2
-rw-r--r--main/src/cgeo/geocaching/maps/AbstractMap.java2
-rw-r--r--main/src/cgeo/geocaching/maps/CGeoMap.java152
-rw-r--r--main/src/cgeo/geocaching/maps/CachesOverlay.java33
-rw-r--r--main/src/cgeo/geocaching/maps/MapProviderFactory.java9
-rw-r--r--main/src/cgeo/geocaching/maps/PositionOverlay.java11
-rw-r--r--main/src/cgeo/geocaching/maps/google/GoogleCacheOverlay.java4
-rw-r--r--main/src/cgeo/geocaching/maps/google/GoogleCacheOverlayItem.java11
-rw-r--r--main/src/cgeo/geocaching/maps/google/GoogleMapActivity.java11
-rw-r--r--main/src/cgeo/geocaching/maps/google/GoogleMapItemFactory.java5
-rw-r--r--main/src/cgeo/geocaching/maps/interfaces/CachesOverlayItemImpl.java4
-rw-r--r--main/src/cgeo/geocaching/maps/interfaces/MapActivityImpl.java2
-rw-r--r--main/src/cgeo/geocaching/maps/interfaces/MapItemFactory.java3
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/MapsforgeCacheOverlay.java4
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/MapsforgeCacheOverlayItem.java15
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapActivity.java11
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapItemFactory.java5
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapProvider.java4
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeCacheOverlay.java4
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeCacheOverlayItem.java15
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapActivity024.java6
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapItemFactory024.java5
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapView024.java4
-rw-r--r--main/src/cgeo/geocaching/network/HtmlImage.java31
-rw-r--r--main/src/cgeo/geocaching/network/Network.java26
-rw-r--r--main/src/cgeo/geocaching/network/OAuth.java16
-rw-r--r--main/src/cgeo/geocaching/network/OAuthAuthorizationActivity.java326
-rw-r--r--main/src/cgeo/geocaching/network/StatusUpdater.java13
-rw-r--r--main/src/cgeo/geocaching/speech/SpeechService.java188
-rw-r--r--main/src/cgeo/geocaching/speech/TextFactory.java101
-rw-r--r--main/src/cgeo/geocaching/twitter/Twitter.java72
-rw-r--r--main/src/cgeo/geocaching/twitter/TwitterAuthorizationActivity.java305
-rw-r--r--main/src/cgeo/geocaching/ui/AbstractUserClickListener.java77
-rw-r--r--main/src/cgeo/geocaching/ui/AbstractViewHolder.java19
-rw-r--r--main/src/cgeo/geocaching/ui/AddressListAdapter.java21
-rw-r--r--main/src/cgeo/geocaching/ui/CacheDetailsCreator.java23
-rw-r--r--main/src/cgeo/geocaching/ui/CacheListAdapter.java63
-rw-r--r--main/src/cgeo/geocaching/ui/CompassView.java77
-rw-r--r--main/src/cgeo/geocaching/ui/CoordinatesFormatSwitcher.java38
-rw-r--r--main/src/cgeo/geocaching/ui/DecryptTextClickListener.java6
-rw-r--r--main/src/cgeo/geocaching/ui/EditNoteDialog.java70
-rw-r--r--main/src/cgeo/geocaching/ui/FileSelectionListAdapter.java30
-rw-r--r--main/src/cgeo/geocaching/ui/GPXListAdapter.java32
-rw-r--r--main/src/cgeo/geocaching/ui/ImagesList.java54
-rw-r--r--main/src/cgeo/geocaching/ui/LoggingUI.java42
-rw-r--r--main/src/cgeo/geocaching/ui/OwnerActionsClickListener.java28
-rw-r--r--main/src/cgeo/geocaching/ui/UserActionsClickListener.java22
-rw-r--r--main/src/cgeo/geocaching/ui/dialog/CoordinatesInputDialog.java54
-rw-r--r--main/src/cgeo/geocaching/ui/dialog/CustomProgressDialog.java2
-rw-r--r--main/src/cgeo/geocaching/ui/dialog/DateDialog.java12
-rw-r--r--main/src/cgeo/geocaching/ui/dialog/EditorDialog.java60
-rw-r--r--main/src/cgeo/geocaching/ui/dialog/NoTitleDialog.java30
-rw-r--r--main/src/cgeo/geocaching/utils/AngleUtils.java4
-rw-r--r--main/src/cgeo/geocaching/utils/AsyncTaskWithProgress.java139
-rw-r--r--main/src/cgeo/geocaching/utils/ClipboardUtils.java8
-rw-r--r--main/src/cgeo/geocaching/utils/CryptUtils.java62
-rw-r--r--main/src/cgeo/geocaching/utils/DateUtils.java7
-rw-r--r--main/src/cgeo/geocaching/utils/EditUtils.java4
-rw-r--r--main/src/cgeo/geocaching/utils/FileUtils.java8
-rw-r--r--main/src/cgeo/geocaching/utils/GeoDirHandler.java22
-rw-r--r--main/src/cgeo/geocaching/utils/HtmlUtils.java9
-rw-r--r--main/src/cgeo/geocaching/utils/ImageUtils.java (renamed from main/src/cgeo/geocaching/utils/ImageHelper.java)44
-rw-r--r--main/src/cgeo/geocaching/utils/LeastRecentlyUsedSet.java6
-rw-r--r--main/src/cgeo/geocaching/utils/Log.java7
-rw-r--r--main/src/cgeo/geocaching/utils/LogTemplateProvider.java2
-rw-r--r--main/src/cgeo/geocaching/utils/PeriodicHandler.java33
-rw-r--r--main/src/cgeo/geocaching/utils/ProcessUtils.java29
-rw-r--r--main/src/cgeo/geocaching/utils/TextUtils.java (renamed from main/src/cgeo/geocaching/utils/BaseUtils.java)17
-rw-r--r--main/src/cgeo/geocaching/utils/TranslationUtils.java4
-rw-r--r--main/src/cgeo/geocaching/utils/XmlUtils.java2
-rw-r--r--main/src/cgeo/org/kxml2/io/KXmlSerializer.java605
-rw-r--r--main/src/com/viewpagerindicator/PageIndicator.java63
-rw-r--r--main/src/com/viewpagerindicator/TitlePageIndicator.java771
-rw-r--r--main/src/com/viewpagerindicator/TitleProvider.java28
-rw-r--r--main/src/gnu/android/app/appmanualclient/AppManualReaderClient.java375
-rw-r--r--main/src/org/openintents/intents/FileManagerIntents.java127
189 files changed, 6746 insertions, 7096 deletions
diff --git a/main/src/android/support/v4/app/FragmentListActivity.java b/main/src/android/support/v4/app/FragmentListActivity.java
deleted file mode 100644
index e3ed42c..0000000
--- a/main/src/android/support/v4/app/FragmentListActivity.java
+++ /dev/null
@@ -1,316 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * 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 android.support.v4.app;
-
-import android.os.Bundle;
-import android.os.Handler;
-import android.view.View;
-import android.widget.AdapterView;
-import android.widget.ListAdapter;
-import android.widget.ListView;
-
-/**
- * An activity that displays a list of items by binding to a data source such as
- * an array or Cursor, and exposes event handlers when the user selects an item.
- * <p>
- * FragmentListActivity hosts a {@link android.widget.ListView ListView} object that can
- * be bound to different data sources, typically either an array or a Cursor
- * holding query results. Binding, screen layout, and row layout are discussed
- * in the following sections.
- * <p>
- * <strong>Screen Layout</strong>
- * </p>
- * <p>
- * FragmentListActivity has a default layout that consists of a single, full-screen list
- * in the center of the screen. However, if you desire, you can customize the
- * screen layout by setting your own view layout with setContentView() in
- * onCreate(). To do this, your own view MUST contain a ListView object with the
- * id "@android:id/list" (or {@link android.R.id#list} if it's in code)
- * <p>
- * Optionally, your custom view can contain another view object of any type to
- * display when the list view is empty. This "empty list" notifier must have an
- * id "android:empty". Note that when an empty view is present, the list view
- * will be hidden when there is no data to display.
- * <p>
- * The following code demonstrates an (ugly) custom screen layout. It has a list
- * with a green background, and an alternate red "no data" message.
- * </p>
- *
- * <pre>
- * &lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
- * &lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- * android:orientation=&quot;vertical&quot;
- * android:layout_width=&quot;fill_parent&quot;
- * android:layout_height=&quot;fill_parent&quot;
- * android:paddingLeft=&quot;8dp&quot;
- * android:paddingRight=&quot;8dp&quot;&gt;
- *
- * &lt;ListView android:id=&quot;@id/android:list&quot;
- * android:layout_width=&quot;fill_parent&quot;
- * android:layout_height=&quot;fill_parent&quot;
- * android:background=&quot;#00FF00&quot;
- * android:layout_weight=&quot;1&quot;
- * android:drawSelectorOnTop=&quot;false&quot;/&gt;
- *
- * &lt;TextView android:id=&quot;@id/android:empty&quot;
- * android:layout_width=&quot;fill_parent&quot;
- * android:layout_height=&quot;fill_parent&quot;
- * android:background=&quot;#FF0000&quot;
- * android:text=&quot;No data&quot;/&gt;
- * &lt;/LinearLayout&gt;
- * </pre>
- *
- * <p>
- * <strong>Row Layout</strong>
- * </p>
- * <p>
- * You can specify the layout of individual rows in the list. You do this by
- * specifying a layout resource in the ListAdapter object hosted by the activity
- * (the ListAdapter binds the ListView to the data; more on this later).
- * <p>
- * A ListAdapter constructor takes a parameter that specifies a layout resource
- * for each row. It also has two additional parameters that let you specify
- * which data field to associate with which object in the row layout resource.
- * These two parameters are typically parallel arrays.
- * </p>
- * <p>
- * Android provides some standard row layout resources. These are in the
- * {@link android.R.layout} class, and have names such as simple_list_item_1,
- * simple_list_item_2, and two_line_list_item. The following layout XML is the
- * source for the resource two_line_list_item, which displays two data
- * fields,one above the other, for each list row.
- * </p>
- *
- * <pre>
- * &lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
- * &lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- * android:layout_width=&quot;fill_parent&quot;
- * android:layout_height=&quot;wrap_content&quot;
- * android:orientation=&quot;vertical&quot;&gt;
- *
- * &lt;TextView android:id=&quot;@+id/text1&quot;
- * android:textSize=&quot;16sp&quot;
- * android:textStyle=&quot;bold&quot;
- * android:layout_width=&quot;fill_parent&quot;
- * android:layout_height=&quot;wrap_content&quot;/&gt;
- *
- * &lt;TextView android:id=&quot;@+id/text2&quot;
- * android:textSize=&quot;16sp&quot;
- * android:layout_width=&quot;fill_parent&quot;
- * android:layout_height=&quot;wrap_content&quot;/&gt;
- * &lt;/LinearLayout&gt;
- * </pre>
- *
- * <p>
- * You must identify the data bound to each TextView object in this layout. The
- * syntax for this is discussed in the next section.
- * </p>
- * <p>
- * <strong>Binding to Data</strong>
- * </p>
- * <p>
- * You bind the FragmentListActivity's ListView object to data using a class that
- * implements the {@link android.widget.ListAdapter ListAdapter} interface.
- * Android provides two standard list adapters:
- * {@link android.widget.SimpleAdapter SimpleAdapter} for static data (Maps),
- * and {@link android.widget.SimpleCursorAdapter SimpleCursorAdapter} for Cursor
- * query results.
- * </p>
- * <p>
- * The following code from a custom FragmentListActivity demonstrates querying the
- * Contacts provider for all contacts, then binding the Name and Company fields
- * to a two line row layout in the activity's ListView.
- * </p>
- *
- * <pre>
- * public class MyListAdapter extends FragmentListActivity {
- *
- * &#064;Override
- * protected void onCreate(Bundle savedInstanceState){
- * super.onCreate(savedInstanceState);
- *
- * // We'll define a custom screen layout here (the one shown above), but
- * // typically, you could just use the standard FragmentListActivity layout.
- * setContentView(R.layout.custom_list_activity_view);
- *
- * // Query for all people contacts using the {@link android.provider.Contacts.People} convenience class.
- * // Put a managed wrapper around the retrieved cursor so we don't have to worry about
- * // requerying or closing it as the activity changes state.
- * mCursor = this.getContentResolver().query(People.CONTENT_URI, null, null, null, null);
- * startManagingCursor(mCursor);
- *
- * // Now create a new list adapter bound to the cursor.
- * // SimpleListAdapter is designed for binding to a Cursor.
- * ListAdapter adapter = new SimpleCursorAdapter(
- * this, // Context.
- * android.R.layout.two_line_list_item, // Specify the row template to use (here, two columns bound to the two retrieved cursor
- * rows).
- * mCursor, // Pass in the cursor to bind to.
- * new String[] {People.NAME, People.COMPANY}, // Array of cursor columns to bind to.
- * new int[] {android.R.id.text1, android.R.id.text2}); // Parallel array of which template objects to bind to those columns.
- *
- * // Bind to our new adapter.
- * setListAdapter(adapter);
- * }
- * }
- * </pre>
- *
- * @see #setListAdapter
- * @see android.widget.ListView
- */
-public class FragmentListActivity extends FragmentActivity {
- /**
- * This field should be made private, so it is hidden from the SDK.
- * {@hide}
- */
- protected ListAdapter mAdapter;
- /**
- * This field should be made private, so it is hidden from the SDK.
- * {@hide}
- */
- protected ListView mList;
-
- private Handler mHandler = new Handler();
- private boolean mFinishedStart = false;
-
- private Runnable mRequestFocus = new Runnable() {
- @Override
- public void run() {
- mList.focusableViewAvailable(mList);
- }
- };
-
- /**
- * This method will be called when an item in the list is selected.
- * Subclasses should override. Subclasses can call
- * getListView().getItemAtPosition(position) if they need to access the
- * data associated with the selected item.
- *
- * @param l The ListView where the click happened
- * @param v The view that was clicked within the ListView
- * @param position The position of the view in the list
- * @param id The row id of the item that was clicked
- */
- protected void onListItemClick(ListView l, View v, int position, long id) {
- }
-
- /**
- * Ensures the list view has been created before Activity restores all
- * of the view states.
- *
- *@see Activity#onRestoreInstanceState(Bundle)
- */
- @Override
- protected void onRestoreInstanceState(Bundle state) {
- ensureList();
- super.onRestoreInstanceState(state);
- }
-
- /**
- * Updates the screen state (current list and other views) when the
- * content changes.
- *
- * @see Activity#onContentChanged()
- */
- @Override
- public void onContentChanged() {
- super.onContentChanged();
- View emptyView = findViewById(android.R.id.empty);
- mList = (ListView)findViewById(android.R.id.list);
- if (mList == null) {
- throw new RuntimeException(
- "Your content must have a ListView whose id attribute is " +
- "'android.R.id.list'");
- }
- if (emptyView != null) {
- mList.setEmptyView(emptyView);
- }
- mList.setOnItemClickListener(mOnClickListener);
- if (mFinishedStart) {
- setListAdapter(mAdapter);
- }
- mHandler.post(mRequestFocus);
- mFinishedStart = true;
- }
-
- /**
- * Provide the cursor for the list view.
- */
- public void setListAdapter(ListAdapter adapter) {
- synchronized (this) {
- ensureList();
- mAdapter = adapter;
- mList.setAdapter(adapter);
- }
- }
-
- /**
- * Set the currently selected list item to the specified
- * position with the adapter's data
- *
- * @param position
- */
- public void setSelection(int position) {
- mList.setSelection(position);
- }
-
- /**
- * Get the position of the currently selected list item.
- */
- public int getSelectedItemPosition() {
- return mList.getSelectedItemPosition();
- }
-
- /**
- * Get the cursor row ID of the currently selected list item.
- */
- public long getSelectedItemId() {
- return mList.getSelectedItemId();
- }
-
- /**
- * Get the activity's list view widget.
- */
- public ListView getListView() {
- ensureList();
- return mList;
- }
-
- /**
- * Get the ListAdapter associated with this activity's ListView.
- */
- public ListAdapter getListAdapter() {
- return mAdapter;
- }
-
- private void ensureList() {
- if (mList != null) {
- return;
- }
- setContentView(android.R.layout.list_content);
-
- }
-
- private AdapterView.OnItemClickListener mOnClickListener = new AdapterView.OnItemClickListener() {
- @Override
- public void onItemClick(AdapterView<?> parent, View v, int position, long id)
- {
- onListItemClick((ListView)parent, v, position, id);
- }
- };
-}
-
diff --git a/main/src/cgeo/geocaching/AboutActivity.java b/main/src/cgeo/geocaching/AboutActivity.java
index c154ffb..f947655 100644
--- a/main/src/cgeo/geocaching/AboutActivity.java
+++ b/main/src/cgeo/geocaching/AboutActivity.java
@@ -1,75 +1,73 @@
package cgeo.geocaching;
import cgeo.geocaching.activity.AbstractActivity;
+import cgeo.geocaching.ui.AnchorAwareLinkMovementMethod;
import cgeo.geocaching.utils.Version;
+import com.googlecode.androidannotations.annotations.AfterViews;
+import com.googlecode.androidannotations.annotations.Click;
+import com.googlecode.androidannotations.annotations.EActivity;
+import com.googlecode.androidannotations.annotations.ViewById;
+
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
-import android.text.method.LinkMovementMethod;
-import android.view.View;
import android.widget.TextView;
+@EActivity
public class AboutActivity extends AbstractActivity {
+ @ViewById(R.id.about_version_string) protected TextView version;
+ @ViewById(R.id.contributors) protected TextView contributors;
+ @ViewById(R.id.changelog) protected TextView changeLog;
@Override
public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- setTheme();
- setContentView(R.layout.about_activity);
- setTitle(res.getString(R.string.about));
+ // TODO remove this after the theme has been fixed
+ super.onCreate(savedInstanceState, R.layout.about_activity);
+ }
- ((TextView) findViewById(R.id.about_version_string)).setText(Version.getVersionName(this));
- ((TextView) findViewById(R.id.contributors)).setMovementMethod(LinkMovementMethod.getInstance());
- ((TextView) findViewById(R.id.changelog)).setMovementMethod(LinkMovementMethod.getInstance());
+ @AfterViews
+ void initializeViews() {
+ version.setText(Version.getVersionName(this));
+ contributors.setMovementMethod(AnchorAwareLinkMovementMethod.getInstance());
+ changeLog.setMovementMethod(AnchorAwareLinkMovementMethod.getInstance());
}
- /**
- * @param view
- * unused here but needed since this method is referenced from XML layout
- */
- public void donate(View view) {
+ @Click(R.id.donate)
+ public void donate() {
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=FMLNN8GXZKJEE")));
}
- /**
- * @param view
- * unused here but needed since this method is referenced from XML layout
- */
- public void support(View view) {
+ @Click(R.id.support)
+ public void support() {
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("mailto:support@cgeo.org")));
}
- /**
- * @param view
- * unused here but needed since this method is referenced from XML layout
- */
- public void website(View view) {
+
+ @Click(R.id.website)
+ void webSite() {
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.cgeo.org/")));
}
- /**
- * @param view
- * unused here but needed since this method is referenced from XML layout
- */
- public void facebook(View view) {
+ @Click(R.id.facebook)
+ public void facebook() {
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.facebook.com/pages/cgeo/297269860090")));
}
- /**
- * @param view
- * unused here but needed since this method is referenced from XML layout
- */
- public void twitter(View view) {
+ @Click(R.id.twitter)
+ public void twitter() {
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://twitter.com/android_gc")));
}
- /**
- * @param view
- * unused here but needed since this method is referenced from XML layout
- */
- public void nutshellmanual(View view) {
- startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.cgeo.org/")));
+ @Click(R.id.nutshellmanual)
+ public void nutshellmanual() {
+ startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://manual.cgeo.org/")));
+ }
+
+ @Click(R.id.market)
+ public void market() {
+ final Intent marketIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + getPackageName()));
+ marketIntent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY | Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
+ startActivity(marketIntent);
}
}
diff --git a/main/src/cgeo/geocaching/AbstractLoggingActivity.java b/main/src/cgeo/geocaching/AbstractLoggingActivity.java
index 37c3643..78da757 100644
--- a/main/src/cgeo/geocaching/AbstractLoggingActivity.java
+++ b/main/src/cgeo/geocaching/AbstractLoggingActivity.java
@@ -17,27 +17,17 @@ import android.view.SubMenu;
import android.widget.EditText;
public abstract class AbstractLoggingActivity extends AbstractActivity {
- private static final int MENU_SIGNATURE = 1;
- private static final int MENU_SMILEY = 2;
-
- protected AbstractLoggingActivity(String helpTopic) {
- super(helpTopic);
- }
@Override
public boolean onCreateOptionsMenu(final Menu menu) {
- // signature menu
- menu.add(0, MENU_SIGNATURE, 0, res.getString(R.string.init_signature)).setIcon(R.drawable.ic_menu_edit);
+ getMenuInflater().inflate(R.menu.abstract_logging_activity, menu);
- // templates menu
- final SubMenu menuLog = menu.addSubMenu(0, 0, 0, res.getString(R.string.log_add)).setIcon(R.drawable.ic_menu_add);
+ final SubMenu menuLog = menu.findItem(R.id.menu_templates).getSubMenu();
for (LogTemplate template : LogTemplateProvider.getTemplates()) {
menuLog.add(0, template.getItemId(), 0, template.getResourceId());
}
- menuLog.add(0, MENU_SIGNATURE, 0, res.getString(R.string.init_signature));
- // smilies
- final SubMenu menuSmilies = menu.addSubMenu(0, MENU_SMILEY, 0, res.getString(R.string.log_smilies)).setIcon(R.drawable.ic_menu_emoticons);
+ final SubMenu menuSmilies = menu.findItem(R.id.menu_smilies).getSubMenu();
for (Smiley smiley : GCSmiliesProvider.getSmilies()) {
menuSmilies.add(0, smiley.getItemId(), 0, smiley.text);
}
@@ -48,7 +38,7 @@ public abstract class AbstractLoggingActivity extends AbstractActivity {
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
final boolean signatureAvailable = StringUtils.isNotBlank(Settings.getSignature());
- menu.findItem(MENU_SIGNATURE).setVisible(signatureAvailable);
+ menu.findItem(R.id.menu_signature).setVisible(signatureAvailable);
boolean smileyVisible = false;
final Geocache cache = getLogContext().getCache();
@@ -60,7 +50,7 @@ public abstract class AbstractLoggingActivity extends AbstractActivity {
smileyVisible = true;
}
- menu.findItem(MENU_SMILEY).setVisible(smileyVisible);
+ menu.findItem(R.id.menu_smilies).setVisible(smileyVisible);
return true;
}
@@ -69,7 +59,7 @@ public abstract class AbstractLoggingActivity extends AbstractActivity {
public boolean onOptionsItemSelected(MenuItem item) {
final int id = item.getItemId();
- if (id == MENU_SIGNATURE) {
+ if (id == R.id.menu_signature) {
insertIntoLog(LogTemplateProvider.applyTemplates(Settings.getSignature(), getLogContext()), true);
return true;
}
diff --git a/main/src/cgeo/geocaching/AbstractPopupActivity.java b/main/src/cgeo/geocaching/AbstractPopupActivity.java
index f903d00..64e5539 100644
--- a/main/src/cgeo/geocaching/AbstractPopupActivity.java
+++ b/main/src/cgeo/geocaching/AbstractPopupActivity.java
@@ -34,11 +34,6 @@ import android.widget.TextView;
public abstract class AbstractPopupActivity extends AbstractActivity {
- private static final int MENU_CACHES_AROUND = 5;
- private static final int MENU_NAVIGATION = 3;
- private static final int MENU_DEFAULT_NAVIGATION = 2;
- private static final int MENU_SHOW_IN_BROWSER = 7;
-
protected Geocache cache = null;
protected String geocode = null;
protected CacheDetailsCreator details;
@@ -52,7 +47,7 @@ public abstract class AbstractPopupActivity extends AbstractActivity {
public void handleMessage(Message msg) {
try {
details.addRating(cache);
- } catch (Exception e) {
+ } catch (final Exception e) {
// nothing
}
}
@@ -67,14 +62,24 @@ public abstract class AbstractPopupActivity extends AbstractActivity {
cacheDistance.setText(Units.getDistanceFromKilometers(geo.getCoords().distanceTo(cache.getCoords())));
cacheDistance.bringToFront();
}
- } catch (Exception e) {
+ onUpdateGeoData(geo);
+ } catch (final Exception e) {
Log.w("Failed to UpdateLocation location.");
}
}
};
- protected AbstractPopupActivity(String helpTopic, int layout) {
- super(helpTopic);
+ /**
+ * Callback to run when new location information is available.
+ * This may be overridden by deriving classes. The default implementation does nothing.
+ *
+ * @param geo
+ * the new data
+ */
+ public void onUpdateGeoData(final IGeoData geo) {
+ }
+
+ protected AbstractPopupActivity(int layout) {
this.layout = layout;
}
@@ -102,12 +107,6 @@ public abstract class AbstractPopupActivity extends AbstractActivity {
}).start();
}
- @Override
- public void goManual(View view) {
- super.goManual(view);
- finish();
- }
-
protected void init() {
cache = cgData.loadCache(geocode, LoadFlags.LOAD_CACHE_OR_DB);
@@ -134,7 +133,6 @@ public abstract class AbstractPopupActivity extends AbstractActivity {
this.setTheme(ActivityMixin.getDialogTheme());
// set layout
setContentView(layout);
- setTitle(res.getString(R.string.detail));
// get parameters
final Bundle extras = getIntent().getExtras();
@@ -162,12 +160,7 @@ public abstract class AbstractPopupActivity extends AbstractActivity {
@Override
public boolean onCreateOptionsMenu(Menu menu) {
- menu.add(0, MENU_DEFAULT_NAVIGATION, 0, NavigationAppFactory.getDefaultNavigationApplication().getName()).setIcon(R.drawable.ic_menu_compass); // default navigation tool
- menu.add(0, MENU_NAVIGATION, 0, res.getString(R.string.cache_menu_navigate)).setIcon(R.drawable.ic_menu_mapmode);
- LoggingUI.addMenuItems(menu, cache);
- menu.add(0, MENU_CACHES_AROUND, 0, res.getString(R.string.cache_menu_around)).setIcon(R.drawable.ic_menu_rotate); // caches around
- menu.add(0, MENU_SHOW_IN_BROWSER, 0, res.getString(R.string.cache_menu_browser)).setIcon(R.drawable.ic_menu_info_details); // browser
-
+ getMenuInflater().inflate(R.menu.abstract_popup_activity, menu);
return true;
}
@@ -176,16 +169,16 @@ public abstract class AbstractPopupActivity extends AbstractActivity {
final int menuItem = item.getItemId();
switch (menuItem) {
- case MENU_DEFAULT_NAVIGATION:
+ case R.id.menu_default_navigation:
navigateTo();
return true;
- case MENU_NAVIGATION:
+ case R.id.menu_navigate:
showNavigationMenu();
return true;
- case MENU_CACHES_AROUND:
+ case R.id.menu_caches_around:
cachesAround();
return true;
- case MENU_SHOW_IN_BROWSER:
+ case R.id.menu_show_in_browser:
showInBrowser();
return true;
default:
@@ -209,12 +202,13 @@ public abstract class AbstractPopupActivity extends AbstractActivity {
try {
final boolean visible = getCoordinates() != null;
- menu.findItem(MENU_DEFAULT_NAVIGATION).setVisible(visible);
- menu.findItem(MENU_NAVIGATION).setVisible(visible);
- menu.findItem(MENU_CACHES_AROUND).setVisible(visible);
+ menu.findItem(R.id.menu_default_navigation).setVisible(visible);
+ menu.findItem(R.id.menu_navigate).setVisible(visible);
+ menu.findItem(R.id.menu_caches_around).setVisible(visible);
- LoggingUI.onPrepareOptionsMenu(menu);
- } catch (Exception e) {
+ menu.findItem(R.id.menu_default_navigation).setTitle(NavigationAppFactory.getDefaultNavigationApplication().getName());
+ LoggingUI.onPrepareOptionsMenu(menu, cache);
+ } catch (final Exception e) {
// nothing
}
@@ -269,8 +263,8 @@ public abstract class AbstractPopupActivity extends AbstractActivity {
aquireGCVote();
}
- // favourite count
- details.add(R.string.cache_favourite, cache.getFavoritePoints() + "×");
+ // favorite count
+ details.add(R.string.cache_favorite, cache.getFavoritePoints() + "×");
// more details
final Button buttonMore = (Button) findViewById(R.id.more_details);
diff --git a/main/src/cgeo/geocaching/AddressListActivity.java b/main/src/cgeo/geocaching/AddressListActivity.java
index b1de065..c984d28 100644
--- a/main/src/cgeo/geocaching/AddressListActivity.java
+++ b/main/src/cgeo/geocaching/AddressListActivity.java
@@ -20,11 +20,7 @@ public class AddressListActivity extends AbstractListActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- setTheme();
- setContentView(R.layout.addresses);
- setTitle(res.getString(R.string.search_address_result));
+ super.onCreate(savedInstanceState, R.layout.addresslist_activity);
// get parameters
final String keyword = getIntent().getStringExtra(Intents.EXTRA_KEYWORD);
diff --git a/main/src/cgeo/geocaching/CacheDetailActivity.java b/main/src/cgeo/geocaching/CacheDetailActivity.java
index 1662bb6..d140be1 100644
--- a/main/src/cgeo/geocaching/CacheDetailActivity.java
+++ b/main/src/cgeo/geocaching/CacheDetailActivity.java
@@ -1,5 +1,8 @@
package cgeo.geocaching;
+import butterknife.InjectView;
+import butterknife.Views;
+
import cgeo.calendar.ICalendar;
import cgeo.geocaching.activity.AbstractViewPagerActivity;
import cgeo.geocaching.activity.Progress;
@@ -21,23 +24,26 @@ import cgeo.geocaching.network.Parameters;
import cgeo.geocaching.ui.AbstractCachingPageViewCreator;
import cgeo.geocaching.ui.AnchorAwareLinkMovementMethod;
import cgeo.geocaching.ui.CacheDetailsCreator;
+import cgeo.geocaching.ui.CoordinatesFormatSwitcher;
import cgeo.geocaching.ui.DecryptTextClickListener;
+import cgeo.geocaching.ui.EditNoteDialog;
+import cgeo.geocaching.ui.EditNoteDialog.EditNoteDialogListener;
import cgeo.geocaching.ui.Formatter;
import cgeo.geocaching.ui.ImagesList;
-import cgeo.geocaching.ui.ImagesList.ImageType;
import cgeo.geocaching.ui.LoggingUI;
+import cgeo.geocaching.ui.OwnerActionsClickListener;
+import cgeo.geocaching.ui.UserActionsClickListener;
import cgeo.geocaching.ui.WeakReferenceHandler;
-import cgeo.geocaching.ui.dialog.EditorDialog;
-import cgeo.geocaching.utils.BaseUtils;
import cgeo.geocaching.utils.CancellableHandler;
import cgeo.geocaching.utils.ClipboardUtils;
import cgeo.geocaching.utils.CryptUtils;
import cgeo.geocaching.utils.GeoDirHandler;
import cgeo.geocaching.utils.HtmlUtils;
-import cgeo.geocaching.utils.ImageHelper;
+import cgeo.geocaching.utils.ImageUtils;
import cgeo.geocaching.utils.Log;
import cgeo.geocaching.utils.MatcherWrapper;
import cgeo.geocaching.utils.RunnableWithArgument;
+import cgeo.geocaching.utils.TextUtils;
import cgeo.geocaching.utils.TranslationUtils;
import cgeo.geocaching.utils.UnknownTagsHandler;
@@ -65,12 +71,12 @@ import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
+import android.support.v4.app.FragmentManager;
import android.text.Editable;
import android.text.Html;
import android.text.Spannable;
import android.text.Spanned;
import android.text.format.DateUtils;
-import android.text.method.LinkMovementMethod;
import android.text.style.ForegroundColorSpan;
import android.text.style.StrikethroughSpan;
import android.text.style.StyleSpan;
@@ -112,7 +118,8 @@ import java.util.regex.Pattern;
*
* e.g. details, description, logs, waypoints, inventory...
*/
-public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailActivity.Page> {
+public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailActivity.Page>
+ implements EditNoteDialogListener {
private static final int MENU_FIELD_COPY = 1;
private static final int MENU_FIELD_TRANSLATE = 2;
@@ -132,13 +139,21 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
private static final int CONTEXT_MENU_WAYPOINT_DEFAULT_NAVIGATION = 1240;
private static final int CONTEXT_MENU_WAYPOINT_RESET_ORIGINAL_CACHE_COORDINATES = 1241;
- private static final Pattern DARK_COLOR_PATTERN = Pattern.compile(Pattern.quote("color=\"#") + "(0[0-9]){3}" + "\"");
+ private static final Pattern[] DARK_COLOR_PATTERNS = {
+ Pattern.compile("((?<!bg)color)=\"#" + "(0[0-9]){3}" + "\"", Pattern.CASE_INSENSITIVE),
+ Pattern.compile("((?<!bg)color)=\"" + "black" + "\"", Pattern.CASE_INSENSITIVE),
+ Pattern.compile("((?<!bg)color)=\"#" + "000080" + "\"", Pattern.CASE_INSENSITIVE) };
+ private static final Pattern[] LIGHT_COLOR_PATTERNS = {
+ Pattern.compile("((?<!bg)color)=\"#" + "([F][6-9A-F]){3}" + "\"", Pattern.CASE_INSENSITIVE),
+ Pattern.compile("((?<!bg)color)=\"" + "white" + "\"", Pattern.CASE_INSENSITIVE) };
public static final String STATE_PAGE_INDEX = "cgeo.geocaching.pageIndex";
private Geocache cache;
private final Progress progress = new Progress();
private SearchResult search;
+ private EditNoteDialogListener editNoteDialogListener;
+
private final GeoDirHandler locationUpdater = new GeoDirHandler() {
@Override
public void updateGeoData(final IGeoData geo) {
@@ -162,7 +177,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
cacheDistanceView.setText(dist.toString());
cacheDistanceView.bringToFront();
- } catch (Exception e) {
+ } catch (final Exception e) {
Log.w("Failed to update location.");
}
}
@@ -179,7 +194,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
// some views that must be available from everywhere // TODO: Reference can block GC?
private TextView cacheDistanceView;
- private Handler cacheChangeNotificationHandler = new Handler() {
+ private final Handler cacheChangeNotificationHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
notifyDataSetChanged();
@@ -187,18 +202,11 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
};
protected ImagesList imagesList;
- public CacheDetailActivity() {
- // identifier for manual
- super("c:geolocation-cache-details");
- }
-
@Override
public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
+ super.onCreate(savedInstanceState, R.layout.cachedetail_activity);
- // initialize the main view and set a default title
- setTheme();
- setContentView(R.layout.cacheview);
+ // set title in code, as the activity needs a hard coded title due to the intent filters
setTitle(res.getString(R.string.cache));
String geocode = null;
@@ -226,9 +234,9 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
// try to get data from URI
if (geocode == null && guid == null && uri != null) {
- String uriHost = uri.getHost().toLowerCase(Locale.US);
- String uriPath = uri.getPath().toLowerCase(Locale.US);
- String uriQuery = uri.getQuery();
+ final String uriHost = uri.getHost().toLowerCase(Locale.US);
+ final String uriPath = uri.getPath().toLowerCase(Locale.US);
+ final String uriQuery = uri.getQuery();
if (uriQuery != null) {
Log.i("Opening URI: " + uriHost + uriPath + "?" + uriQuery);
@@ -259,6 +267,23 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
finish();
return;
}
+ } else if (uriHost.contains("opencaching.de")) {
+ if (uriPath != null && uriPath.startsWith("/oc")) {
+ geocode = uriPath.substring(1).toUpperCase(Locale.US);
+ } else {
+ geocode = uri.getQueryParameter("wp");
+ if (StringUtils.isNotBlank(geocode)) {
+ geocode = geocode.toUpperCase(Locale.US);
+ } else {
+ showToast(res.getString(R.string.err_detail_open));
+ finish();
+ return;
+ }
+ }
+ } else {
+ showToast(res.getString(R.string.err_detail_open));
+ finish();
+ return;
}
}
@@ -279,11 +304,11 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
title = geocode;
}
progress.show(this, title, res.getString(R.string.cache_dialog_loading_details), true, loadCacheHandler.cancelMessage());
- } catch (Exception e) {
+ } catch (final Exception e) {
// nothing, we lost the window
}
- ImageView defaultNavigationImageView = (ImageView) findViewById(R.id.defaultNavigation);
+ final ImageView defaultNavigationImageView = (ImageView) findViewById(R.id.defaultNavigation);
defaultNavigationImageView.setOnLongClickListener(new OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
@@ -352,7 +377,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
switch (viewId) {
case R.id.value: // coordinates, gc-code, name
clickedItemText = ((TextView) view).getText();
- String itemTitle = (String) ((TextView) ((View) view.getParent()).findViewById(R.id.name)).getText();
+ final String itemTitle = (String) ((TextView) ((View) view.getParent()).findViewById(R.id.name)).getText();
buildOptionsContextmenu(menu, viewId, itemTitle, true);
break;
case R.id.shortdesc:
@@ -361,7 +386,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
break;
case R.id.longdesc:
// combine short and long description
- String shortDesc = cache.getShortDescription();
+ final String shortDesc = cache.getShortDescription();
if (StringUtils.isBlank(shortDesc)) {
clickedItemText = ((TextView) view).getText();
} else {
@@ -410,7 +435,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
break;
}
}
- } catch (Exception e) {
+ } catch (final Exception e) {
}
}
break;
@@ -541,7 +566,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
NavigationAppFactory.addMenuItems(subMenu, cache);
menu.add(0, MENU_CALENDAR, 0, res.getString(R.string.cache_menu_event)).setIcon(R.drawable.ic_menu_agenda); // add event to calendar
- LoggingUI.addMenuItems(menu, cache);
+ LoggingUI.addMenuItems(this, menu, cache);
menu.add(0, MENU_CACHES_AROUND, 0, res.getString(R.string.cache_menu_around)).setIcon(R.drawable.ic_menu_rotate); // caches around
menu.add(0, MENU_BROWSER, 0, res.getString(R.string.cache_menu_browser)).setIcon(R.drawable.ic_menu_globe); // browser
menu.add(0, MENU_SHARE, 0, res.getString(R.string.cache_menu_share)).setIcon(R.drawable.ic_menu_share); // share cache
@@ -557,6 +582,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
menu.findItem(MENU_CACHES_AROUND).setVisible(null != cache.getCoords() && cache.supportsCachesAround());
menu.findItem(MENU_BROWSER).setVisible(cache.canOpenInBrowser());
}
+ LoggingUI.onPrepareOptionsMenu(menu, cache);
return super.onPrepareOptionsMenu(menu);
}
@@ -764,7 +790,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
.setPositiveButton(getString(android.R.string.yes), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
- Intent intent = new Intent(Intent.ACTION_VIEW);
+ final Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse(ICalendar.CALENDAR_ADDON_URI));
startActivity(intent);
}
@@ -797,7 +823,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
/**
* Wrapper for the referenced method in the xml-layout.
*/
- public void startDefaultNavigation(@SuppressWarnings("unused") View view) {
+ public void goDefaultNavigation(@SuppressWarnings("unused") View view) {
startDefaultNavigation();
}
@@ -808,100 +834,20 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
NavigationAppFactory.showNavigationMenu(this, cache, null, null, true, true);
}
- /**
- * Listener for clicks on username
- */
- private class UserActionsClickListener implements View.OnClickListener {
-
- @Override
- public void onClick(View view) {
- if (view == null) {
- return;
- }
- if (!cache.supportsUserActions()) {
- return;
- }
-
- clickedItemText = ((TextView) view).getText().toString();
- showUserActionsDialog(clickedItemText);
- }
- }
-
- /**
- * Listener for clicks on owner name
- */
- private class OwnerActionsClickListener implements View.OnClickListener {
-
- @Override
- public void onClick(View view) {
- if (view == null) {
- return;
- }
- if (!cache.supportsUserActions()) {
- return;
- }
-
- // Use real owner name vice the one owner chose to display
- if (StringUtils.isNotBlank(cache.getOwnerUserId())) {
- clickedItemText = cache.getOwnerUserId();
- } else {
- clickedItemText = ((TextView) view).getText().toString();
- }
- showUserActionsDialog(clickedItemText);
- }
- }
-
- /**
- * Opens a dialog to do actions on an username
- */
- private void showUserActionsDialog(final CharSequence name) {
- final CharSequence[] items = { res.getString(R.string.user_menu_view_hidden),
- res.getString(R.string.user_menu_view_found),
- res.getString(R.string.user_menu_open_browser),
- res.getString(R.string.user_menu_send_message)
- };
-
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setTitle(res.getString(R.string.user_menu_title) + " " + name);
- builder.setItems(items, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int item) {
- switch (item) {
- case 0:
- cgeocaches.startActivityOwner(CacheDetailActivity.this, name.toString());
- return;
- case 1:
- cgeocaches.startActivityUserName(CacheDetailActivity.this, name.toString());
- return;
- case 2:
- startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.geocaching.com/profile/?u=" + Network.encode(name.toString()))));
- return;
- case 3:
- startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.geocaching.com/email/?u=" + Network.encode(name.toString()))));
- return;
- default:
- break;
- }
- }
- });
- AlertDialog alert = builder.create();
- alert.show();
- }
-
private void loadCacheImages() {
if (imagesList != null) {
return;
}
- PageViewCreator creator = getViewCreator(Page.IMAGES);
+ final PageViewCreator creator = getViewCreator(Page.IMAGES);
if (creator == null) {
return;
}
- View imageView = creator.getView();
+ final View imageView = creator.getView();
if (imageView == null) {
return;
}
imagesList = new ImagesList(this, cache.getGeocode());
- imagesList.loadImages(imageView, cache.getImages(), ImageType.AllImages, false);
+ imagesList.loadImages(imageView, cache.getImages(), false);
}
public static void startActivity(final Context context, final String geocode) {
@@ -1038,12 +984,12 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
noAttributeIconsFound = true;
- for (String attributeName : cache.getAttributes()) {
+ for (final String attributeName : cache.getAttributes()) {
// check if another attribute icon fits in this row
attributeRow.measure(0, 0);
- int rowWidth = attributeRow.getMeasuredWidth();
- FrameLayout fl = (FrameLayout) getLayoutInflater().inflate(R.layout.attribute_image, null);
- ImageView iv = (ImageView) fl.getChildAt(0);
+ final int rowWidth = attributeRow.getMeasuredWidth();
+ final FrameLayout fl = (FrameLayout) getLayoutInflater().inflate(R.layout.attribute_image, null);
+ final ImageView iv = (ImageView) fl.getChildAt(0);
if ((parentWidth - rowWidth) < iv.getLayoutParams().width) {
// make a new row
attributeRow = newAttributeIconsRow();
@@ -1059,14 +1005,14 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
// strike through?
if (strikethru) {
// generate strikethru image with same properties as attribute image
- ImageView strikethruImage = new ImageView(CacheDetailActivity.this);
+ final ImageView strikethruImage = new ImageView(CacheDetailActivity.this);
strikethruImage.setLayoutParams(iv.getLayoutParams());
d = res.getDrawable(R.drawable.attribute__strikethru);
strikethruImage.setImageDrawable(d);
fl.addView(strikethruImage);
}
} else {
- Drawable d = res.getDrawable(R.drawable.attribute_unknown);
+ final Drawable d = res.getDrawable(R.drawable.attribute_unknown);
iv.setImageDrawable(d);
}
@@ -1077,7 +1023,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
}
private LinearLayout newAttributeIconsRow() {
- LinearLayout rowLayout = new LinearLayout(CacheDetailActivity.this);
+ final LinearLayout rowLayout = new LinearLayout(CacheDetailActivity.this);
rowLayout.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT));
rowLayout.setOrientation(LinearLayout.HORIZONTAL);
@@ -1131,7 +1077,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
return null;
}
- view = (ScrollView) getLayoutInflater().inflate(R.layout.cacheview_details, null);
+ view = (ScrollView) getLayoutInflater().inflate(R.layout.cachedetail_details_page, null);
// Start loading preview map
if (Settings.isStoreOfflineMaps()) {
@@ -1142,7 +1088,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
final CacheDetailsCreator details = new CacheDetailsCreator(CacheDetailActivity.this, detailsList);
// cache name (full name)
- Spannable span = (new Spannable.Factory()).newSpannable(Html.fromHtml(cache.getName()).toString());
+ final Spannable span = (new Spannable.Factory()).newSpannable(Html.fromHtml(cache.getName()).toString());
if (cache.isDisabled() || cache.isArchived()) { // strike
span.setSpan(new StrikethroughSpan(), 0, span.toString().length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
@@ -1165,7 +1111,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
// favorite count
if (cache.getFavoritePoints() > 0) {
- details.add(R.string.cache_favourite, cache.getFavoritePoints() + "×");
+ details.add(R.string.cache_favorite, cache.getFavoritePoints() + "×");
}
// own rating
@@ -1175,18 +1121,18 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
// cache author
if (StringUtils.isNotBlank(cache.getOwnerDisplayName()) || StringUtils.isNotBlank(cache.getOwnerUserId())) {
- TextView ownerView = details.add(R.string.cache_owner, "");
+ final TextView ownerView = details.add(R.string.cache_owner, "");
if (StringUtils.isNotBlank(cache.getOwnerDisplayName())) {
ownerView.setText(cache.getOwnerDisplayName(), TextView.BufferType.SPANNABLE);
} else { // OwnerReal guaranteed to be not blank based on above
ownerView.setText(cache.getOwnerUserId(), TextView.BufferType.SPANNABLE);
}
- ownerView.setOnClickListener(new OwnerActionsClickListener());
+ ownerView.setOnClickListener(new OwnerActionsClickListener(cache));
}
// cache hidden
if (cache.getHiddenDate() != null) {
- long time = cache.getHiddenDate().getTime();
+ final long time = cache.getHiddenDate().getTime();
if (time > 0) {
String dateString = Formatter.formatFullDate(time);
if (cache.isEventCache()) {
@@ -1203,24 +1149,8 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
// cache coordinates
if (cache.getCoords() != null) {
- TextView valueView = details.add(R.string.cache_coordinates, cache.getCoords().toString());
- valueView.setOnClickListener(new View.OnClickListener() {
- private int position = 0;
- private GeopointFormatter.Format[] availableFormats = new GeopointFormatter.Format[] {
- GeopointFormatter.Format.LAT_LON_DECMINUTE,
- GeopointFormatter.Format.LAT_LON_DECSECOND,
- GeopointFormatter.Format.LAT_LON_DECDEGREE
- };
-
- // rotate coordinate formats on click
- @Override
- public void onClick(View view) {
- position = (position + 1) % availableFormats.length;
-
- final TextView valueView = (TextView) view.findViewById(R.id.value);
- valueView.setText(cache.getCoords().format(availableFormats[position]));
- }
- });
+ final TextView valueView = details.add(R.string.cache_coordinates, cache.getCoords().toString());
+ valueView.setOnClickListener(new CoordinatesFormatSwitcher(cache.getCoords()));
registerForContextMenu(valueView);
}
@@ -1233,34 +1163,34 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
updateOfflineBox(view, cache, res, new RefreshCacheClickListener(), new DropCacheClickListener(), new StoreCacheClickListener());
// watchlist
- Button buttonWatchlistAdd = (Button) view.findViewById(R.id.add_to_watchlist);
- Button buttonWatchlistRemove = (Button) view.findViewById(R.id.remove_from_watchlist);
+ final Button buttonWatchlistAdd = (Button) view.findViewById(R.id.add_to_watchlist);
+ final Button buttonWatchlistRemove = (Button) view.findViewById(R.id.remove_from_watchlist);
buttonWatchlistAdd.setOnClickListener(new AddToWatchlistClickListener());
buttonWatchlistRemove.setOnClickListener(new RemoveFromWatchlistClickListener());
updateWatchlistBox();
// favorite points
- Button buttonFavPointAdd = (Button) view.findViewById(R.id.add_to_favpoint);
- Button buttonFavPointRemove = (Button) view.findViewById(R.id.remove_from_favpoint);
+ final Button buttonFavPointAdd = (Button) view.findViewById(R.id.add_to_favpoint);
+ final Button buttonFavPointRemove = (Button) view.findViewById(R.id.remove_from_favpoint);
buttonFavPointAdd.setOnClickListener(new FavoriteAddClickListener());
buttonFavPointRemove.setOnClickListener(new FavoriteRemoveClickListener());
updateFavPointBox();
// list
- Button buttonChangeList = (Button) view.findViewById(R.id.change_list);
+ final Button buttonChangeList = (Button) view.findViewById(R.id.change_list);
buttonChangeList.setOnClickListener(new ChangeListClickListener());
updateListBox();
// data license
- IConnector connector = ConnectorFactory.getConnector(cache);
+ final IConnector connector = ConnectorFactory.getConnector(cache);
if (connector != null) {
- String license = connector.getLicenseText(cache);
+ final String license = connector.getLicenseText(cache);
if (StringUtils.isNotBlank(license)) {
view.findViewById(R.id.license_box).setVisibility(View.VISIBLE);
- TextView licenseView = ((TextView) view.findViewById(R.id.license));
+ final TextView licenseView = ((TextView) view.findViewById(R.id.license));
licenseView.setText(Html.fromHtml(license), BufferType.SPANNABLE);
licenseView.setClickable(true);
- licenseView.setMovementMethod(LinkMovementMethod.getInstance());
+ licenseView.setMovementMethod(AnchorAwareLinkMovementMethod.getInstance());
} else {
view.findViewById(R.id.license_box).setVisibility(View.GONE);
}
@@ -1356,6 +1286,11 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
return;
}
+ if (!Network.isNetworkConnected(getApplicationContext())) {
+ showToast(getString(R.string.err_server));
+ return;
+ }
+
final RefreshCacheHandler refreshCacheHandler = new RefreshCacheHandler();
progress.show(CacheDetailActivity.this, res.getString(R.string.cache_dialog_refresh_title), res.getString(R.string.cache_dialog_refresh_message), true, refreshCacheHandler.cancelMessage());
@@ -1482,7 +1417,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
@Override
public void run() {
- handler.sendEmptyMessage(GCConnector.addToWatchlist(cache) ? 1 : -1);
+ handler.sendEmptyMessage(ConnectorFactory.getConnector(cache).addToWatchlist(cache) ? 1 : -1);
}
}
@@ -1496,11 +1431,11 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
@Override
public void run() {
- handler.sendEmptyMessage(GCConnector.removeFromWatchlist(cache) ? 1 : -1);
+ handler.sendEmptyMessage(ConnectorFactory.getConnector(cache).removeFromWatchlist(cache) ? 1 : -1);
}
}
- /** Thread to add this cache to the favourite list of the user */
+ /** Thread to add this cache to the favorite list of the user */
private class FavoriteAddThread extends Thread {
private final Handler handler;
@@ -1514,7 +1449,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
}
}
- /** Thread to remove this cache to the favourite list of the user */
+ /** Thread to remove this cache to the favorite list of the user */
private class FavoriteRemoveThread extends Thread {
private final Handler handler;
@@ -1541,25 +1476,25 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
}
/**
- * Listener for "add to favourites" button
+ * Listener for "add to favorites" button
*/
private class FavoriteAddClickListener extends AbstractWatchlistClickListener {
@Override
public void onClick(View arg0) {
- doExecute(R.string.cache_dialog_favourite_add_title,
- R.string.cache_dialog_favourite_add_message,
+ doExecute(R.string.cache_dialog_favorite_add_title,
+ R.string.cache_dialog_favorite_add_message,
new FavoriteAddThread(new FavoriteUpdateHandler()));
}
}
/**
- * Listener for "remove from favourites" button
+ * Listener for "remove from favorites" button
*/
private class FavoriteRemoveClickListener extends AbstractWatchlistClickListener {
@Override
public void onClick(View arg0) {
- doExecute(R.string.cache_dialog_favourite_remove_title,
- R.string.cache_dialog_favourite_remove_message,
+ doExecute(R.string.cache_dialog_favorite_remove_title,
+ R.string.cache_dialog_favorite_remove_message,
new FavoriteRemoveThread(new FavoriteUpdateHandler()));
}
}
@@ -1600,15 +1535,15 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
* shows/hides buttons, sets text in watchlist box
*/
private void updateWatchlistBox() {
- LinearLayout layout = (LinearLayout) view.findViewById(R.id.watchlist_box);
- boolean supportsWatchList = cache.supportsWatchList();
+ final LinearLayout layout = (LinearLayout) view.findViewById(R.id.watchlist_box);
+ final boolean supportsWatchList = cache.supportsWatchList();
layout.setVisibility(supportsWatchList ? View.VISIBLE : View.GONE);
if (!supportsWatchList) {
return;
}
- Button buttonAdd = (Button) view.findViewById(R.id.add_to_watchlist);
- Button buttonRemove = (Button) view.findViewById(R.id.remove_from_watchlist);
- TextView text = (TextView) view.findViewById(R.id.watchlist_text);
+ final Button buttonAdd = (Button) view.findViewById(R.id.add_to_watchlist);
+ final Button buttonRemove = (Button) view.findViewById(R.id.remove_from_watchlist);
+ final TextView text = (TextView) view.findViewById(R.id.watchlist_text);
if (cache.isOnWatchlist() || cache.isOwner()) {
buttonAdd.setVisibility(View.GONE);
@@ -1634,15 +1569,15 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
* shows/hides buttons, sets text in watchlist box
*/
private void updateFavPointBox() {
- LinearLayout layout = (LinearLayout) view.findViewById(R.id.favpoint_box);
- boolean supportsFavoritePoints = cache.supportsFavoritePoints();
+ final LinearLayout layout = (LinearLayout) view.findViewById(R.id.favpoint_box);
+ final boolean supportsFavoritePoints = cache.supportsFavoritePoints();
layout.setVisibility(supportsFavoritePoints ? View.VISIBLE : View.GONE);
if (!supportsFavoritePoints || cache.isOwner() || !Settings.isPremiumMember()) {
return;
}
- Button buttonAdd = (Button) view.findViewById(R.id.add_to_favpoint);
- Button buttonRemove = (Button) view.findViewById(R.id.remove_from_favpoint);
- TextView text = (TextView) view.findViewById(R.id.favpoint_text);
+ final Button buttonAdd = (Button) view.findViewById(R.id.add_to_favpoint);
+ final Button buttonRemove = (Button) view.findViewById(R.id.remove_from_favpoint);
+ final TextView text = (TextView) view.findViewById(R.id.favpoint_text);
if (cache.isFavorite()) {
buttonAdd.setVisibility(View.GONE);
@@ -1667,15 +1602,15 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
* shows/hides/updates list box
*/
private void updateListBox() {
- View box = view.findViewById(R.id.list_box);
+ final View box = view.findViewById(R.id.list_box);
if (cache.isOffline()) {
// show box
box.setVisibility(View.VISIBLE);
// update text
- TextView text = (TextView) view.findViewById(R.id.list_text);
- StoredList list = cgData.getList(cache.getListId());
+ final TextView text = (TextView) view.findViewById(R.id.list_text);
+ final StoredList list = cgData.getList(cache.getListId());
if (list != null) {
text.setText(res.getString(R.string.cache_list_text) + " " + list.title);
} else {
@@ -1719,8 +1654,8 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
}
}
- return ImageHelper.scaleBitmapToFitDisplay(image);
- } catch (Exception e) {
+ return ImageUtils.scaleBitmapToFitDisplay(image);
+ } catch (final Exception e) {
Log.w("CacheDetailActivity.PreviewMapTask", e);
return null;
}
@@ -1744,7 +1679,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
((ImageView) view.findViewById(R.id.map_preview)).setImageDrawable(image);
view.findViewById(R.id.map_preview_box).setVisibility(View.VISIBLE);
- } catch (Exception e) {
+ } catch (final Exception e) {
Log.e("CacheDetailActivity.PreviewMapTask", e);
}
}
@@ -1752,7 +1687,9 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
}
- private class DescriptionViewCreator extends AbstractCachingPageViewCreator<ScrollView> {
+ protected class DescriptionViewCreator extends AbstractCachingPageViewCreator<ScrollView> {
+
+ @InjectView(R.id.personalnote) protected TextView personalNoteView;
@Override
public ScrollView getDispatchedView() {
@@ -1761,12 +1698,12 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
return null;
}
- view = (ScrollView) getLayoutInflater().inflate(R.layout.cacheview_description, null);
+ view = (ScrollView) getLayoutInflater().inflate(R.layout.cachedetail_description_page, null);
+ Views.inject(this, view);
// cache short description
if (StringUtils.isNotBlank(cache.getShortDescription())) {
- new LoadDescriptionTask().execute(cache.getShortDescription(), view.findViewById(R.id.shortdesc), null);
- registerForContextMenu(view.findViewById(R.id.shortdesc));
+ new LoadDescriptionTask(cache.getShortDescription(), view.findViewById(R.id.shortdesc), null, null).execute();
}
// long description
@@ -1774,7 +1711,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
if (Settings.isAutoLoadDescription()) {
loadLongDescription();
} else {
- Button showDesc = (Button) view.findViewById(R.id.show_description);
+ final Button showDesc = (Button) view.findViewById(R.id.show_description);
showDesc.setVisibility(View.VISIBLE);
showDesc.setOnClickListener(new View.OnClickListener() {
@Override
@@ -1786,31 +1723,20 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
}
// cache personal note
- final TextView personalNoteView = (TextView) view.findViewById(R.id.personalnote);
- setPersonalNote(personalNoteView);
- personalNoteView.setMovementMethod(LinkMovementMethod.getInstance());
+ setPersonalNote();
+ personalNoteView.setMovementMethod(AnchorAwareLinkMovementMethod.getInstance());
registerForContextMenu(personalNoteView);
final Button personalNoteEdit = (Button) view.findViewById(R.id.edit_personalnote);
- if (cache.isOffline()) {
- personalNoteEdit.setVisibility(View.VISIBLE);
- personalNoteEdit.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- EditorDialog editor = new EditorDialog(CacheDetailActivity.this, personalNoteView.getText());
- editor.setOnEditorUpdate(new EditorDialog.EditorUpdate() {
- @Override
- public void update(CharSequence editorText) {
- cache.setPersonalNote(editorText.toString());
- setPersonalNote(personalNoteView);
- cgData.saveCache(cache, EnumSet.of(SaveFlag.SAVE_DB));
- }
- });
- editor.show();
+ personalNoteEdit.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (cache.isOffline()) {
+ editPersonalNote();
+ } else {
+ warnPersonalNoteNeedsStoring();
}
- });
- } else {
- personalNoteEdit.setVisibility(View.INVISIBLE);
- }
+ }
+ });
// cache hint and spoiler images
final View hintBoxView = view.findViewById(R.id.hint_box);
@@ -1822,7 +1748,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
final TextView hintView = ((TextView) view.findViewById(R.id.hint));
if (StringUtils.isNotBlank(cache.getHint())) {
- if (BaseUtils.containsHtml(cache.getHint())) {
+ if (TextUtils.containsHtml(cache.getHint())) {
hintView.setText(Html.fromHtml(cache.getHint(), new HtmlImage(cache.getGeocode(), false, cache.getListId(), false), null), TextView.BufferType.SPANNABLE);
hintView.setText(CryptUtils.rot13((Spannable) hintView.getText()));
}
@@ -1863,29 +1789,77 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
return view;
}
- private void setPersonalNote(final TextView personalNoteView) {
+ private void editPersonalNote() {
+ if (cache.isOffline()) {
+ editNoteDialogListener = new EditNoteDialogListener() {
+ @Override
+ public void onFinishEditNoteDialog(final String note) {
+ cache.setPersonalNote(note);
+ cache.parseWaypointsFromNote();
+ setPersonalNote();
+ cgData.saveCache(cache, EnumSet.of(SaveFlag.SAVE_DB));
+ CacheDetailActivity.this.notifyDataSetChanged();
+ }
+ };
+ final FragmentManager fm = getSupportFragmentManager();
+ final EditNoteDialog dialog = EditNoteDialog.newInstance(cache.getPersonalNote());
+ dialog.show(fm, "fragment_edit_note");
+ }
+ }
+
+ private void setPersonalNote() {
final String personalNote = cache.getPersonalNote();
personalNoteView.setText(personalNote, TextView.BufferType.SPANNABLE);
if (StringUtils.isNotBlank(personalNote)) {
personalNoteView.setVisibility(View.VISIBLE);
- }
- else {
+ } else {
personalNoteView.setVisibility(View.GONE);
}
}
private void loadLongDescription() {
- Button showDesc = (Button) view.findViewById(R.id.show_description);
+ final Button showDesc = (Button) view.findViewById(R.id.show_description);
showDesc.setVisibility(View.GONE);
showDesc.setOnClickListener(null);
view.findViewById(R.id.loading).setVisibility(View.VISIBLE);
- new LoadDescriptionTask().execute(cache.getDescription(), view.findViewById(R.id.longdesc), view.findViewById(R.id.loading));
- registerForContextMenu(view.findViewById(R.id.longdesc));
+ new LoadDescriptionTask(cache.getDescription(), view.findViewById(R.id.longdesc), view.findViewById(R.id.loading), view.findViewById(R.id.shortdesc)).execute();
+ }
+
+ private void warnPersonalNoteNeedsStoring() {
+ final AlertDialog.Builder builder = new AlertDialog.Builder(CacheDetailActivity.this);
+ builder.setTitle(R.string.cache_personal_note_unstored);
+ builder.setMessage(R.string.cache_personal_note_store);
+ builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
+
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ // do nothing
+ }
+ });
+
+ builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ dialog.dismiss();
+ cache.store(null);
+ editPersonalNote();
+ }
+
+ });
+ final AlertDialog dialog = builder.create();
+ dialog.setOwnerActivity(CacheDetailActivity.this);
+ dialog.show();
}
}
+ @Override
+ public void onFinishEditNoteDialog(final String note) {
+ editNoteDialogListener.onFinishEditNoteDialog(note);
+ }
+
private static class HtmlImageCounter implements Html.ImageGetter {
private int imageCount = 0;
@@ -1912,28 +1886,33 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
* </ol>
*/
private class LoadDescriptionTask extends AsyncTask<Object, Void, Void> {
- private View loadingIndicatorView;
- private TextView descriptionView;
- private String descriptionString;
+ private final View loadingIndicatorView;
+ private final TextView descriptionView;
+ private final String descriptionString;
private Spanned description;
+ private final View shortDescView;
+ public LoadDescriptionTask(final String description, final View descriptionView, final View loadingIndicatorView, final View shortDescView) {
+ this.descriptionString = description;
+ this.descriptionView = (TextView) descriptionView;
+ this.loadingIndicatorView = loadingIndicatorView;
+ this.shortDescView = shortDescView;
+ }
@Override
protected Void doInBackground(Object... params) {
try {
- descriptionString = ((String) params[0]);
- descriptionView = (TextView) params[1];
- loadingIndicatorView = (View) params[2];
-
// Fast preview: parse only HTML without loading any images
- HtmlImageCounter imageCounter = new HtmlImageCounter();
+ final HtmlImageCounter imageCounter = new HtmlImageCounter();
final UnknownTagsHandler unknownTagsHandler = new UnknownTagsHandler();
description = Html.fromHtml(descriptionString, imageCounter, unknownTagsHandler);
publishProgress();
+
+ boolean needsRefresh = false;
if (imageCounter.getImageCount() > 0) {
// Complete view: parse again with loading images - if necessary ! If there are any images causing problems the user can see at least the preview
description = Html.fromHtml(descriptionString, new HtmlImage(cache.getGeocode(), true, cache.getListId(), false), unknownTagsHandler);
- publishProgress();
+ needsRefresh = true;
}
// If description has an HTML construct which may be problematic to render, add a note at the end of the long description.
@@ -1945,56 +1924,94 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
final Spanned tableNote = Html.fromHtml(res.getString(R.string.cache_description_table_note, "<a href=\"" + cache.getUrl() + "\">" + connector.getName() + "</a>"));
((Editable) description).append("\n\n").append(tableNote);
((Editable) description).setSpan(new StyleSpan(Typeface.ITALIC), startPos, description.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ needsRefresh = true;
+ }
+
+ if (needsRefresh) {
publishProgress();
}
- } catch (Exception e) {
+ } catch (final Exception e) {
Log.e("LoadDescriptionTask: ", e);
}
return null;
}
- /*
- * (non-Javadoc)
- *
- * @see android.os.AsyncTask#onProgressUpdate(Progress[])
- */
@Override
protected void onProgressUpdate(Void... values) {
- if (description != null) {
- if (StringUtils.isNotBlank(descriptionString)) {
+ if (description == null) {
+ showToast(res.getString(R.string.err_load_descr_failed));
+ return;
+ }
+ if (StringUtils.isNotBlank(descriptionString)) {
+ try {
descriptionView.setText(description, TextView.BufferType.SPANNABLE);
- descriptionView.setMovementMethod(AnchorAwareLinkMovementMethod.getInstance());
- fixBlackTextColor(descriptionView, descriptionString);
- }
-
+ } catch (final Exception e) {
+ // On 4.1, there is sometimes a crash on measuring the layout: https://code.google.com/p/android/issues/detail?id=35412
+ Log.e("Android bug setting text: ", e);
+ // remove the formatting by converting to a simple string
+ descriptionView.setText(description.toString());
+ }
+ descriptionView.setMovementMethod(AnchorAwareLinkMovementMethod.getInstance());
+ fixTextColor(descriptionView, descriptionString);
descriptionView.setVisibility(View.VISIBLE);
- } else {
- showToast(res.getString(R.string.err_load_descr_failed));
+ registerForContextMenu(descriptionView);
+
+ hideDuplicatedShortDescription();
}
+ }
+ /**
+ * Hide the short description, if it is contained somewhere at the start of the long description.
+ */
+ private void hideDuplicatedShortDescription() {
+ if (shortDescView != null) {
+ final String shortDescription = cache.getShortDescription();
+ if (StringUtils.isNotBlank(shortDescription)) {
+ final int index = descriptionString.indexOf(shortDescription);
+ if (index >= 0 && index < 200) {
+ shortDescView.setVisibility(View.GONE);
+ }
+ }
+ }
+ }
+
+ @Override
+ protected void onPostExecute(Void result) {
if (null != loadingIndicatorView) {
loadingIndicatorView.setVisibility(View.GONE);
}
}
/**
- * handle caches with black font color
+ * Handle caches with black font color in dark skin and white font color in light skin
+ * by changing background color of the view
*
* @param view
+ * containing the text
* @param text
+ * to be checked
*/
- private void fixBlackTextColor(final TextView view, final String text) {
+ private void fixTextColor(final TextView view, final String text) {
+ int backcolor;
if (Settings.isLightSkin()) {
- return;
- }
- int backcolor = color.black;
- if (-1 != StringUtils.indexOfAny(text, new String[] { "color=\"black", "color=\"#000080\"" })) {
- backcolor = color.darker_gray;
- }
- else {
- MatcherWrapper matcher = new MatcherWrapper(DARK_COLOR_PATTERN, text);
- if (matcher.find()) {
- backcolor = color.darker_gray;
+ backcolor = color.white;
+
+ for (final Pattern pattern : LIGHT_COLOR_PATTERNS) {
+ final MatcherWrapper matcher = new MatcherWrapper(pattern, text);
+ if (matcher.find()) {
+ view.setBackgroundResource(color.darker_gray);
+ return;
+ }
+ }
+ } else {
+ backcolor = color.black;
+
+ for (final Pattern pattern : DARK_COLOR_PATTERNS) {
+ final MatcherWrapper matcher = new MatcherWrapper(pattern, text);
+ if (matcher.find()) {
+ view.setBackgroundResource(color.darker_gray);
+ return;
+ }
}
}
view.setBackgroundResource(backcolor);
@@ -2015,13 +2032,13 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
return null;
}
- view = (ListView) getLayoutInflater().inflate(R.layout.cacheview_logs, null);
+ view = (ListView) getLayoutInflater().inflate(R.layout.cachedetail_logs_page, null);
// log count
final Map<LogType, Integer> logCounts = cache.getLogCounts();
if (logCounts != null) {
final List<Entry<LogType, Integer>> sortedLogCounts = new ArrayList<Entry<LogType, Integer>>(logCounts.size());
- for (Entry<LogType, Integer> entry : logCounts.entrySet()) {
+ for (final Entry<LogType, Integer> entry : logCounts.entrySet()) {
// it may happen that the label is unknown -> then avoid any output for this type
if (entry.getKey() != LogType.PUBLISH_LISTING && entry.getKey().getL10n() != null) {
sortedLogCounts.add(entry);
@@ -2038,8 +2055,8 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
}
});
- ArrayList<String> labels = new ArrayList<String>(sortedLogCounts.size());
- for (Entry<LogType, Integer> pair : sortedLogCounts) {
+ final ArrayList<String> labels = new ArrayList<String>(sortedLogCounts.size());
+ for (final Entry<LogType, Integer> pair : sortedLogCounts) {
labels.add(pair.getValue() + "× " + pair.getKey().getL10n());
}
@@ -2050,27 +2067,26 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
}
final List<LogEntry> logs = allLogs ? cache.getLogs() : cache.getFriendsLogs();
- view.setAdapter(new ArrayAdapter<LogEntry>(CacheDetailActivity.this, R.layout.cacheview_logs_item, logs) {
- final UserActionsClickListener userActionsClickListener = new UserActionsClickListener();
+ view.setAdapter(new ArrayAdapter<LogEntry>(CacheDetailActivity.this, R.layout.logs_item, logs) {
+ final UserActionsClickListener userActionsClickListener = new UserActionsClickListener(cache);
final DecryptTextClickListener decryptTextClickListener = new DecryptTextClickListener();
@Override
public View getView(final int position, final View convertView, final ViewGroup parent) {
View rowView = convertView;
if (null == rowView) {
- rowView = getLayoutInflater().inflate(R.layout.cacheview_logs_item, null);
+ rowView = getLayoutInflater().inflate(R.layout.logs_item, null);
}
LogViewHolder holder = (LogViewHolder) rowView.getTag();
if (null == holder) {
holder = new LogViewHolder(rowView);
- rowView.setTag(holder);
}
holder.setPosition(position);
final LogEntry log = getItem(position);
if (log.date > 0) {
- holder.date.setText(Formatter.formatShortDate(log.date));
+ holder.date.setText(Formatter.formatShortDateVerbally(log.date));
holder.date.setVisibility(View.VISIBLE);
} else {
holder.date.setVisibility(View.GONE);
@@ -2080,29 +2096,29 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
holder.author.setText(StringEscapeUtils.unescapeHtml4(log.author));
// finds count
- holder.count.setVisibility(View.VISIBLE);
+ holder.countOrLocation.setVisibility(View.VISIBLE);
if (log.found == -1) {
- holder.count.setVisibility(View.GONE);
+ holder.countOrLocation.setVisibility(View.GONE);
} else {
- holder.count.setText(res.getQuantityString(R.plurals.cache_counts, log.found, log.found));
+ holder.countOrLocation.setText(res.getQuantityString(R.plurals.cache_counts, log.found, log.found));
}
// logtext, avoid parsing HTML if not necessary
String logText = log.log;
- if (BaseUtils.containsHtml(logText)) {
+ if (TextUtils.containsHtml(logText)) {
logText = log.getDisplayText();
// Fast preview: parse only HTML without loading any images
- HtmlImageCounter imageCounter = new HtmlImageCounter();
+ final HtmlImageCounter imageCounter = new HtmlImageCounter();
final UnknownTagsHandler unknownTagsHandler = new UnknownTagsHandler();
- holder.text.setText(Html.fromHtml(logText, imageCounter, unknownTagsHandler));
+ holder.text.setText(Html.fromHtml(logText, imageCounter, unknownTagsHandler), TextView.BufferType.SPANNABLE);
if (imageCounter.getImageCount() > 0) {
// Complete view: parse again with loading images - if necessary ! If there are any images causing problems the user can see at least the preview
- LogImageLoader loader = new LogImageLoader(holder);
- loader.execute(new String[] { logText });
+ final LogImageLoader loader = new LogImageLoader(holder);
+ loader.execute(logText);
}
}
else {
- holder.text.setText(logText);
+ holder.text.setText(logText, TextView.BufferType.SPANNABLE);
}
// images
@@ -2120,19 +2136,19 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
}
// colored marker
- int marker = log.type.markerId;
+ final int marker = log.type.markerId;
if (marker != 0) {
- holder.statusMarker.setVisibility(View.VISIBLE);
- holder.statusMarker.setImageResource(marker);
+ holder.marker.setVisibility(View.VISIBLE);
+ holder.marker.setImageResource(marker);
}
else {
- holder.statusMarker.setVisibility(View.GONE);
+ holder.marker.setVisibility(View.GONE);
}
if (null == convertView) {
// if convertView != null then this listeners are already set
holder.author.setOnClickListener(userActionsClickListener);
- holder.text.setMovementMethod(LinkMovementMethod.getInstance());
+ holder.text.setMovementMethod(AnchorAwareLinkMovementMethod.getInstance());
holder.text.setOnClickListener(decryptTextClickListener);
registerForContextMenu(holder.text);
}
@@ -2170,35 +2186,6 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
}
- private class LogViewHolder {
- final TextView date;
- final TextView type;
- final TextView author;
- final TextView count;
- final TextView text;
- final TextView images;
- final ImageView statusMarker;
- private int position;
-
- public LogViewHolder(final View base) {
- date = (TextView) base.findViewById(R.id.added);
- type = (TextView) base.findViewById(R.id.type);
- author = (TextView) base.findViewById(R.id.author);
- count = (TextView) base.findViewById(R.id.count);
- text = (TextView) base.findViewById(R.id.log);
- images = (TextView) base.findViewById(R.id.log_images);
- statusMarker = (ImageView) base.findViewById(R.id.log_mark);
- }
-
- public int getPosition() {
- return position;
- }
-
- public void setPosition(final int position) {
- this.position = position;
- }
-
- }
}
private class WaypointsViewCreator extends AbstractCachingPageViewCreator<ScrollView> {
@@ -2210,7 +2197,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
return null;
}
- view = (ScrollView) getLayoutInflater().inflate(R.layout.cacheview_waypoints, null);
+ view = (ScrollView) getLayoutInflater().inflate(R.layout.cachedetail_waypoints_page, null);
final LinearLayout waypoints = (LinearLayout) view.findViewById(R.id.waypoints);
@@ -2224,6 +2211,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
// coordinates
if (null != wpt.getCoords()) {
final TextView coordinatesView = (TextView) waypointView.findViewById(R.id.coordinates);
+ coordinatesView.setOnClickListener(new CoordinatesFormatSwitcher(wpt.getCoords()));
coordinatesView.setText(wpt.getCoords().toString());
coordinatesView.setVisibility(View.VISIBLE);
}
@@ -2249,7 +2237,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
// visited
if (wpt.isVisited()) {
- TypedValue a = new TypedValue();
+ final TypedValue a = new TypedValue();
getTheme().resolveAttribute(R.attr.text_color_grey, a, true);
if (a.type >= TypedValue.TYPE_FIRST_COLOR_INT && a.type <= TypedValue.TYPE_LAST_COLOR_INT) {
// really should be just a color!
@@ -2261,7 +2249,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
if (StringUtils.isNotBlank(wpt.getNote())) {
final TextView noteView = (TextView) waypointView.findViewById(R.id.note);
noteView.setVisibility(View.VISIBLE);
- if (BaseUtils.containsHtml(wpt.getNote())) {
+ if (TextUtils.containsHtml(wpt.getNote())) {
noteView.setText(Html.fromHtml(wpt.getNote()), TextView.BufferType.SPANNABLE);
}
else {
@@ -2292,6 +2280,15 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
}
});
+ waypointView.setOnLongClickListener(new View.OnLongClickListener() {
+ @Override
+ public boolean onLongClick(View v) {
+ EditWaypointActivity.startActivityEditWaypoint(CacheDetailActivity.this, wpt.getId());
+ refreshOnResume = true;
+ return true;
+ }
+ });
+
waypoints.addView(waypointView);
}
@@ -2319,7 +2316,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
return null;
}
- view = (ListView) getLayoutInflater().inflate(R.layout.cacheview_inventory, null);
+ view = (ListView) getLayoutInflater().inflate(R.layout.cachedetail_inventory_page, null);
// TODO: fix layout, then switch back to Android-resource and delete copied one
// this copy is modified to respect the text color
@@ -2327,9 +2324,9 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
view.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
- Object selection = arg0.getItemAtPosition(arg2);
+ final Object selection = arg0.getItemAtPosition(arg2);
if (selection instanceof Trackable) {
- Trackable trackable = (Trackable) selection;
+ final Trackable trackable = (Trackable) selection;
TrackableActivity.startActivity(CacheDetailActivity.this, trackable.getGuid(), trackable.getGeocode(), trackable.getName());
}
}
@@ -2347,7 +2344,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
return null; // something is really wrong
}
- view = getLayoutInflater().inflate(R.layout.caches_images, null);
+ view = getLayoutInflater().inflate(R.layout.cachedetail_images_page, null);
if (imagesList == null && isCurrentPage(Page.IMAGES)) {
loadCacheImages();
}
@@ -2374,10 +2371,10 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
*/
private AlertDialog createResetCacheCoordinatesDialog(final Geocache cache, final Waypoint wpt) {
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.waypoint_reset_cache_coords);
- String[] items = new String[] { res.getString(R.string.waypoint_localy_reset_cache_coords), res.getString(R.string.waypoint_reset_local_and_remote_cache_coords) };
+ final String[] items = new String[] { res.getString(R.string.waypoint_localy_reset_cache_coords), res.getString(R.string.waypoint_reset_local_and_remote_cache_coords) };
builder.setSingleChoiceItems(items, 0, new DialogInterface.OnClickListener() {
@Override
@@ -2429,7 +2426,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
private final boolean local;
private final boolean remote;
private final Waypoint wpt;
- private ProgressDialog progress;
+ private final ProgressDialog progress;
public static final int LOCAL = 0;
public static final int ON_WEBSITE = 1;
@@ -2459,7 +2456,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
handler.sendEmptyMessage(LOCAL);
}
- IConnector con = ConnectorFactory.getConnector(cache);
+ final IConnector con = ConnectorFactory.getConnector(cache);
if (remote && con.supportsOwnCoordinates()) {
runOnUiThread(new Runnable() {
@Override
@@ -2560,7 +2557,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
final Button offlineStore = (Button) view.findViewById(R.id.offline_store);
if (cache.isOffline()) {
- long diff = (System.currentTimeMillis() / (60 * 1000)) - (cache.getDetailedUpdate() / (60 * 1000)); // minutes
+ final long diff = (System.currentTimeMillis() / (60 * 1000)) - (cache.getDetailedUpdate() / (60 * 1000)); // minutes
String ago;
if (diff < 15) {
diff --git a/main/src/cgeo/geocaching/CachePopup.java b/main/src/cgeo/geocaching/CachePopup.java
index e6d0148..39a896a 100644
--- a/main/src/cgeo/geocaching/CachePopup.java
+++ b/main/src/cgeo/geocaching/CachePopup.java
@@ -3,6 +3,7 @@ package cgeo.geocaching;
import cgeo.geocaching.activity.Progress;
import cgeo.geocaching.apps.cache.navi.NavigationAppFactory;
import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.network.Network;
import cgeo.geocaching.ui.CacheDetailsCreator;
import cgeo.geocaching.utils.CancellableHandler;
import cgeo.geocaching.utils.Log;
@@ -64,7 +65,7 @@ public class CachePopup extends AbstractPopupActivity {
}
public CachePopup() {
- super("c:geo-cache-info", R.layout.popup);
+ super(R.layout.popup);
}
@Override
@@ -93,7 +94,7 @@ public class CachePopup extends AbstractPopupActivity {
CacheDetailActivity.updateOfflineBox(findViewById(android.R.id.content), cache, res, new RefreshCacheClickListener(), new DropCacheClickListener(), new StoreCacheClickListener());
} catch (Exception e) {
- Log.e("cgeopopup.init", e);
+ Log.e("CachePopup.init", e);
}
// cache is loaded. remove progress-popup if any there
@@ -160,6 +161,11 @@ public class CachePopup extends AbstractPopupActivity {
return;
}
+ if (!Network.isNetworkConnected(getApplicationContext())) {
+ showToast(getString(R.string.err_server));
+ return;
+ }
+
final RefreshCacheHandler refreshCacheHandler = new RefreshCacheHandler();
progress.show(CachePopup.this, res.getString(R.string.cache_dialog_refresh_title), res.getString(R.string.cache_dialog_refresh_message), true, refreshCacheHandler.cancelMessage());
new RefreshCacheThread(refreshCacheHandler).start();
diff --git a/main/src/cgeo/geocaching/cgeonavigate.java b/main/src/cgeo/geocaching/CompassActivity.java
index c029ee7..9da428d 100644
--- a/main/src/cgeo/geocaching/cgeonavigate.java
+++ b/main/src/cgeo/geocaching/CompassActivity.java
@@ -1,9 +1,13 @@
package cgeo.geocaching;
+import butterknife.InjectView;
+import butterknife.Views;
+
import cgeo.geocaching.activity.AbstractActivity;
import cgeo.geocaching.geopoint.Geopoint;
import cgeo.geocaching.geopoint.Units;
import cgeo.geocaching.maps.CGeoMap;
+import cgeo.geocaching.speech.SpeechService;
import cgeo.geocaching.ui.CompassView;
import cgeo.geocaching.utils.GeoDirHandler;
import cgeo.geocaching.utils.Log;
@@ -15,7 +19,7 @@ import android.content.Intent;
import android.hardware.Sensor;
import android.hardware.SensorManager;
import android.os.Bundle;
-import android.os.PowerManager;
+import android.speech.tts.TextToSpeech.Engine;
import android.view.Menu;
import android.view.MenuItem;
import android.view.SubMenu;
@@ -26,40 +30,34 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
-public class cgeonavigate extends AbstractActivity {
+public class CompassActivity extends AbstractActivity {
+
+ @InjectView(R.id.nav_type) protected TextView navType;
+ @InjectView(R.id.nav_accuracy) protected TextView navAccuracy;
+ @InjectView(R.id.nav_satellites) protected TextView navSatellites;
+ @InjectView(R.id.nav_location) protected TextView navLocation;
+ @InjectView(R.id.distance) protected TextView distanceView;
+ @InjectView(R.id.heading) protected TextView headingView;
+ @InjectView(R.id.rose) protected CompassView compassView;
+ @InjectView(R.id.destination) protected TextView destinationTextView;
+ @InjectView(R.id.cacheinfo) protected TextView cacheInfoView;
private static final String EXTRAS_COORDS = "coords";
private static final String EXTRAS_NAME = "name";
private static final String EXTRAS_GEOCODE = "geocode";
private static final String EXTRAS_CACHE_INFO = "cacheinfo";
private static final List<IWaypoint> coordinates = new ArrayList<IWaypoint>();
- private static final int MENU_MAP = 0;
- private static final int MENU_SWITCH_COMPASS_GPS = 1;
- private PowerManager pm = null;
+ private static final int COORDINATES_OFFSET = 10;
+ private static final int REQUEST_TTS_DATA_CHECK = 1;
private Geopoint dstCoords = null;
private float cacheHeading = 0;
private String title = null;
private String info = null;
- private TextView navType = null;
- private TextView navAccuracy = null;
- private TextView navSatellites = null;
- private TextView navLocation = null;
- private TextView distanceView = null;
- private TextView headingView = null;
- private CompassView compassView = null;
private boolean hasMagneticFieldSensor;
- public cgeonavigate() {
- super("c:geo-compass", true);
- }
-
@Override
public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- setTheme();
- setContentView(R.layout.navigate);
- setTitle(res.getString(R.string.compass_title));
+ super.onCreate(savedInstanceState, R.layout.compass_activity);
final SensorManager sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
hasMagneticFieldSensor = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) != null;
@@ -72,7 +70,7 @@ public class cgeonavigate extends AbstractActivity {
if (extras != null) {
title = extras.getString(EXTRAS_GEOCODE);
final String name = extras.getString(EXTRAS_NAME);
- dstCoords = (Geopoint) extras.getParcelable(EXTRAS_COORDS);
+ dstCoords = extras.getParcelable(EXTRAS_COORDS);
info = extras.getString(EXTRAS_CACHE_INFO);
if (StringUtils.isNotBlank(name)) {
@@ -95,8 +93,7 @@ public class cgeonavigate extends AbstractActivity {
setDestCoords();
setCacheInfo();
- // get textviews once
- compassView = (CompassView) findViewById(R.id.rose);
+ Views.inject(this);
}
@Override
@@ -105,11 +102,6 @@ public class cgeonavigate extends AbstractActivity {
// sensor & geolocation manager
geoDirHandler.startGeoAndDir();
-
- // keep backlight on
- if (pm == null) {
- pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
- }
}
@Override
@@ -121,24 +113,22 @@ public class cgeonavigate extends AbstractActivity {
@Override
public void onDestroy() {
compassView.destroyDrawingCache();
+ SpeechService.stopService(this);
super.onDestroy();
}
@Override
public boolean onCreateOptionsMenu(final Menu menu) {
- menu.add(0, MENU_SWITCH_COMPASS_GPS, 0, res.getString(Settings.isUseCompass() ? R.string.use_gps : R.string.use_compass)).setIcon(R.drawable.ic_menu_compass);
- menu.findItem(MENU_SWITCH_COMPASS_GPS).setVisible(hasMagneticFieldSensor);
- menu.add(0, MENU_MAP, 0, res.getString(R.string.caches_on_map)).setIcon(R.drawable.ic_menu_mapmode);
- menu.add(0, 2, 0, res.getString(R.string.destination_set)).setIcon(R.drawable.ic_menu_edit);
+ getMenuInflater().inflate(R.menu.compass_activity_options, menu);
+ menu.findItem(R.id.menu_switch_compass_gps).setVisible(hasMagneticFieldSensor);
+ final SubMenu subMenu = menu.findItem(R.id.menu_select_destination).getSubMenu();
if (coordinates.size() > 1) {
- final SubMenu subMenu = menu.addSubMenu(0, 3, 0, res.getString(R.string.destination_select)).setIcon(R.drawable.ic_menu_myplaces);
- int cnt = 4;
- for (final IWaypoint coordinate : coordinates) {
- subMenu.add(0, cnt, 0, coordinate.getName() + " (" + coordinate.getCoordType() + ")");
- cnt++;
+ for (int i = 0; i < coordinates.size(); i++) {
+ final IWaypoint coordinate = coordinates.get(i);
+ subMenu.add(0, COORDINATES_OFFSET + i, 0, coordinate.getName() + " (" + coordinate.getCoordType() + ")");
}
} else {
- menu.add(0, 3, 0, res.getString(R.string.destination_select)).setIcon(R.drawable.ic_menu_myplaces).setEnabled(false);
+ menu.findItem(R.id.menu_select_destination).setVisible(false);
}
return true;
}
@@ -146,46 +136,72 @@ public class cgeonavigate extends AbstractActivity {
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
- menu.findItem(MENU_SWITCH_COMPASS_GPS).setTitle(res.getString(Settings.isUseCompass() ? R.string.use_gps : R.string.use_compass));
+ menu.findItem(R.id.menu_switch_compass_gps).setTitle(res.getString(Settings.isUseCompass() ? R.string.use_gps : R.string.use_compass));
+ menu.findItem(R.id.menu_tts_start).setVisible(!SpeechService.isRunning());
+ menu.findItem(R.id.menu_tts_stop).setVisible(SpeechService.isRunning());
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
+ switch (id) {
+ case R.id.menu_map:
+ CGeoMap.startActivityCoords(this, dstCoords, null, null);
+ return true;
+ case R.id.menu_switch_compass_gps:
+ boolean oldSetting = Settings.isUseCompass();
+ Settings.setUseCompass(!oldSetting);
+ invalidateOptionsMenuCompatible();
+ if (oldSetting) {
+ geoDirHandler.stopDir();
+ } else {
+ geoDirHandler.startDir();
+ }
+ return true;
+ case R.id.menu_edit_destination:
+ Intent pointIntent = new Intent(this, NavigateAnyPointActivity.class);
+ startActivity(pointIntent);
+
+ finish();
+ return true;
+ case R.id.menu_tts_start:
+ initTextToSpeech();
+ return true;
+ case R.id.menu_tts_stop:
+ SpeechService.stopService(this);
+ return true;
+ default:
+ int coordinatesIndex = id - COORDINATES_OFFSET;
+ if (coordinatesIndex >= 0 && coordinatesIndex < coordinates.size()) {
+ final IWaypoint coordinate = coordinates.get(coordinatesIndex);
+ title = coordinate.getName();
+ dstCoords = coordinate.getCoords();
+ setTitle();
+ setDestCoords();
+ setCacheInfo();
+ updateDistanceInfo(app.currentGeo());
+
+ Log.d("destination set: " + title + " (" + dstCoords + ")");
+ return true;
+ }
+ }
+ return false;
+ }
- if (id == MENU_MAP) {
- CGeoMap.startActivityCoords(this, dstCoords, null, null);
- } else if (id == MENU_SWITCH_COMPASS_GPS) {
- boolean oldSetting = Settings.isUseCompass();
- Settings.setUseCompass(!oldSetting);
- invalidateOptionsMenuCompatible();
- if (oldSetting) {
- geoDirHandler.stopDir();
- } else {
- geoDirHandler.startDir();
- }
- } else if (id == 2) {
- Intent pointIntent = new Intent(this, NavigateAnyPointActivity.class);
- startActivity(pointIntent);
+ private void initTextToSpeech() {
+ Intent intent = new Intent(Engine.ACTION_CHECK_TTS_DATA);
+ startActivityForResult(intent, REQUEST_TTS_DATA_CHECK);
+ }
- finish();
- return true;
- } else if (id > 3 && coordinates.get(id - 4) != null) {
- final IWaypoint coordinate = coordinates.get(id - 4);
-
- title = coordinate.getName();
- dstCoords = coordinate.getCoords();
- setTitle();
- setDestCoords();
- setCacheInfo();
- updateDistanceInfo(app.currentGeo());
-
- Log.d("destination set: " + title + " (" + dstCoords + ")");
- return true;
+ @Override
+ protected void onActivityResult(int request, int result, Intent data) {
+ if (request == REQUEST_TTS_DATA_CHECK && result == Engine.CHECK_VOICE_DATA_PASS) {
+ SpeechService.startService(this, dstCoords);
+ } else {
+ Log.i("TTS failed to start. Request: " + request + " result: " + result);
+ startActivity(new Intent(Engine.ACTION_INSTALL_TTS_DATA));
}
-
- return false;
}
private void setTitle() {
@@ -201,11 +217,10 @@ public class cgeonavigate extends AbstractActivity {
return;
}
- ((TextView) findViewById(R.id.destination)).setText(dstCoords.toString());
+ destinationTextView.setText(dstCoords.toString());
}
private void setCacheInfo() {
- final TextView cacheInfoView = (TextView) findViewById(R.id.cacheinfo);
if (info == null) {
cacheInfoView.setVisibility(View.GONE);
return;
@@ -219,13 +234,6 @@ public class cgeonavigate extends AbstractActivity {
return;
}
- if (distanceView == null) {
- distanceView = (TextView) findViewById(R.id.distance);
- }
- if (headingView == null) {
- headingView = (TextView) findViewById(R.id.heading);
- }
-
cacheHeading = geo.getCoords().bearingTo(dstCoords);
distanceView.setText(Units.getDistanceFromKilometers(geo.getCoords().distanceTo(dstCoords)));
headingView.setText(Math.round(cacheHeading) + "°");
@@ -235,18 +243,10 @@ public class cgeonavigate extends AbstractActivity {
@Override
public void updateGeoData(final IGeoData geo) {
try {
- if (navType == null || navLocation == null || navAccuracy == null) {
- navType = (TextView) findViewById(R.id.nav_type);
- navAccuracy = (TextView) findViewById(R.id.nav_accuracy);
- navSatellites = (TextView) findViewById(R.id.nav_satellites);
- navLocation = (TextView) findViewById(R.id.nav_location);
- }
-
if (geo.getCoords() != null) {
if (geo.getSatellitesVisible() >= 0) {
navSatellites.setText(res.getString(R.string.loc_sat) + ": " + geo.getSatellitesFixed() + "/" + geo.getSatellitesVisible());
- }
- else {
+ } else {
navSatellites.setText("");
}
navType.setText(res.getString(geo.getLocationProvider().resourceId));
@@ -282,7 +282,7 @@ public class cgeonavigate extends AbstractActivity {
@Override
public void updateDirection(final float direction) {
if (app.currentGeo().getSpeed() <= 5) { // use compass when speed is lower than 18 km/h
- updateNorthHeading(DirectionProvider.getDirectionNow(cgeonavigate.this, direction));
+ updateNorthHeading(DirectionProvider.getDirectionNow(CompassActivity.this, direction));
}
}
};
@@ -296,11 +296,15 @@ public class cgeonavigate extends AbstractActivity {
public static void startActivity(final Context context, final String geocode, final String displayedName, final Geopoint coords, final Collection<IWaypoint> coordinatesWithType,
final String info) {
coordinates.clear();
- if (coordinatesWithType != null) { // avoid possible NPE
- coordinates.addAll(coordinatesWithType);
+ if (coordinatesWithType != null) {
+ for (IWaypoint coordinate : coordinatesWithType) {
+ if (coordinate != null) {
+ coordinates.add(coordinate);
+ }
+ }
}
- final Intent navigateIntent = new Intent(context, cgeonavigate.class);
+ final Intent navigateIntent = new Intent(context, CompassActivity.class);
navigateIntent.putExtra(EXTRAS_COORDS, coords);
navigateIntent.putExtra(EXTRAS_GEOCODE, geocode);
if (null != displayedName) {
@@ -311,7 +315,7 @@ public class cgeonavigate extends AbstractActivity {
}
public static void startActivity(final Context context, final String geocode, final String displayedName, final Geopoint coords, final Collection<IWaypoint> coordinatesWithType) {
- cgeonavigate.startActivity(context, geocode, displayedName, coords, coordinatesWithType, null);
+ CompassActivity.startActivity(context, geocode, displayedName, coords, coordinatesWithType, null);
}
}
diff --git a/main/src/cgeo/geocaching/DirectionProvider.java b/main/src/cgeo/geocaching/DirectionProvider.java
index c1f83ac..37b184a 100644
--- a/main/src/cgeo/geocaching/DirectionProvider.java
+++ b/main/src/cgeo/geocaching/DirectionProvider.java
@@ -14,7 +14,7 @@ public class DirectionProvider extends MemorySubject<Float> implements SensorEve
private final SensorManager sensorManager;
- // Previous values signaled to observers to avoid resending the same value when the
+ // Previous values signaled to observers to avoid re-sending the same value when the
// device doesn't change orientation. The orientation is usually given with a 1 degree
// precision by Android, so it is not uncommon to obtain exactly the same value several
// times.
@@ -27,7 +27,8 @@ public class DirectionProvider extends MemorySubject<Float> implements SensorEve
@Override
protected void onFirstObserver() {
- sensorManager.registerListener(this, sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION), SensorManager.SENSOR_DELAY_NORMAL);
+ final Sensor defaultSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
+ sensorManager.registerListener(this, defaultSensor, SensorManager.SENSOR_DELAY_NORMAL);
}
@Override
@@ -43,7 +44,7 @@ public class DirectionProvider extends MemorySubject<Float> implements SensorEve
* this event leads to the log being flooded with multiple entries _per second_,
* which I experienced when running cgeo in a building (with GPS and network being
* unreliable).
- *
+ *
* See for example https://code.google.com/p/android/issues/detail?id=14792
*/
diff --git a/main/src/cgeo/geocaching/EditWaypointActivity.java b/main/src/cgeo/geocaching/EditWaypointActivity.java
index 7f011fc..dce49a3 100644
--- a/main/src/cgeo/geocaching/EditWaypointActivity.java
+++ b/main/src/cgeo/geocaching/EditWaypointActivity.java
@@ -1,7 +1,6 @@
package cgeo.geocaching;
import cgeo.geocaching.activity.AbstractActivity;
-import cgeo.geocaching.activity.ActivityMixin;
import cgeo.geocaching.connector.ConnectorFactory;
import cgeo.geocaching.connector.IConnector;
import cgeo.geocaching.enumerations.CacheType;
@@ -12,15 +11,19 @@ import cgeo.geocaching.geopoint.DistanceParser;
import cgeo.geocaching.geopoint.Geopoint;
import cgeo.geocaching.geopoint.GeopointFormatter;
import cgeo.geocaching.ui.dialog.CoordinatesInputDialog;
-import cgeo.geocaching.utils.BaseUtils;
+import cgeo.geocaching.utils.TextUtils;
import cgeo.geocaching.utils.GeoDirHandler;
import cgeo.geocaching.utils.Log;
+import com.googlecode.androidannotations.annotations.EActivity;
+import com.googlecode.androidannotations.annotations.Extra;
+import com.googlecode.androidannotations.annotations.InstanceState;
+import com.googlecode.androidannotations.annotations.ViewById;
+
import org.apache.commons.lang3.StringUtils;
import android.app.ProgressDialog;
import android.content.Context;
-import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
@@ -28,76 +31,88 @@ import android.os.Message;
import android.text.Html;
import android.view.View;
import android.widget.AdapterView;
-import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
import android.widget.Button;
import android.widget.CheckBox;
-import android.widget.CompoundButton;
-import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.EditText;
import android.widget.RadioButton;
+import android.widget.RadioGroup;
import android.widget.Spinner;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.EnumSet;
import java.util.List;
+@EActivity
public class EditWaypointActivity extends AbstractActivity {
+ @ViewById(R.id.buttonLatitude) protected Button buttonLat;
+ @ViewById(R.id.buttonLongitude) protected Button buttonLon;
+ @ViewById(R.id.add_waypoint) protected Button addWaypoint;
+ @ViewById(R.id.note) protected EditText note;
+ @ViewById(R.id.wpt_visited_checkbox) protected CheckBox visitedCheckBox;
+ @ViewById(R.id.name) protected AutoCompleteTextView waypointName;
+ @ViewById(R.id.type) protected Spinner waypointTypeSelector;
+ @ViewById(R.id.distance) protected EditText distanceView;
+ @ViewById(R.id.modify_cache_coordinates_group) protected RadioGroup coordinatesGroup;
+ @ViewById(R.id.modify_cache_coordinates_local_and_remote) protected RadioButton modifyBoth;
+ @ViewById(R.id.distanceUnit) protected Spinner distanceUnitSelector;
+ @ViewById(R.id.bearing) protected EditText bearing;
+ @ViewById(R.id.modify_cache_coordinates_local) protected RadioButton modifyLocal;
+
+ @Extra(Intents.EXTRA_GEOCODE) protected String geocode = null;
+ @Extra(Intents.EXTRA_WAYPOINT_ID) protected int id = -1;
+ /**
+ * number of waypoints that the corresponding cache has until now
+ */
+ @Extra(Intents.EXTRA_COUNT) protected int wpCount = 0;
- private String geocode = null;
- private int id = -1;
+ @InstanceState protected int waypointTypeSelectorPosition = -1;
private ProgressDialog waitDialog = null;
private Waypoint waypoint = null;
- private Geopoint gpTemp = null;
- private WaypointType type = WaypointType.OWN;
private String prefix = "OWN";
private String lookup = "---";
private boolean own = true;
- private boolean visited = false;
ArrayList<WaypointType> wpTypes = null;
- String distanceUnit = "";
+ ArrayList<String> distanceUnits = null;
+ private boolean initViews = true;
- /**
- * number of waypoints that the corresponding cache has until now
- */
- private int wpCount = 0;
private Handler loadWaypointHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
try {
if (waypoint == null) {
+ Log.d("No waypoint loaded to edit. id= " + id);
id = -1;
} else {
geocode = waypoint.getGeocode();
- type = waypoint.getWaypointType();
prefix = waypoint.getPrefix();
lookup = waypoint.getLookup();
own = waypoint.isUserDefined();
- visited = waypoint.isVisited();
- if (waypoint.getCoords() != null) {
- ((Button) findViewById(R.id.buttonLatitude)).setText(waypoint.getCoords().format(GeopointFormatter.Format.LAT_DECMINUTE));
- ((Button) findViewById(R.id.buttonLongitude)).setText(waypoint.getCoords().format(GeopointFormatter.Format.LON_DECMINUTE));
- }
- ((EditText) findViewById(R.id.name)).setText(Html.fromHtml(StringUtils.trimToEmpty(waypoint.getName())).toString());
- if (BaseUtils.containsHtml(waypoint.getNote())) {
- ((EditText) findViewById(R.id.note)).setText(Html.fromHtml(StringUtils.trimToEmpty(waypoint.getNote())).toString());
- }
- else {
- ((EditText) findViewById(R.id.note)).setText(StringUtils.trimToEmpty(waypoint.getNote()));
+ if (initViews) {
+ visitedCheckBox.setChecked(waypoint.isVisited());
+ if (waypoint.getCoords() != null) {
+ buttonLat.setText(waypoint.getCoords().format(GeopointFormatter.Format.LAT_DECMINUTE));
+ buttonLon.setText(waypoint.getCoords().format(GeopointFormatter.Format.LON_DECMINUTE));
+ }
+ waypointName.setText(Html.fromHtml(StringUtils.trimToEmpty(waypoint.getName())).toString());
+ if (TextUtils.containsHtml(waypoint.getNote())) {
+ note.setText(Html.fromHtml(StringUtils.trimToEmpty(waypoint.getNote())).toString());
+ }
+ else {
+ note.setText(StringUtils.trimToEmpty(waypoint.getNote()));
+ }
}
- Geocache cache = cgData.loadCache(geocode, LoadFlags.LOAD_CACHE_ONLY);
+ final Geocache cache = cgData.loadCache(geocode, LoadFlags.LOAD_CACHE_ONLY);
setCoordsModificationVisibility(ConnectorFactory.getConnector(geocode), cache);
}
if (own) {
initializeWaypointTypeSelector();
}
- ((CheckBox) findViewById(R.id.wpt_visited_checkbox)).setChecked(visited);
-
- initializeDistanceUnitSelector();
} catch (Exception e) {
Log.e("EditWaypointActivity.loadWaypointHandler", e);
} finally {
@@ -111,19 +126,7 @@ public class EditWaypointActivity extends AbstractActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- setTheme();
- setContentView(R.layout.edit_waypoint_activity);
- setTitle("waypoint");
-
- // get parameters
- Bundle extras = getIntent().getExtras();
- if (extras != null) {
- geocode = extras.getString(Intents.EXTRA_GEOCODE);
- wpCount = extras.getInt(Intents.EXTRA_COUNT, 0);
- id = extras.getInt(Intents.EXTRA_WAYPOINT_ID);
- }
+ super.onCreate(savedInstanceState, R.layout.editwaypoint_activity);
if (StringUtils.isBlank(geocode) && id <= 0) {
showToast(res.getString(R.string.err_waypoint_cache_unknown));
@@ -138,59 +141,49 @@ public class EditWaypointActivity extends AbstractActivity {
setTitle(res.getString(R.string.waypoint_edit_title));
}
- Button buttonLat = (Button) findViewById(R.id.buttonLatitude);
buttonLat.setOnClickListener(new CoordDialogListener());
- Button buttonLon = (Button) findViewById(R.id.buttonLongitude);
buttonLon.setOnClickListener(new CoordDialogListener());
- Button addWaypoint = (Button) findViewById(R.id.add_waypoint);
- addWaypoint.setOnClickListener(new CoordsListener());
+ addWaypoint.setOnClickListener(new SaveWaypointListener());
List<String> wayPointNames = new ArrayList<String>();
for (WaypointType wpt : WaypointType.ALL_TYPES_EXCEPT_OWN_AND_ORIGINAL) {
wayPointNames.add(wpt.getL10n());
}
- AutoCompleteTextView textView = (AutoCompleteTextView) findViewById(R.id.name);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_dropdown_item_1line, wayPointNames);
- textView.setAdapter(adapter);
+ waypointName.setAdapter(adapter);
- if (id > 0) {
- Spinner waypointTypeSelector = (Spinner) findViewById(R.id.type);
- waypointTypeSelector.setVisibility(View.GONE);
+ if (savedInstanceState != null) {
+ initViews = false;
+ }
+ if (id > 0) { // existing waypoint
waitDialog = ProgressDialog.show(this, null, res.getString(R.string.waypoint_loading), true);
waitDialog.setCancelable(true);
(new LoadWaypointThread()).start();
- } else {
+
+ } else { // new waypoint
initializeWaypointTypeSelector();
- }
- if (geocode != null) {
- Geocache cache = cgData.loadCache(geocode, LoadFlags.LOAD_CACHE_OR_DB);
- IConnector con = ConnectorFactory.getConnector(geocode);
- setCoordsModificationVisibility(con, cache);
- }
- CheckBox visitedCheckBox = ((CheckBox) findViewById(R.id.wpt_visited_checkbox));
- visitedCheckBox.setOnCheckedChangeListener(new OnCheckedChangeListener() {
- @Override
- public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
- visited = isChecked;
+ if (geocode != null) {
+ final Geocache cache = cgData.loadCache(geocode, LoadFlags.LOAD_CACHE_OR_DB);
+ setCoordsModificationVisibility(ConnectorFactory.getConnector(geocode), cache);
}
- });
+ }
initializeDistanceUnitSelector();
- disableSuggestions((EditText) findViewById(R.id.distance));
+ disableSuggestions(distanceView);
}
private void setCoordsModificationVisibility(IConnector con, Geocache cache) {
if (cache != null && (cache.getType() == CacheType.MYSTERY || cache.getType() == CacheType.MULTI)) {
- findViewById(R.id.modify_cache_coordinates_group).setVisibility(View.VISIBLE);
- findViewById(R.id.modify_cache_coordinates_local_and_remote).setVisibility(con.supportsOwnCoordinates() ? View.VISIBLE : View.GONE);
+ coordinatesGroup.setVisibility(View.VISIBLE);
+ modifyBoth.setVisibility(con.supportsOwnCoordinates() ? View.VISIBLE : View.GONE);
} else {
- findViewById(R.id.modify_cache_coordinates_group).setVisibility(View.GONE);
- findViewById(R.id.modify_cache_coordinates_local_and_remote).setVisibility(View.GONE);
+ coordinatesGroup.setVisibility(View.GONE);
+ modifyBoth.setVisibility(View.GONE);
}
}
@@ -199,25 +192,6 @@ public class EditWaypointActivity extends AbstractActivity {
super.onResume();
geoDirHandler.startGeo();
-
- if (id > 0) {
- if (waitDialog == null) {
- waitDialog = ProgressDialog.show(this, null, res.getString(R.string.waypoint_loading), true);
- waitDialog.setCancelable(true);
-
- (new LoadWaypointThread()).start();
- }
- }
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- }
-
- @Override
- public void onStop() {
- super.onStop();
}
@Override
@@ -227,40 +201,40 @@ public class EditWaypointActivity extends AbstractActivity {
}
private void initializeWaypointTypeSelector() {
-
- Spinner waypointTypeSelector = (Spinner) findViewById(R.id.type);
-
wpTypes = new ArrayList<WaypointType>(WaypointType.ALL_TYPES_EXCEPT_OWN_AND_ORIGINAL);
ArrayAdapter<WaypointType> wpAdapter = new ArrayAdapter<WaypointType>(this, android.R.layout.simple_spinner_item, wpTypes.toArray(new WaypointType[wpTypes.size()]));
wpAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
waypointTypeSelector.setAdapter(wpAdapter);
- int typeIndex = wpTypes.indexOf(type);
- if (typeIndex < 0) {
- typeIndex = wpTypes.indexOf(WaypointType.WAYPOINT);
- }
+ waypointTypeSelector.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView<?> parent, View v, int pos, long id) {
+ waypointTypeSelectorPosition = pos;
+ }
- waypointTypeSelector.setSelection(typeIndex);
- waypointTypeSelector.setOnItemSelectedListener(new ChangeWaypointType(this));
+ @Override
+ public void onNothingSelected(AdapterView<?> parent) {
+ }
+ });
+
+ if (initViews) {
+ int typeIndex = -1;
+ if (waypoint != null) {
+ typeIndex = wpTypes.indexOf(waypoint.getWaypointType());
+ }
+ waypointTypeSelector.setSelection(typeIndex >= 0 ? typeIndex : wpTypes.indexOf(WaypointType.WAYPOINT));
+ } else {
+ waypointTypeSelector.setSelection(waypointTypeSelectorPosition);
+ }
waypointTypeSelector.setVisibility(View.VISIBLE);
}
private void initializeDistanceUnitSelector() {
-
- Spinner distanceUnitSelector = (Spinner) findViewById(R.id.distanceUnit);
-
- if (StringUtils.isBlank(distanceUnit)) {
- if (Settings.isUseMetricUnits()) {
- distanceUnitSelector.setSelection(0); // m
- distanceUnit = res.getStringArray(R.array.distance_units)[0];
- } else {
- distanceUnitSelector.setSelection(2); // ft
- distanceUnit = res.getStringArray(R.array.distance_units)[2];
- }
+ distanceUnits = new ArrayList<String>(Arrays.asList(res.getStringArray(R.array.distance_units)));
+ if (initViews) {
+ distanceUnitSelector.setSelection(Settings.isUseMetricUnits() ? 0 : 2); //0:m, 2:ft
}
-
- distanceUnitSelector.setOnItemSelectedListener(new ChangeDistanceUnit(this));
}
final private GeoDirHandler geoDirHandler = new GeoDirHandler() {
@@ -271,10 +245,8 @@ public class EditWaypointActivity extends AbstractActivity {
}
try {
- Button bLat = (Button) findViewById(R.id.buttonLatitude);
- Button bLon = (Button) findViewById(R.id.buttonLongitude);
- bLat.setHint(geo.getCoords().format(GeopointFormatter.Format.LAT_DECMINUTE_RAW));
- bLon.setHint(geo.getCoords().format(GeopointFormatter.Format.LON_DECMINUTE_RAW));
+ buttonLat.setHint(geo.getCoords().format(GeopointFormatter.Format.LAT_DECMINUTE_RAW));
+ buttonLon.setHint(geo.getCoords().format(GeopointFormatter.Format.LON_DECMINUTE_RAW));
} catch (final Exception e) {
Log.e("failed to update location", e);
}
@@ -290,7 +262,7 @@ public class EditWaypointActivity extends AbstractActivity {
loadWaypointHandler.sendMessage(Message.obtain());
} catch (Exception e) {
- Log.e("cgeowaypoint.loadWaypoint.run", e);
+ Log.e("EditWaypointActivity.loadWaypoint.run", e);
}
}
}
@@ -300,10 +272,10 @@ public class EditWaypointActivity extends AbstractActivity {
@Override
public void onClick(View arg0) {
Geopoint gp = null;
- if (waypoint != null && waypoint.getCoords() != null) {
- gp = waypoint.getCoords();
- } else if (gpTemp != null) {
- gp = gpTemp;
+ try {
+ gp = new Geopoint(buttonLat.getText().toString(), buttonLon.getText().toString());
+ } catch (Geopoint.ParseException e) {
+ // button text is blank when creating new waypoint
}
Geocache cache = cgData.loadCache(geocode, LoadFlags.LOAD_WAYPOINTS);
CoordinatesInputDialog coordsDialog = new CoordinatesInputDialog(EditWaypointActivity.this, cache, gp, app.currentGeo());
@@ -311,62 +283,14 @@ public class EditWaypointActivity extends AbstractActivity {
coordsDialog.setOnCoordinateUpdate(new CoordinatesInputDialog.CoordinateUpdate() {
@Override
public void update(final Geopoint gp) {
- ((Button) findViewById(R.id.buttonLatitude)).setText(gp.format(GeopointFormatter.Format.LAT_DECMINUTE));
- ((Button) findViewById(R.id.buttonLongitude)).setText(gp.format(GeopointFormatter.Format.LON_DECMINUTE));
- if (waypoint != null) {
- waypoint.setCoords(gp);
- } else {
- gpTemp = gp;
- }
+ buttonLat.setText(gp.format(GeopointFormatter.Format.LAT_DECMINUTE));
+ buttonLon.setText(gp.format(GeopointFormatter.Format.LON_DECMINUTE));
}
});
coordsDialog.show();
}
}
- private static class ChangeWaypointType implements OnItemSelectedListener {
-
- private ChangeWaypointType(EditWaypointActivity wpView) {
- this.wpView = wpView;
- }
-
- private EditWaypointActivity wpView;
-
- @Override
- public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2,
- long arg3) {
- if (null != wpView.wpTypes) {
- wpView.type = wpView.wpTypes.get(arg2);
- }
- }
-
- @Override
- public void onNothingSelected(AdapterView<?> arg0) {
- if (null != wpView.wpTypes) {
- arg0.setSelection(wpView.wpTypes.indexOf(wpView.type));
- }
- }
- }
-
- private static class ChangeDistanceUnit implements OnItemSelectedListener {
-
- private ChangeDistanceUnit(EditWaypointActivity unitView) {
- this.unitView = unitView;
- }
-
- private EditWaypointActivity unitView;
-
- @Override
- public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2,
- long arg3) {
- unitView.distanceUnit = (String) arg0.getItemAtPosition(arg2);
- }
-
- @Override
- public void onNothingSelected(AdapterView<?> arg0) {
- }
- }
-
public static final int SUCCESS = 0;
public static final int UPLOAD_START = 1;
public static final int UPLOAD_ERROR = 2;
@@ -374,15 +298,15 @@ public class EditWaypointActivity extends AbstractActivity {
public static final int UPLOAD_SUCCESS = 4;
public static final int SAVE_ERROR = 5;
- private class CoordsListener implements View.OnClickListener {
+ private class SaveWaypointListener implements View.OnClickListener {
@Override
public void onClick(View arg0) {
- final String bearingText = ((EditText) findViewById(R.id.bearing)).getText().toString();
+ final String bearingText = bearing.getText().toString();
// combine distance from EditText and distanceUnit saved from Spinner
- final String distanceText = ((EditText) findViewById(R.id.distance)).getText().toString() + distanceUnit;
- final String latText = ((Button) findViewById(R.id.buttonLatitude)).getText().toString();
- final String lonText = ((Button) findViewById(R.id.buttonLongitude)).getText().toString();
+ final String distanceText = distanceView.getText().toString() + distanceUnits.get(distanceUnitSelector.getSelectedItemPosition());
+ final String latText = buttonLat.getText().toString();
+ final String lonText = buttonLon.getText().toString();
if (StringUtils.isBlank(bearingText) && StringUtils.isBlank(distanceText)
&& StringUtils.isBlank(latText) && StringUtils.isBlank(lonText)) {
@@ -430,10 +354,12 @@ public class EditWaypointActivity extends AbstractActivity {
}
// if no name is given, just give the waypoint its number as name
- final String givenName = ((EditText) findViewById(R.id.name)).getText().toString().trim();
+ final String givenName = waypointName.getText().toString().trim();
final String name = StringUtils.isNotEmpty(givenName) ? givenName : res.getString(R.string.waypoint) + " " + (wpCount + 1);
- final String note = ((EditText) findViewById(R.id.note)).getText().toString().trim();
+ final String noteText = note.getText().toString().trim();
final Geopoint coordsToSave = coords;
+ final WaypointType type = wpTypes.get(waypointTypeSelector.getSelectedItemPosition());
+ final boolean visited = visitedCheckBox.isChecked();
final ProgressDialog progress = ProgressDialog.show(EditWaypointActivity.this, getString(R.string.cache), getString(R.string.waypoint_being_saved), true);
final Handler finishHandler = new Handler() {
@@ -483,7 +409,7 @@ public class EditWaypointActivity extends AbstractActivity {
waypoint.setPrefix(prefix);
waypoint.setLookup(lookup);
waypoint.setCoords(coordsToSave);
- waypoint.setNote(note);
+ waypoint.setNote(noteText);
waypoint.setVisited(visited);
waypoint.setId(id);
@@ -501,8 +427,6 @@ public class EditWaypointActivity extends AbstractActivity {
StaticMapsProvider.storeWaypointStaticMap(cache, waypoint, false);
}
}
- final RadioButton modifyLocal = (RadioButton) findViewById(R.id.modify_cache_coordinates_local);
- final RadioButton modifyBoth = (RadioButton) findViewById(R.id.modify_cache_coordinates_local_and_remote);
if (modifyLocal.isChecked() || modifyBoth.isChecked()) {
if (!cache.hasUserModifiedCoords()) {
final Waypoint origWaypoint = new Waypoint(cgeoapplication.getInstance().getString(R.string.cache_coordinates_original), WaypointType.ORIGINAL, false);
@@ -541,19 +465,11 @@ public class EditWaypointActivity extends AbstractActivity {
return con.supportsOwnCoordinates() && con.uploadModifiedCoordinates(cache, waypointUploaded);
}
- @Override
- public void goManual(final View view) {
- ActivityMixin.goManual(this, id >= 0 ? "c:geo-waypoint-edit" : "c:geo-waypoint-new");
- }
-
public static void startActivityEditWaypoint(final Context context, final int waypointId) {
- context.startActivity(new Intent(context, EditWaypointActivity.class)
- .putExtra(Intents.EXTRA_WAYPOINT_ID, waypointId));
+ EditWaypointActivity_.intent(context).id(waypointId).start();
}
public static void startActivityAddWaypoint(final Context context, final Geocache cache) {
- context.startActivity(new Intent(context, EditWaypointActivity.class)
- .putExtra(Intents.EXTRA_GEOCODE, cache.getGeocode())
- .putExtra(Intents.EXTRA_COUNT, cache.getWaypoints().size()));
+ EditWaypointActivity_.intent(context).geocode(cache.getGeocode()).wpCount(cache.getWaypoints().size()).start();
}
}
diff --git a/main/src/cgeo/geocaching/Geocache.java b/main/src/cgeo/geocaching/Geocache.java
index 836cccb..1972c7a 100644
--- a/main/src/cgeo/geocaching/Geocache.java
+++ b/main/src/cgeo/geocaching/Geocache.java
@@ -5,13 +5,13 @@ import cgeo.geocaching.activity.ActivityMixin;
import cgeo.geocaching.activity.IAbstractActivity;
import cgeo.geocaching.connector.ConnectorFactory;
import cgeo.geocaching.connector.IConnector;
+import cgeo.geocaching.connector.ILoggingManager;
import cgeo.geocaching.connector.capability.ISearchByCenter;
import cgeo.geocaching.connector.capability.ISearchByGeocode;
import cgeo.geocaching.connector.gc.GCConnector;
import cgeo.geocaching.connector.gc.GCConstants;
import cgeo.geocaching.connector.gc.Tile;
import cgeo.geocaching.enumerations.CacheAttribute;
-import cgeo.geocaching.enumerations.CacheRealm;
import cgeo.geocaching.enumerations.CacheSize;
import cgeo.geocaching.enumerations.CacheType;
import cgeo.geocaching.enumerations.LoadFlags;
@@ -47,8 +47,8 @@ import java.util.Collections;
import java.util.Date;
import java.util.EnumSet;
import java.util.HashMap;
-import java.util.LinkedList;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
import java.util.regex.Pattern;
@@ -175,7 +175,9 @@ public class Geocache implements ICache, IWaypoint {
}
/**
- * Gather missing information from another cache object.
+ * Gather missing information for new Geocache object from the stored Geocache object.
+ * This is called in the new Geocache parsed from website to set information not yet
+ * parsed.
*
* @param other
* the other version, or null if non-existent
@@ -187,6 +189,8 @@ public class Geocache implements ICache, IWaypoint {
}
updated = System.currentTimeMillis();
+ // if parsed cache is not yet detailed and stored is, the information of
+ // the parsed cache will be overwritten
if (!detailed && (other.detailed || zoomlevel < other.zoomlevel)) {
detailed = other.detailed;
detailedUpdate = other.detailedUpdate;
@@ -194,15 +198,19 @@ public class Geocache implements ICache, IWaypoint {
cacheType = other.cacheType;
zoomlevel = other.zoomlevel;
// boolean values must be enumerated here. Other types are assigned outside this if-statement
+ // TODO: check whether a search or a live map systematically returns those, in which case
+ // we want to keep the most recent one instead of getting information from the previously
+ // stored data. This is the case for "archived" for example which has been taken out of this
+ // list.
premiumMembersOnly = other.premiumMembersOnly;
reliableLatLon = other.reliableLatLon;
- archived = other.archived;
found = other.found;
disabled = other.disabled;
favorite = other.favorite;
onWatchlist = other.onWatchlist;
logOffline = other.logOffline;
finalDefined = other.finalDefined;
+ archived = other.archived;
}
/*
@@ -447,13 +455,13 @@ public class Geocache implements ICache, IWaypoint {
}
public void logVisit(final IAbstractActivity fromActivity) {
- if (StringUtils.isBlank(cacheId)) {
+ if (!getConnector().canLog(this)) {
fromActivity.showToast(((Activity) fromActivity).getResources().getString(R.string.err_cannot_log_visit));
return;
}
- Intent logVisitIntent = new Intent((Activity) fromActivity, VisitCacheActivity.class);
- logVisitIntent.putExtra(VisitCacheActivity.EXTRAS_ID, cacheId);
- logVisitIntent.putExtra(VisitCacheActivity.EXTRAS_GEOCODE, geocode);
+ Intent logVisitIntent = new Intent((Activity) fromActivity, LogCacheActivity.class);
+ logVisitIntent.putExtra(LogCacheActivity.EXTRAS_ID, cacheId);
+ logVisitIntent.putExtra(LogCacheActivity.EXTRAS_GEOCODE, geocode);
((Activity) fromActivity).startActivity(logVisitIntent);
}
@@ -482,35 +490,43 @@ public class Geocache implements ICache, IWaypoint {
}
}
+ public void clearOfflineLog() {
+ cgData.clearLogOffline(geocode);
+ notifyChange();
+ }
+
public List<LogType> getPossibleLogTypes() {
- final List<LogType> logTypes = new LinkedList<LogType>();
+ final List<LogType> logTypes = new ArrayList<LogType>();
if (isEventCache()) {
logTypes.add(LogType.WILL_ATTEND);
- logTypes.add(LogType.NOTE);
logTypes.add(LogType.ATTENDED);
- logTypes.add(LogType.NEEDS_ARCHIVE);
if (isOwner()) {
logTypes.add(LogType.ANNOUNCEMENT);
}
} else if (CacheType.WEBCAM == cacheType) {
logTypes.add(LogType.WEBCAM_PHOTO_TAKEN);
- logTypes.add(LogType.DIDNT_FIND_IT);
- logTypes.add(LogType.NOTE);
- logTypes.add(LogType.NEEDS_ARCHIVE);
- logTypes.add(LogType.NEEDS_MAINTENANCE);
} else {
logTypes.add(LogType.FOUND_IT);
+ }
+ if (!isEventCache()) {
logTypes.add(LogType.DIDNT_FIND_IT);
- logTypes.add(LogType.NOTE);
- logTypes.add(LogType.NEEDS_ARCHIVE);
+ }
+ logTypes.add(LogType.NOTE);
+ if (!isEventCache()) {
logTypes.add(LogType.NEEDS_MAINTENANCE);
}
if (isOwner()) {
logTypes.add(LogType.OWNER_MAINTENANCE);
- logTypes.add(LogType.TEMP_DISABLE_LISTING);
- logTypes.add(LogType.ENABLE_LISTING);
+ if (isDisabled()) {
+ logTypes.add(LogType.ENABLE_LISTING);
+ }
+ else {
+ logTypes.add(LogType.TEMP_DISABLE_LISTING);
+ }
logTypes.add(LogType.ARCHIVE);
- logTypes.remove(LogType.UPDATE_COORDINATES);
+ }
+ if (!isArchived() && !isOwner()) {
+ logTypes.add(LogType.NEEDS_ARCHIVE);
}
return logTypes;
}
@@ -551,12 +567,16 @@ public class Geocache implements ICache, IWaypoint {
return getConnector().supportsLogging();
}
+ public boolean supportsLogImages() {
+ return getConnector().supportsLogImages();
+ }
+
public boolean supportsOwnCoordinates() {
return getConnector().supportsOwnCoordinates();
}
- public CacheRealm getCacheRealm() {
- return getConnector().getCacheRealm();
+ public ILoggingManager getLoggingManager(Activity activity) {
+ return getConnector().getLoggingManager(activity, this);
}
@Override
@@ -710,10 +730,7 @@ public class Geocache implements ICache, IWaypoint {
public String getPersonalNote() {
// non premium members have no personal notes, premium members have an empty string by default.
// map both to null, so other code doesn't need to differentiate
- if (StringUtils.isBlank(personalNote)) {
- return null;
- }
- return personalNote;
+ return StringUtils.defaultIfBlank(personalNote, null);
}
public boolean supportsUserActions() {
@@ -765,8 +782,8 @@ public class Geocache implements ICache, IWaypoint {
return favorite;
}
- public void setFavorite(boolean favourite) {
- this.favorite = favourite;
+ public void setFavorite(boolean favorite) {
+ this.favorite = favorite;
}
@Override
@@ -829,8 +846,7 @@ public class Geocache implements ICache, IWaypoint {
}
public boolean isVirtual() {
- return CacheType.VIRTUAL == cacheType || CacheType.WEBCAM == cacheType
- || CacheType.EARTH == cacheType;
+ return cacheType.isVirtual();
}
public boolean showSize() {
@@ -1360,6 +1376,9 @@ public class Geocache implements ICache, IWaypoint {
return null;
}
+ /**
+ * Detect coordinates in the personal note and convert them to user defined waypoints. Works by rule of thumb.
+ */
public void parseWaypointsFromNote() {
try {
if (StringUtils.isBlank(getPersonalNote())) {
@@ -1378,7 +1397,8 @@ public class Geocache implements ICache, IWaypoint {
((point.getLatitudeE6() % 1000) != 0 || (point.getLongitudeE6() % 1000) != 0) &&
!hasIdenticalWaypoint(point)) {
final String name = cgeoapplication.getInstance().getString(R.string.cache_personal_note) + " " + count;
- final Waypoint waypoint = new Waypoint(name, WaypointType.WAYPOINT, false);
+ final String potentialWaypointType = note.substring(Math.max(0, matcher.start() - 15));
+ final Waypoint waypoint = new Waypoint(name, parseWaypointType(potentialWaypointType), false);
waypoint.setCoords(point);
addOrChangeWaypoint(waypoint, false);
count++;
@@ -1395,9 +1415,30 @@ public class Geocache implements ICache, IWaypoint {
}
}
+ /**
+ * Detect waypoint types in the personal note text. It works by rule of thumb only.
+ */
+ private static WaypointType parseWaypointType(final String input) {
+ final String lowerInput = StringUtils.substring(input, 0, 20).toLowerCase(Locale.getDefault());
+ for (WaypointType wpType : WaypointType.values()) {
+ if (lowerInput.contains(wpType.getL10n().toLowerCase(Locale.getDefault()))) {
+ return wpType;
+ }
+ if (lowerInput.contains(wpType.id)) {
+ return wpType;
+ }
+ if (lowerInput.contains(wpType.name().toLowerCase(Locale.US))) {
+ return wpType;
+ }
+ }
+ return WaypointType.WAYPOINT;
+ }
+
private boolean hasIdenticalWaypoint(final Geopoint point) {
for (final Waypoint waypoint: waypoints) {
- if (waypoint.getCoords().equals(point)) {
+ // waypoint can have no coords such as a Final set by cache owner
+ final Geopoint coords = waypoint.getCoords();
+ if (coords != null && coords.equals(point)) {
return true;
}
}
@@ -1525,9 +1566,12 @@ public class Geocache implements ICache, IWaypoint {
Geocache cache;
// get cache details, they may not yet be complete
if (origCache != null) {
+ SearchResult search = null;
// only reload the cache if it was already stored or doesn't have full details (by checking the description)
if (origCache.isOffline() || StringUtils.isBlank(origCache.getDescription())) {
- final SearchResult search = searchByGeocode(origCache.getGeocode(), null, listId, false, handler);
+ search = searchByGeocode(origCache.getGeocode(), null, listId, false, handler);
+ }
+ if (search != null) {
cache = search.getFirstCacheFromResult(LoadFlags.LOAD_CACHE_OR_DB);
} else {
cache = origCache;
@@ -1601,7 +1645,7 @@ public class Geocache implements ICache, IWaypoint {
handler.sendMessage(Message.obtain());
}
} catch (Exception e) {
- Log.e("cgBase.storeCache");
+ Log.e("Geocache.storeCache", e);
}
}
@@ -1724,4 +1768,8 @@ public class Geocache implements ICache, IWaypoint {
}
return false;
}
+
+ public int getMapMarkerId() {
+ return getConnector().getCacheMapMarkerId(isDisabled() || isArchived());
+ }
}
diff --git a/main/src/cgeo/geocaching/GpxFileListActivity.java b/main/src/cgeo/geocaching/GpxFileListActivity.java
index f12a30c..de0be21 100644
--- a/main/src/cgeo/geocaching/GpxFileListActivity.java
+++ b/main/src/cgeo/geocaching/GpxFileListActivity.java
@@ -31,14 +31,9 @@ public class GpxFileListActivity extends AbstractFileListActivity<GPXListAdapter
return Collections.singletonList(new File(Settings.getGpxImportDir()));
}
- @Override
- protected void setTitle() {
- setTitle(res.getString(R.string.gpx_import_title));
- }
-
public static void startSubActivity(Activity fromActivity, int listId) {
final Intent intent = new Intent(fromActivity, GpxFileListActivity.class);
- intent.putExtra(Intents.EXTRA_LIST_ID, listId);
+ intent.putExtra(Intents.EXTRA_LIST_ID, StoredList.getConcreteList(listId));
fromActivity.startActivityForResult(intent, 0);
}
diff --git a/main/src/cgeo/geocaching/ImageSelectActivity.java b/main/src/cgeo/geocaching/ImageSelectActivity.java
index 347cd86..39824a9 100644
--- a/main/src/cgeo/geocaching/ImageSelectActivity.java
+++ b/main/src/cgeo/geocaching/ImageSelectActivity.java
@@ -1,7 +1,11 @@
package cgeo.geocaching;
+import butterknife.InjectView;
+import butterknife.Views;
+
import cgeo.geocaching.activity.AbstractActivity;
import cgeo.geocaching.compatibility.Compatibility;
+import cgeo.geocaching.utils.ImageUtils;
import cgeo.geocaching.utils.Log;
import org.apache.commons.lang3.StringUtils;
@@ -10,14 +14,18 @@ import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
+import android.graphics.drawable.BitmapDrawable;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.provider.MediaStore.MediaColumns;
import android.view.View;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
+import android.widget.Spinner;
import java.io.File;
import java.text.SimpleDateFormat;
@@ -25,37 +33,41 @@ import java.util.Date;
import java.util.Locale;
public class ImageSelectActivity extends AbstractActivity {
+
+ @InjectView(R.id.caption) protected EditText captionView;
+ @InjectView(R.id.description) protected EditText descriptionView;
+ @InjectView(R.id.logImageScale) protected Spinner scaleView;
+ @InjectView(R.id.camera) protected Button cameraButton;
+ @InjectView(R.id.stored) protected Button storedButton;
+ @InjectView(R.id.save) protected Button saveButton;
+ @InjectView(R.id.cancel) protected Button clearButton;
+ @InjectView(R.id.image_preview) protected ImageView imagePreview;
+
static final String EXTRAS_CAPTION = "caption";
static final String EXTRAS_DESCRIPTION = "description";
static final String EXTRAS_URI_AS_STRING = "uri";
+ static final String EXTRAS_SCALE = "scale";
private static final String SAVED_STATE_IMAGE_CAPTION = "cgeo.geocaching.saved_state_image_caption";
private static final String SAVED_STATE_IMAGE_DESCRIPTION = "cgeo.geocaching.saved_state_image_description";
private static final String SAVED_STATE_IMAGE_URI = "cgeo.geocaching.saved_state_image_uri";
+ private static final String SAVED_STATE_IMAGE_SCALE = "cgeo.geocaching.saved_state_image_scale";
private static final int SELECT_NEW_IMAGE = 1;
private static final int SELECT_STORED_IMAGE = 2;
- private EditText captionView;
- private EditText descriptionView;
-
// Data to be saved while reconfiguring
private String imageCaption;
private String imageDescription;
+ private int scaleChoiceIndex;
private Uri imageUri;
- public ImageSelectActivity() {
- super("c:geo-selectimage");
- }
-
@Override
public void onCreate(final Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- setTheme();
- setContentView(R.layout.visit_image);
- setTitle(res.getString(R.string.log_image));
+ super.onCreate(savedInstanceState, R.layout.imageselect_activity);
+ Views.inject(this);
+ scaleChoiceIndex = Settings.getLogImageScale();
imageCaption = "";
imageDescription = "";
imageUri = Uri.EMPTY;
@@ -66,6 +78,7 @@ public class ImageSelectActivity extends AbstractActivity {
imageCaption = extras.getString(EXTRAS_CAPTION);
imageDescription = extras.getString(EXTRAS_DESCRIPTION);
imageUri = Uri.parse(extras.getString(EXTRAS_URI_AS_STRING));
+ scaleChoiceIndex = extras.getInt(EXTRAS_SCALE, scaleChoiceIndex);
}
// Restore previous state
@@ -73,9 +86,9 @@ public class ImageSelectActivity extends AbstractActivity {
imageCaption = savedInstanceState.getString(SAVED_STATE_IMAGE_CAPTION);
imageDescription = savedInstanceState.getString(SAVED_STATE_IMAGE_DESCRIPTION);
imageUri = Uri.parse(savedInstanceState.getString(SAVED_STATE_IMAGE_URI));
+ scaleChoiceIndex = savedInstanceState.getInt(SAVED_STATE_IMAGE_SCALE);
}
- final Button cameraButton = (Button) findViewById(R.id.camera);
cameraButton.setOnClickListener(new View.OnClickListener() {
@Override
@@ -84,7 +97,6 @@ public class ImageSelectActivity extends AbstractActivity {
}
});
- final Button storedButton = (Button) findViewById(R.id.stored);
storedButton.setOnClickListener(new View.OnClickListener() {
@Override
@@ -93,17 +105,27 @@ public class ImageSelectActivity extends AbstractActivity {
}
});
- captionView = (EditText) findViewById(R.id.caption);
if (StringUtils.isNotBlank(imageCaption)) {
captionView.setText(imageCaption);
}
- descriptionView = (EditText) findViewById(R.id.description);
if (StringUtils.isNotBlank(imageDescription)) {
descriptionView.setText(imageDescription);
}
- final Button saveButton = (Button) findViewById(R.id.save);
+ scaleView.setSelection(scaleChoiceIndex);
+ scaleView.setOnItemSelectedListener(new OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
+ scaleChoiceIndex = scaleView.getSelectedItemPosition();
+ Settings.setLogImageScale(scaleChoiceIndex);
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> arg0) {
+ }
+ });
+
saveButton.setOnClickListener(new View.OnClickListener() {
@Override
@@ -112,7 +134,6 @@ public class ImageSelectActivity extends AbstractActivity {
}
});
- final Button clearButton = (Button) findViewById(R.id.cancel);
clearButton.setOnClickListener(new View.OnClickListener() {
@Override
@@ -131,15 +152,19 @@ public class ImageSelectActivity extends AbstractActivity {
outState.putString(SAVED_STATE_IMAGE_CAPTION, imageCaption);
outState.putString(SAVED_STATE_IMAGE_DESCRIPTION, imageDescription);
outState.putString(SAVED_STATE_IMAGE_URI, imageUri != null ? imageUri.getPath() : StringUtils.EMPTY);
+ outState.putInt(SAVED_STATE_IMAGE_SCALE, scaleChoiceIndex);
}
public void saveImageInfo(boolean saveInfo) {
if (saveInfo) {
+ String filename = writeScaledImage(imageUri.getPath());
+ imageUri = Uri.parse(filename);
Intent intent = new Intent();
syncEditTexts();
intent.putExtra(EXTRAS_CAPTION, imageCaption);
intent.putExtra(EXTRAS_DESCRIPTION, imageDescription);
intent.putExtra(EXTRAS_URI_AS_STRING, imageUri.toString());
+ intent.putExtra(EXTRAS_SCALE, scaleChoiceIndex);
setResult(RESULT_OK, intent);
} else {
@@ -152,6 +177,7 @@ public class ImageSelectActivity extends AbstractActivity {
private void syncEditTexts() {
imageCaption = captionView.getText().toString();
imageDescription = descriptionView.getText().toString();
+ scaleChoiceIndex = scaleView.getSelectedItemPosition();
}
private void selectImageFromCamera() {
@@ -231,8 +257,40 @@ public class ImageSelectActivity extends AbstractActivity {
loadImagePreview();
}
+ /**
+ * Scales and writes the scaled image.
+ *
+ * @param filePath
+ * @return
+ */
+ private String writeScaledImage(final String filePath) {
+ scaleChoiceIndex = scaleView.getSelectedItemPosition();
+ final int maxXY = getResources().getIntArray(R.array.log_image_scale_values)[scaleChoiceIndex];
+ if (maxXY == 0) {
+ return filePath;
+ }
+ BitmapFactory.Options sizeOnlyOptions = new BitmapFactory.Options();
+ sizeOnlyOptions.inJustDecodeBounds = true;
+ BitmapFactory.decodeFile(filePath, sizeOnlyOptions);
+ final int myMaxXY = Math.max(sizeOnlyOptions.outHeight, sizeOnlyOptions.outWidth);
+ final int sampleSize = myMaxXY / maxXY;
+ Bitmap image;
+ if (sampleSize > 1) {
+ BitmapFactory.Options sampleOptions = new BitmapFactory.Options();
+ sampleOptions.inSampleSize = sampleSize;
+ image = BitmapFactory.decodeFile(filePath, sampleOptions);
+ } else {
+ image = BitmapFactory.decodeFile(filePath);
+ }
+ final BitmapDrawable scaledImage = ImageUtils.scaleBitmapTo(image, maxXY, maxXY);
+ image = null;
+ final String uploadFilename = getOutputImageFile().getPath();
+ ImageUtils.storeBitmap(scaledImage.getBitmap(), Bitmap.CompressFormat.JPEG, 75, uploadFilename);
+ return uploadFilename;
+ }
+
private void showFailure() {
- showToast(getResources().getString(R.string.err_aquire_image_failed));
+ showToast(getResources().getString(R.string.err_acquire_image_failed));
}
private void loadImagePreview() {
@@ -244,7 +302,6 @@ public class ImageSelectActivity extends AbstractActivity {
return;
}
- final ImageView imagePreview = (ImageView) findViewById(R.id.image_preview);
BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();
bitmapOptions.inSampleSize = 8;
final Bitmap bitmap = BitmapFactory.decodeFile(imageUri.getPath(), bitmapOptions);
diff --git a/main/src/cgeo/geocaching/ImagesActivity.java b/main/src/cgeo/geocaching/ImagesActivity.java
index 24f699e..030b3f7 100644
--- a/main/src/cgeo/geocaching/ImagesActivity.java
+++ b/main/src/cgeo/geocaching/ImagesActivity.java
@@ -19,10 +19,6 @@ import java.util.List;
public class ImagesActivity extends AbstractActivity {
- private static final String EXTRAS_IMAGES = "images";
- private static final String EXTRAS_TYPE = "type";
- private static final String EXTRAS_GEOCODE = "geocode";
-
private boolean offline;
private ArrayList<Image> imageNames;
private ImagesList imagesList;
@@ -37,8 +33,8 @@ public class ImagesActivity extends AbstractActivity {
String geocode = null;
if (extras != null) {
- geocode = extras.getString(EXTRAS_GEOCODE);
- imgType = (ImageType) extras.getSerializable(EXTRAS_TYPE);
+ geocode = extras.getString(Intents.EXTRA_GEOCODE);
+ imgType = (ImageType) extras.getSerializable(Intents.EXTRA_TYPE);
}
if (extras == null || geocode == null) {
@@ -49,12 +45,12 @@ public class ImagesActivity extends AbstractActivity {
// init
setTheme();
- setContentView(R.layout.spoilers);
+ setContentView(R.layout.images_activity);
setTitle(res.getString(imgType.getTitle()));
imagesList = new ImagesList(this, geocode);
- imageNames = extras.getParcelableArrayList(EXTRAS_IMAGES);
+ imageNames = extras.getParcelableArrayList(Intents.EXTRA_IMAGES);
if (CollectionUtils.isEmpty(imageNames)) {
showToast(res.getString(R.string.warn_load_images));
finish();
@@ -67,7 +63,7 @@ public class ImagesActivity extends AbstractActivity {
@Override
public void onStart() {
super.onStart();
- imagesList.loadImages(findViewById(R.id.spoiler_list), imageNames, imgType, offline);
+ imagesList.loadImages(findViewById(R.id.spoiler_list), imageNames, offline);
}
@Override
@@ -85,12 +81,12 @@ public class ImagesActivity extends AbstractActivity {
final Intent logImgIntent = new Intent(fromActivity, ImagesActivity.class);
// if resuming our app within this activity, finish it and return to the cache activity
logImgIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET)
- .putExtra(EXTRAS_GEOCODE, geocode)
- .putExtra(EXTRAS_TYPE, imageType);
+ .putExtra(Intents.EXTRA_GEOCODE, geocode)
+ .putExtra(Intents.EXTRA_TYPE, imageType);
// avoid forcing the array list as parameter type
final ArrayList<Image> arrayList = new ArrayList<Image>(logImages);
- logImgIntent.putParcelableArrayListExtra(EXTRAS_IMAGES, arrayList);
+ logImgIntent.putParcelableArrayListExtra(Intents.EXTRA_IMAGES, arrayList);
fromActivity.startActivity(logImgIntent);
}
diff --git a/main/src/cgeo/geocaching/Intents.java b/main/src/cgeo/geocaching/Intents.java
index 7f0a004..a700451 100644
--- a/main/src/cgeo/geocaching/Intents.java
+++ b/main/src/cgeo/geocaching/Intents.java
@@ -9,10 +9,11 @@ public class Intents {
private static final String PREFIX = "cgeo.geocaching.intent.extra.";
public static final String EXTRA_ADDRESS = PREFIX + "address";
- public static final String EXTRAS_COORDS = PREFIX + "coords";
+ public static final String EXTRA_COORDS = PREFIX + "coords";
public static final String EXTRA_COUNT = PREFIX + "count";
public static final String EXTRA_GEOCODE = PREFIX + "geocode";
public static final String EXTRA_GUID = PREFIX + "guid";
+ public static final String EXTRA_IMAGES = PREFIX + "images";
public static final String EXTRA_ID = PREFIX + "id";
public static final String EXTRA_KEYWORD = PREFIX + "keyword";
public static final String EXTRA_KEYWORD_SEARCH = PREFIX + "keyword_search";
@@ -23,6 +24,7 @@ public class Intents {
public static final String EXTRA_SEARCH = PREFIX + "search";
public static final String EXTRA_START_DIR = PREFIX + "start_dir";
public static final String EXTRA_TRACKING_CODE = PREFIX + "tracking_code";
+ public static final String EXTRA_TYPE = PREFIX + "type";
public static final String EXTRA_USERNAME = PREFIX + "username";
public static final String EXTRA_WAYPOINT_ID = PREFIX + "waypoint_id";
public static final String EXTRA_CACHELIST = PREFIX + "cache_list";
diff --git a/main/src/cgeo/geocaching/VisitCacheActivity.java b/main/src/cgeo/geocaching/LogCacheActivity.java
index dce0fbf..62c94ce 100644
--- a/main/src/cgeo/geocaching/VisitCacheActivity.java
+++ b/main/src/cgeo/geocaching/LogCacheActivity.java
@@ -1,38 +1,34 @@
package cgeo.geocaching;
-import cgeo.geocaching.connector.gc.GCParser;
-import cgeo.geocaching.connector.gc.Login;
+import cgeo.geocaching.connector.ILoggingManager;
+import cgeo.geocaching.connector.ImageResult;
+import cgeo.geocaching.connector.LogResult;
import cgeo.geocaching.enumerations.LoadFlags;
import cgeo.geocaching.enumerations.LogType;
import cgeo.geocaching.enumerations.LogTypeTrackable;
import cgeo.geocaching.enumerations.StatusCode;
import cgeo.geocaching.gcvote.GCVote;
-import cgeo.geocaching.loaders.UrlLoader;
-import cgeo.geocaching.network.Parameters;
import cgeo.geocaching.twitter.Twitter;
import cgeo.geocaching.ui.Formatter;
import cgeo.geocaching.ui.dialog.DateDialog;
+import cgeo.geocaching.utils.AsyncTaskWithProgress;
+import cgeo.geocaching.utils.DateUtils;
import cgeo.geocaching.utils.Log;
import cgeo.geocaching.utils.LogTemplateProvider;
import cgeo.geocaching.utils.LogTemplateProvider.LogContext;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.tuple.ImmutablePair;
+import android.app.Activity;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.app.Dialog;
-import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.support.v4.app.LoaderManager;
-import android.support.v4.content.Loader;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.Menu;
@@ -51,7 +47,7 @@ import java.util.Date;
import java.util.List;
import java.util.Locale;
-public class VisitCacheActivity extends AbstractLoggingActivity implements DateDialog.DateDialogParent, LoaderManager.LoaderCallbacks<String> {
+public class LogCacheActivity extends AbstractLoggingActivity implements DateDialog.DateDialogParent {
static final String EXTRAS_GEOCODE = "geocode";
static final String EXTRAS_ID = "id";
@@ -67,12 +63,10 @@ public class VisitCacheActivity extends AbstractLoggingActivity implements DateD
private LayoutInflater inflater = null;
private Geocache cache = null;
- private ProgressDialog waitDialog = null;
private String cacheid = null;
private String geocode = null;
private String text = null;
private List<LogType> possibleLogTypes = new ArrayList<LogType>();
- private String[] viewstates = null;
private List<TrackableLog> trackables = null;
private Button postButton = null;
private CheckBox tweetCheck = null;
@@ -80,6 +74,8 @@ public class VisitCacheActivity extends AbstractLoggingActivity implements DateD
private boolean tbChanged = false;
private SparseArray<TrackableLog> actionButtons;
+ private ILoggingManager loggingManager;
+
// Data to be saved while reconfiguring
private double rating;
private LogType typeSelected;
@@ -88,31 +84,16 @@ public class VisitCacheActivity extends AbstractLoggingActivity implements DateD
private String imageDescription;
private Uri imageUri;
- @Override
- public Loader<String> onCreateLoader(final int id, final Bundle args) {
- if (!Settings.isLogin()) { // allow offline logging
- showToast(res.getString(R.string.err_login));
- return null;
- }
- return new UrlLoader(getBaseContext(), "http://www.geocaching.com/seek/log.aspx", new Parameters("ID", cacheid));
- }
- @Override
- public void onLoaderReset(final Loader<String> loader) {
- // Nothing to do
- }
+ public void onLoadFinished() {
- @Override
- public void onLoadFinished(final Loader<String> loader, final String page) {
- if (page == null) {
+ if (loggingManager.hasLoaderError()) {
showErrorLoadingData();
return;
}
- viewstates = Login.getViewstates(page);
- trackables = GCParser.parseTrackableLog(page);
- possibleLogTypes = GCParser.parseTypes(page);
- possibleLogTypes.remove(LogType.UPDATE_COORDINATES);
+ trackables = loggingManager.getTrackables();
+ possibleLogTypes = loggingManager.getPossibleLogTypes();
if (possibleLogTypes.isEmpty()) {
showErrorLoadingData();
@@ -161,7 +142,7 @@ public class VisitCacheActivity extends AbstractLoggingActivity implements DateD
inventoryView.removeAllViews();
for (TrackableLog tb : trackables) {
- LinearLayout inventoryItem = (LinearLayout) inflater.inflate(R.layout.visit_trackable, null);
+ LinearLayout inventoryItem = (LinearLayout) inflater.inflate(R.layout.logcache_trackable_item, null);
((TextView) inventoryItem.findViewById(R.id.trackcode)).setText(tb.trackCode);
((TextView) inventoryItem.findViewById(R.id.name)).setText(tb.name);
@@ -183,7 +164,7 @@ public class VisitCacheActivity extends AbstractLoggingActivity implements DateD
@Override
public void onClick(View view) {
- final Intent trackablesIntent = new Intent(VisitCacheActivity.this, TrackableActivity.class);
+ final Intent trackablesIntent = new Intent(LogCacheActivity.this, TrackableActivity.class);
trackablesIntent.putExtra(Intents.EXTRA_GEOCODE, tbCode);
startActivity(trackablesIntent);
}
@@ -231,7 +212,7 @@ public class VisitCacheActivity extends AbstractLoggingActivity implements DateD
if (!postButton.isEnabled()) {
return res.getString(R.string.log_post_not_possible);
}
- if (typeSelected != LogType.FOUND_IT || !Settings.isGCvoteLogin()) {
+ if (typeSelected != LogType.FOUND_IT || !Settings.isGCvoteLogin() || !cache.supportsGCVote()) {
return res.getString(R.string.log_post);
}
if (rating == 0) {
@@ -240,45 +221,9 @@ public class VisitCacheActivity extends AbstractLoggingActivity implements DateD
return res.getString(R.string.log_post_rate) + " " + ratingTextValue(rating) + "*";
}
- private final Handler postLogHandler = new Handler() {
-
- @Override
- public void handleMessage(final Message msg) {
- if (waitDialog != null) {
- waitDialog.dismiss();
- }
-
- final StatusCode error = (StatusCode) msg.obj;
- if (error == StatusCode.NO_ERROR) {
- showToast(res.getString(R.string.info_log_posted));
- // No need to save the log when quitting if it has been posted.
- text = currentLogText();
- finish();
- } else if (error == StatusCode.LOG_SAVED) {
- showToast(res.getString(R.string.info_log_saved));
-
- if (waitDialog != null) {
- waitDialog.dismiss();
- }
-
- finish();
- } else {
- showToast(error.getErrorString(res));
- }
- }
- };
-
- public VisitCacheActivity() {
- super("c:geo-log");
- }
-
@Override
public void onCreate(final Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- setTheme();
- setContentView(R.layout.visit);
- setTitle(res.getString(R.string.log_new_log));
+ super.onCreate(savedInstanceState, R.layout.logcache_activity);
// Get parameters from intent and basic cache information from database
final Bundle extras = getIntent().getExtras();
@@ -333,7 +278,7 @@ public class VisitCacheActivity extends AbstractLoggingActivity implements DateD
}
}
updatePostButtonText();
- setImageButtonText();
+ updateImageButton();
enablePostButton(false);
final Button typeButton = (Button) findViewById(R.id.type);
@@ -385,15 +330,25 @@ public class VisitCacheActivity extends AbstractLoggingActivity implements DateD
}
});
- getSupportLoaderManager().initLoader(0, null, this);
+ loggingManager = cache.getLoggingManager(this);
+
+ loggingManager.init();
}
private void setDefaultValues() {
date = Calendar.getInstance();
rating = 0.0;
if (cache.isEventCache()) {
- if (cache.hasOwnLog(LogType.WILL_ATTEND)) {
- typeSelected = LogType.ATTENDED;
+ final Date eventDate = cache.getHiddenDate();
+ boolean expired = DateUtils.daysSince(eventDate.getTime()) > 0;
+
+ if (cache.hasOwnLog(LogType.WILL_ATTEND) || expired) {
+ if (cache.hasOwnLog(LogType.ATTENDED)) {
+ typeSelected = LogType.NOTE;
+ }
+ else {
+ typeSelected = LogType.ATTENDED;
+ }
}
else {
typeSelected = LogType.WILL_ATTEND;
@@ -407,13 +362,13 @@ public class VisitCacheActivity extends AbstractLoggingActivity implements DateD
}
}
text = null;
- imageCaption = "";
- imageDescription = "";
+ imageCaption = StringUtils.EMPTY;
+ imageDescription = StringUtils.EMPTY;
imageUri = Uri.EMPTY;
}
private void clearLog() {
- cgData.clearLogOffline(geocode);
+ cache.clearOfflineLog();
setDefaultValues();
@@ -423,7 +378,7 @@ public class VisitCacheActivity extends AbstractLoggingActivity implements DateD
final EditText logView = (EditText) findViewById(R.id.log);
logView.setText(StringUtils.EMPTY);
- setImageButtonText();
+ updateImageButton();
showToast(res.getString(R.string.info_log_cleared));
}
@@ -463,7 +418,7 @@ public class VisitCacheActivity extends AbstractLoggingActivity implements DateD
public boolean onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
- final boolean voteAvailable = Settings.isGCvoteLogin() && typeSelected == LogType.FOUND_IT && StringUtils.isNotBlank(cache.getGuid());
+ final boolean voteAvailable = Settings.isGCvoteLogin() && typeSelected == LogType.FOUND_IT && StringUtils.isNotBlank(cache.getGuid()) && cache.supportsGCVote();
menu.findItem(SUBMENU_VOTE).setVisible(voteAvailable);
return true;
@@ -540,7 +495,7 @@ public class VisitCacheActivity extends AbstractLoggingActivity implements DateD
@Override
public void onClick(View arg0) {
- final Dialog dateDialog = new DateDialog(VisitCacheActivity.this, VisitCacheActivity.this, date);
+ final Dialog dateDialog = new DateDialog(LogCacheActivity.this, LogCacheActivity.this, date);
dateDialog.setCancelable(true);
dateDialog.show();
}
@@ -549,81 +504,77 @@ public class VisitCacheActivity extends AbstractLoggingActivity implements DateD
private class PostListener implements View.OnClickListener {
@Override
public void onClick(View arg0) {
- waitDialog = ProgressDialog.show(VisitCacheActivity.this, null,
- res.getString(StringUtils.isBlank(imageUri.getPath()) ? R.string.log_saving : R.string.log_saving_and_uploading), true);
- waitDialog.setCancelable(true);
-
- final Thread thread = new PostLogThread(postLogHandler, currentLogText());
- thread.start();
+ final String message = res.getString(StringUtils.isBlank(imageUri.getPath()) ?
+ R.string.log_saving :
+ R.string.log_saving_and_uploading);
+ new Poster(LogCacheActivity.this, message).execute(currentLogText());
}
}
- private class PostLogThread extends Thread {
-
- private final Handler handler;
- private final String log;
+ private class Poster extends AsyncTaskWithProgress<String, StatusCode> {
- public PostLogThread(Handler handlerIn, String logIn) {
- super("Post log");
- handler = handlerIn;
- log = logIn;
+ public Poster(final Activity activity, final String progressMessage) {
+ super(activity, null, progressMessage, true);
}
@Override
- public void run() {
- final StatusCode status = postLogFn(log);
- handler.sendMessage(handler.obtainMessage(0, status));
- }
- }
-
- public StatusCode postLogFn(String log) {
-
- StatusCode result = StatusCode.LOG_POST_ERROR;
-
- try {
-
- final ImmutablePair<StatusCode, String> logResult = GCParser.postLog(geocode, cacheid, viewstates, typeSelected,
- date.get(Calendar.YEAR), (date.get(Calendar.MONTH) + 1), date.get(Calendar.DATE),
- log, trackables);
-
- result = logResult.left;
-
- if (logResult.left == StatusCode.NO_ERROR) {
- final LogEntry logNow = new LogEntry(date, typeSelected, log);
-
- cache.getLogs().add(0, logNow);
-
- if (typeSelected == LogType.FOUND_IT || typeSelected == LogType.ATTENDED) {
- cache.setFound(true);
+ protected StatusCode doInBackgroundInternal(final String[] logTexts) {
+ final String log = logTexts[0];
+ try {
+ final LogResult logResult = loggingManager.postLog(cache, typeSelected, date, log, trackables);
+
+ if (logResult.getPostLogResult() == StatusCode.NO_ERROR) {
+ final LogEntry logNow = new LogEntry(date, typeSelected, log);
+
+ cache.getLogs().add(0, logNow);
+
+ if (typeSelected == LogType.FOUND_IT || typeSelected == LogType.ATTENDED) {
+ cache.setFound(true);
+ }
+
+ cgData.saveChangedCache(cache);
+ cache.clearOfflineLog();
+
+ if (typeSelected == LogType.FOUND_IT) {
+ if (tweetCheck.isChecked() && tweetBox.getVisibility() == View.VISIBLE) {
+ Twitter.postTweetCache(geocode);
+ }
+ GCVote.setRating(cache, rating);
+ }
+
+ if (StringUtils.isNotBlank(imageUri.getPath())) {
+ ImageResult imageResult = loggingManager.postLogImage(logResult.getLogId(), imageCaption, imageDescription, imageUri);
+ final String uploadedImageUrl = imageResult.getImageUri();
+ if (StringUtils.isNotEmpty(uploadedImageUrl)) {
+ logNow.addLogImage(new Image(uploadedImageUrl, imageCaption, imageDescription));
+ cgData.saveChangedCache(cache);
+ }
+ return imageResult.getPostResult();
+ }
}
- cgData.saveChangedCache(cache);
- }
-
- if (logResult.left == StatusCode.NO_ERROR) {
- cgData.clearLogOffline(geocode);
- }
-
- if (logResult.left == StatusCode.NO_ERROR && typeSelected == LogType.FOUND_IT && Settings.isUseTwitter()
- && Settings.isTwitterLoginValid()
- && tweetCheck.isChecked() && tweetBox.getVisibility() == View.VISIBLE) {
- Twitter.postTweetCache(geocode);
+ return logResult.getPostLogResult();
+ } catch (Exception e) {
+ Log.e("VisitCacheActivity.Poster.doInBackgroundInternal", e);
}
- if (logResult.left == StatusCode.NO_ERROR && typeSelected == LogType.FOUND_IT && Settings.isGCvoteLogin()) {
- GCVote.setRating(cache, rating);
- }
+ return StatusCode.LOG_POST_ERROR;
+ }
- if (logResult.left == StatusCode.NO_ERROR && StringUtils.isNotBlank(imageUri.getPath())) {
- result = GCParser.uploadLogImage(logResult.right, imageCaption, imageDescription, imageUri);
+ @Override
+ protected void onPostExecuteInternal(final StatusCode status) {
+ if (status == StatusCode.NO_ERROR) {
+ showToast(res.getString(R.string.info_log_posted));
+ // No need to save the log when quitting if it has been posted.
+ text = currentLogText();
+ finish();
+ } else if (status == StatusCode.LOG_SAVED) {
+ showToast(res.getString(R.string.info_log_saved));
+ finish();
+ } else {
+ showToast(status.getErrorString(res));
}
-
- return result;
- } catch (Exception e) {
- Log.e("cgeovisit.postLogFn", e);
}
-
- return StatusCode.LOG_POST_ERROR;
}
private void saveLog(final boolean force) {
@@ -677,16 +628,19 @@ public class VisitCacheActivity extends AbstractLoggingActivity implements DateD
}
private void selectLogType() {
+ // use a local copy of the possible types, as that one might be modified in the background by the loader
+ final ArrayList<LogType> possible = new ArrayList<LogType>(possibleLogTypes);
+
Builder alert = new AlertDialog.Builder(this);
- String[] choices = new String[possibleLogTypes.size()];
+ String[] choices = new String[possible.size()];
for (int i = 0; i < choices.length; i++) {
- choices[i] = possibleLogTypes.get(i).getL10n();
+ choices[i] = possible.get(i).getL10n();
}
- alert.setSingleChoiceItems(choices, possibleLogTypes.indexOf(typeSelected), new OnClickListener() {
+ alert.setSingleChoiceItems(choices, possible.indexOf(typeSelected), new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int position) {
- setType(possibleLogTypes.get(position));
+ setType(possible.get(position));
dialog.dismiss();
}
});
@@ -734,14 +688,19 @@ public class VisitCacheActivity extends AbstractLoggingActivity implements DateD
// Image capture failed, advise user
showToast(getResources().getString(R.string.err_select_logimage_failed));
}
- setImageButtonText();
+ updateImageButton();
}
}
- private void setImageButtonText() {
+ private void updateImageButton() {
final Button imageButton = (Button) findViewById(R.id.image_btn);
- imageButton.setText(StringUtils.isNotBlank(imageUri.getPath()) ?
+ if (cache.supportsLogImages()) {
+ imageButton.setVisibility(View.VISIBLE);
+ imageButton.setText(StringUtils.isNotBlank(imageUri.getPath()) ?
res.getString(R.string.log_image_edit) : res.getString(R.string.log_image_attach));
+ } else {
+ imageButton.setVisibility(View.GONE);
+ }
}
}
diff --git a/main/src/cgeo/geocaching/LogTrackableActivity.java b/main/src/cgeo/geocaching/LogTrackableActivity.java
index b8983ba..1f6feb7 100644
--- a/main/src/cgeo/geocaching/LogTrackableActivity.java
+++ b/main/src/cgeo/geocaching/LogTrackableActivity.java
@@ -1,5 +1,8 @@
package cgeo.geocaching;
+import butterknife.InjectView;
+import butterknife.Views;
+
import cgeo.geocaching.connector.gc.GCParser;
import cgeo.geocaching.connector.gc.Login;
import cgeo.geocaching.enumerations.LogType;
@@ -36,6 +39,14 @@ import java.util.Calendar;
import java.util.List;
public class LogTrackableActivity extends AbstractLoggingActivity implements DateDialog.DateDialogParent {
+
+ @InjectView(R.id.post) protected Button buttonPost;
+ @InjectView(R.id.type) protected Button typeButton;
+ @InjectView(R.id.date) protected Button dateButton;
+ @InjectView(R.id.tracking) protected EditText trackingEditText;
+ @InjectView(R.id.tweet) protected CheckBox tweetCheck;
+ @InjectView(R.id.tweet_box) protected LinearLayout tweetBox;
+
private List<LogType> possibleLogTypes = new ArrayList<LogType>();
private ProgressDialog waitDialog = null;
private String guid = null;
@@ -45,8 +56,6 @@ public class LogTrackableActivity extends AbstractLoggingActivity implements Dat
private Calendar date = Calendar.getInstance();
private LogType typeSelected = LogType.getById(Settings.getTrackableAction());
private int attempts = 0;
- private CheckBox tweetCheck = null;
- private LinearLayout tweetBox = null;
private Trackable trackable;
private Handler showProgressHandler = new Handler() {
@@ -57,6 +66,7 @@ public class LogTrackableActivity extends AbstractLoggingActivity implements Dat
};
private Handler loadDataHandler = new Handler() {
+
@Override
public void handleMessage(final Message msg) {
if (!possibleLogTypes.contains(typeSelected)) {
@@ -78,7 +88,6 @@ public class LogTrackableActivity extends AbstractLoggingActivity implements Dat
gettingViewstate = false; // we're done, user can post log
- final Button buttonPost = (Button) findViewById(R.id.post);
buttonPost.setEnabled(true);
buttonPost.setOnClickListener(new PostListener());
@@ -104,17 +113,10 @@ public class LogTrackableActivity extends AbstractLoggingActivity implements Dat
}
};
- public LogTrackableActivity() {
- super("c:geo-log-trackable");
- }
-
@Override
public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- setTheme();
- setContentView(R.layout.touch);
- setTitle(res.getString(R.string.trackable_touch));
+ super.onCreate(savedInstanceState, R.layout.logtrackable_activity);
+ Views.inject(this);
// get parameters
final Bundle extras = getIntent().getExtras();
@@ -123,7 +125,7 @@ public class LogTrackableActivity extends AbstractLoggingActivity implements Dat
guid = extras.getString(Intents.EXTRA_GUID);
if (StringUtils.isNotBlank(extras.getString(Intents.EXTRA_TRACKING_CODE))) {
- ((EditText) findViewById(R.id.tracking)).setText(extras.getString(Intents.EXTRA_TRACKING_CODE));
+ trackingEditText.setText(extras.getString(Intents.EXTRA_TRACKING_CODE));
}
}
@@ -146,11 +148,6 @@ public class LogTrackableActivity extends AbstractLoggingActivity implements Dat
}
@Override
- public void onResume() {
- super.onResume();
- }
-
- @Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
@@ -184,7 +181,6 @@ public class LogTrackableActivity extends AbstractLoggingActivity implements Dat
}
public void init() {
- final Button typeButton = (Button) findViewById(R.id.type);
registerForContextMenu(typeButton);
typeButton.setText(typeSelected.getL10n());
typeButton.setOnClickListener(new View.OnClickListener() {
@@ -194,23 +190,15 @@ public class LogTrackableActivity extends AbstractLoggingActivity implements Dat
}
});
- final Button dateButton = (Button) findViewById(R.id.date);
dateButton.setOnClickListener(new DateListener());
setDate(date);
- if (tweetBox == null) {
- tweetBox = (LinearLayout) findViewById(R.id.tweet_box);
- }
- if (tweetCheck == null) {
- tweetCheck = (CheckBox) findViewById(R.id.tweet);
- }
tweetCheck.setChecked(true);
if (CollectionUtils.isEmpty(possibleLogTypes)) {
possibleLogTypes = Trackable.getPossibleLogTypes();
}
- final Button buttonPost = (Button) findViewById(R.id.post);
if (Login.isEmpty(viewstates)) {
buttonPost.setEnabled(false);
buttonPost.setOnTouchListener(null);
@@ -221,20 +209,17 @@ public class LogTrackableActivity extends AbstractLoggingActivity implements Dat
buttonPost.setEnabled(true);
buttonPost.setOnClickListener(new PostListener());
}
- disableSuggestions((EditText) findViewById(R.id.tracking));
+ disableSuggestions(trackingEditText);
}
@Override
public void setDate(Calendar dateIn) {
date = dateIn;
- final Button dateButton = (Button) findViewById(R.id.date);
dateButton.setText(Formatter.formatShortDateVerbally(date.getTime().getTime()));
}
public void setType(LogType type) {
- final Button typeButton = (Button) findViewById(R.id.type);
-
typeSelected = type;
typeButton.setText(typeSelected.getL10n());
@@ -257,6 +242,8 @@ public class LogTrackableActivity extends AbstractLoggingActivity implements Dat
private class PostListener implements View.OnClickListener {
+ protected EditText logEditText = (EditText) findViewById(R.id.log);
+
@Override
public void onClick(View arg0) {
if (!gettingViewstate) {
@@ -265,8 +252,8 @@ public class LogTrackableActivity extends AbstractLoggingActivity implements Dat
Settings.setTrackableAction(typeSelected.id);
- final String tracking = ((EditText) findViewById(R.id.tracking)).getText().toString();
- final String log = ((EditText) findViewById(R.id.log)).getText().toString();
+ final String tracking = trackingEditText.getText().toString();
+ final String log = logEditText.getText().toString();
new PostLogThread(postLogHandler, tracking, log).start();
} else {
showToast(res.getString(R.string.err_log_load_data_still));
diff --git a/main/src/cgeo/geocaching/LogViewHolder.java b/main/src/cgeo/geocaching/LogViewHolder.java
new file mode 100644
index 0000000..14148d0
--- /dev/null
+++ b/main/src/cgeo/geocaching/LogViewHolder.java
@@ -0,0 +1,46 @@
+package cgeo.geocaching;
+
+import butterknife.InjectView;
+
+import cgeo.geocaching.ui.AbstractViewHolder;
+
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+public class LogViewHolder extends AbstractViewHolder {
+ @InjectView(R.id.added) protected TextView date ;
+ @InjectView(R.id.type) protected TextView type;
+ @InjectView(R.id.author) protected TextView author;
+ @InjectView(R.id.count_or_location) protected TextView countOrLocation;
+ @InjectView(R.id.log) protected TextView text;
+ @InjectView(R.id.log_images) protected TextView images;
+ @InjectView(R.id.log_mark) protected ImageView marker;
+
+ private int position;
+
+ public LogViewHolder(View rowView) {
+ super(rowView);
+ }
+
+ /**
+ * Read the position of the cursor pointed to by this holder. <br/>
+ * This must be called by the UI thread.
+ *
+ * @return the cursor position
+ */
+ public int getPosition() {
+ return position;
+ }
+
+ /**
+ * Set the position of the cursor pointed to by this holder. <br/>
+ * This must be called by the UI thread.
+ *
+ * @param position
+ * the cursor position
+ */
+ public void setPosition(final int position) {
+ this.position = position;
+ }
+} \ No newline at end of file
diff --git a/main/src/cgeo/geocaching/cgeo.java b/main/src/cgeo/geocaching/MainActivity.java
index 5680ff3..03a1d0d 100644
--- a/main/src/cgeo/geocaching/cgeo.java
+++ b/main/src/cgeo/geocaching/MainActivity.java
@@ -1,8 +1,13 @@
package cgeo.geocaching;
+import butterknife.InjectView;
+import butterknife.Views;
+
import cgeo.geocaching.activity.AbstractActivity;
-import cgeo.geocaching.activity.ActivityMixin;
+import cgeo.geocaching.connector.ConnectorFactory;
+import cgeo.geocaching.connector.IConnector;
import cgeo.geocaching.connector.gc.Login;
+import cgeo.geocaching.connector.oc.OCApiLiveConnector;
import cgeo.geocaching.enumerations.CacheType;
import cgeo.geocaching.enumerations.StatusCode;
import cgeo.geocaching.geopoint.Geopoint;
@@ -14,6 +19,9 @@ import cgeo.geocaching.utils.Log;
import cgeo.geocaching.utils.RunnableWithArgument;
import cgeo.geocaching.utils.Version;
+import com.google.zxing.integration.android.IntentIntegrator;
+import com.google.zxing.integration.android.IntentResult;
+
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
@@ -31,11 +39,10 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.Menu;
-import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
-import android.widget.RelativeLayout;
+import android.widget.ImageView;
import android.widget.TextView;
import java.util.ArrayList;
@@ -45,14 +52,26 @@ import java.util.Comparator;
import java.util.List;
import java.util.Locale;
-public class cgeo extends AbstractActivity {
+public class MainActivity extends AbstractActivity {
+ @InjectView(R.id.user_info_gc) protected TextView userInfoViewGc;
+ @InjectView(R.id.user_info_ocde) protected TextView userInfoViewOcDe;
+ @InjectView(R.id.nav_satellites) protected TextView navSatellites;
+ @InjectView(R.id.filter_button_title)protected TextView filterTitle;
+ @InjectView(R.id.map) protected ImageView findOnMap;
+ @InjectView(R.id.search_offline) protected ImageView findByOffline;
+ @InjectView(R.id.advanced_button) protected ImageView advanced;
+ @InjectView(R.id.any_button) protected ImageView any;
+ @InjectView(R.id.filter_button) protected ImageView filter;
+ @InjectView(R.id.nearest) protected ImageView nearestView;
+ @InjectView(R.id.nav_type) protected TextView navType ;
+ @InjectView(R.id.nav_accuracy) protected TextView navAccuracy ;
+ @InjectView(R.id.nav_location) protected TextView navLocation ;
+ @InjectView(R.id.offline_count) protected TextView countBubble ;
private static final String SCAN_INTENT = "com.google.zxing.client.android.SCAN";
- private static final int SCAN_REQUEST_CODE = 1;
public static final int SEARCH_REQUEST_CODE = 2;
private int version = 0;
- private TextView filterTitle = null;
private boolean cleanupRunning = false;
private int countBubbleCnt = 0;
private Geopoint addCoords = null;
@@ -67,19 +86,47 @@ public class cgeo extends AbstractActivity {
@Override
public void handleMessage(Message msg) {
- TextView userInfoView = (TextView) findViewById(R.id.user_info);
+ //TODO: Rework to be fully dynamic
+ if (Settings.isGCConnectorActive()) {
+ StringBuilder userInfo = new StringBuilder("geocaching.com").append(Formatter.SEPARATOR);
+ if (Login.isActualLoginStatus()) {
+ userInfo.append(Login.getActualUserName());
+ if (Login.getActualCachesFound() >= 0) {
+ userInfo.append(" (").append(String.valueOf(Login.getActualCachesFound())).append(')');
+ }
+ userInfo.append(Formatter.SEPARATOR);
+ }
+ userInfo.append(Login.getActualStatus());
+
+ userInfoViewGc.setText(userInfo.toString());
+ userInfoViewGc.setVisibility(View.VISIBLE);
+ }
+ else {
+ userInfoViewGc.setVisibility(View.GONE);
+ }
- StringBuilder userInfo = new StringBuilder("geocaching.com").append(Formatter.SEPARATOR);
- if (Login.isActualLoginStatus()) {
- userInfo.append(Login.getActualUserName());
- if (Login.getActualCachesFound() >= 0) {
- userInfo.append(" (").append(String.valueOf(Login.getActualCachesFound())).append(')');
+ if (Settings.isOCConnectorActive()) {
+ StringBuilder userInfo = new StringBuilder("opencaching.de").append(Formatter.SEPARATOR);
+ IConnector conn = ConnectorFactory.getConnector("OCXXXX");
+ if (conn instanceof OCApiLiveConnector) {
+ OCApiLiveConnector ocapiConn = (OCApiLiveConnector) conn;
+ if (ocapiConn.supportsPersonalization()) {
+ userInfo.append(ocapiConn.getUserName());
+ int count = ocapiConn.getCachesFound();
+ if (count >= 0) {
+ userInfo.append(" (").append(String.valueOf(count)).append(')');
+ }
+ } else {
+ userInfo.append("Anonymous");
+ }
}
- userInfo.append(Formatter.SEPARATOR);
+ userInfoViewOcDe.setText(userInfo.toString());
+ userInfoViewOcDe.setVisibility(View.VISIBLE);
+ }
+ else {
+ userInfoViewOcDe.setVisibility(View.GONE);
}
- userInfo.append(Login.getActualStatus());
- userInfoView.setText(userInfo.toString());
}
};
@@ -109,7 +156,6 @@ public class cgeo extends AbstractActivity {
addCoords = app.currentGeo().getCoords();
- TextView navLocation = (TextView) findViewById(R.id.nav_location);
navLocation.setText(addText.toString());
}
} catch (Exception e) {
@@ -137,7 +183,6 @@ public class cgeo extends AbstractActivity {
satellitesFixed = data.getSatellitesFixed();
satellitesVisible = data.getSatellitesVisible();
- final TextView navSatellites = (TextView) findViewById(R.id.nav_satellites);
if (gpsEnabled) {
if (satellitesFixed > 0) {
navSatellites.setText(res.getString(R.string.loc_sat) + ": " + satellitesFixed + '/' + satellitesVisible);
@@ -164,18 +209,17 @@ public class cgeo extends AbstractActivity {
showToast(res.getString(reason == StatusCode.MAINTENANCE ? reason.getErrorString() : R.string.err_login_failed_toast));
}
} catch (Exception e) {
- Log.w("cgeo.firstLoginHander", e);
+ Log.w("MainActivity.firstLoginHander", e);
}
}
};
- public cgeo() {
- super("c:geo-main-screen");
- }
-
@Override
public void onCreate(Bundle savedInstanceState) {
+ // don't call the super implementation with the layout argument, as that would set the wrong theme
super.onCreate(savedInstanceState);
+ setContentView(R.layout.main_activity);
+ Views.inject(this);
if ((getIntent().getFlags() & Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT) != 0) {
// If we had been open already, start from the last used activity.
@@ -183,33 +227,11 @@ public class cgeo extends AbstractActivity {
return;
}
- setContentView(R.layout.main);
setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL); // type to search
version = Version.getVersionCode(this);
Log.i("Starting " + getPackageName() + ' ' + version + " a.k.a " + Version.getVersionName(this));
- try {
- if (!Settings.isHelpShown()) {
- final RelativeLayout helper = (RelativeLayout) findViewById(R.id.helper);
- if (helper != null) {
- helper.setVisibility(View.VISIBLE);
- helper.setClickable(true);
- helper.setOnClickListener(new View.OnClickListener() {
-
- @Override
- public void onClick(View view) {
- ActivityMixin.goManual(cgeo.this, "c:geo-intro");
- view.setVisibility(View.GONE);
- }
- });
- Settings.setHelpShown();
- }
- }
- } catch (Exception e) {
- // nothing
- }
-
init();
}
@@ -253,8 +275,7 @@ public class cgeo extends AbstractActivity {
@Override
public boolean onCreateOptionsMenu(Menu menu) {
- MenuInflater inflater = getMenuInflater();
- inflater.inflate(R.menu.main_options, menu);
+ getMenuInflater().inflate(R.menu.main_activity_options, menu);
return true;
}
@@ -302,25 +323,19 @@ public class cgeo extends AbstractActivity {
}
private void startScannerApplication() {
- Intent intent = new Intent(SCAN_INTENT);
- intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); // when resuming our app, cancel this activity
- intent.putExtra("SCAN_MODE", "QR_CODE_MODE");
- startActivityForResult(intent, SCAN_REQUEST_CODE);
+ IntentIntegrator integrator = new IntentIntegrator(this);
+ integrator.initiateScan(IntentIntegrator.QR_CODE_TYPES);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
- if (requestCode == SCAN_REQUEST_CODE) {
- if (resultCode == RESULT_OK) {
- String scan = intent.getStringExtra("SCAN_RESULT");
- if (StringUtils.isBlank(scan)) {
- return;
- }
-
- SearchActivity.startActivityScan(scan, this);
- } else if (resultCode == RESULT_CANCELED) {
- // do nothing
+ IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, intent);
+ if (scanResult != null) {
+ String scan = scanResult.getContents();
+ if (StringUtils.isBlank(scan)) {
+ return;
}
+ SearchActivity.startActivityScan(scan, this);
} else if (requestCode == SEARCH_REQUEST_CODE) {
// SearchActivity activity returned without making a search
if (resultCode == RESULT_CANCELED) {
@@ -338,9 +353,6 @@ public class cgeo extends AbstractActivity {
}
private void setFilterTitle() {
- if (filterTitle == null) {
- filterTitle = (TextView) findViewById(R.id.filter_button_title);
- }
filterTitle.setText(Settings.getCacheType().getL10n());
}
@@ -358,7 +370,6 @@ public class cgeo extends AbstractActivity {
(new FirstLoginThread()).start();
}
- final View findOnMap = findViewById(R.id.map);
findOnMap.setClickable(true);
findOnMap.setOnClickListener(new OnClickListener() {
@Override
@@ -367,7 +378,6 @@ public class cgeo extends AbstractActivity {
}
});
- final View findByOffline = findViewById(R.id.search_offline);
findByOffline.setClickable(true);
findByOffline.setOnClickListener(new OnClickListener() {
@Override
@@ -379,12 +389,12 @@ public class cgeo extends AbstractActivity {
@Override
public boolean onLongClick(View v) {
- new StoredList.UserInterface(cgeo.this).promptForListSelection(R.string.list_title, new RunnableWithArgument<Integer>() {
+ new StoredList.UserInterface(MainActivity.this).promptForListSelection(R.string.list_title, new RunnableWithArgument<Integer>() {
@Override
public void run(Integer selectedListId) {
Settings.saveLastList(selectedListId);
- cgeocaches.startActivityOffline(cgeo.this);
+ cgeocaches.startActivityOffline(MainActivity.this);
}
});
return true;
@@ -392,7 +402,6 @@ public class cgeo extends AbstractActivity {
});
findByOffline.setLongClickable(true);
- final View advanced = findViewById(R.id.advanced_button);
advanced.setClickable(true);
advanced.setOnClickListener(new OnClickListener() {
@Override
@@ -401,7 +410,6 @@ public class cgeo extends AbstractActivity {
}
});
- final View any = findViewById(R.id.any_button);
any.setClickable(true);
any.setOnClickListener(new OnClickListener() {
@Override
@@ -410,7 +418,6 @@ public class cgeo extends AbstractActivity {
}
});
- final View filter = findViewById(R.id.filter_button);
filter.setClickable(true);
filter.setOnClickListener(new View.OnClickListener() {
@Override
@@ -501,7 +508,7 @@ public class cgeo extends AbstractActivity {
public void onClick(DialogInterface dialog, int id) {
dialog.dismiss();
cgData.resetNewlyCreatedDatabase();
- app.restoreDatabase(cgeo.this);
+ app.restoreDatabase(MainActivity.this);
}
})
.setNegativeButton(getString(android.R.string.no), new DialogInterface.OnClickListener() {
@@ -519,10 +526,6 @@ public class cgeo extends AbstractActivity {
@Override
public void updateGeoData(final IGeoData geo) {
- final View nearestView = findViewById(R.id.nearest);
- final TextView navType = (TextView) findViewById(R.id.nav_type);
- final TextView navAccuracy = (TextView) findViewById(R.id.nav_accuracy);
- final TextView navLocation = (TextView) findViewById(R.id.nav_location);
try {
if (geo.getCoords() != null) {
if (!nearestView.isClickable()) {
@@ -583,7 +586,7 @@ public class cgeo extends AbstractActivity {
* unused here but needed since this method is referenced from XML layout
*/
public void cgeoFindOnMap(View v) {
- findViewById(R.id.map).setPressed(true);
+ findOnMap.setPressed(true);
CGeoMap.startActivityLiveMap(this);
}
@@ -596,7 +599,7 @@ public class cgeo extends AbstractActivity {
return;
}
- findViewById(R.id.nearest).setPressed(true);
+ nearestView.setPressed(true);
cgeocaches.startActivityNearest(this, app.currentGeo().getCoords());
}
@@ -605,7 +608,7 @@ public class cgeo extends AbstractActivity {
* unused here but needed since this method is referenced from XML layout
*/
public void cgeoFindByOffline(View v) {
- findViewById(R.id.search_offline).setPressed(true);
+ findByOffline.setPressed(true);
cgeocaches.startActivityOffline(this);
}
@@ -614,7 +617,7 @@ public class cgeo extends AbstractActivity {
* unused here but needed since this method is referenced from XML layout
*/
public void cgeoSearch(View v) {
- findViewById(R.id.advanced_button).setPressed(true);
+ advanced.setPressed(true);
startActivity(new Intent(this, SearchActivity.class));
}
@@ -623,7 +626,7 @@ public class cgeo extends AbstractActivity {
* unused here but needed since this method is referenced from XML layout
*/
public void cgeoPoint(View v) {
- findViewById(R.id.any_button).setPressed(true);
+ any.setPressed(true);
startActivity(new Intent(this, NavigateAnyPointActivity.class));
}
@@ -632,8 +635,8 @@ public class cgeo extends AbstractActivity {
* unused here but needed since this method is referenced from XML layout
*/
public void cgeoFilter(View v) {
- findViewById(R.id.filter_button).setPressed(true);
- findViewById(R.id.filter_button).performClick();
+ filter.setPressed(true);
+ filter.performClick();
}
/**
@@ -646,15 +649,10 @@ public class cgeo extends AbstractActivity {
private class CountBubbleUpdateThread extends Thread {
private Handler countBubbleHandler = new Handler() {
- private TextView countBubble = null;
@Override
public void handleMessage(Message msg) {
try {
- if (countBubble == null) {
- countBubble = (TextView) findViewById(R.id.offline_count);
- }
-
if (countBubbleCnt == 0) {
countBubble.setVisibility(View.GONE);
} else {
@@ -663,7 +661,7 @@ public class cgeo extends AbstractActivity {
countBubble.setVisibility(View.VISIBLE);
}
} catch (Exception e) {
- Log.w("cgeo.countBubbleHander", e);
+ Log.w("MainActivity.countBubbleHander", e);
}
}
};
@@ -730,22 +728,35 @@ public class cgeo extends AbstractActivity {
return;
}
- // login
- final StatusCode status = Login.login();
+ //TODO: Rework to be fully dynamic
+ if (Settings.isGCConnectorActive()) {
+ // login
+ final StatusCode status = Login.login();
- if (status == StatusCode.NO_ERROR) {
- app.firstRun = false;
- Login.detectGcCustomDate();
- updateUserInfoHandler.sendEmptyMessage(-1);
- }
+ if (status == StatusCode.NO_ERROR) {
+ app.firstRun = false;
+ Login.detectGcCustomDate();
+ updateUserInfoHandler.sendEmptyMessage(-1);
+ }
- if (app.showLoginToast) {
- firstLoginHandler.sendMessage(firstLoginHandler.obtainMessage(0, status));
- app.showLoginToast = false;
+ if (app.showLoginToast) {
+ firstLoginHandler.sendMessage(firstLoginHandler.obtainMessage(0, status));
+ app.showLoginToast = false;
- // invoke settings activity to insert login details
- if (status == StatusCode.NO_LOGIN_INFO_STORED) {
- SettingsActivity.startActivity(cgeo.this);
+ // invoke settings activity to insert login details
+ if (status == StatusCode.NO_LOGIN_INFO_STORED) {
+ SettingsActivity.startActivity(MainActivity.this);
+ }
+ }
+ }
+ if (Settings.isOCConnectorActive()) {
+ IConnector conn = ConnectorFactory.getConnector("OCXXXX");
+ if (conn instanceof OCApiLiveConnector) {
+ OCApiLiveConnector ocapiConn = (OCApiLiveConnector) conn;
+ if (ocapiConn.supportsPersonalization()) {
+ ocapiConn.retrieveUserInfo();
+ }
+ updateUserInfoHandler.sendEmptyMessage(-1);
}
}
}
@@ -765,7 +776,7 @@ public class cgeo extends AbstractActivity {
addressObtaining = true;
try {
- final Geocoder geocoder = new Geocoder(cgeo.this, Locale.getDefault());
+ final Geocoder geocoder = new Geocoder(MainActivity.this, Locale.getDefault());
final Geopoint coords = app.currentGeo().getCoords();
addresses = geocoder.getFromLocation(coords.getLatitude(), coords.getLongitude(), 1);
} catch (Exception e) {
@@ -783,7 +794,7 @@ public class cgeo extends AbstractActivity {
* unused here but needed since this method is referenced from XML layout
*/
public void showAbout(View view) {
- startActivity(new Intent(this, AboutActivity.class));
+ AboutActivity_.intent(this).start();
}
/**
diff --git a/main/src/cgeo/geocaching/NavigateAnyPointActivity.java b/main/src/cgeo/geocaching/NavigateAnyPointActivity.java
index efea819..6f94944 100644
--- a/main/src/cgeo/geocaching/NavigateAnyPointActivity.java
+++ b/main/src/cgeo/geocaching/NavigateAnyPointActivity.java
@@ -1,10 +1,14 @@
package cgeo.geocaching;
+import butterknife.InjectView;
+import butterknife.Views;
+
import cgeo.geocaching.activity.AbstractActivity;
import cgeo.geocaching.apps.cache.navi.NavigationAppFactory;
import cgeo.geocaching.geopoint.DistanceParser;
import cgeo.geocaching.geopoint.Geopoint;
import cgeo.geocaching.geopoint.GeopointFormatter;
+import cgeo.geocaching.ui.AbstractViewHolder;
import cgeo.geocaching.ui.Formatter;
import cgeo.geocaching.ui.dialog.CoordinatesInputDialog;
import cgeo.geocaching.utils.GeoDirHandler;
@@ -37,10 +41,37 @@ import android.widget.TextView;
import java.util.List;
public class NavigateAnyPointActivity extends AbstractActivity {
- private static final int MENU_DEFAULT_NAVIGATION = 2;
- private static final int MENU_NAVIGATE = 0;
- private static final int MENU_CACHES_AROUND = 5;
- private static final int MENU_CLEAR_HISTORY = 6;
+
+ @InjectView(R.id.buttonLatitude) protected Button latButton;
+ @InjectView(R.id.buttonLongitude) protected Button lonButton;
+ @InjectView(R.id.current) protected Button buttonCurrent;
+ @InjectView(R.id.historyList) protected ListView historyListView;
+ @InjectView(R.id.distanceUnit) protected Spinner distanceUnitSelector;
+ @InjectView(R.id.bearing) protected EditText bearingEditText;
+ @InjectView(R.id.distance) protected EditText distanceEditText;
+
+ private boolean changed = false;
+ private List<Destination> historyOfSearchedLocations;
+ private DestinationHistoryAdapter destinationHistoryAdapter;
+ private TextView historyFooter;
+
+ private static final int CONTEXT_MENU_NAVIGATE = 1;
+ private static final int CONTEXT_MENU_DELETE_WAYPOINT = 2;
+ private static final int CONTEXT_MENU_EDIT_WAYPOINT = 3;
+
+ private int contextMenuItemPosition;
+
+ private String distanceUnit = "";
+
+ protected static class ViewHolder extends AbstractViewHolder {
+ @InjectView(R.id.simple_way_point_longitude) protected TextView longitude;
+ @InjectView(R.id.simple_way_point_latitude) protected TextView latitude;
+ @InjectView(R.id.date) protected TextView date;
+
+ public ViewHolder(View rowView) {
+ super(rowView);
+ }
+ }
private static class DestinationHistoryAdapter extends ArrayAdapter<Destination> {
private LayoutInflater inflater = null;
@@ -52,29 +83,29 @@ public class NavigateAnyPointActivity extends AbstractActivity {
@Override
public View getView(final int position, final View convertView, final ViewGroup parent) {
+ View rowView = convertView;
- Destination loc = getItem(position);
+ ViewHolder viewHolder;
+ if (rowView == null) {
+ rowView = getInflater().inflate(R.layout.simple_way_point, null);
+ viewHolder = new ViewHolder(rowView);
+ }
+ else {
+ viewHolder = (ViewHolder) rowView.getTag();
+ }
- View v = convertView;
+ fillViewHolder(viewHolder, getItem(position));
- if (v == null) {
- v = getInflater().inflate(R.layout.simple_way_point,
- null);
- }
- TextView longitude = (TextView) v
- .findViewById(R.id.simple_way_point_longitude);
- TextView latitude = (TextView) v
- .findViewById(R.id.simple_way_point_latitude);
- TextView date = (TextView) v.findViewById(R.id.date);
+ return rowView;
+ }
+ private void fillViewHolder(ViewHolder viewHolder, Destination loc) {
String lonString = loc.getCoords().format(GeopointFormatter.Format.LON_DECMINUTE);
String latString = loc.getCoords().format(GeopointFormatter.Format.LAT_DECMINUTE);
- longitude.setText(lonString);
- latitude.setText(latString);
- date.setText(Formatter.formatShortDateTime(getContext(), loc.getDate()));
-
- return v;
+ viewHolder.longitude.setText(lonString);
+ viewHolder.latitude.setText(latString);
+ viewHolder.date.setText(Formatter.formatShortDateTime(getContext(), loc.getDate()));
}
private LayoutInflater getInflater() {
@@ -86,46 +117,22 @@ public class NavigateAnyPointActivity extends AbstractActivity {
}
}
- private Button latButton = null;
- private Button lonButton = null;
- private boolean changed = false;
- private List<Destination> historyOfSearchedLocations;
- private DestinationHistoryAdapter destionationHistoryAdapter;
- private ListView historyListView;
- private TextView historyFooter;
-
- private static final int CONTEXT_MENU_NAVIGATE = 1;
- private static final int CONTEXT_MENU_DELETE_WAYPOINT = 2;
- private static final int CONTEXT_MENU_EDIT_WAYPOINT = 3;
-
- private int contextMenuItemPosition;
-
- String distanceUnit = "";
-
- public NavigateAnyPointActivity() {
- super("c:geo-navigate-any");
- }
-
@Override
public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- setTheme();
- setContentView(R.layout.point);
- setTitle(res.getString(R.string.search_destination));
+ super.onCreate(savedInstanceState, R.layout.navigateanypoint_activity);
+ Views.inject(this);
createHistoryView();
-
init();
}
private void createHistoryView() {
- historyListView = (ListView) findViewById(R.id.historyList);
-
- final View pointControls = getLayoutInflater().inflate(
- R.layout.point_controls, null);
+ final View pointControls = getLayoutInflater().inflate(R.layout.navigateanypoint_header, null);
historyListView.addHeaderView(pointControls, null, false);
+ // inject a second time to also find the dynamically expanded views above
+ Views.inject(this);
+
if (getHistoryOfSearchedLocations().isEmpty()) {
historyListView.addFooterView(getEmptyHistoryFooter(), null, false);
}
@@ -146,7 +153,7 @@ public class NavigateAnyPointActivity extends AbstractActivity {
historyListView.setOnCreateContextMenuListener(new OnCreateContextMenuListener() {
@Override
public void onCreateContextMenu(ContextMenu menu, View v,
- ContextMenuInfo menuInfo) {
+ ContextMenuInfo menuInfo) {
menu.add(Menu.NONE, CONTEXT_MENU_NAVIGATE, Menu.NONE, res.getString(R.string.cache_menu_navigate));
menu.add(Menu.NONE, CONTEXT_MENU_EDIT_WAYPOINT, Menu.NONE, R.string.waypoint_edit);
menu.add(Menu.NONE, CONTEXT_MENU_DELETE_WAYPOINT, Menu.NONE, R.string.waypoint_delete);
@@ -190,19 +197,17 @@ public class NavigateAnyPointActivity extends AbstractActivity {
private TextView getEmptyHistoryFooter() {
if (historyFooter == null) {
- historyFooter = (TextView) getLayoutInflater().inflate(
- R.layout.caches_footer, null);
+ historyFooter = (TextView) getLayoutInflater().inflate(R.layout.cacheslist_footer, null);
historyFooter.setText(R.string.search_history_empty);
}
return historyFooter;
}
private DestinationHistoryAdapter getDestionationHistoryAdapter() {
- if (destionationHistoryAdapter == null) {
- destionationHistoryAdapter = new DestinationHistoryAdapter(this,
- getHistoryOfSearchedLocations());
+ if (destinationHistoryAdapter == null) {
+ destinationHistoryAdapter = new DestinationHistoryAdapter(this, getHistoryOfSearchedLocations());
}
- return destionationHistoryAdapter;
+ return destinationHistoryAdapter;
}
private List<Destination> getHistoryOfSearchedLocations() {
@@ -229,25 +234,12 @@ public class NavigateAnyPointActivity extends AbstractActivity {
}
@Override
- public void onDestroy() {
- super.onDestroy();
- }
-
- @Override
- public void onStop() {
- super.onStop();
- }
-
- @Override
public void onPause() {
geoDirHandler.stopGeo();
super.onPause();
}
private void init() {
- latButton = (Button) findViewById(R.id.buttonLatitude);
- lonButton = (Button) findViewById(R.id.buttonLongitude);
-
latButton.setOnClickListener(new CoordDialogListener());
lonButton.setOnClickListener(new CoordDialogListener());
@@ -257,19 +249,15 @@ public class NavigateAnyPointActivity extends AbstractActivity {
lonButton.setText(coords.format(GeopointFormatter.Format.LON_DECMINUTE));
}
- Button buttonCurrent = (Button) findViewById(R.id.current);
buttonCurrent.setOnClickListener(new CurrentListener());
getDestionationHistoryAdapter().notifyDataSetChanged();
- disableSuggestions((EditText) findViewById(R.id.distance));
+ disableSuggestions(distanceEditText);
initializeDistanceUnitSelector();
}
private void initializeDistanceUnitSelector() {
-
- Spinner distanceUnitSelector = (Spinner) findViewById(R.id.distanceUnit);
-
if (StringUtils.isBlank(distanceUnit)) {
if (Settings.isUseMetricUnits()) {
distanceUnitSelector.setSelection(0); // m
@@ -326,14 +314,8 @@ public class NavigateAnyPointActivity extends AbstractActivity {
@Override
public boolean onCreateOptionsMenu(Menu menu) {
- menu.add(0, MENU_DEFAULT_NAVIGATION, 0, NavigationAppFactory.getDefaultNavigationApplication().getName()).setIcon(R.drawable.ic_menu_compass); // default navigation tool
-
- menu.add(0, MENU_NAVIGATE, 0, res.getString(R.string.cache_menu_navigate)).setIcon(R.drawable.ic_menu_mapmode);
-
- menu.add(0, MENU_CACHES_AROUND, 0, res.getString(R.string.cache_menu_around)).setIcon(R.drawable.ic_menu_rotate); // caches around
-
- menu.add(0, MENU_CLEAR_HISTORY, 0, res.getString(R.string.search_clear_history)).setIcon(R.drawable.ic_menu_delete); // clear history
-
+ getMenuInflater().inflate(R.menu.navigate_any_point_activity_options, menu);
+ menu.findItem(R.id.menu_default_navigation).setTitle(NavigationAppFactory.getDefaultNavigationApplication().getName());
return true;
}
@@ -343,11 +325,11 @@ public class NavigateAnyPointActivity extends AbstractActivity {
try {
boolean visible = getDestination() != null;
- menu.findItem(MENU_NAVIGATE).setVisible(visible);
- menu.findItem(MENU_DEFAULT_NAVIGATION).setVisible(visible);
- menu.findItem(MENU_CACHES_AROUND).setVisible(visible);
+ menu.findItem(R.id.menu_navigate).setVisible(visible);
+ menu.findItem(R.id.menu_default_navigation).setVisible(visible);
+ menu.findItem(R.id.menu_caches_around).setVisible(visible);
- menu.findItem(MENU_CLEAR_HISTORY).setEnabled(!getHistoryOfSearchedLocations().isEmpty());
+ menu.findItem(R.id.menu_clear_history).setEnabled(!getHistoryOfSearchedLocations().isEmpty());
} catch (Exception e) {
// nothing
}
@@ -366,19 +348,19 @@ public class NavigateAnyPointActivity extends AbstractActivity {
}
switch (menuItem) {
- case MENU_DEFAULT_NAVIGATION:
+ case R.id.menu_default_navigation:
navigateTo();
return true;
- case MENU_CACHES_AROUND:
+ case R.id.menu_caches_around:
cachesAround();
return true;
- case MENU_CLEAR_HISTORY:
+ case R.id.menu_clear_history:
clearHistory();
return true;
- case MENU_NAVIGATE:
+ case R.id.menu_navigate:
NavigationAppFactory.showNavigationMenu(this, null, null, coords);
return true;
default:
@@ -402,7 +384,7 @@ public class NavigateAnyPointActivity extends AbstractActivity {
runOnUiThread(new Runnable() {
@Override
public void run() {
- destionationHistoryAdapter.notifyDataSetChanged();
+ destinationHistoryAdapter.notifyDataSetChanged();
}
});
}
@@ -495,10 +477,9 @@ public class NavigateAnyPointActivity extends AbstractActivity {
}
private Geopoint getDestination() {
-
- String bearingText = ((EditText) findViewById(R.id.bearing)).getText().toString();
+ String bearingText = bearingEditText.getText().toString();
// combine distance from EditText and distanceUnit saved from Spinner
- String distanceText = ((EditText) findViewById(R.id.distance)).getText().toString() + distanceUnit;
+ String distanceText = distanceEditText.getText().toString() + distanceUnit;
String latText = latButton.getText().toString();
String lonText = lonButton.getText().toString();
diff --git a/main/src/cgeo/geocaching/SearchActivity.java b/main/src/cgeo/geocaching/SearchActivity.java
index 6fdff5a..c2a7b6d 100644
--- a/main/src/cgeo/geocaching/SearchActivity.java
+++ b/main/src/cgeo/geocaching/SearchActivity.java
@@ -1,14 +1,16 @@
package cgeo.geocaching;
+import butterknife.InjectView;
+import butterknife.Views;
+
import cgeo.geocaching.activity.AbstractActivity;
import cgeo.geocaching.connector.ConnectorFactory;
import cgeo.geocaching.connector.IConnector;
import cgeo.geocaching.connector.capability.ISearchByGeocode;
-import cgeo.geocaching.connector.gc.GCConstants;
+import cgeo.geocaching.connector.trackable.TrackableConnector;
import cgeo.geocaching.geopoint.Geopoint;
import cgeo.geocaching.geopoint.GeopointFormatter;
import cgeo.geocaching.ui.dialog.CoordinatesInputDialog;
-import cgeo.geocaching.utils.BaseUtils;
import cgeo.geocaching.utils.EditUtils;
import cgeo.geocaching.utils.GeoDirHandler;
import cgeo.geocaching.utils.Log;
@@ -33,20 +35,32 @@ import java.util.Locale;
public class SearchActivity extends AbstractActivity {
- private static final int MENU_SEARCH_OWN_CACHES = 1;
- private EditText latEdit = null;
- private EditText lonEdit = null;
-
- public SearchActivity() {
- super("c:geo-search");
- }
+ @InjectView(R.id.buttonLatitude) protected Button buttonLatitude;
+ @InjectView(R.id.buttonLongitude) protected Button buttonLongitude;
+ @InjectView(R.id.search_coordinates) protected Button findByCoords;
+ @InjectView(R.id.search_address) protected Button findByAddress;
+ @InjectView(R.id.geocode) protected AutoCompleteTextView geocodeEdit;
+ @InjectView(R.id.display_geocode) protected Button displayByGeocode;
+ @InjectView(R.id.search_keyword) protected Button findByKeyword;
+ @InjectView(R.id.search_username) protected Button findByUserName;
+ @InjectView(R.id.search_owner) protected Button findByOwner;
+ @InjectView(R.id.trackable) protected AutoCompleteTextView trackable;
+ @InjectView(R.id.display_trackable) protected Button displayTrackable;
+ @InjectView(R.id.latitude) protected EditText latEdit;
+ @InjectView(R.id.longitude) protected EditText lonEdit;
+ @InjectView(R.id.keyword) protected EditText keywordEditText;
+ @InjectView(R.id.address) protected EditText addressEditText;
+ @InjectView(R.id.username) protected EditText userNameEditText;
+ @InjectView(R.id.owner) protected EditText ownerNameEditText;
+ @InjectView(R.id.geocode) protected EditText geocodeEditText;
+ @InjectView(R.id.trackable) protected EditText trackableEditText;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// search query
- Intent intent = getIntent();
+ final Intent intent = getIntent();
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
final String query = intent.getStringExtra(SearchManager.QUERY);
final boolean keywordSearch = intent.getBooleanExtra(Intents.EXTRA_KEYWORD_SEARCH, true);
@@ -63,9 +77,12 @@ public class SearchActivity extends AbstractActivity {
}
setTheme();
- setContentView(R.layout.search);
+ setContentView(R.layout.search_activity);
+
+ // set title in code, as the activity needs a hard coded title due to the intent filters
setTitle(res.getString(R.string.search));
+ Views.inject(this);
init();
}
@@ -104,7 +121,7 @@ public class SearchActivity extends AbstractActivity {
// otherwise see if this is a pure geocode
if (StringUtils.isEmpty(geocode)) {
- geocode = StringUtils.trim(query);
+ geocode = StringUtils.upperCase(StringUtils.trim(query));
}
final IConnector connector = ConnectorFactory.getConnector(geocode);
@@ -116,10 +133,10 @@ public class SearchActivity extends AbstractActivity {
}
// Check if the query is a TB code
- final String trackable = BaseUtils.getMatch(query, GCConstants.PATTERN_TB_CODE, true, 0, "", false);
- if (StringUtils.isNotBlank(trackable)) {
+ final TrackableConnector trackableConnector = ConnectorFactory.getTrackableConnector(geocode);
+ if (trackableConnector != ConnectorFactory.UNKNOWN_TRACKABLE_CONNECTOR) {
final Intent trackablesIntent = new Intent(this, TrackableActivity.class);
- trackablesIntent.putExtra(Intents.EXTRA_GEOCODE, trackable.toUpperCase(Locale.US));
+ trackablesIntent.putExtra(Intents.EXTRA_GEOCODE, geocode.toUpperCase(Locale.US));
startActivity(trackablesIntent);
return true;
}
@@ -135,10 +152,8 @@ public class SearchActivity extends AbstractActivity {
private void init() {
Settings.getLogin();
- findViewById(R.id.buttonLatitude).setOnClickListener(new FindByCoordsAction());
- findViewById(R.id.buttonLongitude).setOnClickListener(new FindByCoordsAction());
-
- final Button findByCoords = (Button) findViewById(R.id.search_coordinates);
+ buttonLatitude.setOnClickListener(new FindByCoordsAction());
+ buttonLongitude.setOnClickListener(new FindByCoordsAction());
findByCoords.setOnClickListener(new FindByCoordsListener());
EditUtils.setActionListener((EditText) findViewById(R.id.address), new Runnable() {
@@ -148,11 +163,8 @@ public class SearchActivity extends AbstractActivity {
findByAddressFn();
}
});
-
- final Button findByAddress = (Button) findViewById(R.id.search_address);
findByAddress.setOnClickListener(new FindByAddressListener());
- final AutoCompleteTextView geocodeEdit = (AutoCompleteTextView) findViewById(R.id.geocode);
EditUtils.setActionListener(geocodeEdit, new Runnable() {
@Override
@@ -161,8 +173,6 @@ public class SearchActivity extends AbstractActivity {
}
});
addHistoryEntries(geocodeEdit, cgData.getRecentGeocodesForSearch());
-
- final Button displayByGeocode = (Button) findViewById(R.id.display_geocode);
displayByGeocode.setOnClickListener(new FindByGeocodeListener());
EditUtils.setActionListener((EditText) findViewById(R.id.keyword), new Runnable() {
@@ -172,8 +182,6 @@ public class SearchActivity extends AbstractActivity {
findByKeywordFn();
}
});
-
- final Button findByKeyword = (Button) findViewById(R.id.search_keyword);
findByKeyword.setOnClickListener(new FindByKeywordListener());
EditUtils.setActionListener((EditText) findViewById(R.id.username), new Runnable() {
@@ -183,8 +191,6 @@ public class SearchActivity extends AbstractActivity {
findByUsernameFn();
}
});
-
- final Button findByUserName = (Button) findViewById(R.id.search_username);
findByUserName.setOnClickListener(new FindByUsernameListener());
EditUtils.setActionListener((EditText) findViewById(R.id.owner), new Runnable() {
@@ -194,8 +200,6 @@ public class SearchActivity extends AbstractActivity {
findByOwnerFn();
}
});
-
- final Button findByOwner = (Button) findViewById(R.id.search_owner);
findByOwner.setOnClickListener(new OnClickListener() {
@Override
@@ -204,7 +208,6 @@ public class SearchActivity extends AbstractActivity {
}
});
- AutoCompleteTextView trackable = (AutoCompleteTextView) findViewById(R.id.trackable);
EditUtils.setActionListener(trackable, new Runnable() {
@Override
@@ -213,10 +216,7 @@ public class SearchActivity extends AbstractActivity {
}
});
addHistoryEntries(trackable, cgData.getTrackableCodes());
-
disableSuggestions(trackable);
-
- final Button displayTrackable = (Button) findViewById(R.id.display_trackable);
displayTrackable.setOnClickListener(new FindTrackableListener());
}
@@ -231,13 +231,6 @@ public class SearchActivity extends AbstractActivity {
@Override
public void updateGeoData(final IGeoData geo) {
try {
- if (latEdit == null) {
- latEdit = (EditText) findViewById(R.id.latitude);
- }
- if (lonEdit == null) {
- lonEdit = (EditText) findViewById(R.id.longitude);
- }
-
if (geo.getCoords() != null) {
if (latEdit != null) {
latEdit.setHint(geo.getCoords().format(GeopointFormatter.Format.LAT_DECMINUTE_RAW));
@@ -246,7 +239,7 @@ public class SearchActivity extends AbstractActivity {
lonEdit.setHint(geo.getCoords().format(GeopointFormatter.Format.LON_DECMINUTE_RAW));
}
}
- } catch (Exception e) {
+ } catch (final Exception e) {
Log.w("Failed to update location.");
}
}
@@ -256,13 +249,13 @@ public class SearchActivity extends AbstractActivity {
@Override
public void onClick(View arg0) {
- CoordinatesInputDialog coordsDialog = new CoordinatesInputDialog(SearchActivity.this, null, null, app.currentGeo());
+ final CoordinatesInputDialog coordsDialog = new CoordinatesInputDialog(SearchActivity.this, null, null, app.currentGeo());
coordsDialog.setCancelable(true);
coordsDialog.setOnCoordinateUpdate(new CoordinatesInputDialog.CoordinateUpdate() {
@Override
public void update(Geopoint gp) {
- ((Button) findViewById(R.id.buttonLatitude)).setText(gp.format(GeopointFormatter.Format.LAT_DECMINUTE));
- ((Button) findViewById(R.id.buttonLongitude)).setText(gp.format(GeopointFormatter.Format.LON_DECMINUTE));
+ buttonLatitude.setText(gp.format(GeopointFormatter.Format.LAT_DECMINUTE));
+ buttonLongitude.setText(gp.format(GeopointFormatter.Format.LON_DECMINUTE));
}
});
coordsDialog.show();
@@ -278,21 +271,19 @@ public class SearchActivity extends AbstractActivity {
}
private void findByCoordsFn() {
- final Button latView = (Button) findViewById(R.id.buttonLatitude);
- final Button lonView = (Button) findViewById(R.id.buttonLongitude);
- final String latText = latView.getText().toString();
- final String lonText = lonView.getText().toString();
+ final String latText = buttonLatitude.getText().toString();
+ final String lonText = buttonLongitude.getText().toString();
if (StringUtils.isEmpty(latText) || StringUtils.isEmpty(lonText)) {
final IGeoData geo = app.currentGeo();
if (geo.getCoords() != null) {
- latView.setText(geo.getCoords().format(GeopointFormatter.Format.LAT_DECMINUTE));
- lonView.setText(geo.getCoords().format(GeopointFormatter.Format.LON_DECMINUTE));
+ buttonLatitude.setText(geo.getCoords().format(GeopointFormatter.Format.LAT_DECMINUTE));
+ buttonLongitude.setText(geo.getCoords().format(GeopointFormatter.Format.LON_DECMINUTE));
}
} else {
try {
cgeocaches.startActivityCoordinates(this, new Geopoint(StringUtils.trim(latText), StringUtils.trim(lonText)));
- } catch (Geopoint.ParseException e) {
+ } catch (final Geopoint.ParseException e) {
showToast(res.getString(e.resource));
}
}
@@ -308,7 +299,7 @@ public class SearchActivity extends AbstractActivity {
private void findByKeywordFn() {
// find caches by coordinates
- String keyText = ((EditText) findViewById(R.id.keyword)).getText().toString();
+ final String keyText = keywordEditText.getText().toString();
if (StringUtils.isBlank(keyText)) {
helpDialog(res.getString(R.string.warn_search_help_title), res.getString(R.string.warn_search_help_keyword));
@@ -326,7 +317,7 @@ public class SearchActivity extends AbstractActivity {
}
private void findByAddressFn() {
- final String addText = ((EditText) findViewById(R.id.address)).getText().toString();
+ final String addText = addressEditText.getText().toString();
if (StringUtils.isBlank(addText)) {
helpDialog(res.getString(R.string.warn_search_help_title), res.getString(R.string.warn_search_help_address));
@@ -347,7 +338,7 @@ public class SearchActivity extends AbstractActivity {
}
public void findByUsernameFn() {
- final String usernameText = ((EditText) findViewById(R.id.username)).getText().toString();
+ final String usernameText = userNameEditText.getText().toString();
if (StringUtils.isBlank(usernameText)) {
helpDialog(res.getString(R.string.warn_search_help_title), res.getString(R.string.warn_search_help_user));
@@ -358,7 +349,7 @@ public class SearchActivity extends AbstractActivity {
}
private void findByOwnerFn() {
- findByOwnerFn(((EditText) findViewById(R.id.owner)).getText().toString());
+ findByOwnerFn(ownerNameEditText.getText().toString());
}
private void findByOwnerFn(String userName) {
@@ -381,7 +372,7 @@ public class SearchActivity extends AbstractActivity {
}
private void findByGeocodeFn() {
- final String geocodeText = ((EditText) findViewById(R.id.geocode)).getText().toString();
+ final String geocodeText = geocodeEditText.getText().toString();
if (StringUtils.isBlank(geocodeText) || geocodeText.equalsIgnoreCase("GC")) {
helpDialog(res.getString(R.string.warn_search_help_title), res.getString(R.string.warn_search_help_gccode));
@@ -400,7 +391,7 @@ public class SearchActivity extends AbstractActivity {
}
private void findTrackableFn() {
- final String trackableText = ((EditText) findViewById(R.id.trackable)).getText().toString();
+ final String trackableText = trackableEditText.getText().toString();
if (StringUtils.isBlank(trackableText) || trackableText.equalsIgnoreCase("TB")) {
helpDialog(res.getString(R.string.warn_search_help_title), res.getString(R.string.warn_search_help_tb));
@@ -414,13 +405,13 @@ public class SearchActivity extends AbstractActivity {
@Override
public boolean onCreateOptionsMenu(Menu menu) {
- menu.add(0, MENU_SEARCH_OWN_CACHES, 0, res.getString(R.string.search_own_caches)).setIcon(R.drawable.ic_menu_myplaces);
+ getMenuInflater().inflate(R.menu.search_activity_options, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
- if (item.getItemId() == MENU_SEARCH_OWN_CACHES) {
+ if (item.getItemId() == R.id.menu_search_own_caches) {
findByOwnerFn(Settings.getUsername());
return true;
}
@@ -432,6 +423,6 @@ public class SearchActivity extends AbstractActivity {
searchIntent.setAction(Intent.ACTION_SEARCH).
putExtra(SearchManager.QUERY, scan).
putExtra(Intents.EXTRA_KEYWORD_SEARCH, false);
- fromActivity.startActivityForResult(searchIntent, cgeo.SEARCH_REQUEST_CODE);
+ fromActivity.startActivityForResult(searchIntent, MainActivity.SEARCH_REQUEST_CODE);
}
}
diff --git a/main/src/cgeo/geocaching/SearchResult.java b/main/src/cgeo/geocaching/SearchResult.java
index b0540f2..4cef95e 100644
--- a/main/src/cgeo/geocaching/SearchResult.java
+++ b/main/src/cgeo/geocaching/SearchResult.java
@@ -114,7 +114,7 @@ public class SearchResult implements Parcelable {
public SearchResult(final Collection<Geocache> caches) {
this();
for (final Geocache cache : caches) {
- addCache(cache);
+ addAndPutInCache(cache);
}
}
@@ -199,7 +199,7 @@ public class SearchResult implements Parcelable {
(excludeMine && (cache.isOwner() || cache.isFound())) ||
(!cacheType.contains(cache));
if (!excludeCache) {
- result.addCache(cache);
+ result.addAndPutInCache(cache);
cachesForVote.add(cache);
}
}
@@ -229,7 +229,7 @@ public class SearchResult implements Parcelable {
}
/** Add the cache geocode to the search and store the cache in the CacheCache */
- public boolean addCache(final Geocache cache) {
+ public boolean addAndPutInCache(final Geocache cache) {
addGeocode(cache.getGeocode());
return cgData.saveCache(cache, EnumSet.of(SaveFlag.SAVE_CACHE));
}
diff --git a/main/src/cgeo/geocaching/SelectMapfileActivity.java b/main/src/cgeo/geocaching/SelectMapfileActivity.java
index 9557f3e..aa6d46a 100644
--- a/main/src/cgeo/geocaching/SelectMapfileActivity.java
+++ b/main/src/cgeo/geocaching/SelectMapfileActivity.java
@@ -55,11 +55,6 @@ public class SelectMapfileActivity extends AbstractFileListActivity<FileSelectio
}
@Override
- protected void setTitle() {
- setTitle(res.getString(R.string.map_file_select_title));
- }
-
- @Override
public String getCurrentFile() {
return mapFile;
}
diff --git a/main/src/cgeo/geocaching/Settings.java b/main/src/cgeo/geocaching/Settings.java
index 0c157e1..7a5db12 100644
--- a/main/src/cgeo/geocaching/Settings.java
+++ b/main/src/cgeo/geocaching/Settings.java
@@ -40,8 +40,8 @@ import java.util.Locale;
*/
public final class Settings {
- private static final String KEY_TEMP_TOKEN_SECRET = "temp-token-secret";
- private static final String KEY_TEMP_TOKEN_PUBLIC = "temp-token-public";
+ private static final String KEY_TEMP_TWITTER_TOKEN_SECRET = "temp-token-secret";
+ private static final String KEY_TEMP_TWITTER_TOKEN_PUBLIC = "temp-token-public";
private static final String KEY_HELP_SHOWN = "helper";
private static final String KEY_ANYLONGITUDE = "anylongitude";
private static final String KEY_ANYLATITUDE = "anylatitude";
@@ -110,8 +110,14 @@ public final class Settings {
private static final String KEY_PLAIN_LOGS = "plainLogs";
private static final String KEY_NATIVE_UA = "nativeUa";
private static final String KEY_MAP_DIRECTORY = "mapDirectory";
+ private static final String KEY_CONNECTOR_GC_ACTIVE = "connectorGCActive";
private static final String KEY_CONNECTOR_OC_ACTIVE = "connectorOCActive";
- private static final String KEY_CONNECTOR_OC_USER = "connectorOCUser";
+ private static final String KEY_LOG_IMAGE_SCALE = "logImageScale";
+ private static final String KEY_OCDE_TOKEN_SECRET = "ocde_tokensecret";
+ private static final String KEY_OCDE_TOKEN_PUBLIC = "ocde_tokenpublic";
+ private static final String KEY_TEMP_OCDE_TOKEN_SECRET = "ocde-temp-token-secret";
+ private static final String KEY_TEMP_OCDE_TOKEN_PUBLIC = "ocde-temp-token-public";
+
private final static int unitsMetric = 1;
@@ -149,6 +155,7 @@ public final class Settings {
// maps
private static MapProvider mapProvider = null;
+ private static String cacheTwitterMessage = "I found [NAME] ([URL])";
private Settings() {
// this class is not to be instantiated;
@@ -161,8 +168,8 @@ public final class Settings {
final SharedPreferences old = cgeoapplication.getInstance().getSharedPreferences(oldPreferencesName, Context.MODE_PRIVATE);
final Editor e = sharedPrefs.edit();
- e.putString(KEY_TEMP_TOKEN_SECRET, old.getString(KEY_TEMP_TOKEN_SECRET, null));
- e.putString(KEY_TEMP_TOKEN_PUBLIC, old.getString(KEY_TEMP_TOKEN_PUBLIC, null));
+ e.putString(KEY_TEMP_TWITTER_TOKEN_SECRET, old.getString(KEY_TEMP_TWITTER_TOKEN_SECRET, null));
+ e.putString(KEY_TEMP_TWITTER_TOKEN_PUBLIC, old.getString(KEY_TEMP_TWITTER_TOKEN_PUBLIC, null));
e.putBoolean(KEY_HELP_SHOWN, old.getInt(KEY_HELP_SHOWN, 0) != 0);
e.putFloat(KEY_ANYLONGITUDE, old.getFloat(KEY_ANYLONGITUDE, 0));
e.putFloat(KEY_ANYLATITUDE, old.getFloat(KEY_ANYLATITUDE, 0));
@@ -185,9 +192,9 @@ public final class Settings {
e.putString(KEY_TWITTER_TOKEN_SECRET, old.getString(KEY_TWITTER_TOKEN_SECRET, null));
e.putString(KEY_TWITTER_TOKEN_PUBLIC, old.getString(KEY_TWITTER_TOKEN_PUBLIC, null));
e.putInt(KEY_VERSION, old.getInt(KEY_VERSION, 0));
- e.putBoolean(KEY_LOAD_DESCRIPTION, 0 != old.getInt(KEY_LOAD_DESCRIPTION, 0));
+ e.putBoolean(KEY_LOAD_DESCRIPTION, 0 != old.getInt(KEY_LOAD_DESCRIPTION, 1));
e.putBoolean(KEY_RATING_WANTED, old.getBoolean(KEY_RATING_WANTED, true));
- e.putBoolean(KEY_ELEVATION_WANTED, old.getBoolean(KEY_ELEVATION_WANTED, true));
+ e.putBoolean(KEY_ELEVATION_WANTED, old.getBoolean(KEY_ELEVATION_WANTED, false));
e.putBoolean(KEY_FRIENDLOGS_WANTED, old.getBoolean(KEY_FRIENDLOGS_WANTED, true));
e.putBoolean(KEY_USE_ENGLISH, old.getBoolean(KEY_USE_ENGLISH, false));
e.putBoolean(KEY_USE_COMPASS, 0 != old.getInt(KEY_USE_COMPASS, 1));
@@ -282,6 +289,20 @@ public final class Settings {
});
}
+ public static boolean isGCConnectorActive() {
+ return sharedPrefs.getBoolean(KEY_CONNECTOR_GC_ACTIVE, true);
+ }
+
+ public static boolean setGCConnectorActive(final boolean isActive) {
+ return editSharedSettings(new PrefRunnable() {
+
+ @Override
+ public void edit(Editor edit) {
+ edit.putBoolean(KEY_CONNECTOR_GC_ACTIVE, isActive);
+ }
+ });
+ }
+
public static boolean isPremiumMember() {
// Basic Member, Premium Member, ???
String memberStatus = Settings.getMemberStatus();
@@ -323,26 +344,44 @@ public final class Settings {
});
}
- public static String getOCConnectorUserName() {
- String ocConnectorUser = sharedPrefs.getString(KEY_CONNECTOR_OC_USER, null);
- if (StringUtils.isBlank(ocConnectorUser)) {
- return StringUtils.EMPTY;
- }
- return ocConnectorUser;
+ public static String getOCDETokenPublic() {
+ return sharedPrefs.getString(KEY_OCDE_TOKEN_PUBLIC, "");
}
- public static boolean setOCConnectorUserName(final String userName) {
- return editSharedSettings(new PrefRunnable() {
+ public static String getOCDETokenSecret() {
+ return sharedPrefs.getString(KEY_OCDE_TOKEN_SECRET, "");
+ }
+
+ public static void setOCDETokens(final String tokenPublic, final String tokenSecret, boolean enableOcDe) {
+ editSharedSettings(new PrefRunnable() {
@Override
public void edit(Editor edit) {
- if (StringUtils.isBlank(userName)) {
- edit.remove(KEY_CONNECTOR_OC_USER);
- } else {
- edit.putString(KEY_CONNECTOR_OC_USER, userName);
+ edit.putString(KEY_OCDE_TOKEN_PUBLIC, tokenPublic);
+ edit.putString(KEY_OCDE_TOKEN_SECRET, tokenSecret);
+ if (tokenPublic != null) {
+ edit.remove(KEY_TEMP_OCDE_TOKEN_PUBLIC);
+ edit.remove(KEY_TEMP_OCDE_TOKEN_SECRET);
}
}
});
+ setOCConnectorActive(enableOcDe);
+ }
+
+ public static void setOCDETempTokens(final String tokenPublic, final String tokenSecret) {
+ editSharedSettings(new PrefRunnable() {
+ @Override
+ public void edit(Editor edit) {
+ edit.putString(KEY_TEMP_OCDE_TOKEN_PUBLIC, tokenPublic);
+ edit.putString(KEY_TEMP_OCDE_TOKEN_SECRET, tokenSecret);
+ }
+ });
+ }
+
+ public static ImmutablePair<String, String> getTempOCDEToken() {
+ String tokenPublic = sharedPrefs.getString(KEY_TEMP_OCDE_TOKEN_PUBLIC, null);
+ String tokenSecret = sharedPrefs.getString(KEY_TEMP_OCDE_TOKEN_SECRET, null);
+ return new ImmutablePair<String, String>(tokenPublic, tokenSecret);
}
public static boolean isGCvoteLogin() {
@@ -725,7 +764,7 @@ public final class Settings {
}
public static boolean isAutoLoadDescription() {
- return sharedPrefs.getBoolean(KEY_LOAD_DESCRIPTION, false);
+ return sharedPrefs.getBoolean(KEY_LOAD_DESCRIPTION, true);
}
public static void setAutoLoadDesc(final boolean autoLoad) {
@@ -753,7 +792,7 @@ public final class Settings {
}
public static boolean isElevationWanted() {
- return sharedPrefs.getBoolean(KEY_ELEVATION_WANTED, true);
+ return sharedPrefs.getBoolean(KEY_ELEVATION_WANTED, false);
}
public static void setElevationWanted(final boolean elevationWanted) {
@@ -1120,8 +1159,8 @@ public final class Settings {
edit.putString(KEY_TWITTER_TOKEN_PUBLIC, tokenPublic);
edit.putString(KEY_TWITTER_TOKEN_SECRET, tokenSecret);
if (tokenPublic != null) {
- edit.remove(KEY_TEMP_TOKEN_PUBLIC);
- edit.remove(KEY_TEMP_TOKEN_SECRET);
+ edit.remove(KEY_TEMP_TWITTER_TOKEN_PUBLIC);
+ edit.remove(KEY_TEMP_TWITTER_TOKEN_SECRET);
}
}
});
@@ -1132,15 +1171,15 @@ public final class Settings {
editSharedSettings(new PrefRunnable() {
@Override
public void edit(Editor edit) {
- edit.putString(KEY_TEMP_TOKEN_PUBLIC, tokenPublic);
- edit.putString(KEY_TEMP_TOKEN_SECRET, tokenSecret);
+ edit.putString(KEY_TEMP_TWITTER_TOKEN_PUBLIC, tokenPublic);
+ edit.putString(KEY_TEMP_TWITTER_TOKEN_SECRET, tokenSecret);
}
});
}
public static ImmutablePair<String, String> getTempToken() {
- String tokenPublic = sharedPrefs.getString(KEY_TEMP_TOKEN_PUBLIC, null);
- String tokenSecret = sharedPrefs.getString(KEY_TEMP_TOKEN_SECRET, null);
+ String tokenPublic = sharedPrefs.getString(KEY_TEMP_TWITTER_TOKEN_PUBLIC, null);
+ String tokenSecret = sharedPrefs.getString(KEY_TEMP_TWITTER_TOKEN_SECRET, null);
return new ImmutablePair<String, String>(tokenPublic, tokenSecret);
}
@@ -1424,4 +1463,32 @@ public final class Settings {
}
});
}
+
+ public static String getCacheTwitterMessage() {
+ // TODO make customizable from UI
+ return cacheTwitterMessage;
+ }
+
+ public static String getTrackableTwitterMessage() {
+ // TODO make customizable from UI
+ return "I touched [NAME] ([URL])!";
+ }
+
+ public static void setCacheTwitterMessage(final String message) {
+ cacheTwitterMessage = message;
+ }
+
+ public static int getLogImageScale() {
+ return sharedPrefs.getInt(KEY_LOG_IMAGE_SCALE, -1);
+ }
+
+ public static void setLogImageScale(final int scale) {
+ editSharedSettings(new PrefRunnable() {
+
+ @Override
+ public void edit(Editor edit) {
+ edit.putInt(KEY_LOG_IMAGE_SCALE, scale);
+ }
+ });
+ }
}
diff --git a/main/src/cgeo/geocaching/SettingsActivity.java b/main/src/cgeo/geocaching/SettingsActivity.java
index 0678617..872d5ee 100644
--- a/main/src/cgeo/geocaching/SettingsActivity.java
+++ b/main/src/cgeo/geocaching/SettingsActivity.java
@@ -5,6 +5,7 @@ import cgeo.geocaching.apps.cache.navi.NavigationAppFactory;
import cgeo.geocaching.apps.cache.navi.NavigationAppFactory.NavigationAppsEnum;
import cgeo.geocaching.compatibility.Compatibility;
import cgeo.geocaching.connector.gc.Login;
+import cgeo.geocaching.connector.oc.OCAuthorizationActivity;
import cgeo.geocaching.enumerations.StatusCode;
import cgeo.geocaching.files.SimpleDirChooser;
import cgeo.geocaching.maps.MapProviderFactory;
@@ -123,19 +124,9 @@ public class SettingsActivity extends AbstractActivity {
}
};
- public SettingsActivity() {
- super("c:geo-configuration");
- }
-
@Override
public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- // init
-
- setTheme();
- setContentView(R.layout.init);
- setTitle(res.getString(R.string.settings));
+ super.onCreate(savedInstanceState, R.layout.settings_activity);
init();
}
@@ -169,14 +160,13 @@ public class SettingsActivity extends AbstractActivity {
@Override
public boolean onCreateOptionsMenu(Menu menu) {
- menu.add(0, 0, 0, res.getString(R.string.init_clear)).setIcon(R.drawable.ic_menu_delete);
-
+ getMenuInflater().inflate(R.menu.settings_activity_options, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
- if (item.getItemId() == 0) {
+ if (item.getItemId() == R.id.menu_clear) {
((EditText) findViewById(R.id.username)).setText("");
((EditText) findViewById(R.id.password)).setText("");
((EditText) findViewById(R.id.passvote)).setText("");
@@ -223,6 +213,15 @@ public class SettingsActivity extends AbstractActivity {
public void init() {
// geocaching.com settings
+ final CheckBox gcCheck = (CheckBox) findViewById(R.id.gc_option);
+ gcCheck.setChecked(Settings.isGCConnectorActive());
+ gcCheck.setOnClickListener(new View.OnClickListener() {
+
+ @Override
+ public void onClick(View v) {
+ Settings.setGCConnectorActive(gcCheck.isChecked());
+ }
+ });
final ImmutablePair<String, String> login = Settings.getLogin();
if (login != null) {
((EditText) findViewById(R.id.username)).setText(login.left);
@@ -252,10 +251,9 @@ public class SettingsActivity extends AbstractActivity {
Settings.setOCConnectorActive(ocCheck.isChecked());
}
});
- EditText ocUserEdit = (EditText) findViewById(R.id.oc_username);
- if (ocUserEdit.getText().length() == 0) {
- ocUserEdit.setText(Settings.getOCConnectorUserName());
- }
+
+ Button checkOCUser = (Button) findViewById(R.id.register_oc_de);
+ checkOCUser.setOnClickListener(new OCDEAuthorizeCgeoListener());
// gcvote settings
final ImmutablePair<String, String> gcvoteLogin = Settings.getGCvoteLogin();
@@ -839,7 +837,6 @@ public class SettingsActivity extends AbstractActivity {
String signatureNew = ((EditText) findViewById(R.id.signature)).getText().toString();
String mapDirectoryNew = StringUtils.trimToEmpty(((EditText) findViewById(R.id.map_directory)).getText().toString());
String themesDirectoryNew = StringUtils.trimToEmpty(((EditText) findViewById(R.id.themefolder)).getText().toString());
- String ocUserName = StringUtils.trimToEmpty(((EditText) findViewById(R.id.oc_username)).getText().toString());
String altitudeNew = StringUtils.trimToNull(((EditText) findViewById(R.id.altitude)).getText().toString());
int altitudeNewInt = parseNumber(altitudeNew, 0);
@@ -853,7 +850,6 @@ public class SettingsActivity extends AbstractActivity {
final boolean status4 = Settings.setAltCorrection(altitudeNewInt);
final boolean status5 = Settings.setMapFileDirectory(mapDirectoryNew);
final boolean status6 = Settings.setCustomRenderThemeBaseFolder(themesDirectoryNew);
- final boolean status7 = Settings.setOCConnectorUserName(ocUserName);
Settings.setShowWaypointsThreshold(waypointThreshold);
String importNew = StringUtils.trimToEmpty(((EditText) findViewById(R.id.gpx_importdir)).getText().toString());
@@ -861,7 +857,7 @@ public class SettingsActivity extends AbstractActivity {
Settings.setGpxImportDir(importNew);
Settings.setGpxExportDir(exportNew);
- return status1 && status2 && status3 && status4 && status5 && status6 && status7;
+ return status1 && status2 && status3 && status4 && status5 && status6;
}
/**
@@ -930,6 +926,15 @@ public class SettingsActivity extends AbstractActivity {
}
}
+ private class OCDEAuthorizeCgeoListener implements View.OnClickListener {
+
+ @Override
+ public void onClick(View v) {
+ Intent authIntent = new Intent(SettingsActivity.this, OCAuthorizationActivity.class);
+ startActivity(authIntent);
+ }
+ }
+
private class WebAuthListener implements View.OnClickListener {
@Override
diff --git a/main/src/cgeo/geocaching/StaticMapsActivity.java b/main/src/cgeo/geocaching/StaticMapsActivity.java
index 005ee9e..4658262 100644
--- a/main/src/cgeo/geocaching/StaticMapsActivity.java
+++ b/main/src/cgeo/geocaching/StaticMapsActivity.java
@@ -4,34 +4,39 @@ import cgeo.geocaching.activity.AbstractActivity;
import cgeo.geocaching.enumerations.LoadFlags;
import cgeo.geocaching.utils.Log;
+import com.googlecode.androidannotations.annotations.EActivity;
+import com.googlecode.androidannotations.annotations.Extra;
+import com.googlecode.androidannotations.annotations.OptionsItem;
+import com.googlecode.androidannotations.annotations.OptionsMenu;
+
import org.apache.commons.collections.CollectionUtils;
import android.app.ProgressDialog;
import android.content.Context;
-import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuItem;
import android.widget.ImageView;
import android.widget.LinearLayout;
import java.util.ArrayList;
import java.util.List;
+@EActivity
+@OptionsMenu(R.menu.static_maps_activity_options)
public class StaticMapsActivity extends AbstractActivity {
private static final String EXTRAS_WAYPOINT = "waypoint";
private static final String EXTRAS_DOWNLOAD = "download";
private static final String EXTRAS_GEOCODE = "geocode";
- private static final int MENU_REFRESH = 1;
+
+ @Extra(EXTRAS_DOWNLOAD) boolean download = false;
+ @Extra(EXTRAS_WAYPOINT) Integer waypoint_id = null;
+ @Extra(EXTRAS_GEOCODE) String geocode = null;
+
private final List<Bitmap> maps = new ArrayList<Bitmap>();
- private boolean download = false;
- private Integer waypoint_id = null;
- private String geocode = null;
private LayoutInflater inflater = null;
private ProgressDialog waitDialog = null;
private LinearLayout smapsView = null;
@@ -79,7 +84,7 @@ public class StaticMapsActivity extends AbstractActivity {
for (final Bitmap image : maps) {
if (image != null) {
- final ImageView map = (ImageView) inflater.inflate(R.layout.map_static_item, null);
+ final ImageView map = (ImageView) inflater.inflate(R.layout.staticmaps_activity_item, null);
map.setImageBitmap(image);
smapsView.addView(map);
}
@@ -88,23 +93,7 @@ public class StaticMapsActivity extends AbstractActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- setTheme();
- setContentView(R.layout.map_static);
- setTitle(res.getString(R.string.map_static_title));
-
- // get parameters
- final Bundle extras = getIntent().getExtras();
-
- // try to get data from extras
- if (extras != null) {
- download = extras.getBoolean(EXTRAS_DOWNLOAD, false);
- geocode = extras.getString(EXTRAS_GEOCODE);
- if (extras.containsKey(EXTRAS_WAYPOINT)) {
- waypoint_id = extras.getInt(EXTRAS_WAYPOINT);
- }
- }
+ super.onCreate(savedInstanceState, R.layout.staticmaps_activity);
if (geocode == null) {
showToast("Sorry, c:geo forgot for what cache you want to load static maps.");
@@ -161,20 +150,10 @@ public class StaticMapsActivity extends AbstractActivity {
}
}
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- menu.add(0, MENU_REFRESH, 0, res.getString(R.string.cache_offline_refresh));
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- if (item.getItemId() == MENU_REFRESH) {
- downloadStaticMaps();
- restartActivity();
- return true;
- }
- return super.onOptionsItemSelected(item);
+ @OptionsItem(R.id.menu_refresh)
+ void refreshMaps() {
+ downloadStaticMaps();
+ restartActivity();
}
private boolean downloadStaticMaps() {
@@ -197,16 +176,10 @@ public class StaticMapsActivity extends AbstractActivity {
}
public static void startActivity(final Context activity, final String geocode, final boolean download, final Waypoint waypoint) {
- final Intent intent = new Intent(activity, StaticMapsActivity.class);
- // if resuming our app within this activity, finish it and return to the cache activity
- intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
- intent.putExtra(EXTRAS_GEOCODE, geocode);
- if (download) {
- intent.putExtra(EXTRAS_DOWNLOAD, true);
- }
+ StaticMapsActivity_.IntentBuilder_ builder = StaticMapsActivity_.intent(activity).geocode(geocode).download(download);
if (waypoint != null) {
- intent.putExtra(EXTRAS_WAYPOINT, waypoint.getId());
+ builder.waypoint_id(waypoint.getId());
}
- activity.startActivity(intent);
+ builder.start();
}
} \ No newline at end of file
diff --git a/main/src/cgeo/geocaching/StaticMapsProvider.java b/main/src/cgeo/geocaching/StaticMapsProvider.java
index cd88071..9a4c00b 100644
--- a/main/src/cgeo/geocaching/StaticMapsProvider.java
+++ b/main/src/cgeo/geocaching/StaticMapsProvider.java
@@ -10,7 +10,6 @@ import cgeo.geocaching.utils.Log;
import ch.boye.httpclientandroidlib.HttpResponse;
-import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import android.content.Context;
@@ -81,10 +80,6 @@ public class StaticMapsProvider {
}
public static void downloadMaps(Geocache cache) {
- if (cache == null) {
- Log.e("downloadMaps - missing input parameter cache");
- return;
- }
if ((!Settings.isStoreOfflineMaps() && !Settings.isStoreOfflineWpMaps()) || StringUtils.isBlank(cache.getGeocode())) {
return;
}
@@ -96,8 +91,8 @@ public class StaticMapsProvider {
}
// clean old and download static maps for waypoints if one is missing
- if (Settings.isStoreOfflineWpMaps() && CollectionUtils.isNotEmpty(cache.getWaypoints())) {
- for (Waypoint waypoint : cache.getWaypoints()) {
+ if (Settings.isStoreOfflineWpMaps()) {
+ for (final Waypoint waypoint : cache.getWaypoints()) {
if (!hasAllStaticMapsForWaypoint(cache.getGeocode(), waypoint)) {
refreshAllWpStaticMaps(cache, edge);
}
@@ -167,10 +162,6 @@ public class StaticMapsProvider {
}
public static void storeCachePreviewMap(final Geocache cache) {
- if (cache == null) {
- Log.e("storeCachePreviewMap - missing input parameter cache");
- return;
- }
final String latlonMap = cache.getCoords().format(Format.LAT_LON_DECDEGREE_COMMA);
final Display display = ((WindowManager) cgeoapplication.getInstance().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
DisplayMetrics metrics = new DisplayMetrics();
@@ -183,12 +174,7 @@ public class StaticMapsProvider {
private static int guessMaxDisplaySide() {
Point displaySize = Compatibility.getDisplaySize();
- final int maxWidth = displaySize.x - 25;
- final int maxHeight = displaySize.y - 25;
- if (maxWidth > maxHeight) {
- return maxWidth;
- }
- return maxHeight;
+ return Math.max(displaySize.x, displaySize.y) - 25;
}
private static void downloadMaps(final String geocode, final String markerUrl, final String prefix, final String latlonMap, final int edge,
@@ -245,7 +231,7 @@ public class StaticMapsProvider {
/**
* Check if at least one map file exists for the given cache.
- *
+ *
* @param cache
* @return <code>true</code> if at least one map file exists; <code>false</code> otherwise
*/
@@ -268,7 +254,7 @@ public class StaticMapsProvider {
/**
* Checks if at least one map file exists for the given geocode and waypoint ID.
- *
+ *
* @param geocode
* @param waypoint
* @return <code>true</code> if at least one map file exists; <code>false</code> otherwise
@@ -287,7 +273,7 @@ public class StaticMapsProvider {
/**
* Checks if all map files exist for the given geocode and waypoint ID.
- *
+ *
* @param geocode
* @param waypoint
* @return <code>true</code> if all map files exist; <code>false</code> otherwise
@@ -326,5 +312,4 @@ public class StaticMapsProvider {
}
return null;
}
-
}
diff --git a/main/src/cgeo/geocaching/StoredList.java b/main/src/cgeo/geocaching/StoredList.java
index 5a6f132..55a155c 100644
--- a/main/src/cgeo/geocaching/StoredList.java
+++ b/main/src/cgeo/geocaching/StoredList.java
@@ -12,10 +12,13 @@ import android.content.res.Resources;
import android.view.View;
import android.widget.EditText;
+import java.text.Collator;
import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.List;
-public class StoredList {
+public final class StoredList {
public static final int TEMPORARY_LIST_ID = 0;
public static final int STANDARD_LIST_ID = 1;
public static final int ALL_LIST_ID = 2;
@@ -68,8 +71,8 @@ public class StoredList {
promptForListSelection(titleId, runAfterwards, false, -1);
}
- public void promptForListSelection(final int titleId, final RunnableWithArgument<Integer> runAfterwards, final boolean onlyMoveTargets, final int exceptListId) {
- final List<StoredList> lists = cgData.getLists();
+ public void promptForListSelection(final int titleId, final RunnableWithArgument<Integer> runAfterwards, final boolean onlyConcreteLists, final int exceptListId) {
+ final List<StoredList> lists = getSortedLists();
if (lists == null) {
return;
@@ -86,7 +89,7 @@ public class StoredList {
for (StoredList list : lists) {
listsTitle.add(list.getTitleAndCount());
}
- if (!onlyMoveTargets) {
+ if (!onlyConcreteLists) {
listsTitle.add("<" + res.getString(R.string.list_menu_all_lists) + ">");
}
listsTitle.add("<" + res.getString(R.string.list_menu_create) + ">");
@@ -98,7 +101,7 @@ public class StoredList {
builder.setItems(listsTitle.toArray(items), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int itemId) {
- if (itemId == lists.size() && !onlyMoveTargets) {
+ if (itemId == lists.size() && !onlyConcreteLists) {
// all lists
runAfterwards.run(StoredList.ALL_LIST_ID);
} else if (itemId >= lists.size()) {
@@ -115,6 +118,19 @@ public class StoredList {
builder.create().show();
}
+ private static List<StoredList> getSortedLists() {
+ final Collator collator = Collator.getInstance();
+ final List<StoredList> lists = cgData.getLists();
+ Collections.sort(lists, new Comparator<StoredList>() {
+
+ @Override
+ public int compare(StoredList lhs, StoredList rhs) {
+ return collator.compare(lhs.getTitle(), rhs.getTitle());
+ }
+ });
+ return lists;
+ }
+
public void promptForListCreation(final RunnableWithArgument<Integer> runAfterwards) {
handleListNameInput("", R.string.list_dialog_create_title, R.string.list_dialog_create, new RunnableWithArgument<String>() {
@@ -176,4 +192,23 @@ public class StoredList {
});
}
}
+
+ /**
+ * Get the list title. This method is not public by intention to make clients use the {@link UserInterface} class.
+ *
+ * @return
+ */
+ protected String getTitle() {
+ return title;
+ }
+
+ /**
+ * Return the given list, if it is a concrete list. Return the default list otherwise.
+ */
+ public static int getConcreteList(int listId) {
+ if (listId == ALL_LIST_ID || listId == TEMPORARY_LIST_ID) {
+ return STANDARD_LIST_ID;
+ }
+ return listId;
+ }
}
diff --git a/main/src/cgeo/geocaching/Trackable.java b/main/src/cgeo/geocaching/Trackable.java
index f777351..d532cda 100644
--- a/main/src/cgeo/geocaching/Trackable.java
+++ b/main/src/cgeo/geocaching/Trackable.java
@@ -1,7 +1,8 @@
package cgeo.geocaching;
+import cgeo.geocaching.connector.ConnectorFactory;
+import cgeo.geocaching.connector.trackable.TrackableConnector;
import cgeo.geocaching.enumerations.LogType;
-import cgeo.geocaching.utils.Log;
import org.apache.commons.lang3.StringUtils;
@@ -38,17 +39,11 @@ public class Trackable implements ILogable {
private String trackingcode = null;
public String getUrl() {
- if (StringUtils.startsWithIgnoreCase(getGeocode(), "GK")) {
- String hex = getGeocode().substring(3);
- try {
- int id = Integer.parseInt(hex, 16);
- return "http://geokrety.org/konkret.php?id=" + id;
- } catch (NumberFormatException e) {
- Log.e("Trackable.getUrl", e);
- return null;
- }
- }
- return "http://www.geocaching.com//track/details.aspx?tracker=" + geocode;
+ return getConnector().getUrl(this);
+ }
+
+ private TrackableConnector getConnector() {
+ return ConnectorFactory.getConnector(this);
}
public String getGuid() {
@@ -208,7 +203,7 @@ public class Trackable implements ILogable {
}
public boolean isLoggable() {
- return !StringUtils.startsWithIgnoreCase(getGeocode(), "GK");
+ return getConnector().isLoggable();
}
public String getTrackingcode() {
@@ -220,7 +215,7 @@ public class Trackable implements ILogable {
}
static public List<LogType> getPossibleLogTypes() {
- List<LogType> logTypes = new ArrayList<LogType>();
+ final List<LogType> logTypes = new ArrayList<LogType>();
logTypes.add(LogType.RETRIEVED_IT);
logTypes.add(LogType.GRABBED_IT);
logTypes.add(LogType.NOTE);
diff --git a/main/src/cgeo/geocaching/TrackableActivity.java b/main/src/cgeo/geocaching/TrackableActivity.java
index fea4521..8dc29ee 100644
--- a/main/src/cgeo/geocaching/TrackableActivity.java
+++ b/main/src/cgeo/geocaching/TrackableActivity.java
@@ -1,17 +1,23 @@
package cgeo.geocaching;
+import butterknife.InjectView;
+import butterknife.Views;
+
import cgeo.geocaching.activity.AbstractActivity;
import cgeo.geocaching.activity.AbstractViewPagerActivity;
-import cgeo.geocaching.connector.gc.GCParser;
+import cgeo.geocaching.connector.ConnectorFactory;
+import cgeo.geocaching.connector.trackable.TrackableConnector;
import cgeo.geocaching.enumerations.LogType;
import cgeo.geocaching.geopoint.Units;
import cgeo.geocaching.network.HtmlImage;
import cgeo.geocaching.network.Network;
import cgeo.geocaching.ui.AbstractCachingPageViewCreator;
+import cgeo.geocaching.ui.AnchorAwareLinkMovementMethod;
import cgeo.geocaching.ui.CacheDetailsCreator;
import cgeo.geocaching.ui.Formatter;
-import cgeo.geocaching.utils.BaseUtils;
+import cgeo.geocaching.utils.HtmlUtils;
import cgeo.geocaching.utils.Log;
+import cgeo.geocaching.utils.TextUtils;
import cgeo.geocaching.utils.UnknownTagsHandler;
import org.apache.commons.lang3.StringUtils;
@@ -26,7 +32,6 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.Html;
-import android.text.method.LinkMovementMethod;
import android.view.ContextMenu;
import android.view.LayoutInflater;
import android.view.Menu;
@@ -56,8 +61,6 @@ public class TrackableActivity extends AbstractViewPagerActivity<TrackableActivi
this.resId = resId;
}
}
- private static final int MENU_LOG_TOUCH = 1;
- private static final int MENU_BROWSER_TRACKABLE = 2;
private Trackable trackable = null;
private String geocode = null;
private String name = null;
@@ -66,7 +69,7 @@ public class TrackableActivity extends AbstractViewPagerActivity<TrackableActivi
private String contextMenuUser = null;
private LayoutInflater inflater = null;
private ProgressDialog waitDialog = null;
- private Handler loadTrackableHandler = new Handler() {
+ private final Handler loadTrackableHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
@@ -98,7 +101,7 @@ public class TrackableActivity extends AbstractViewPagerActivity<TrackableActivi
invalidateOptionsMenuCompatible();
reinitializeViewPager();
- } catch (Exception e) {
+ } catch (final Exception e) {
Log.e("TrackableActivity.loadTrackableHandler: ", e);
}
@@ -108,21 +111,16 @@ public class TrackableActivity extends AbstractViewPagerActivity<TrackableActivi
}
};
- public TrackableActivity() {
- super("c:geo-trackable-details");
- }
-
@Override
public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
+ super.onCreate(savedInstanceState, R.layout.trackable_activity);
- setTheme();
- setContentView(R.layout.trackable_activity);
+ // set title in code, as the activity needs a hard coded title due to the intent filters
setTitle(res.getString(R.string.trackable));
// get parameters
- Bundle extras = getIntent().getExtras();
- Uri uri = getIntent().getData();
+ final Bundle extras = getIntent().getExtras();
+ final Uri uri = getIntent().getData();
// try to get data from extras
if (extras != null) {
@@ -134,7 +132,7 @@ public class TrackableActivity extends AbstractViewPagerActivity<TrackableActivi
// try to get data from URI
if (geocode == null && guid == null && id == null && uri != null) {
- String uriHost = uri.getHost().toLowerCase(Locale.US);
+ final String uriHost = uri.getHost().toLowerCase(Locale.US);
if (uriHost.contains("geocaching.com")) {
geocode = uri.getQueryParameter("tracker");
guid = uri.getQueryParameter("guid");
@@ -158,7 +156,7 @@ public class TrackableActivity extends AbstractViewPagerActivity<TrackableActivi
return;
}
} else if (uriHost.contains("coord.info")) {
- String uriPath = uri.getPath().toLowerCase(Locale.US);
+ final String uriPath = uri.getPath().toLowerCase(Locale.US);
if (uriPath != null && uriPath.startsWith("/tb")) {
geocode = uriPath.substring(1).toUpperCase(Locale.US);
guid = null;
@@ -189,22 +187,25 @@ public class TrackableActivity extends AbstractViewPagerActivity<TrackableActivi
waitDialog = ProgressDialog.show(this, message, res.getString(R.string.trackable_details_loading), true, true);
createViewPager(0, null);
- LoadTrackableThread thread = new LoadTrackableThread(loadTrackableHandler, geocode, guid, id);
+ final LoadTrackableThread thread = new LoadTrackableThread(loadTrackableHandler, geocode, guid, id);
thread.start();
}
@Override
public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo info) {
+
+ // FIXME: replace this context menu stuff by a UserActionsClickListener instead.
+
super.onCreateContextMenu(menu, view, info);
final int viewId = view.getId();
if (viewId == R.id.author) { // Log item author
contextMenuUser = ((TextView) view).getText().toString();
} else { // Trackable owner, and user holding trackable now
- RelativeLayout itemLayout = (RelativeLayout) view.getParent();
- TextView itemName = (TextView) itemLayout.findViewById(R.id.name);
+ final RelativeLayout itemLayout = (RelativeLayout) view.getParent();
+ final TextView itemName = (TextView) itemLayout.findViewById(R.id.name);
- String selectedName = itemName.getText().toString();
+ final String selectedName = itemName.getText().toString();
if (selectedName.equals(res.getString(R.string.trackable_owner))) {
contextMenuUser = trackable.getOwner();
} else if (selectedName.equals(res.getString(R.string.trackable_spotted))) {
@@ -241,18 +242,17 @@ public class TrackableActivity extends AbstractViewPagerActivity<TrackableActivi
@Override
public boolean onCreateOptionsMenu(Menu menu) {
- menu.add(0, MENU_LOG_TOUCH, 0, res.getString(R.string.trackable_log_touch)).setIcon(R.drawable.ic_menu_agenda); // log touch
- menu.add(0, MENU_BROWSER_TRACKABLE, 0, res.getString(R.string.trackable_browser_open)).setIcon(R.drawable.ic_menu_info_details); // browser
+ getMenuInflater().inflate(R.menu.trackable_activity, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
- case MENU_LOG_TOUCH:
+ case R.id.menu_log_touch:
LogTrackableActivity.startActivity(this, trackable);
return true;
- case MENU_BROWSER_TRACKABLE:
+ case R.id.menu_browser_trackable:
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(trackable.getUrl())));
return true;
default:
@@ -263,8 +263,8 @@ public class TrackableActivity extends AbstractViewPagerActivity<TrackableActivi
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
if (trackable != null) {
- menu.findItem(MENU_LOG_TOUCH).setEnabled(StringUtils.isNotBlank(geocode) && trackable.isLoggable());
- menu.findItem(MENU_BROWSER_TRACKABLE).setEnabled(StringUtils.isNotBlank(trackable.getUrl()));
+ menu.findItem(R.id.menu_log_touch).setEnabled(StringUtils.isNotBlank(geocode) && trackable.isLoggable());
+ menu.findItem(R.id.menu_browser_trackable).setEnabled(StringUtils.isNotBlank(trackable.getUrl()));
}
return super.onPrepareOptionsMenu(menu);
}
@@ -286,8 +286,16 @@ public class TrackableActivity extends AbstractViewPagerActivity<TrackableActivi
public void run() {
trackable = cgData.loadTrackable(geocode);
- if ((trackable == null || trackable.isLoggable()) && !StringUtils.startsWithIgnoreCase(geocode, "GK")) {
- trackable = GCParser.searchTrackable(geocode, guid, id);
+ if (trackable == null || trackable.isLoggable()) {
+ // iterate over the connectors as some codes may be handled by multiple connectors
+ for (final TrackableConnector trackableConnector : ConnectorFactory.getTrackableConnectors()) {
+ if (trackableConnector.canHandleTrackable(geocode)) {
+ trackable = trackableConnector.searchTrackable(geocode, guid, id);
+ if (trackable != null) {
+ break;
+ }
+ }
+ }
}
handler.sendMessage(Message.obtain());
}
@@ -304,7 +312,7 @@ public class TrackableActivity extends AbstractViewPagerActivity<TrackableActivi
try {
registerForContextMenu(view);
openContextMenu(view);
- } catch (Exception e) {
+ } catch (final Exception e) {
Log.e("TrackableActivity.UserActionsListener.onClick ", e);
}
}
@@ -326,12 +334,12 @@ public class TrackableActivity extends AbstractViewPagerActivity<TrackableActivi
}
try {
- HtmlImage imgGetter = new HtmlImage(trackable.getGeocode(), false, 0, false);
+ final HtmlImage imgGetter = new HtmlImage(trackable.getGeocode(), false, 0, false);
- BitmapDrawable image = imgGetter.getDrawable(url);
- Message message = handler.obtainMessage(0, image);
+ final BitmapDrawable image = imgGetter.getDrawable(url);
+ final Message message = handler.obtainMessage(0, image);
handler.sendMessage(message);
- } catch (Exception e) {
+ } catch (final Exception e) {
Log.e("TrackableActivity.TrackableIconThread.run: ", e);
}
}
@@ -382,7 +390,7 @@ public class TrackableActivity extends AbstractViewPagerActivity<TrackableActivi
@Override
protected Pair<List<? extends Page>, Integer> getOrderedPages() {
- List<Page> pages = new ArrayList<TrackableActivity.Page>();
+ final List<Page> pages = new ArrayList<TrackableActivity.Page>();
pages.add(Page.DETAILS);
if (!trackable.getLogs().isEmpty()) {
pages.add(Page.LOGS);
@@ -392,43 +400,21 @@ public class TrackableActivity extends AbstractViewPagerActivity<TrackableActivi
public class LogsViewCreator extends AbstractCachingPageViewCreator<ListView> {
- private class LogViewHolder {
-
- private final TextView added;
- private final TextView type;
- private final TextView author;
- private final TextView location;
- private final TextView log;
- private final ImageView marker;
- private final LinearLayout logImages;
-
- public LogViewHolder(View rowView) {
- added = ((TextView) rowView.findViewById(R.id.added));
- type = ((TextView) rowView.findViewById(R.id.type));
- author = ((TextView) rowView.findViewById(R.id.author));
- location = ((TextView) rowView.findViewById(R.id.location));
- log = (TextView) rowView.findViewById(R.id.log);
- marker = (ImageView) rowView.findViewById(R.id.log_mark);
- logImages = (LinearLayout) rowView.findViewById(R.id.log_layout);
- }
- }
-
@Override
public ListView getDispatchedView() {
view = (ListView) getLayoutInflater().inflate(R.layout.trackable_logs_view, null);
if (trackable != null && trackable.getLogs() != null) {
- view.setAdapter(new ArrayAdapter<LogEntry>(TrackableActivity.this, R.layout.trackable_logs_item, trackable.getLogs()) {
+ view.setAdapter(new ArrayAdapter<LogEntry>(TrackableActivity.this, R.layout.logs_item, trackable.getLogs()) {
@Override
public View getView(int position, View convertView, android.view.ViewGroup parent) {
View rowView = convertView;
if (null == rowView) {
- rowView = getLayoutInflater().inflate(R.layout.trackable_logs_item, null);
+ rowView = getLayoutInflater().inflate(R.layout.logs_item, null);
}
LogViewHolder holder = (LogViewHolder) rowView.getTag();
if (null == holder) {
holder = new LogViewHolder(rowView);
- rowView.setTag(holder);
}
final LogEntry log = getItem(position);
@@ -440,21 +426,21 @@ public class TrackableActivity extends AbstractViewPagerActivity<TrackableActivi
return view;
}
- protected void fillViewHolder(LogViewHolder holder, LogEntry log) {
+ protected void fillViewHolder(LogViewHolder holder, final LogEntry log) {
if (log.date > 0) {
- holder.added.setText(Formatter.formatShortDate(log.date));
+ holder.date.setText(Formatter.formatShortDateVerbally(log.date));
}
holder.type.setText(log.type.getL10n());
holder.author.setText(Html.fromHtml(log.author), TextView.BufferType.SPANNABLE);
if (StringUtils.isBlank(log.cacheName)) {
- holder.location.setVisibility(View.GONE);
+ holder.countOrLocation.setVisibility(View.GONE);
} else {
- holder.location.setText(Html.fromHtml(log.cacheName));
+ holder.countOrLocation.setText(Html.fromHtml(log.cacheName));
final String cacheGuid = log.cacheGuid;
final String cacheName = log.cacheName;
- holder.location.setOnClickListener(new View.OnClickListener() {
+ holder.countOrLocation.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View arg0) {
CacheDetailActivity.startActivityGuid(TrackableActivity.this, cacheGuid, Html.fromHtml(cacheName).toString());
@@ -462,11 +448,11 @@ public class TrackableActivity extends AbstractViewPagerActivity<TrackableActivi
});
}
- TextView logView = holder.log;
- logView.setMovementMethod(LinkMovementMethod.getInstance());
+ final TextView logView = holder.text;
+ logView.setMovementMethod(AnchorAwareLinkMovementMethod.getInstance());
String logText = log.log;
- if (BaseUtils.containsHtml(logText)) {
+ if (TextUtils.containsHtml(logText)) {
logText = log.getDisplayText();
logView.setText(Html.fromHtml(logText, new HtmlImage(null, false, StoredList.TEMPORARY_LIST_ID, false), null), TextView.BufferType.SPANNABLE);
}
@@ -474,9 +460,9 @@ public class TrackableActivity extends AbstractViewPagerActivity<TrackableActivi
logView.setText(logText);
}
- ImageView statusMarker = holder.marker;
+ final ImageView statusMarker = holder.marker;
// colored marker
- int marker = log.type.markerId;
+ final int marker = log.type.markerId;
if (marker != 0) {
statusMarker.setVisibility(View.VISIBLE);
statusMarker.setImageResource(marker);
@@ -485,25 +471,18 @@ public class TrackableActivity extends AbstractViewPagerActivity<TrackableActivi
statusMarker.setVisibility(View.GONE);
}
- // add LogImages
- LinearLayout logLayout = holder.logImages;
-
+ // images
if (log.hasLogImages()) {
-
- final ArrayList<Image> logImages = new ArrayList<Image>(log.getLogImages());
-
- final View.OnClickListener listener = new View.OnClickListener() {
+ holder.images.setText(log.getImageTitles());
+ holder.images.setVisibility(View.VISIBLE);
+ holder.images.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- ImagesActivity.startActivityLogImages(TrackableActivity.this, trackable.getGeocode(), logImages);
+ ImagesActivity.startActivityLogImages(TrackableActivity.this, trackable.getGeocode(), new ArrayList<Image>(log.getLogImages()));
}
- };
-
- LinearLayout log_imgView = (LinearLayout) getLayoutInflater().inflate(R.layout.trackable_logs_img, null);
- TextView log_img_title = (TextView) log_imgView.findViewById(R.id.title);
- log_img_title.setText(log.getImageTitles());
- log_img_title.setOnClickListener(listener);
- logLayout.addView(log_imgView);
+ });
+ } else {
+ holder.images.setVisibility(View.GONE);
}
holder.author.setOnClickListener(new UserActionsListener());
@@ -513,10 +492,20 @@ public class TrackableActivity extends AbstractViewPagerActivity<TrackableActivi
public class DetailsViewCreator extends AbstractCachingPageViewCreator<ScrollView> {
+ @InjectView(R.id.goal_box) protected LinearLayout goalBox;
+ @InjectView(R.id.goal) protected TextView goalTextView;
+ @InjectView(R.id.details_box) protected LinearLayout detailsBox;
+ @InjectView(R.id.details) protected TextView detailsTextView;
+ @InjectView(R.id.image_box) protected LinearLayout imageBox;
+ @InjectView(R.id.details_list) protected LinearLayout detailsList;
+ @InjectView(R.id.image) protected LinearLayout imageView;
+
@Override
public ScrollView getDispatchedView() {
view = (ScrollView) getLayoutInflater().inflate(R.layout.trackable_details_view, null);
- final CacheDetailsCreator details = new CacheDetailsCreator(TrackableActivity.this, (LinearLayout) view.findViewById(R.id.details_list));
+ Views.inject(this, view);
+
+ final CacheDetailsCreator details = new CacheDetailsCreator(TrackableActivity.this, detailsList);
// action bar icon
if (StringUtils.isNotBlank(trackable.getIconUrl())) {
@@ -541,7 +530,7 @@ public class TrackableActivity extends AbstractViewPagerActivity<TrackableActivi
details.add(R.string.trackable_code, trackable.getGeocode());
// trackable owner
- TextView owner = details.add(R.string.trackable_owner, res.getString(R.string.trackable_unknown));
+ final TextView owner = details.add(R.string.trackable_owner, res.getString(R.string.trackable_unknown));
if (StringUtils.isNotBlank(trackable.getOwner())) {
owner.setText(Html.fromHtml(trackable.getOwner()), TextView.BufferType.SPANNABLE);
owner.setOnClickListener(new UserActionsListener());
@@ -569,7 +558,7 @@ public class TrackableActivity extends AbstractViewPagerActivity<TrackableActivi
// days since last spotting
if (showTimeSpan && trackable.getLogs() != null) {
- for (LogEntry log : trackable.getLogs()) {
+ for (final LogEntry log : trackable.getLogs()) {
if (log.type == LogType.RETRIEVED_IT || log.type == LogType.GRABBED_IT || log.type == LogType.DISCOVERED_IT || log.type == LogType.PLACED_IT) {
final int days = log.daysSinceLog();
text.append(" (").append(res.getQuantityString(R.plurals.days_ago, days, days)).append(')');
@@ -594,7 +583,7 @@ public class TrackableActivity extends AbstractViewPagerActivity<TrackableActivi
// trackable origin
if (StringUtils.isNotBlank(trackable.getOrigin())) {
- TextView origin = details.add(R.string.trackable_origin, "");
+ final TextView origin = details.add(R.string.trackable_origin, "");
origin.setText(Html.fromHtml(trackable.getOrigin()), TextView.BufferType.SPANNABLE);
}
@@ -609,28 +598,24 @@ public class TrackableActivity extends AbstractViewPagerActivity<TrackableActivi
}
// trackable goal
- if (StringUtils.isNotBlank(trackable.getGoal())) {
- view.findViewById(R.id.goal_box).setVisibility(View.VISIBLE);
- TextView descView = (TextView) view.findViewById(R.id.goal);
- descView.setVisibility(View.VISIBLE);
- descView.setText(Html.fromHtml(trackable.getGoal(), new HtmlImage(geocode, true, 0, false), null), TextView.BufferType.SPANNABLE);
- descView.setMovementMethod(LinkMovementMethod.getInstance());
+ if (StringUtils.isNotBlank(HtmlUtils.extractText(trackable.getGoal()))) {
+ goalBox.setVisibility(View.VISIBLE);
+ goalTextView.setVisibility(View.VISIBLE);
+ goalTextView.setText(Html.fromHtml(trackable.getGoal(), new HtmlImage(geocode, true, 0, false), null), TextView.BufferType.SPANNABLE);
+ goalTextView.setMovementMethod(AnchorAwareLinkMovementMethod.getInstance());
}
// trackable details
- if (StringUtils.isNotBlank(trackable.getDetails())) {
- view.findViewById(R.id.details_box).setVisibility(View.VISIBLE);
- TextView descView = (TextView) view.findViewById(R.id.details);
- descView.setVisibility(View.VISIBLE);
- descView.setText(Html.fromHtml(trackable.getDetails(), new HtmlImage(geocode, true, 0, false), new UnknownTagsHandler()), TextView.BufferType.SPANNABLE);
- descView.setMovementMethod(LinkMovementMethod.getInstance());
+ if (StringUtils.isNotBlank(HtmlUtils.extractText(trackable.getDetails()))) {
+ detailsBox.setVisibility(View.VISIBLE);
+ detailsTextView.setVisibility(View.VISIBLE);
+ detailsTextView.setText(Html.fromHtml(trackable.getDetails(), new HtmlImage(geocode, true, 0, false), new UnknownTagsHandler()), TextView.BufferType.SPANNABLE);
+ detailsTextView.setMovementMethod(AnchorAwareLinkMovementMethod.getInstance());
}
// trackable image
if (StringUtils.isNotBlank(trackable.getImage())) {
- view.findViewById(R.id.image_box).setVisibility(View.VISIBLE);
- LinearLayout imgView = (LinearLayout) view.findViewById(R.id.image);
-
+ imageBox.setVisibility(View.VISIBLE);
final ImageView trackableImage = (ImageView) inflater.inflate(R.layout.trackable_image, null);
trackableImage.setImageResource(R.drawable.image_not_loaded);
@@ -648,7 +633,7 @@ public class TrackableActivity extends AbstractViewPagerActivity<TrackableActivi
@Override
public void handleMessage(Message message) {
- BitmapDrawable image = (BitmapDrawable) message.obj;
+ final BitmapDrawable image = (BitmapDrawable) message.obj;
if (image != null) {
trackableImage.setImageDrawable((BitmapDrawable) message.obj);
}
@@ -660,18 +645,18 @@ public class TrackableActivity extends AbstractViewPagerActivity<TrackableActivi
@Override
public void run() {
try {
- HtmlImage imgGetter = new HtmlImage(geocode, true, 0, false);
+ final HtmlImage imgGetter = new HtmlImage(geocode, true, 0, false);
- BitmapDrawable image = imgGetter.getDrawable(trackable.getImage());
- Message message = handler.obtainMessage(0, image);
+ final BitmapDrawable image = imgGetter.getDrawable(trackable.getImage());
+ final Message message = handler.obtainMessage(0, image);
handler.sendMessage(message);
- } catch (Exception e) {
- Log.e("cgeospoilers.onCreate.onClick.run: ", e);
+ } catch (final Exception e) {
+ Log.e("TrackableActivity.DetailsViewCreator.ImageGetterThread: ", e);
}
}
}.start();
- imgView.addView(trackableImage);
+ imageView.addView(trackableImage);
}
return view;
}
diff --git a/main/src/cgeo/geocaching/UsefulAppsActivity.java b/main/src/cgeo/geocaching/UsefulAppsActivity.java
index af643b3..8093bba 100644
--- a/main/src/cgeo/geocaching/UsefulAppsActivity.java
+++ b/main/src/cgeo/geocaching/UsefulAppsActivity.java
@@ -1,79 +1,107 @@
package cgeo.geocaching;
+import butterknife.InjectView;
+import butterknife.Views;
+
import cgeo.geocaching.activity.AbstractActivity;
+import cgeo.geocaching.ui.AbstractViewHolder;
+import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
-import android.view.View.OnClickListener;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
import android.widget.ImageView;
-import android.widget.LinearLayout;
+import android.widget.ListView;
import android.widget.TextView;
-import java.util.Locale;
-
public class UsefulAppsActivity extends AbstractActivity {
- private LinearLayout parentLayout;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
+ @InjectView(R.id.apps_list) protected ListView list;
- // init
- setTheme();
- setContentView(R.layout.useful_apps);
- setTitle(res.getString(R.string.helpers));
- parentLayout = (LinearLayout) findViewById(R.id.parent);
+ protected static class ViewHolder extends AbstractViewHolder {
+ @InjectView(R.id.title) protected TextView title;
+ @InjectView(R.id.image) protected ImageView image;
+ @InjectView(R.id.description) protected TextView description;
- final Locale loc = Locale.getDefault();
- final String language = loc.getLanguage();
+ public ViewHolder(View rowView) {
+ super(rowView);
+ }
+ }
- final String tutorialUrl;
- if ("de".equalsIgnoreCase(language)) {
- tutorialUrl = "gnu.android.app.cgeomanual.de";
+ private static class HelperApp {
+ private final int titleId;
+ private final int descriptionId;
+ private final int iconId;
+ private final String packageName;
+
+ public HelperApp(final int title, final int description, final int icon, final String packageName) {
+ this.titleId = title;
+ this.descriptionId = description;
+ this.iconId = icon;
+ this.packageName = packageName;
}
- else {
- tutorialUrl = "gnu.android.app.cgeomanual.en";
+
+ private void installFromMarket(Activity activity) {
+ try {
+ Intent marketIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + packageName));
+ marketIntent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY | Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
+ activity.startActivity(marketIntent);
+
+ } catch (Exception e) {
+ // market not available in standard emulator
+ }
}
- addApp(R.string.helper_manual_title, R.string.helper_manual_description, R.drawable.helper_manual, tutorialUrl);
- addApp(R.string.helper_calendar_title, R.string.helper_calendar_description, R.drawable.cgeo, "cgeo.calendar");
- addApp(R.string.helper_locus_title, R.string.helper_locus_description, R.drawable.helper_locus, "menion.android.locus");
- addApp(R.string.helper_gpsstatus_title, R.string.helper_gpsstatus_description, R.drawable.helper_gpsstatus, "com.eclipsim.gpsstatus2");
- addApp(R.string.helper_bluetoothgps_title, R.string.helper_bluetoothgps_description, R.drawable.helper_bluetoothgps, "googoo.android.btgps");
- addApp(R.string.helper_barcode_title, R.string.helper_barcode_description, R.drawable.helper_barcode, "com.google.zxing.client.android");
}
+ private static final HelperApp[] HELPER_APPS = {
+ new HelperApp(R.string.helper_calendar_title, R.string.helper_calendar_description, R.drawable.cgeo, "cgeo.calendar"),
+ new HelperApp(R.string.helper_pocketquery_title, R.string.helper_pocketquery_description, R.drawable.helper_pocketquery, "org.pquery"),
+ new HelperApp(R.string.helper_locus_title, R.string.helper_locus_description, R.drawable.helper_locus, "menion.android.locus"),
+ new HelperApp(R.string.helper_gpsstatus_title, R.string.helper_gpsstatus_description, R.drawable.helper_gpsstatus, "com.eclipsim.gpsstatus2"),
+ new HelperApp(R.string.helper_bluetoothgps_title, R.string.helper_bluetoothgps_description, R.drawable.helper_bluetoothgps, "googoo.android.btgps"),
+ new HelperApp(R.string.helper_barcode_title, R.string.helper_barcode_description, R.drawable.helper_barcode, "com.google.zxing.client.android"),
+ };
+
@Override
- public void onResume() {
- super.onResume();
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState, R.layout.usefulapps_activity);
- }
+ Views.inject(this);
- private void installFromMarket(String marketId) {
- try {
- startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://search?q=pname:" + marketId)));
- } catch (Exception e) {
- // market not available in standard emulator
- }
+ list.setAdapter(new ArrayAdapter<HelperApp>(this, R.layout.usefulapps_item, HELPER_APPS) {
+ @Override
+ public View getView(int position, View convertView, android.view.ViewGroup parent) {
+ View rowView = convertView;
+ if (null == rowView) {
+ rowView = getLayoutInflater().inflate(R.layout.usefulapps_item, null);
+ }
+ ViewHolder holder = (ViewHolder) rowView.getTag();
+ if (null == holder) {
+ holder = new ViewHolder(rowView);
+ }
+
+ final HelperApp app = getItem(position);
+ fillViewHolder(holder, app);
+ return rowView;
+ }
- finish();
- }
+ private void fillViewHolder(ViewHolder holder, HelperApp app) {
+ holder.title.setText(res.getString(app.titleId));
+ holder.image.setImageDrawable(res.getDrawable(app.iconId));
+ holder.description.setText(res.getString(app.descriptionId));
+ }
+ });
- private void addApp(final int titleId, final int descriptionId, final int imageId, final String marketUrl) {
- final LinearLayout layout = (LinearLayout) getLayoutInflater().inflate(R.layout.useful_apps_item, null);
- ((TextView) layout.findViewById(R.id.title)).setText(res.getString(titleId));
- ((ImageView) layout.findViewById(R.id.image)).setImageDrawable(res.getDrawable(imageId));
- ((TextView) layout.findViewById(R.id.description)).setText(res.getString(descriptionId));
- layout.findViewById(R.id.app_layout).setOnClickListener(new OnClickListener() {
+ list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
- public void onClick(View v) {
- installFromMarket(marketUrl);
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ HelperApp helperApp = HELPER_APPS[position];
+ helperApp.installFromMarket(UsefulAppsActivity.this);
}
});
- parentLayout.addView(layout);
}
-
}
diff --git a/main/src/cgeo/geocaching/Waypoint.java b/main/src/cgeo/geocaching/Waypoint.java
index 48c9bc5..e39d26a 100644
--- a/main/src/cgeo/geocaching/Waypoint.java
+++ b/main/src/cgeo/geocaching/Waypoint.java
@@ -275,7 +275,8 @@ public class Waypoint implements IWaypoint, Comparable<Waypoint> {
if (coords != null) {
hash = coords.hashCode();
}
- hash = hash ^ waypointType.markerId;
+ hash ^= waypointType.markerId;
return (int) hash;
}
+
}
diff --git a/main/src/cgeo/geocaching/WaypointPopup.java b/main/src/cgeo/geocaching/WaypointPopup.java
index 766d43d..a1ab36a 100644
--- a/main/src/cgeo/geocaching/WaypointPopup.java
+++ b/main/src/cgeo/geocaching/WaypointPopup.java
@@ -1,7 +1,11 @@
package cgeo.geocaching;
+import butterknife.InjectView;
+import butterknife.Views;
+
import cgeo.geocaching.apps.cache.navi.NavigationAppFactory;
import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.geopoint.Units;
import cgeo.geocaching.ui.CacheDetailsCreator;
import cgeo.geocaching.utils.Log;
@@ -17,16 +21,23 @@ import android.widget.LinearLayout;
import android.widget.TextView;
public class WaypointPopup extends AbstractPopupActivity {
+ @InjectView(R.id.actionbar_title) protected TextView actionBarTitle;
+ @InjectView(R.id.waypoint_details_list) protected LinearLayout waypointDetailsLayout;
+ @InjectView(R.id.edit) protected Button buttonEdit;
+ @InjectView(R.id.details_list) protected LinearLayout cacheDetailsLayout;
+
private int waypointId = 0;
private Waypoint waypoint = null;
+ private TextView waypointDistance = null;
public WaypointPopup() {
- super("c:geo-waypoint-info", R.layout.waypoint_popup);
+ super(R.layout.waypoint_popup);
}
@Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ Views.inject(this);
// get parameters
final Bundle extras = getIntent().getExtras();
if (extras != null) {
@@ -35,6 +46,14 @@ public class WaypointPopup extends AbstractPopupActivity {
}
@Override
+ public void onUpdateGeoData(IGeoData geo) {
+ if (geo.getCoords() != null && waypoint != null && waypoint.getCoords() != null) {
+ waypointDistance.setText(Units.getDistanceFromKilometers(geo.getCoords().distanceTo(waypoint.getCoords())));
+ waypointDistance.bringToFront();
+ }
+ }
+
+ @Override
protected void init() {
super.init();
waypoint = cgData.loadWaypoint(waypointId);
@@ -45,17 +64,16 @@ public class WaypointPopup extends AbstractPopupActivity {
setTitle(waypoint.getGeocode());
}
- // actionbar icon
- ((TextView) findViewById(R.id.actionbar_title)).setCompoundDrawablesWithIntrinsicBounds(getResources().getDrawable(waypoint.getWaypointType().markerId), null, null, null);
+ actionBarTitle.setCompoundDrawablesWithIntrinsicBounds(getResources().getDrawable(waypoint.getWaypointType().markerId), null, null, null);
- //Start filling waypoint details
- details = new CacheDetailsCreator(this, (LinearLayout) findViewById(R.id.waypoint_details_list));
+ details = new CacheDetailsCreator(this, waypointDetailsLayout);
//Waypoint geocode
details.add(R.string.cache_geocode, waypoint.getPrefix() + waypoint.getGeocode().substring(2));
+ details.addDistance(waypoint, waypointDistance);
+ waypointDistance = details.getValueView();
+ details.add(R.string.waypoint_note, waypoint.getNote());
- // Edit Button
- final Button buttonEdit = (Button) findViewById(R.id.edit);
buttonEdit.setOnClickListener(new OnClickListener() {
@Override
@@ -65,14 +83,13 @@ public class WaypointPopup extends AbstractPopupActivity {
}
});
- //Start filling cache details
- details = new CacheDetailsCreator(this, (LinearLayout) findViewById(R.id.details_list));
+ details = new CacheDetailsCreator(this, cacheDetailsLayout);
details.add(R.string.cache_name, cache.getName());
addCacheDetails();
} catch (Exception e) {
- Log.e("cgeopopup.init", e);
+ Log.e("WaypointPopup.init", e);
}
}
diff --git a/main/src/cgeo/geocaching/activity/AbstractActivity.java b/main/src/cgeo/geocaching/activity/AbstractActivity.java
index 557665e..964ef96 100644
--- a/main/src/cgeo/geocaching/activity/AbstractActivity.java
+++ b/main/src/cgeo/geocaching/activity/AbstractActivity.java
@@ -1,5 +1,7 @@
package cgeo.geocaching.activity;
+import butterknife.Views;
+
import cgeo.geocaching.Settings;
import cgeo.geocaching.cgeoapplication;
import cgeo.geocaching.compatibility.Compatibility;
@@ -14,22 +16,15 @@ import android.widget.EditText;
public abstract class AbstractActivity extends FragmentActivity implements IAbstractActivity {
- final private String helpTopic;
-
protected cgeoapplication app = null;
protected Resources res = null;
private boolean keepScreenOn = false;
protected AbstractActivity() {
- this(null);
- }
-
- protected AbstractActivity(final String helpTopic) {
- this.helpTopic = helpTopic;
+ this(false);
}
- protected AbstractActivity(final String helpTopic, final boolean keepScreenOn) {
- this(helpTopic);
+ protected AbstractActivity(final boolean keepScreenOn) {
this.keepScreenOn = keepScreenOn;
}
@@ -38,20 +33,15 @@ public abstract class AbstractActivity extends FragmentActivity implements IAbst
ActivityMixin.goHome(this);
}
- @Override
- public void goManual(final View view) {
- ActivityMixin.goManual(this, helpTopic);
- }
-
- final public void setTitle(final String title) {
+ final protected void setTitle(final String title) {
ActivityMixin.setTitle(this, title);
}
- final public void showProgress(final boolean show) {
+ final protected void showProgress(final boolean show) {
ActivityMixin.showProgress(this, show);
}
- final public void setTheme() {
+ final protected void setTheme() {
ActivityMixin.setTheme(this);
}
@@ -70,22 +60,14 @@ public abstract class AbstractActivity extends FragmentActivity implements IAbst
ActivityMixin.helpDialog(this, title, message);
}
- public final void helpDialog(final String title, final String message, final Drawable icon) {
+ protected final void helpDialog(final String title, final String message, final Drawable icon) {
ActivityMixin.helpDialog(this, title, message, icon);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
-
- // init
- res = this.getResources();
- app = (cgeoapplication) this.getApplication();
-
- // Restore cookie store if needed
- Cookies.restoreCookieStore(Settings.getCookieStore());
-
- ActivityMixin.keepScreenOn(this, keepScreenOn);
+ initializeCommonFields();
}
protected static void disableSuggestions(final EditText edit) {
@@ -128,4 +110,34 @@ public abstract class AbstractActivity extends FragmentActivity implements IAbst
editText.setSelection(newCursor, newCursor);
}
+ protected void onCreate(final Bundle savedInstanceState, final int resourceLayoutID) {
+ super.onCreate(savedInstanceState);
+
+ initializeCommonFields();
+
+ // non declarative part of layout
+ setTheme();
+ setContentView(resourceLayoutID);
+
+ // create view variables
+ Views.inject(this);
+ }
+
+ private void initializeCommonFields() {
+ // initialize commonly used members
+ res = this.getResources();
+ app = (cgeoapplication) this.getApplication();
+
+ // only needed in some activities, but implemented in super class nonetheless
+ Cookies.restoreCookieStore(Settings.getCookieStore());
+ ActivityMixin.keepScreenOn(this, keepScreenOn);
+ }
+
+ @Override
+ public void setContentView(int layoutResID) {
+ super.setContentView(layoutResID);
+
+ // initialize the action bar title with the activity title for single source
+ ActivityMixin.setTitle(this, getTitle());
+ }
}
diff --git a/main/src/cgeo/geocaching/activity/AbstractListActivity.java b/main/src/cgeo/geocaching/activity/AbstractListActivity.java
index f96a769..47c747f 100644
--- a/main/src/cgeo/geocaching/activity/AbstractListActivity.java
+++ b/main/src/cgeo/geocaching/activity/AbstractListActivity.java
@@ -12,35 +12,24 @@ import android.view.View;
public abstract class AbstractListActivity extends FragmentListActivity implements
IAbstractActivity {
- private String helpTopic;
private boolean keepScreenOn = false;
protected cgeoapplication app = null;
protected Resources res = null;
protected AbstractListActivity() {
- this(null);
+ this(false);
}
protected AbstractListActivity(final boolean keepScreenOn) {
- this(null);
this.keepScreenOn = keepScreenOn;
}
- protected AbstractListActivity(final String helpTopic) {
- this.helpTopic = helpTopic;
- }
-
@Override
final public void goHome(View view) {
ActivityMixin.goHome(this);
}
- @Override
- public void goManual(View view) {
- ActivityMixin.goManual(this, helpTopic);
- }
-
final public void showProgress(final boolean show) {
ActivityMixin.showProgress(this, show);
}
@@ -71,7 +60,10 @@ public abstract class AbstractListActivity extends FragmentListActivity implemen
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ initializeCommonFields();
+ }
+ private void initializeCommonFields() {
// init
res = this.getResources();
app = (cgeoapplication) this.getApplication();
@@ -79,7 +71,7 @@ public abstract class AbstractListActivity extends FragmentListActivity implemen
ActivityMixin.keepScreenOn(this, keepScreenOn);
}
- final public void setTitle(final String title) {
+ final protected void setTitle(final String title) {
ActivityMixin.setTitle(this, title);
}
@@ -87,4 +79,20 @@ public abstract class AbstractListActivity extends FragmentListActivity implemen
public void invalidateOptionsMenuCompatible() {
Compatibility.invalidateOptionsMenu(this);
}
+
+ public void onCreate(Bundle savedInstanceState, int resourceLayoutID) {
+ super.onCreate(savedInstanceState);
+ initializeCommonFields();
+
+ setTheme();
+ setContentView(resourceLayoutID);
+ }
+
+ @Override
+ public void setContentView(int layoutResID) {
+ super.setContentView(layoutResID);
+
+ // initialize action bar title with activity title
+ ActivityMixin.setTitle(this, getTitle());
+ }
}
diff --git a/main/src/cgeo/geocaching/activity/AbstractViewPagerActivity.java b/main/src/cgeo/geocaching/activity/AbstractViewPagerActivity.java
index 366a59d..0345633 100644
--- a/main/src/cgeo/geocaching/activity/AbstractViewPagerActivity.java
+++ b/main/src/cgeo/geocaching/activity/AbstractViewPagerActivity.java
@@ -14,6 +14,7 @@ import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.view.View;
+import android.view.ViewGroup;
import java.util.ArrayList;
import java.util.HashMap;
@@ -29,10 +30,6 @@ import java.util.Map;
*/
public abstract class AbstractViewPagerActivity<Page extends Enum<Page>> extends AbstractActivity {
- protected AbstractViewPagerActivity(String helpTopic) {
- super(helpTopic);
- }
-
/**
* A {@link List} of all available pages.
*
@@ -95,12 +92,12 @@ public abstract class AbstractViewPagerActivity<Page extends Enum<Page>> extends
private class ViewPagerAdapter extends PagerAdapter implements TitleProvider {
@Override
- public void destroyItem(View container, int position, Object object) {
+ public void destroyItem(ViewGroup container, int position, Object object) {
((ViewPager) container).removeView((View) object);
}
@Override
- public void finishUpdate(View container) {
+ public void finishUpdate(ViewGroup container) {
}
@Override
@@ -109,7 +106,7 @@ public abstract class AbstractViewPagerActivity<Page extends Enum<Page>> extends
}
@Override
- public Object instantiateItem(View container, int position) {
+ public Object instantiateItem(ViewGroup container, int position) {
final Page page = pageOrder.get(position);
PageViewCreator creator = viewCreators.get(page);
@@ -150,7 +147,7 @@ public abstract class AbstractViewPagerActivity<Page extends Enum<Page>> extends
}
@Override
- public void startUpdate(View arg0) {
+ public void startUpdate(ViewGroup arg0) {
}
@Override
@@ -211,6 +208,7 @@ public abstract class AbstractViewPagerActivity<Page extends Enum<Page>> extends
pageOrder.add(null);
}
}
+ viewPagerAdapter.notifyDataSetChanged();
viewPager.setCurrentItem(startPageIndex, false);
}
@@ -236,15 +234,19 @@ public abstract class AbstractViewPagerActivity<Page extends Enum<Page>> extends
final Pair<List<? extends Page>, Integer> pagesAndIndex = getOrderedPages();
pageOrder.addAll(pagesAndIndex.getLeft());
+ // Since we just added pages notifyDataSetChanged needs to be called before we possibly setCurrentItem below.
+ // But, calling it will reset current item and we won't be able to tell if we would have been out of bounds
+ final int currentItem = getCurrentItem();
+
+ // notify the adapter that the data has changed
+ viewPagerAdapter.notifyDataSetChanged();
+
// switch to details page, if we're out of bounds
final int defaultPage = pagesAndIndex.getRight();
- if (getCurrentItem() < 0 || getCurrentItem() >= viewPagerAdapter.getCount()) {
+ if (currentItem < 0 || currentItem >= viewPagerAdapter.getCount()) {
viewPager.setCurrentItem(defaultPage, false);
}
- // notify the adapter that the data has changed
- viewPagerAdapter.notifyDataSetChanged();
-
// notify the indicator that the data has changed
titleIndicator.notifyDataSetChanged();
}
diff --git a/main/src/cgeo/geocaching/activity/ActivityMixin.java b/main/src/cgeo/geocaching/activity/ActivityMixin.java
index c97cb9a..12ab0be 100644
--- a/main/src/cgeo/geocaching/activity/ActivityMixin.java
+++ b/main/src/cgeo/geocaching/activity/ActivityMixin.java
@@ -1,15 +1,14 @@
package cgeo.geocaching.activity;
+import cgeo.geocaching.MainActivity;
import cgeo.geocaching.R;
import cgeo.geocaching.Settings;
-import cgeo.geocaching.cgeo;
import cgeo.geocaching.compatibility.Compatibility;
import org.apache.commons.lang3.StringUtils;
import android.app.Activity;
import android.app.AlertDialog;
-import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.drawable.Drawable;
@@ -21,34 +20,17 @@ import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
-import gnu.android.app.appmanualclient.AppManualReaderClient;
-
public final class ActivityMixin {
public final static void goHome(final Activity fromActivity) {
- final Intent intent = new Intent(fromActivity, cgeo.class);
+ final Intent intent = new Intent(fromActivity, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
fromActivity.startActivity(intent);
fromActivity.finish();
}
- public static void goManual(final Context context, final String helpTopic) {
- if (StringUtils.isBlank(helpTopic)) {
- return;
- }
- try {
- AppManualReaderClient.openManual(
- "c-geo",
- helpTopic,
- context,
- "http://manual.cgeo.org/");
- } catch (Exception e) {
- // nothing
- }
- }
-
- public static void setTitle(final Activity activity, final String text) {
+ public static void setTitle(final Activity activity, final CharSequence text) {
if (StringUtils.isBlank(text)) {
return;
}
diff --git a/main/src/cgeo/geocaching/activity/IAbstractActivity.java b/main/src/cgeo/geocaching/activity/IAbstractActivity.java
index 04709c6..61c218b 100644
--- a/main/src/cgeo/geocaching/activity/IAbstractActivity.java
+++ b/main/src/cgeo/geocaching/activity/IAbstractActivity.java
@@ -6,8 +6,6 @@ public interface IAbstractActivity {
public void goHome(View view);
- public void goManual(View view);
-
public void showToast(String text);
public void showShortToast(String text);
diff --git a/main/src/cgeo/geocaching/apps/AbstractApp.java b/main/src/cgeo/geocaching/apps/AbstractApp.java
index c95e8b4..f3715f3 100644
--- a/main/src/cgeo/geocaching/apps/AbstractApp.java
+++ b/main/src/cgeo/geocaching/apps/AbstractApp.java
@@ -1,10 +1,12 @@
package cgeo.geocaching.apps;
import cgeo.geocaching.Geocache;
-import cgeo.geocaching.cgeo;
+import cgeo.geocaching.MainActivity;
import cgeo.geocaching.cgeoapplication;
import cgeo.geocaching.utils.ProcessUtils;
+import org.apache.commons.lang3.StringUtils;
+
import android.content.Intent;
public abstract class AbstractApp implements App {
@@ -26,10 +28,10 @@ public abstract class AbstractApp implements App {
@Override
public boolean isInstalled() {
- if (ProcessUtils.isInstalled(packageName)) {
+ if (StringUtils.isNotEmpty(packageName) && ProcessUtils.isInstalled(packageName)) {
return true;
}
- return cgeo.isIntentAvailable(intent);
+ return MainActivity.isIntentAvailable(intent);
}
protected Intent getLaunchIntent() {
diff --git a/main/src/cgeo/geocaching/apps/cache/navi/CompassApp.java b/main/src/cgeo/geocaching/apps/cache/navi/CompassApp.java
index 4811916..47010df 100644
--- a/main/src/cgeo/geocaching/apps/cache/navi/CompassApp.java
+++ b/main/src/cgeo/geocaching/apps/cache/navi/CompassApp.java
@@ -3,7 +3,7 @@ package cgeo.geocaching.apps.cache.navi;
import cgeo.geocaching.Geocache;
import cgeo.geocaching.R;
import cgeo.geocaching.Waypoint;
-import cgeo.geocaching.cgeonavigate;
+import cgeo.geocaching.CompassActivity;
import cgeo.geocaching.geopoint.Geopoint;
import cgeo.geocaching.ui.Formatter;
@@ -22,18 +22,18 @@ class CompassApp extends AbstractPointNavigationApp {
@Override
public void navigate(Activity activity, Geopoint coords) {
- cgeonavigate.startActivity(activity, getString(R.string.navigation_direct_navigation), getString(R.string.navigation_target), coords, null);
+ CompassActivity.startActivity(activity, getString(R.string.navigation_direct_navigation), getString(R.string.navigation_target), coords, null);
}
@Override
public void navigate(Activity activity, Waypoint waypoint) {
- cgeonavigate.startActivity(activity, waypoint.getPrefix() + "/" + waypoint.getLookup(), waypoint.getName(), waypoint.getCoords(), null,
+ CompassActivity.startActivity(activity, waypoint.getPrefix() + "/" + waypoint.getLookup(), waypoint.getName(), waypoint.getCoords(), null,
waypoint.getWaypointType().getL10n());
}
@Override
public void navigate(Activity activity, Geocache cache) {
- cgeonavigate.startActivity(activity, cache.getGeocode(), cache.getName(), cache.getCoords(), null,
+ CompassActivity.startActivity(activity, cache.getGeocode(), cache.getName(), cache.getCoords(), null,
Formatter.formatCacheInfoShort(cache));
}
diff --git a/main/src/cgeo/geocaching/apps/cache/navi/GoogleMapsApp.java b/main/src/cgeo/geocaching/apps/cache/navi/GoogleMapsApp.java
index eac33cc..03fae9e 100644
--- a/main/src/cgeo/geocaching/apps/cache/navi/GoogleMapsApp.java
+++ b/main/src/cgeo/geocaching/apps/cache/navi/GoogleMapsApp.java
@@ -30,7 +30,7 @@ class GoogleMapsApp extends AbstractPointNavigationApp {
} catch (Exception e) {
// nothing
}
- Log.i("cgBase.runExternalMap: No maps application available.");
+ Log.i("GoogleMapsApp.navigate: No maps application available.");
ActivityMixin.showToast(activity, getString(R.string.err_application_no));
}
diff --git a/main/src/cgeo/geocaching/apps/cache/navi/GoogleMapsDirectionApp.java b/main/src/cgeo/geocaching/apps/cache/navi/GoogleMapsDirectionApp.java
index db4fc1c..a84b7e8 100644
--- a/main/src/cgeo/geocaching/apps/cache/navi/GoogleMapsDirectionApp.java
+++ b/main/src/cgeo/geocaching/apps/cache/navi/GoogleMapsDirectionApp.java
@@ -40,7 +40,7 @@ public class GoogleMapsDirectionApp extends AbstractPointNavigationApp {
}
} catch (Exception e) {
- Log.i("GoogleMapsDirection: application not available.");
+ Log.i("GoogleMapsDirectionApp: application not available.", e);
}
}
diff --git a/main/src/cgeo/geocaching/apps/cache/navi/GoogleNavigationApp.java b/main/src/cgeo/geocaching/apps/cache/navi/GoogleNavigationApp.java
index f1616ad..a3532a5 100644
--- a/main/src/cgeo/geocaching/apps/cache/navi/GoogleNavigationApp.java
+++ b/main/src/cgeo/geocaching/apps/cache/navi/GoogleNavigationApp.java
@@ -27,22 +27,28 @@ abstract class GoogleNavigationApp extends AbstractPointNavigationApp {
try {
activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri
.parse("google.navigation:ll=" + coords.getLatitude() + ","
- + coords.getLongitude() + mode)));
+ + coords.getLongitude() + "&mode=" + mode)));
- } catch (Exception e) {
- Log.i("cgBase.runNavigation: No navigation application available.");
+ } catch (final Exception e) {
+ Log.i("GoogleNavigationApp.navigate: No navigation application available.", e);
}
}
static class GoogleNavigationWalkingApp extends GoogleNavigationApp {
GoogleNavigationWalkingApp() {
- super(R.string.cache_menu_navigation_walk, "&mode=w");
+ super(R.string.cache_menu_navigation_walk, "w");
}
}
static class GoogleNavigationDrivingApp extends GoogleNavigationApp {
GoogleNavigationDrivingApp() {
- super(R.string.cache_menu_navigation_drive, "&mode=d");
+ super(R.string.cache_menu_navigation_drive, "d");
+ }
+ }
+
+ static class GoogleNavigationBikeApp extends GoogleNavigationApp {
+ GoogleNavigationBikeApp() {
+ super(R.string.cache_menu_navigation_bike, "b");
}
}
} \ No newline at end of file
diff --git a/main/src/cgeo/geocaching/apps/cache/navi/NavigationAppFactory.java b/main/src/cgeo/geocaching/apps/cache/navi/NavigationAppFactory.java
index 5545936..7316d4c 100644
--- a/main/src/cgeo/geocaching/apps/cache/navi/NavigationAppFactory.java
+++ b/main/src/cgeo/geocaching/apps/cache/navi/NavigationAppFactory.java
@@ -11,6 +11,7 @@ import cgeo.geocaching.apps.App;
import cgeo.geocaching.apps.cache.CacheBeaconApp;
import cgeo.geocaching.apps.cache.GccApp;
import cgeo.geocaching.apps.cache.WhereYouGoApp;
+import cgeo.geocaching.apps.cache.navi.GoogleNavigationApp.GoogleNavigationBikeApp;
import cgeo.geocaching.apps.cache.navi.GoogleNavigationApp.GoogleNavigationDrivingApp;
import cgeo.geocaching.apps.cache.navi.GoogleNavigationApp.GoogleNavigationWalkingApp;
import cgeo.geocaching.geopoint.Geopoint;
@@ -59,6 +60,10 @@ public final class NavigationAppFactory extends AbstractAppFactory {
*/
GOOGLE_NAVIGATION_WALK(new GoogleNavigationWalkingApp(), 12),
/**
+ * Google Navigation in walking mode
+ */
+ GOOGLE_NAVIGATION_BIKE(new GoogleNavigationBikeApp(), 21),
+ /**
* Google Maps Directions
*/
GOOGLE_MAPS_DIRECTIONS(new GoogleMapsDirectionApp(), 13),
@@ -134,7 +139,7 @@ public final class NavigationAppFactory extends AbstractAppFactory {
builder.setTitle(R.string.cache_menu_navigate);
final List<NavigationAppsEnum> items = new ArrayList<NavigationAppFactory.NavigationAppsEnum>();
final int defaultNavigationTool = Settings.getDefaultNavigationTool();
- for (NavigationAppsEnum navApp : getInstalledNavigationApps()) {
+ for (final NavigationAppsEnum navApp : getInstalledNavigationApps()) {
if ((showInternalMap || !(navApp.app instanceof InternalMap)) &&
(showDefaultNavigation || defaultNavigationTool != navApp.id)) {
boolean add = false;
@@ -161,8 +166,8 @@ public final class NavigationAppFactory extends AbstractAppFactory {
builder.setAdapter(adapter, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int item) {
- NavigationAppsEnum selectedItem = adapter.getItem(item);
- App app = selectedItem.app;
+ final NavigationAppsEnum selectedItem = adapter.getItem(item);
+ final App app = selectedItem.app;
if (cache != null) {
navigateCache(activity, cache, app);
}
@@ -185,7 +190,7 @@ public final class NavigationAppFactory extends AbstractAppFactory {
*/
public static List<NavigationAppsEnum> getInstalledNavigationApps() {
final List<NavigationAppsEnum> installedNavigationApps = new ArrayList<NavigationAppsEnum>();
- for (NavigationAppsEnum appEnum : NavigationAppsEnum.values()) {
+ for (final NavigationAppsEnum appEnum : NavigationAppsEnum.values()) {
if (appEnum.app.isInstalled()) {
installedNavigationApps.add(appEnum);
}
@@ -200,7 +205,7 @@ public final class NavigationAppFactory extends AbstractAppFactory {
*/
public static List<NavigationAppsEnum> getInstalledDefaultNavigationApps() {
final List<NavigationAppsEnum> installedNavigationApps = new ArrayList<NavigationAppsEnum>();
- for (NavigationAppsEnum appEnum : NavigationAppsEnum.values()) {
+ for (final NavigationAppsEnum appEnum : NavigationAppsEnum.values()) {
if (appEnum.app.isInstalled() && appEnum.app.isDefaultNavigationApp()) {
installedNavigationApps.add(appEnum);
}
@@ -225,9 +230,9 @@ public final class NavigationAppFactory extends AbstractAppFactory {
* @param menu
*/
public static void addMenuItems(final Menu menu, final Geocache cache) {
- for (NavigationAppsEnum navApp : getInstalledNavigationApps()) {
+ for (final NavigationAppsEnum navApp : getInstalledNavigationApps()) {
if (navApp.app instanceof CacheNavigationApp) {
- CacheNavigationApp cacheApp = (CacheNavigationApp) navApp.app;
+ final CacheNavigationApp cacheApp = (CacheNavigationApp) navApp.app;
if (cacheApp.isEnabled(cache)) {
menu.add(0, MENU_ITEM_OFFSET + navApp.id, 0, navApp.app.getName());
}
@@ -236,9 +241,9 @@ public final class NavigationAppFactory extends AbstractAppFactory {
}
public static void addMenuItems(final Menu menu, final Waypoint waypoint) {
- for (NavigationAppsEnum navApp : getInstalledNavigationApps()) {
+ for (final NavigationAppsEnum navApp : getInstalledNavigationApps()) {
if (navApp.app instanceof WaypointNavigationApp) {
- WaypointNavigationApp waypointApp = (WaypointNavigationApp) navApp.app;
+ final WaypointNavigationApp waypointApp = (WaypointNavigationApp) navApp.app;
if (waypointApp.isEnabled(waypoint)) {
menu.add(0, MENU_ITEM_OFFSET + navApp.id, 0, navApp.app.getName());
}
@@ -262,7 +267,7 @@ public final class NavigationAppFactory extends AbstractAppFactory {
private static void navigateCache(Activity activity, Geocache cache, App app) {
if (app instanceof CacheNavigationApp) {
- CacheNavigationApp cacheApp = (CacheNavigationApp) app;
+ final CacheNavigationApp cacheApp = (CacheNavigationApp) app;
cacheApp.navigate(activity, cache);
}
}
@@ -275,21 +280,21 @@ public final class NavigationAppFactory extends AbstractAppFactory {
private static void navigateWaypoint(Activity activity, Waypoint waypoint, App app) {
if (app instanceof WaypointNavigationApp) {
- WaypointNavigationApp waypointApp = (WaypointNavigationApp) app;
+ final WaypointNavigationApp waypointApp = (WaypointNavigationApp) app;
waypointApp.navigate(activity, waypoint);
}
}
private static void navigateGeopoint(Activity activity, Geopoint destination, App app) {
if (app instanceof GeopointNavigationApp) {
- GeopointNavigationApp geopointApp = (GeopointNavigationApp) app;
+ final GeopointNavigationApp geopointApp = (GeopointNavigationApp) app;
geopointApp.navigate(activity, destination);
}
}
private static App getAppFromMenuItem(MenuItem item) {
final int id = item.getItemId();
- for (NavigationAppsEnum navApp : NavigationAppsEnum.values()) {
+ for (final NavigationAppsEnum navApp : NavigationAppsEnum.values()) {
if (MENU_ITEM_OFFSET + navApp.id == id) {
return navApp.app;
}
@@ -362,7 +367,7 @@ public final class NavigationAppFactory extends AbstractAppFactory {
private static App getNavigationAppForId(final int navigationAppId) {
final List<NavigationAppsEnum> installedNavigationApps = getInstalledNavigationApps();
- for (NavigationAppsEnum navigationApp : installedNavigationApps) {
+ for (final NavigationAppsEnum navigationApp : installedNavigationApps) {
if (navigationApp.id == navigationAppId) {
return navigationApp.app;
}
diff --git a/main/src/cgeo/geocaching/apps/cache/navi/StreetviewApp.java b/main/src/cgeo/geocaching/apps/cache/navi/StreetviewApp.java
index 012b94f..e2c0828 100644
--- a/main/src/cgeo/geocaching/apps/cache/navi/StreetviewApp.java
+++ b/main/src/cgeo/geocaching/apps/cache/navi/StreetviewApp.java
@@ -4,6 +4,7 @@ import cgeo.geocaching.R;
import cgeo.geocaching.cgeoapplication;
import cgeo.geocaching.activity.ActivityMixin;
import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.utils.ProcessUtils;
import android.app.Activity;
import android.content.ActivityNotFoundException;
@@ -12,13 +13,16 @@ import android.net.Uri;
class StreetviewApp extends AbstractPointNavigationApp {
+ private static final String PACKAGE_NAME_STREET_VIEW = "com.google.android.street";
+ private static final boolean INSTALLED = ProcessUtils.isInstalled(PACKAGE_NAME_STREET_VIEW);
+
StreetviewApp() {
super(getString(R.string.cache_menu_streetview), null);
}
@Override
public boolean isInstalled() {
- return true;
+ return INSTALLED;
}
@Override
@@ -26,7 +30,7 @@ class StreetviewApp extends AbstractPointNavigationApp {
try {
activity.startActivity(new Intent(Intent.ACTION_VIEW,
Uri.parse("google.streetview:cbll=" + point.getLatitude() + "," + point.getLongitude())));
- } catch (ActivityNotFoundException e) {
+ } catch (final ActivityNotFoundException e) {
ActivityMixin.showToast(activity, cgeoapplication.getInstance().getString(R.string.err_application_no));
}
}
diff --git a/main/src/cgeo/geocaching/cgData.java b/main/src/cgeo/geocaching/cgData.java
index 28485a5..2ef5b27 100644
--- a/main/src/cgeo/geocaching/cgData.java
+++ b/main/src/cgeo/geocaching/cgData.java
@@ -33,6 +33,7 @@ import java.io.File;
import java.io.FilenameFilter;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.EnumSet;
@@ -85,7 +86,7 @@ public class cgData {
private static int[] cacheColumnIndex;
private static CacheCache cacheCache = new CacheCache();
private static SQLiteDatabase database = null;
- private static final int dbVersion = 66;
+ private static final int dbVersion = 67;
public static final int customListIdOffset = 10;
private static final String dbName = "data";
private static final String dbTableCaches = "cg_caches";
@@ -107,7 +108,7 @@ public class cgData {
+ "detailedupdate long, "
+ "visiteddate long, "
+ "geocode text unique not null, "
- + "reason integer not null default 0, " // cached, favourite...
+ + "reason integer not null default 0, " // cached, favorite...
+ "cacheid text, "
+ "guid text, "
+ "type text, "
@@ -674,6 +675,16 @@ public class cgData {
}
}
+ // issue2662 OC: Leichtes Klettern / Easy climbing
+ if (oldVersion < 67) {
+ try {
+ db.execSQL("update " + dbTableAttributes + " set attribute = 'easy_climbing_yes' where geocode like 'OC%' and attribute = 'climbing_yes'");
+ db.execSQL("update " + dbTableAttributes + " set attribute = 'easy_climbing_no' where geocode like 'OC%' and attribute = 'climbing_no'");
+ } catch (Exception e) {
+ Log.e("Failed to upgrade to ver. 67", e);
+
+ }
+ }
}
db.setTransactionSuccessful();
@@ -962,25 +973,32 @@ public class cgData {
throw new IllegalArgumentException("cache must not be null");
}
- // merge always with data already stored in the CacheCache or DB
- if (saveFlags.contains(SaveFlag.SAVE_CACHE)) {
- cache.gatherMissingFrom(cacheCache.getCacheFromCache(cache.getGeocode()));
- cacheCache.putCacheInCache(cache);
- }
+ // Merge with the data already stored in the CacheCache or in the database if
+ // the cache had not been loaded before, and update the CacheCache.
+ // Also, a DB update is required if the merge data comes from the CacheCache
+ // (as it may be more recent than the version in the database), or if the
+ // version coming from the database is different than the version we are entering
+ // into the cache (that includes absence from the database).
+ final String geocode = cache.getGeocode();
+ final Geocache cacheFromCache = cacheCache.getCacheFromCache(geocode);
+ final boolean dbUpdateRequired =
+ !cache.gatherMissingFrom(cacheFromCache != null ?
+ cacheFromCache :
+ loadCache(geocode, LoadFlags.LOAD_ALL_DB_ONLY)) ||
+ cacheFromCache != null;
+ cache.addStorageLocation(StorageLocation.CACHE);
+ cacheCache.putCacheInCache(cache);
+ // Only save the cache in the database if it is requested by the caller and
+ // the cache contains detailed information.
if (!saveFlags.contains(SaveFlag.SAVE_DB)) {
return true;
}
- boolean updateRequired = !cache.gatherMissingFrom(loadCache(cache.getGeocode(), LoadFlags.LOAD_ALL_DB_ONLY));
- // only save a cache to the database if
- // - the cache is detailed
- // - there are changes
- // - the cache is only stored in the CacheCache so far
- if ((!updateRequired || !cache.isDetailed()) && cache.getStorageLocation().contains(StorageLocation.DATABASE)) {
- return false;
- }
+ return cache.isDetailed() && dbUpdateRequired && storeIntoDatabase(cache);
+ }
+ private static boolean storeIntoDatabase(final Geocache cache) {
cache.addStorageLocation(StorageLocation.DATABASE);
cacheCache.putCacheInCache(cache);
Log.d("Saving " + cache.toString() + " (" + cache.getListId() + ") to DB");
@@ -1396,7 +1414,7 @@ public class cgData {
* @param geocodes
* @return Set of loaded caches. Never null.
*/
- public static Set<Geocache> loadCaches(final Set<String> geocodes, final EnumSet<LoadFlag> loadFlags) {
+ public static Set<Geocache> loadCaches(final Collection<String> geocodes, final EnumSet<LoadFlag> loadFlags) {
if (CollectionUtils.isEmpty(geocodes)) {
return new HashSet<Geocache>();
}
@@ -1440,7 +1458,7 @@ public class cgData {
}
if (remaining.size() >= 1) {
- Log.i("cgData.loadCaches(" + remaining.toString() + ") failed");
+ Log.d("cgData.loadCaches(" + remaining.toString() + ") returned no results");
}
return result;
}
diff --git a/main/src/cgeo/geocaching/cgeoapplication.java b/main/src/cgeo/geocaching/cgeoapplication.java
index a1fd7d1..b8f63ee 100644
--- a/main/src/cgeo/geocaching/cgeoapplication.java
+++ b/main/src/cgeo/geocaching/cgeoapplication.java
@@ -103,8 +103,8 @@ public class cgeoapplication extends Application {
boolean restored = atomic.get();
String message = restored ? res.getString(R.string.init_restore_success) : res.getString(R.string.init_restore_failed);
ActivityMixin.helpDialog(fromActivity, res.getString(R.string.init_backup_restore), message);
- if (fromActivity instanceof cgeo) {
- ((cgeo) fromActivity).updateCacheCounter();
+ if (fromActivity instanceof MainActivity) {
+ ((MainActivity) fromActivity).updateCacheCounter();
}
}
};
diff --git a/main/src/cgeo/geocaching/cgeocaches.java b/main/src/cgeo/geocaching/cgeocaches.java
index 61a32f1..e321d59 100644
--- a/main/src/cgeo/geocaching/cgeocaches.java
+++ b/main/src/cgeo/geocaching/cgeocaches.java
@@ -2,7 +2,6 @@ package cgeo.geocaching;
import cgeo.geocaching.activity.AbstractActivity;
import cgeo.geocaching.activity.AbstractListActivity;
-import cgeo.geocaching.activity.ActivityMixin;
import cgeo.geocaching.activity.FilteredActivity;
import cgeo.geocaching.activity.Progress;
import cgeo.geocaching.apps.cache.navi.NavigationAppFactory;
@@ -39,6 +38,7 @@ import cgeo.geocaching.sorting.VisitComparator;
import cgeo.geocaching.ui.CacheListAdapter;
import cgeo.geocaching.ui.LoggingUI;
import cgeo.geocaching.ui.WeakReferenceHandler;
+import cgeo.geocaching.utils.AsyncTaskWithProgress;
import cgeo.geocaching.utils.DateUtils;
import cgeo.geocaching.utils.GeoDirHandler;
import cgeo.geocaching.utils.Log;
@@ -74,6 +74,7 @@ import android.widget.ListView;
import android.widget.TextView;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
@@ -96,6 +97,7 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
private static final int MENU_REMOVE_FROM_HISTORY = 23;
private static final int MENU_DROP_CACHE = 24;
private static final int MENU_MOVE_TO_LIST = 25;
+ private static final int MENU_REFRESH = 26;
private static final int MENU_SWITCH_SELECT_MODE = 52;
private static final int SUBMENU_SHOW_MAP = 54;
private static final int SUBMENU_MANAGE_LISTS = 55;
@@ -175,7 +177,7 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
showFooterMoreCaches();
if (search != null && search.getError() == StatusCode.UNAPPROVED_LICENSE) {
- AlertDialog.Builder dialog = new AlertDialog.Builder(this);
+ final AlertDialog.Builder dialog = new AlertDialog.Builder(this);
dialog.setTitle(res.getString(R.string.license));
dialog.setMessage(res.getString(R.string.err_license));
dialog.setCancelable(true);
@@ -196,7 +198,7 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
}
});
- AlertDialog alert = dialog.create();
+ final AlertDialog alert = dialog.create();
alert.show();
} else if (search != null && search.getError() != null) {
showToast(res.getString(R.string.err_download_fail) + ' ' + search.getError().getErrorString(res) + '.');
@@ -209,7 +211,7 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
}
setAdapterCurrentCoordinates(false);
- } catch (Exception e) {
+ } catch (final Exception e) {
showToast(res.getString(R.string.err_detail_cache_find_any));
Log.e("cgeocaches.loadCachesHandler", e);
@@ -223,14 +225,14 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
try {
hideLoading();
showProgress(false);
- } catch (Exception e2) {
+ } catch (final Exception e2) {
Log.e("cgeocaches.loadCachesHandler.2", e2);
}
adapter.setSelectMode(false);
}
- private Handler loadCachesHandler = new LoadCachesHandler(this);
+ private final Handler loadCachesHandler = new LoadCachesHandler(this);
private static class LoadCachesHandler extends WeakReferenceHandler<cgeocaches> {
@@ -275,7 +277,7 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
}
protected void updateTitle() {
- ArrayList<Integer> numbers = new ArrayList<Integer>();
+ final ArrayList<Integer> numbers = new ArrayList<Integer>();
if (adapter.isFiltered()) {
numbers.add(adapter.getCount());
}
@@ -290,7 +292,7 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
}
}
- private Handler loadDetailsHandler = new Handler() {
+ private final Handler loadDetailsHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
@@ -301,8 +303,8 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
adapter.notifyDataSetChanged();
- int secondsElapsed = (int) ((System.currentTimeMillis() - detailProgressTime) / 1000);
- int minutesRemaining = ((detailTotal - detailProgress) * secondsElapsed / ((detailProgress > 0) ? detailProgress : 1) / 60);
+ final int secondsElapsed = (int) ((System.currentTimeMillis() - detailProgressTime) / 1000);
+ final int minutesRemaining = ((detailTotal - detailProgress) * secondsElapsed / ((detailProgress > 0) ? detailProgress : 1) / 60);
progress.setProgress(detailProgress);
if (minutesRemaining < 1) {
@@ -338,7 +340,7 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
/**
* TODO Possibly parts should be a Thread not a Handler
*/
- private Handler downloadFromWebHandler = new Handler() {
+ private final Handler downloadFromWebHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
setAdapter();
@@ -373,7 +375,7 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
}
}
};
- private Handler dropDetailsHandler = new Handler() {
+ private final Handler clearOfflineLogsHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
@@ -388,23 +390,8 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
}
}
};
- private Handler clearOfflineLogsHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- if (msg.what != MSG_CANCEL) {
- adapter.setSelectMode(false);
-
- refreshCurrentList();
-
- replaceCacheListFromSearch();
-
- progress.dismiss();
- }
- }
- };
-
- private Handler importGpxAttachementFinishedHandler = new Handler() {
+ private final Handler importGpxAttachementFinishedHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
refreshCurrentList();
@@ -421,14 +408,14 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
super.onCreate(savedInstanceState);
setTheme();
- setContentView(R.layout.caches);
+ setContentView(R.layout.cacheslist_activity);
// get parameters
Bundle extras = getIntent().getExtras();
if (extras != null) {
- Object typeObject = extras.get(Intents.EXTRA_LIST_TYPE);
+ final Object typeObject = extras.get(Intents.EXTRA_LIST_TYPE);
type = (typeObject instanceof CacheListType) ? (CacheListType) typeObject : CacheListType.OFFLINE;
- coords = (Geopoint) extras.getParcelable(Intents.EXTRAS_COORDS);
+ coords = extras.getParcelable(Intents.EXTRA_COORDS);
}
else {
extras = new Bundle();
@@ -440,6 +427,17 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
}
}
+ // Add the list selection in code. This way we can leave the XML layout of the action bar the same as for other activities.
+ final View titleBar = findViewById(R.id.actionbar_title);
+ titleBar.setClickable(true);
+ titleBar.setOnClickListener(new View.OnClickListener() {
+
+ @Override
+ public void onClick(View v) {
+ selectList(v);
+ }
+ });
+
setTitle(title);
setAdapter();
@@ -480,24 +478,14 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
}
private void importGpxAttachement() {
- new AlertDialog.Builder(this)
- .setTitle(res.getString(R.string.gpx_import_title))
- .setMessage(res.getString(R.string.gpx_import_confirm))
- .setCancelable(false)
- .setPositiveButton(getString(android.R.string.yes), new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id) {
- new GPXImporter(cgeocaches.this, listId, importGpxAttachementFinishedHandler).importGPX();
- }
- })
- .setNegativeButton(getString(android.R.string.no), new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id) {
- dialog.cancel();
- }
- })
- .create()
- .show();
+ new StoredList.UserInterface(this).promptForListSelection(R.string.gpx_import_select_list_title, new RunnableWithArgument<Integer>() {
+
+ @Override
+ public void run(Integer listId) {
+ new GPXImporter(cgeocaches.this, listId, importGpxAttachementFinishedHandler).importGPX();
+ switchListById(listId);
+ }
+ }, true, 0);
}
@Override
@@ -516,7 +504,7 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
// refresh standard list if it has changed (new caches downloaded)
if (type == CacheListType.OFFLINE && listId >= StoredList.STANDARD_LIST_ID && search != null) {
- SearchResult newSearch = cgData.getBatchOfStoredCaches(coords, Settings.getCacheType(), listId);
+ final SearchResult newSearch = cgData.getBatchOfStoredCaches(coords, Settings.getCacheType(), listId);
if (newSearch != null && newSearch.getTotal() != search.getTotal()) {
refreshCurrentList();
}
@@ -551,7 +539,7 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
menu.add(0, MENU_SWITCH_SELECT_MODE, 0, res.getString(R.string.caches_select_mode)).setIcon(R.drawable.ic_menu_agenda);
menu.add(0, MENU_INVERT_SELECTION, 0, res.getString(R.string.caches_select_invert)).setIcon(R.drawable.ic_menu_mark);
if (type == CacheListType.OFFLINE) {
- SubMenu subMenu = menu.addSubMenu(0, SUBMENU_MANAGE_OFFLINE, 0, res.getString(R.string.caches_manage)).setIcon(R.drawable.ic_menu_save);
+ final SubMenu subMenu = menu.addSubMenu(0, SUBMENU_MANAGE_OFFLINE, 0, res.getString(R.string.caches_manage)).setIcon(R.drawable.ic_menu_save);
subMenu.add(0, MENU_DROP_CACHES, 0, res.getString(R.string.caches_drop_all)); // delete saved caches
subMenu.add(0, MENU_DROP_CACHES_AND_LIST, 0, res.getString(R.string.caches_drop_all_and_list));
subMenu.add(0, MENU_REFRESH_STORED, 0, res.getString(R.string.cache_offline_refresh)); // download details for all caches
@@ -568,17 +556,20 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
subMenu.add(0, MENU_EXPORT, 0, res.getString(R.string.export)); // export caches
} else {
if (type == CacheListType.HISTORY) {
- SubMenu subMenu = menu.addSubMenu(0, SUBMENU_MANAGE_HISTORY, 0, res.getString(R.string.caches_manage)).setIcon(R.drawable.ic_menu_save);
+ final SubMenu subMenu = menu.addSubMenu(0, SUBMENU_MANAGE_HISTORY, 0, res.getString(R.string.caches_manage)).setIcon(R.drawable.ic_menu_save);
subMenu.add(0, MENU_REMOVE_FROM_HISTORY, 0, res.getString(R.string.cache_clear_history)); // remove from history
subMenu.add(0, MENU_EXPORT, 0, res.getString(R.string.export)); // export caches
+ subMenu.add(0, MENU_CLEAR_OFFLINE_LOGS, 0, res.getString(R.string.caches_clear_offlinelogs));
+ menu.add(0, MENU_REFRESH_STORED, 0, res.getString(R.string.cache_offline_refresh)).setIcon(R.drawable.ic_menu_set_as);
+ } else {
+ menu.add(0, MENU_REFRESH_STORED, 0, res.getString(R.string.caches_store_offline)).setIcon(R.drawable.ic_menu_set_as); // download details for all caches
}
- menu.add(0, MENU_REFRESH_STORED, 0, res.getString(R.string.caches_store_offline)).setIcon(R.drawable.ic_menu_set_as); // download details for all caches
}
navigationMenu = CacheListAppFactory.addMenuItems(menu, this, res);
if (type == CacheListType.OFFLINE) {
- SubMenu subMenu = menu.addSubMenu(0, SUBMENU_MANAGE_LISTS, 0, res.getString(R.string.list_menu)).setIcon(R.drawable.ic_menu_more);
+ final SubMenu subMenu = menu.addSubMenu(0, SUBMENU_MANAGE_LISTS, 0, res.getString(R.string.list_menu)).setIcon(R.drawable.ic_menu_more);
subMenu.add(0, MENU_CREATE_LIST, 0, res.getString(R.string.list_menu_create));
subMenu.add(0, MENU_DROP_LIST, 0, res.getString(R.string.list_menu_drop));
subMenu.add(0, MENU_RENAME_LIST, 0, res.getString(R.string.list_menu_rename));
@@ -625,8 +616,6 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
setVisible(menu, MENU_EXPORT, !isEmpty);
setVisible(menu, MENU_REMOVE_FROM_HISTORY, !isEmpty);
setVisible(menu, MENU_CLEAR_OFFLINE_LOGS, !isEmpty && containsOfflineLogs());
- setVisible(menu, MENU_IMPORT_GPX, isConcrete);
- setVisible(menu, MENU_IMPORT_WEB, isConcrete);
if (navigationMenu != null) {
navigationMenu.setVisible(!isEmpty);
@@ -635,12 +624,12 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
final boolean hasSelection = adapter != null && adapter.getCheckedCount() > 0;
final boolean isNonDefaultList = isConcrete && listId != StoredList.STANDARD_LIST_ID;
- if (type == CacheListType.OFFLINE) { // only offline list
+ if (type == CacheListType.OFFLINE || type == CacheListType.HISTORY) { // only offline list
setMenuItemLabel(menu, MENU_DROP_CACHES, R.string.caches_drop_selected, R.string.caches_drop_all);
menu.findItem(MENU_DROP_CACHES_AND_LIST).setVisible(!hasSelection && isNonDefaultList && !adapter.isFiltered());
setMenuItemLabel(menu, MENU_REFRESH_STORED, R.string.caches_refresh_selected, R.string.caches_refresh_all);
setMenuItemLabel(menu, MENU_MOVE_TO_LIST, R.string.caches_move_selected, R.string.caches_move_all);
- } else { // search and history list (all other than offline)
+ } else { // search and global list (all other than offline and history)
setMenuItemLabel(menu, MENU_REFRESH_STORED, R.string.caches_store_selected, R.string.caches_store_offline);
}
@@ -665,7 +654,7 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
setMenuItemLabel(menu, MENU_REMOVE_FROM_HISTORY, R.string.cache_remove_from_history, R.string.cache_clear_history);
setMenuItemLabel(menu, MENU_EXPORT, R.string.export, R.string.export);
- } catch (Exception e) {
+ } catch (final Exception e) {
Log.e("cgeocaches.onPrepareOptionsMenu", e);
}
@@ -673,7 +662,7 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
}
private boolean containsEvents() {
- for (Geocache cache : adapter.getCheckedOrAllCaches()) {
+ for (final Geocache cache : adapter.getCheckedOrAllCaches()) {
if (cache.isEventCache()) {
return true;
}
@@ -682,7 +671,7 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
}
private boolean containsOfflineLogs() {
- for (Geocache cache : adapter.getCheckedOrAllCaches()) {
+ for (final Geocache cache : adapter.getCheckedOrAllCaches()) {
if (cache.isLogOffline()) {
return true;
}
@@ -695,7 +684,7 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
if (menuItem == null) {
return;
}
- boolean hasSelection = adapter != null && adapter.getCheckedCount() > 0;
+ final boolean hasSelection = adapter != null && adapter.getCheckedCount() > 0;
if (hasSelection) {
menuItem.setTitle(res.getString(resIdSelection) + " (" + adapter.getCheckedCount() + ")");
} else {
@@ -705,7 +694,7 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
@Override
public boolean onOptionsItemSelected(MenuItem item) {
- int itemId = item.getItemId();
+ final int itemId = item.getItemId();
switch (itemId) {
case MENU_SWITCH_SELECT_MODE:
adapter.switchSelectMode();
@@ -794,9 +783,8 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
}
public void deletePastEvents() {
- progress.show(this, null, res.getString(R.string.caches_drop_progress), true, dropDetailsHandler.obtainMessage(MSG_CANCEL));
final List<Geocache> deletion = new ArrayList<Geocache>();
- for (Geocache cache : adapter.getCheckedOrAllCaches()) {
+ for (final Geocache cache : adapter.getCheckedOrAllCaches()) {
if (cache.isEventCache()) {
final Date eventDate = cache.getHiddenDate();
if (DateUtils.daysSince(eventDate.getTime()) > 0) {
@@ -804,7 +792,7 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
}
}
}
- new DropDetailsThread(dropDetailsHandler, deletion).start();
+ new DropDetailsTask(false).execute(deletion.toArray(new Geocache[deletion.size()]));
}
public void clearOfflineLogs() {
@@ -842,7 +830,7 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
AdapterContextMenuInfo adapterInfo = null;
try {
adapterInfo = (AdapterContextMenuInfo) info;
- } catch (Exception e) {
+ } catch (final Exception e) {
Log.w("cgeocaches.onCreateContextMenu", e);
}
@@ -858,13 +846,14 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
if (cache.getCoords() != null) {
menu.add(0, MENU_DEFAULT_NAVIGATION, 0, NavigationAppFactory.getDefaultNavigationApplication().getName());
menu.add(1, MENU_NAVIGATION, 0, res.getString(R.string.cache_menu_navigate)).setIcon(R.drawable.ic_menu_mapmode);
- LoggingUI.addMenuItems(menu, cache);
+ LoggingUI.addMenuItems(this, menu, cache);
menu.add(0, MENU_CACHE_DETAILS, 0, res.getString(R.string.cache_menu_details));
}
if (cache.isOffline()) {
menu.add(0, MENU_DROP_CACHE, 0, res.getString(R.string.cache_offline_drop));
menu.add(0, MENU_MOVE_TO_LIST, 0, res.getString(R.string.cache_menu_move_list));
menu.add(0, MENU_EXPORT, 0, res.getString(R.string.export));
+ menu.add(0, MENU_REFRESH, 0, res.getString(R.string.cache_menu_refresh));
}
else {
menu.add(0, MENU_STORE_CACHE, 0, res.getString(R.string.cache_offline_store));
@@ -898,7 +887,7 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
AdapterContextMenuInfo adapterInfo = null;
try {
adapterInfo = (AdapterContextMenuInfo) info;
- } catch (Exception e) {
+ } catch (final Exception e) {
Log.w("cgeocaches.onContextItemSelected", e);
}
@@ -944,6 +933,7 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
}, true, listId);
break;
case MENU_STORE_CACHE:
+ case MENU_REFRESH:
refreshStored(Collections.singletonList(cache));
break;
case MENU_EXPORT:
@@ -1000,7 +990,7 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
if (inflater == null) {
inflater = getLayoutInflater();
}
- listFooter = inflater.inflate(R.layout.caches_footer, null);
+ listFooter = inflater.inflate(R.layout.cacheslist_footer, null);
listFooter.setClickable(true);
listFooter.setOnClickListener(new MoreCachesListener());
@@ -1082,6 +1072,11 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
return;
}
+ if (!Network.isNetworkConnected(getApplicationContext())) {
+ showToast(getString(R.string.err_server));
+ return;
+ }
+
if (Settings.getChooseList() && type != CacheListType.OFFLINE) {
// let user select list to store cache in
new StoredList.UserInterface(this).promptForListSelection(R.string.list_title,
@@ -1101,7 +1096,7 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
showProgress(false);
- int etaTime = ((detailTotal * 25) / 60);
+ final int etaTime = ((detailTotal * 25) / 60);
String message;
if (etaTime < 1) {
message = res.getString(R.string.caches_downloading) + " " + res.getString(R.string.caches_eta_ltm);
@@ -1119,7 +1114,7 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
}
public void removeFromHistoryCheck() {
- AlertDialog.Builder dialog = new AlertDialog.Builder(this);
+ final AlertDialog.Builder dialog = new AlertDialog.Builder(this);
dialog.setCancelable(true);
dialog.setTitle(res.getString(R.string.caches_removing_from_history));
dialog.setMessage((adapter != null && adapter.getCheckedCount() > 0) ? res.getString(R.string.cache_remove_from_history)
@@ -1138,17 +1133,17 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
}
});
- AlertDialog alert = dialog.create();
+ final AlertDialog alert = dialog.create();
alert.show();
}
public void removeFromHistory() {
final List<Geocache> caches = adapter.getCheckedOrAllCaches();
- final String geocodes[] = new String[caches.size()];
+ final String[] geocodes = new String[caches.size()];
for (int i = 0; i < geocodes.length; i++) {
geocodes[i] = caches.get(i).getGeocode();
}
- Bundle b = new Bundle();
+ final Bundle b = new Bundle();
b.putStringArray(Intents.EXTRA_CACHELIST, geocodes);
getSupportLoaderManager().initLoader(CacheListLoaderType.REMOVE_FROM_HISTORY.ordinal(), b, this);
}
@@ -1164,7 +1159,7 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
}
public void dropStored(final boolean removeListAfterwards) {
- AlertDialog.Builder dialog = new AlertDialog.Builder(this);
+ final AlertDialog.Builder dialog = new AlertDialog.Builder(this);
dialog.setCancelable(true);
dialog.setTitle(res.getString(R.string.caches_drop_stored));
@@ -1177,10 +1172,7 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
@Override
public void onClick(DialogInterface dialog, int id) {
- dropSelected();
- if (removeListAfterwards) {
- removeList(false);
- }
+ dropSelected(removeListAfterwards);
dialog.cancel();
}
});
@@ -1192,13 +1184,13 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
}
});
- AlertDialog alert = dialog.create();
+ final AlertDialog alert = dialog.create();
alert.show();
}
- public void dropSelected() {
- progress.show(this, null, res.getString(R.string.caches_drop_progress), true, dropDetailsHandler.obtainMessage(MSG_CANCEL));
- new DropDetailsThread(dropDetailsHandler, adapter.getCheckedOrAllCaches()).start();
+ public void dropSelected(boolean removeListAfterwards) {
+ final List<Geocache> selected = adapter.getCheckedOrAllCaches();
+ new DropDetailsTask(removeListAfterwards).execute(selected.toArray(new Geocache[selected.size()]));
}
/**
@@ -1230,7 +1222,7 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
removeGeoAndDir();
final List<Geocache> cachesWithStaticMaps = new ArrayList<Geocache>(this.caches.size());
- for (Geocache cache : this.caches) {
+ for (final Geocache cache : this.caches) {
if (Settings.isStoreOfflineMaps() && cache.hasStaticMap()) {
cachesWithStaticMaps.add(cache);
continue;
@@ -1242,7 +1234,7 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
}
}
- for (Geocache cache : cachesWithStaticMaps) {
+ for (final Geocache cache : cachesWithStaticMaps) {
if (!refreshCache(cache)) {
break;
}
@@ -1274,7 +1266,7 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
}
Log.i("Waiting for next cache " + delay + " ms");
- } catch (Exception e) {
+ } catch (final Exception e) {
Log.e("cgeocaches.LoadDetailsThread.sleep", e);
}
}
@@ -1289,10 +1281,10 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
handler.sendEmptyMessage(cacheList.indexOf(cache));
yield();
- } catch (InterruptedException e) {
+ } catch (final InterruptedException e) {
Log.i(e.getMessage());
return false;
- } catch (Exception e) {
+ } catch (final Exception e) {
Log.e("cgeocaches.LoadDetailsThread", e);
}
@@ -1309,7 +1301,7 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
public LoadFromWebThread(Handler handlerIn, int listId) {
handler = handlerIn;
- listIdLFW = listId;
+ listIdLFW = StoredList.getConcreteList(listId);
}
public void kill() {
@@ -1332,7 +1324,7 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
deviceCode = "";
}
final Parameters params = new Parameters("code", deviceCode);
- HttpResponse responseFromWeb = Network.getRequest("http://send2.cgeo.org/read.html", params);
+ final HttpResponse responseFromWeb = Network.getRequest("http://send2.cgeo.org/read.html", params);
if (responseFromWeb != null && responseFromWeb.getStatusLine().getStatusCode() == 200) {
final String response = Network.getResponseData(responseFromWeb);
@@ -1372,7 +1364,7 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
sleep(500); //Cache was loaded 0.5s
times = 0;
}
- } catch (InterruptedException e) {
+ } catch (final InterruptedException e) {
Log.e("cgeocaches.LoadFromWebThread.sleep", e);
}
}
@@ -1383,24 +1375,35 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
}
}
- private class DropDetailsThread extends Thread {
+ private class DropDetailsTask extends AsyncTaskWithProgress<Geocache, Void> {
- final private Handler handler;
- final private List<Geocache> selected;
+ private final boolean removeListAfterwards;
- public DropDetailsThread(Handler handlerIn, List<Geocache> selectedIn) {
- handler = handlerIn;
- selected = selectedIn;
+ public DropDetailsTask(boolean removeListAfterwards) {
+ super(cgeocaches.this, null, res.getString(R.string.caches_drop_progress), true);
+ this.removeListAfterwards = removeListAfterwards;
}
@Override
- public void run() {
+ protected Void doInBackgroundInternal(Geocache[] caches) {
removeGeoAndDir();
- cgData.markDropped(selected);
- handler.sendEmptyMessage(MSG_DONE);
-
+ cgData.markDropped(Arrays.asList(caches));
startGeoAndDir();
+ return null;
+ }
+
+ @Override
+ protected void onPostExecuteInternal(Void result) {
+ // remove list in UI because of toast
+ if (removeListAfterwards) {
+ removeList(false);
+ }
+
+ adapter.setSelectMode(false);
+ refreshCurrentList();
+ replaceCacheListFromSearch();
}
+
}
private class ClearOfflineLogsThread extends Thread {
@@ -1463,7 +1466,7 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
return;
}
- StoredList list = cgData.getList(id);
+ final StoredList list = cgData.getList(id);
if (list == null) {
return;
}
@@ -1552,8 +1555,8 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
}
// apply filter settings (if there's a filter)
- Set<String> geocodes = new HashSet<String>();
- for (Geocache cache : adapter.getFilteredList()) {
+ final Set<String> geocodes = new HashSet<String>();
+ for (final Geocache cache : adapter.getFilteredList()) {
geocodes.add(cache.getGeocode());
}
@@ -1566,21 +1569,6 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
CGeoMap.startActivitySearch(this, searchToUse, mapTitle);
}
- @Override
- public void goManual(View view) {
- switch (type) {
- case OFFLINE:
- ActivityMixin.goManual(this, "c:geo-stored");
- break;
- case HISTORY:
- ActivityMixin.goManual(this, "c:geo-history");
- break;
- default:
- ActivityMixin.goManual(this, "c:geo-nearby");
- break;
- }
- }
-
private void refreshCurrentList() {
switchListById(listId);
}
@@ -1643,7 +1631,7 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
private void setDateComparatorForEventList() {
if (CollectionUtils.isNotEmpty(cacheList)) {
boolean eventsOnly = true;
- for (Geocache cache : cacheList) {
+ for (final Geocache cache : cacheList) {
if (!cache.isEventCache()) {
eventsOnly = false;
break;
@@ -1667,7 +1655,7 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
}
final Intent cachesIntent = new Intent(context, cgeocaches.class);
cachesIntent.putExtra(Intents.EXTRA_LIST_TYPE, CacheListType.NEAREST);
- cachesIntent.putExtra(Intents.EXTRAS_COORDS, coordsNow);
+ cachesIntent.putExtra(Intents.EXTRA_COORDS, coordsNow);
context.startActivity(cachesIntent);
}
@@ -1680,7 +1668,7 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
public static void startActivityAddress(final Context context, final Geopoint coords, final String address) {
final Intent addressIntent = new Intent(context, cgeocaches.class);
addressIntent.putExtra(Intents.EXTRA_LIST_TYPE, CacheListType.ADDRESS);
- addressIntent.putExtra(Intents.EXTRAS_COORDS, coords);
+ addressIntent.putExtra(Intents.EXTRA_COORDS, coords);
addressIntent.putExtra(Intents.EXTRA_ADDRESS, address);
context.startActivity(addressIntent);
}
@@ -1691,7 +1679,7 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
}
final Intent cachesIntent = new Intent(context, cgeocaches.class);
cachesIntent.putExtra(Intents.EXTRA_LIST_TYPE, CacheListType.COORDINATE);
- cachesIntent.putExtra(Intents.EXTRAS_COORDS, coords);
+ cachesIntent.putExtra(Intents.EXTRA_COORDS, coords);
context.startActivity(cachesIntent);
}
@@ -1725,11 +1713,11 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
@Override
public Loader<SearchResult> onCreateLoader(int type, Bundle extras) {
- AbstractSearchLoader loader = null;
if (type >= CacheListLoaderType.values().length) {
throw new IllegalArgumentException("invalid loader type " + type);
}
- CacheListLoaderType enumType = CacheListLoaderType.values()[type];
+ final CacheListLoaderType enumType = CacheListLoaderType.values()[type];
+ AbstractSearchLoader loader = null;
switch (enumType) {
case OFFLINE:
listId = Settings.getLastList();
diff --git a/main/src/cgeo/geocaching/compatibility/AndroidLevel8Emulation.java b/main/src/cgeo/geocaching/compatibility/AndroidLevel8Emulation.java
index a60b48d..6d5781f 100644
--- a/main/src/cgeo/geocaching/compatibility/AndroidLevel8Emulation.java
+++ b/main/src/cgeo/geocaching/compatibility/AndroidLevel8Emulation.java
@@ -19,7 +19,11 @@ public class AndroidLevel8Emulation implements AndroidLevel8Interface {
@Override
public int getRotationOffset(Activity activity) {
final Display display = activity.getWindowManager().getDefaultDisplay();
+
+ // the non deprecated method is available in API 8+ only, so we cannot deal better with this
+ @SuppressWarnings("deprecation")
final int rotation = display.getOrientation();
+
if (rotation == Configuration.ORIENTATION_LANDSCAPE) {
return 90;
}
diff --git a/main/src/cgeo/geocaching/connector/AbstractConnector.java b/main/src/cgeo/geocaching/connector/AbstractConnector.java
index 413291c..83c1b6f 100644
--- a/main/src/cgeo/geocaching/connector/AbstractConnector.java
+++ b/main/src/cgeo/geocaching/connector/AbstractConnector.java
@@ -1,11 +1,13 @@
package cgeo.geocaching.connector;
import cgeo.geocaching.Geocache;
-import cgeo.geocaching.enumerations.CacheRealm;
+import cgeo.geocaching.R;
import cgeo.geocaching.geopoint.Geopoint;
import org.apache.commons.lang3.StringUtils;
+import android.app.Activity;
+
public abstract class AbstractConnector implements IConnector {
@Override
@@ -19,6 +21,16 @@ public abstract class AbstractConnector implements IConnector {
}
@Override
+ public boolean addToWatchlist(Geocache cache) {
+ return false;
+ }
+
+ @Override
+ public boolean removeFromWatchlist(Geocache cache) {
+ return false;
+ }
+
+ @Override
public boolean supportsOwnCoordinates() {
return false;
}
@@ -36,6 +48,17 @@ public abstract class AbstractConnector implements IConnector {
}
/**
+ * Uploading personal note to website
+ *
+ * @param cache
+ * @return success
+ */
+ @Override
+ public boolean uploadPersonalNote(Geocache cache) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
* {@link IConnector}
*/
@Override
@@ -54,6 +77,21 @@ public abstract class AbstractConnector implements IConnector {
}
@Override
+ public boolean supportsLogImages() {
+ return false;
+ }
+
+ @Override
+ public boolean canLog(Geocache cache) {
+ return false;
+ }
+
+ @Override
+ public ILoggingManager getLoggingManager(Activity activity, Geocache cache) {
+ return new NoLoggingManager();
+ }
+
+ @Override
public String getLicenseText(final Geocache cache) {
return null;
}
@@ -111,15 +149,15 @@ public abstract class AbstractConnector implements IConnector {
* {@link IConnector}
*/
@Override
- public CacheRealm getCacheRealm() {
- return CacheRealm.OTHER;
+ public boolean isActivated() {
+ return false;
}
- /**
- * {@link IConnector}
- */
@Override
- public boolean isActivated() {
- return false;
+ public int getCacheMapMarkerId(boolean disabled) {
+ if (disabled) {
+ return R.drawable.marker_disabled_other;
+ }
+ return R.drawable.marker_other;
}
}
diff --git a/main/src/cgeo/geocaching/connector/ConnectorFactory.java b/main/src/cgeo/geocaching/connector/ConnectorFactory.java
index 561bae2..2cf2588 100644
--- a/main/src/cgeo/geocaching/connector/ConnectorFactory.java
+++ b/main/src/cgeo/geocaching/connector/ConnectorFactory.java
@@ -1,15 +1,21 @@
package cgeo.geocaching.connector;
import cgeo.geocaching.ICache;
+import cgeo.geocaching.R;
import cgeo.geocaching.SearchResult;
import cgeo.geocaching.Trackable;
import cgeo.geocaching.connector.capability.ISearchByCenter;
import cgeo.geocaching.connector.capability.ISearchByViewPort;
import cgeo.geocaching.connector.gc.GCConnector;
import cgeo.geocaching.connector.oc.OCApiConnector;
+import cgeo.geocaching.connector.oc.OCApiConnector.ApiSupport;
+import cgeo.geocaching.connector.oc.OCApiLiveConnector;
import cgeo.geocaching.connector.oc.OCConnector;
-import cgeo.geocaching.connector.oc.OCXMLApiConnector;
import cgeo.geocaching.connector.ox.OXConnector;
+import cgeo.geocaching.connector.trackable.GeokretyConnector;
+import cgeo.geocaching.connector.trackable.TrackableConnector;
+import cgeo.geocaching.connector.trackable.TravelBugConnector;
+import cgeo.geocaching.connector.trackable.UnknownTrackableConnector;
import cgeo.geocaching.geopoint.Viewport;
import org.apache.commons.lang3.StringUtils;
@@ -19,39 +25,47 @@ import java.util.List;
public final class ConnectorFactory {
private static final UnknownConnector UNKNOWN_CONNECTOR = new UnknownConnector();
- private static final IConnector[] connectors = new IConnector[] {
+ private static final IConnector[] CONNECTORS = new IConnector[] {
GCConnector.getInstance(),
- new OCXMLApiConnector("OpenCaching.DE", "www.opencaching.de", "OC"),
+ new OCApiLiveConnector("Opencaching.de", "www.opencaching.de", "OC", R.string.oc_de_okapi_consumer_key, R.string.oc_de_okapi_consumer_secret, ApiSupport.current),
new OCConnector("OpenCaching.CZ", "www.opencaching.cz", "OZ"),
- new OCApiConnector("OpenCaching.CO.UK", "www.opencaching.org.uk", "OK", "arU4okouc4GEjMniE2fq"),
+ new OCApiConnector("OpenCaching.CO.UK", "www.opencaching.org.uk", "OK", "arU4okouc4GEjMniE2fq", ApiSupport.oldapi),
new OCConnector("OpenCaching.ES", "www.opencachingspain.es", "OC"),
new OCConnector("OpenCaching.IT", "www.opencaching.it", "OC"),
new OCConnector("OpenCaching.JP", "www.opencaching.jp", "OJ"),
new OCConnector("OpenCaching.NO/SE", "www.opencaching.se", "OS"),
- new OCApiConnector("OpenCaching.NL", "www.opencaching.nl", "OB", "PdzU8jzIlcfMADXaYN8j"),
- new OCApiConnector("OpenCaching.PL", "www.opencaching.pl", "OP", "GkxM47WkUkLQXXsZ9qSh"),
- new OCApiConnector("OpenCaching.US", "www.opencaching.us", "OU", "pTsYAYSXFcfcRQnYE6uA"),
+ new OCApiConnector("OpenCaching.NL", "www.opencaching.nl", "OB", "PdzU8jzIlcfMADXaYN8j", ApiSupport.current),
+ new OCApiConnector("OpenCaching.PL", "www.opencaching.pl", "OP", "GkxM47WkUkLQXXsZ9qSh", ApiSupport.current),
+ new OCApiConnector("OpenCaching.US", "www.opencaching.us", "OU", "pTsYAYSXFcfcRQnYE6uA", ApiSupport.oldapi),
new OXConnector(),
new GeocachingAustraliaConnector(),
new GeopeitusConnector(),
+ new WaymarkingConnector(),
UNKNOWN_CONNECTOR // the unknown connector MUST be the last one
};
+ public static final UnknownTrackableConnector UNKNOWN_TRACKABLE_CONNECTOR = new UnknownTrackableConnector();
+ private static final TrackableConnector[] TRACKABLE_CONNECTORS = new TrackableConnector[] {
+ new GeokretyConnector(), // GK must be first, as it overlaps with the secret codes of travel bugs
+ new TravelBugConnector(),
+ UNKNOWN_TRACKABLE_CONNECTOR // must be last
+ };
+
private static final ISearchByViewPort[] searchByViewPortConns;
private static final ISearchByCenter[] searchByCenterConns;
static {
- List<ISearchByViewPort> vpConns = new ArrayList<ISearchByViewPort>();
- for (IConnector conn : connectors) {
+ final List<ISearchByViewPort> vpConns = new ArrayList<ISearchByViewPort>();
+ for (final IConnector conn : CONNECTORS) {
if (conn instanceof ISearchByViewPort) {
vpConns.add((ISearchByViewPort) conn);
}
}
searchByViewPortConns = vpConns.toArray(new ISearchByViewPort[vpConns.size()]);
- List<ISearchByCenter> centerConns = new ArrayList<ISearchByCenter>();
- for (IConnector conn : connectors) {
+ final List<ISearchByCenter> centerConns = new ArrayList<ISearchByCenter>();
+ for (final IConnector conn : CONNECTORS) {
// GCConnector is handled specially, omit it here!
if (conn instanceof ISearchByCenter && !(conn instanceof GCConnector)) {
centerConns.add((ISearchByCenter) conn);
@@ -61,7 +75,7 @@ public final class ConnectorFactory {
}
public static IConnector[] getConnectors() {
- return connectors;
+ return CONNECTORS;
}
public static ISearchByCenter[] getSearchByCenterConnectors() {
@@ -72,7 +86,7 @@ public final class ConnectorFactory {
if (isInvalidGeocode(geocode)) {
return false;
}
- for (IConnector connector : connectors) {
+ for (final IConnector connector : CONNECTORS) {
if (connector.canHandle(geocode)) {
return true;
}
@@ -84,8 +98,17 @@ public final class ConnectorFactory {
return getConnector(cache.getGeocode());
}
- public static IConnector getConnector(Trackable trackable) {
- return getConnector(trackable.getGeocode());
+ public static TrackableConnector getConnector(Trackable trackable) {
+ return getTrackableConnector(trackable.getGeocode());
+ }
+
+ public static TrackableConnector getTrackableConnector(String geocode) {
+ for (final TrackableConnector connector : TRACKABLE_CONNECTORS) {
+ if (connector.canHandleTrackable(geocode)) {
+ return connector;
+ }
+ }
+ return UNKNOWN_TRACKABLE_CONNECTOR; // avoid null checks by returning a non implementing connector
}
public static IConnector getConnector(final String geocodeInput) {
@@ -94,12 +117,12 @@ public final class ConnectorFactory {
if (isInvalidGeocode(geocode)) {
return UNKNOWN_CONNECTOR;
}
- for (IConnector connector : connectors) {
+ for (final IConnector connector : CONNECTORS) {
if (connector.canHandle(geocode)) {
return connector;
}
}
- // in case of errors, take UNKNOWN
+ // in case of errors, take UNKNOWN to avoid null checks everywhere
return UNKNOWN_CONNECTOR;
}
@@ -110,10 +133,10 @@ public final class ConnectorFactory {
/** @see ISearchByViewPort#searchByViewport */
public static SearchResult searchByViewport(final Viewport viewport, final String[] tokens) {
- SearchResult result = new SearchResult();
- for (ISearchByViewPort vpconn : searchByViewPortConns) {
+ final SearchResult result = new SearchResult();
+ for (final ISearchByViewPort vpconn : searchByViewPortConns) {
if (vpconn.isActivated()) {
- SearchResult temp = vpconn.searchByViewport(viewport, tokens);
+ final SearchResult temp = vpconn.searchByViewport(viewport, tokens);
if (temp != null) {
result.addGeocodes(temp.getGeocodes());
}
@@ -123,8 +146,8 @@ public final class ConnectorFactory {
}
public static String getGeocodeFromURL(final String url) {
- for (IConnector connector : connectors) {
- String geocode = connector.getGeocodeFromUrl(url);
+ for (final IConnector connector : CONNECTORS) {
+ final String geocode = connector.getGeocodeFromUrl(url);
if (StringUtils.isNotBlank(geocode)) {
return geocode;
}
@@ -132,4 +155,8 @@ public final class ConnectorFactory {
return null;
}
+ public static TrackableConnector[] getTrackableConnectors() {
+ return TRACKABLE_CONNECTORS;
+ }
+
}
diff --git a/main/src/cgeo/geocaching/connector/IConnector.java b/main/src/cgeo/geocaching/connector/IConnector.java
index 9169b4a..c44b946 100644
--- a/main/src/cgeo/geocaching/connector/IConnector.java
+++ b/main/src/cgeo/geocaching/connector/IConnector.java
@@ -2,9 +2,10 @@ package cgeo.geocaching.connector;
import cgeo.geocaching.Geocache;
import cgeo.geocaching.ICache;
-import cgeo.geocaching.enumerations.CacheRealm;
import cgeo.geocaching.geopoint.Geopoint;
+import android.app.Activity;
+
public interface IConnector {
/**
* get name for display (currently only used in links)
@@ -45,6 +46,22 @@ public interface IConnector {
public boolean supportsWatchList();
/**
+ * Add the cache to the watchlist
+ *
+ * @param cache
+ * @return True - success/False - failure
+ */
+ public boolean addToWatchlist(Geocache cache);
+
+ /**
+ * Remove the cache from the watchlist
+ *
+ * @param cache
+ * @return True - success/False - failure
+ */
+ public boolean removeFromWatchlist(Geocache cache);
+
+ /**
* enable/disable favorite points controls in cache details
*
* @return
@@ -59,6 +76,20 @@ public interface IConnector {
public boolean supportsLogging();
/**
+ * enable/disable attaching image to log
+ *
+ * @return
+ */
+ public boolean supportsLogImages();
+
+ /**
+ * Get an ILoggingManager to guide the logging process.
+ *
+ * @return
+ */
+ public ILoggingManager getLoggingManager(Activity activity, Geocache cache);
+
+ /**
* get host name of the connector server for dynamic loading of data
*
* @return
@@ -120,13 +151,12 @@ public interface IConnector {
public boolean supportsOwnCoordinates();
/**
- * Uploading modified coordinates to website
+ * Uploading personal note to website
*
* @param cache
- * @param wpt
* @return success
*/
- public boolean uploadModifiedCoordinates(Geocache cache, Geopoint wpt);
+ public boolean uploadPersonalNote(Geocache cache);
/**
* Reseting of modified coordinates on website to details
@@ -137,11 +167,13 @@ public interface IConnector {
public boolean deleteModifiedCoordinates(Geocache cache);
/**
- * The CacheRealm this cache belongs to
+ * Uploading modified coordinates to website
*
- * @return
+ * @param cache
+ * @param wpt
+ * @return success
*/
- public CacheRealm getCacheRealm();
+ public boolean uploadModifiedCoordinates(Geocache cache, Geopoint wpt);
/**
* Return true if this connector is activated for online
@@ -159,4 +191,22 @@ public interface IConnector {
* @return <code>true</code> if the current user is the cache owner, <code>false</code> otherwise
*/
public boolean isOwner(final ICache cache);
+
+ /**
+ * Check if the cache information is complete enough to be
+ * able to log online.
+ *
+ * @param geocache
+ * @return
+ */
+ public boolean canLog(Geocache geocache);
+
+ /**
+ * Return the marker id of the caches for this connector. This creates the different backgrounds for cache markers
+ * on the map.
+ *
+ * @param disabled
+ * Whether to return the enabled or disabled marker type
+ */
+ public int getCacheMapMarkerId(boolean disabled);
}
diff --git a/main/src/cgeo/geocaching/connector/ILoggingManager.java b/main/src/cgeo/geocaching/connector/ILoggingManager.java
new file mode 100644
index 0000000..f0029f9
--- /dev/null
+++ b/main/src/cgeo/geocaching/connector/ILoggingManager.java
@@ -0,0 +1,32 @@
+package cgeo.geocaching.connector;
+
+import cgeo.geocaching.Geocache;
+import cgeo.geocaching.TrackableLog;
+import cgeo.geocaching.enumerations.LogType;
+
+import android.net.Uri;
+
+import java.util.Calendar;
+import java.util.List;
+
+public interface ILoggingManager {
+
+ LogResult postLog(Geocache cache,
+ LogType logType,
+ Calendar date,
+ String log,
+ List<TrackableLog> trackableLogs);
+
+ ImageResult postLogImage(String logId,
+ String imageCaption,
+ String imageDescription,
+ Uri imageUri);
+
+ public boolean hasLoaderError();
+
+ public List<TrackableLog> getTrackables();
+
+ public List<LogType> getPossibleLogTypes();
+
+ public void init();
+}
diff --git a/main/src/cgeo/geocaching/connector/ImageResult.java b/main/src/cgeo/geocaching/connector/ImageResult.java
new file mode 100644
index 0000000..9314cad
--- /dev/null
+++ b/main/src/cgeo/geocaching/connector/ImageResult.java
@@ -0,0 +1,23 @@
+package cgeo.geocaching.connector;
+
+import cgeo.geocaching.enumerations.StatusCode;
+
+public class ImageResult {
+
+ private final StatusCode postResult;
+ private final String imageUri;
+
+ public ImageResult(StatusCode postResult, String imageUri) {
+ this.postResult = postResult;
+ this.imageUri = imageUri;
+ }
+
+ public StatusCode getPostResult() {
+ return postResult;
+ }
+
+ public String getImageUri() {
+ return imageUri;
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/connector/LogResult.java b/main/src/cgeo/geocaching/connector/LogResult.java
new file mode 100644
index 0000000..62111a4
--- /dev/null
+++ b/main/src/cgeo/geocaching/connector/LogResult.java
@@ -0,0 +1,23 @@
+package cgeo.geocaching.connector;
+
+import cgeo.geocaching.enumerations.StatusCode;
+
+public class LogResult {
+
+ private final StatusCode postLogResult;
+ private final String logId;
+
+ public LogResult(StatusCode postLogResult, String logId) {
+ this.postLogResult = postLogResult;
+ this.logId = logId;
+ }
+
+ public StatusCode getPostLogResult() {
+ return postLogResult;
+ }
+
+ public String getLogId() {
+ return logId;
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/connector/NoLoggingManager.java b/main/src/cgeo/geocaching/connector/NoLoggingManager.java
new file mode 100644
index 0000000..bfea4ca
--- /dev/null
+++ b/main/src/cgeo/geocaching/connector/NoLoggingManager.java
@@ -0,0 +1,46 @@
+package cgeo.geocaching.connector;
+
+import cgeo.geocaching.Geocache;
+import cgeo.geocaching.TrackableLog;
+import cgeo.geocaching.enumerations.LogType;
+import cgeo.geocaching.enumerations.StatusCode;
+
+import android.net.Uri;
+
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.List;
+
+public class NoLoggingManager implements ILoggingManager {
+
+ @Override
+ public void init() {
+ // nothing to do
+ }
+
+ @Override
+ public LogResult postLog(Geocache cache, LogType logType, Calendar date, String log, List<TrackableLog> trackableLogs) {
+ return new LogResult(StatusCode.LOG_POST_ERROR, "");
+ }
+
+ @Override
+ public ImageResult postLogImage(String logId, String imageCaption, String imageDescription, Uri imageUri) {
+ return new ImageResult(StatusCode.LOG_POST_ERROR, "");
+ }
+
+ @Override
+ public boolean hasLoaderError() {
+ return true;
+ }
+
+ @Override
+ public List<TrackableLog> getTrackables() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public List<LogType> getPossibleLogTypes() {
+ return Collections.emptyList();
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/connector/UnknownConnector.java b/main/src/cgeo/geocaching/connector/UnknownConnector.java
index b6fc29a..e9fecb9 100644
--- a/main/src/cgeo/geocaching/connector/UnknownConnector.java
+++ b/main/src/cgeo/geocaching/connector/UnknownConnector.java
@@ -1,7 +1,7 @@
package cgeo.geocaching.connector;
-import cgeo.geocaching.ICache;
import cgeo.geocaching.Geocache;
+import cgeo.geocaching.ICache;
import org.apache.commons.lang3.StringUtils;
@@ -36,4 +36,5 @@ public class UnknownConnector extends AbstractConnector {
protected String getCacheUrlPrefix() {
return null;
}
+
}
diff --git a/main/src/cgeo/geocaching/connector/WaymarkingConnector.java b/main/src/cgeo/geocaching/connector/WaymarkingConnector.java
new file mode 100644
index 0000000..f184f6e
--- /dev/null
+++ b/main/src/cgeo/geocaching/connector/WaymarkingConnector.java
@@ -0,0 +1,40 @@
+package cgeo.geocaching.connector;
+
+import cgeo.geocaching.Geocache;
+import cgeo.geocaching.ICache;
+
+import org.apache.commons.lang3.StringUtils;
+
+public class WaymarkingConnector extends AbstractConnector {
+
+ @Override
+ public String getName() {
+ return "Waymarking";
+ }
+
+ @Override
+ public String getCacheUrl(Geocache cache) {
+ return getCacheUrlPrefix() + cache.getGeocode();
+ }
+
+ @Override
+ public String getHost() {
+ return "www.waymarking.com";
+ }
+
+ @Override
+ public boolean isOwner(ICache cache) {
+ // this connector has no user management
+ return false;
+ }
+
+ @Override
+ protected String getCacheUrlPrefix() {
+ return "http://" + getHost() + "/waymarks/";
+ }
+
+ @Override
+ public boolean canHandle(String geocode) {
+ return StringUtils.startsWith(geocode, "WM");
+ }
+}
diff --git a/main/src/cgeo/geocaching/connector/gc/GCConnector.java b/main/src/cgeo/geocaching/connector/gc/GCConnector.java
index 50bf096..fab4332 100644
--- a/main/src/cgeo/geocaching/connector/gc/GCConnector.java
+++ b/main/src/cgeo/geocaching/connector/gc/GCConnector.java
@@ -7,10 +7,10 @@ import cgeo.geocaching.SearchResult;
import cgeo.geocaching.Settings;
import cgeo.geocaching.cgData;
import cgeo.geocaching.connector.AbstractConnector;
+import cgeo.geocaching.connector.ILoggingManager;
import cgeo.geocaching.connector.capability.ISearchByCenter;
import cgeo.geocaching.connector.capability.ISearchByGeocode;
import cgeo.geocaching.connector.capability.ISearchByViewPort;
-import cgeo.geocaching.enumerations.CacheRealm;
import cgeo.geocaching.enumerations.StatusCode;
import cgeo.geocaching.geopoint.Geopoint;
import cgeo.geocaching.geopoint.Viewport;
@@ -20,6 +20,8 @@ import cgeo.geocaching.utils.Log;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
+import android.app.Activity;
+
import java.util.regex.Pattern;
public class GCConnector extends AbstractConnector implements ISearchByGeocode, ISearchByCenter, ISearchByViewPort {
@@ -27,7 +29,16 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode,
private static final String CACHE_URL_SHORT = "http://coord.info/";
// Double slash is used to force open in browser
private static final String CACHE_URL_LONG = "http://www.geocaching.com//seek/cache_details.aspx?wp=";
- private static final Pattern gpxZipFilePattern = Pattern.compile("\\d{7,}(_.+)?\\.zip", Pattern.CASE_INSENSITIVE);
+ /**
+ * Pocket queries downloaded from the website use a numeric prefix. The pocket query creator Android app adds a
+ * verbatim "pocketquery" prefix.
+ */
+ private static final Pattern gpxZipFilePattern = Pattern.compile("((\\d{7,})|(pocketquery))" + "(_.+)?" + "\\.zip", Pattern.CASE_INSENSITIVE);
+
+ /**
+ * Pattern for GC codes
+ */
+ private final static Pattern PATTERN_GC_CODE = Pattern.compile("GC[0-9A-Z]+", Pattern.CASE_INSENSITIVE);
private GCConnector() {
// singleton
@@ -49,7 +60,7 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode,
if (geocode == null) {
return false;
}
- return GCConstants.PATTERN_GC_CODE.matcher(geocode).matches() || GCConstants.PATTERN_TB_CODE.matcher(geocode).matches();
+ return GCConnector.PATTERN_GC_CODE.matcher(geocode).matches();
}
@Override
@@ -78,6 +89,21 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode,
}
@Override
+ public boolean supportsLogImages() {
+ return true;
+ }
+
+ @Override
+ public ILoggingManager getLoggingManager(Activity activity, Geocache cache) {
+ return new GCLoggingManager(activity, cache);
+ }
+
+ @Override
+ public boolean canLog(Geocache cache) {
+ return StringUtils.isNotBlank(cache.getCacheId());
+ }
+
+ @Override
public String getName() {
return "GeoCaching.com";
}
@@ -149,7 +175,8 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode,
}
- public static boolean addToWatchlist(Geocache cache) {
+ @Override
+ public boolean addToWatchlist(Geocache cache) {
final boolean added = GCParser.addToWatchlist(cache);
if (added) {
cgData.saveChangedCache(cache);
@@ -157,7 +184,8 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode,
return added;
}
- public static boolean removeFromWatchlist(Geocache cache) {
+ @Override
+ public boolean removeFromWatchlist(Geocache cache) {
final boolean removed = GCParser.removeFromWatchlist(cache);
if (removed) {
cgData.saveChangedCache(cache);
@@ -218,6 +246,15 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode,
}
@Override
+ public boolean uploadPersonalNote(Geocache cache) {
+ final boolean uploaded = GCParser.uploadPersonalNote(cache);
+ if (uploaded) {
+ cgData.saveChangedCache(cache);
+ }
+ return uploaded;
+ }
+
+ @Override
public SearchResult searchByCenter(Geopoint center) {
// TODO make search by coordinate use this method. currently it is just a marker that this connector supports search by center
return null;
@@ -234,12 +271,15 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode,
}
@Override
- public CacheRealm getCacheRealm() {
- return CacheRealm.GC;
+ public boolean isActivated() {
+ return Settings.isGCConnectorActive();
}
@Override
- public boolean isActivated() {
- return true;
+ public int getCacheMapMarkerId(boolean disabled) {
+ if (disabled) {
+ return R.drawable.marker_disabled;
+ }
+ return R.drawable.marker;
}
}
diff --git a/main/src/cgeo/geocaching/connector/gc/GCConstants.java b/main/src/cgeo/geocaching/connector/gc/GCConstants.java
index b66acb7..f2e2e69 100644
--- a/main/src/cgeo/geocaching/connector/gc/GCConstants.java
+++ b/main/src/cgeo/geocaching/connector/gc/GCConstants.java
@@ -84,6 +84,7 @@ public final class GCConstants {
public final static String ERROR_TB_DOES_NOT_EXIST = "does not exist in the system";
public final static String ERROR_TB_ELEMENT_EXCEPTION = "ElementNotFound Exception";
public final static String ERROR_TB_ARITHMETIC_OVERFLOW = "operation resulted in an overflow";
+ public final static String ERROR_TB_NOT_ACTIVATED = "hasn't been activated";
/**
* some parts of the webpage don't correctly encode the name, therefore this pattern must be checked with a
* trackable name that needs HTML encoding
@@ -152,17 +153,11 @@ public final class GCConstants {
public final static Pattern PATTERN_MAINTENANCE = Pattern.compile("<span id=\"ctl00_ContentBody_LogBookPanel1_lbConfirm\"[^>]*>([^<]*<font[^>]*>)?([^<]+)(</font>[^<]*)?</span>", Pattern.CASE_INSENSITIVE);
public final static Pattern PATTERN_OK1 = Pattern.compile("<h2[^>]*>[^<]*<span id=\"ctl00_ContentBody_lbHeading\"[^>]*>[^<]*</span>[^<]*</h2>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
public final static Pattern PATTERN_OK2 = Pattern.compile("<div id=[\"|']ctl00_ContentBody_LogBookPanel1_ViewLogPanel[\"|']>", Pattern.CASE_INSENSITIVE);
- public final static Pattern PATTERN_OK_IMAGEUPLOAD = Pattern.compile("<div id=[\"|']ctl00_ContentBody_ImageUploadControl1_uxUploadDonePanel[\"|']>", Pattern.CASE_INSENSITIVE);
+ public final static Pattern PATTERN_IMAGE_UPLOAD_URL = Pattern.compile("title=\"Click for Larger Image\"\\s*src=\"(.*?)\"", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
public final static Pattern PATTERN_VIEWSTATEFIELDCOUNT = Pattern.compile("id=\"__VIEWSTATEFIELDCOUNT\"[^(value)]+value=\"(\\d+)\"[^>]+>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
public final static Pattern PATTERN_VIEWSTATES = Pattern.compile("id=\"__VIEWSTATE(\\d*)\"[^(value)]+value=\"([^\"]+)\"[^>]+>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
public final static Pattern PATTERN_USERTOKEN = Pattern.compile("userToken\\s*=\\s*'([^']+)'");
- /**
- * Patterns for GC and TB codes
- */
- public final static Pattern PATTERN_GC_CODE = Pattern.compile("GC[0-9A-Z]+", Pattern.CASE_INSENSITIVE);
- public final static Pattern PATTERN_TB_CODE = Pattern.compile("TB[0-9A-Z]+", Pattern.CASE_INSENSITIVE);
-
/** Live Map since 14.02.2012 */
public final static Pattern PATTERN_USERSESSION = Pattern.compile("UserSession\\('([^']+)'");
public final static Pattern PATTERN_SESSIONTOKEN = Pattern.compile("sessionToken:'([^']+)'");
@@ -194,7 +189,7 @@ public final class GCConstants {
*/
public static long gccodeToGCId(final String gccode) {
long base = GC_BASE31;
- String geocodeWO = gccode.substring(2).toUpperCase(Locale.US);
+ final String geocodeWO = gccode.substring(2).toUpperCase(Locale.US);
if ((geocodeWO.length() < 4) || (geocodeWO.length() == 4 && SEQUENCE_GCID.indexOf(geocodeWO.charAt(0)) < 16)) {
base = GC_BASE16;
diff --git a/main/src/cgeo/geocaching/connector/gc/GCLoggingManager.java b/main/src/cgeo/geocaching/connector/gc/GCLoggingManager.java
new file mode 100644
index 0000000..4f2f8c4
--- /dev/null
+++ b/main/src/cgeo/geocaching/connector/gc/GCLoggingManager.java
@@ -0,0 +1,132 @@
+package cgeo.geocaching.connector.gc;
+
+import cgeo.geocaching.Geocache;
+import cgeo.geocaching.R;
+import cgeo.geocaching.Settings;
+import cgeo.geocaching.TrackableLog;
+import cgeo.geocaching.LogCacheActivity;
+import cgeo.geocaching.activity.ActivityMixin;
+import cgeo.geocaching.connector.ILoggingManager;
+import cgeo.geocaching.connector.ImageResult;
+import cgeo.geocaching.connector.LogResult;
+import cgeo.geocaching.enumerations.LogType;
+import cgeo.geocaching.enumerations.StatusCode;
+import cgeo.geocaching.loaders.UrlLoader;
+import cgeo.geocaching.network.Parameters;
+import cgeo.geocaching.utils.Log;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.tuple.ImmutablePair;
+
+import android.app.Activity;
+import android.net.Uri;
+import android.os.Bundle;
+import android.support.v4.app.LoaderManager;
+import android.support.v4.content.Loader;
+
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.List;
+
+public class GCLoggingManager implements ILoggingManager, LoaderManager.LoaderCallbacks<String> {
+
+ private final LogCacheActivity activity;
+ private final Geocache cache;
+
+ private String[] viewstates;
+ private List<TrackableLog> trackables;
+ private List<LogType> possibleLogTypes;
+ private boolean hasLoaderError = true;
+
+ public GCLoggingManager(Activity activity, Geocache cache) {
+ this.activity = (LogCacheActivity) activity;
+ this.cache = cache;
+ }
+
+ @Override
+ public Loader<String> onCreateLoader(int arg0, Bundle arg1) {
+ if (!Settings.isLogin()) { // allow offline logging
+ ActivityMixin.showToast(activity, activity.getResources().getString(R.string.err_login));
+ return null;
+ }
+ return new UrlLoader(activity.getBaseContext(), "http://www.geocaching.com/seek/log.aspx", new Parameters("ID", cache.getCacheId()));
+ }
+
+ @Override
+ public void onLoadFinished(Loader<String> arg0, String page) {
+
+ if (page == null) {
+ hasLoaderError = true;
+ } else {
+
+ viewstates = Login.getViewstates(page);
+ trackables = GCParser.parseTrackableLog(page);
+ possibleLogTypes = GCParser.parseTypes(page);
+
+ hasLoaderError = possibleLogTypes.isEmpty();
+ }
+
+ activity.onLoadFinished();
+ }
+
+ @Override
+ public void onLoaderReset(Loader<String> arg0) {
+ // nothing to do
+ }
+
+ @Override
+ public void init() {
+ activity.getSupportLoaderManager().initLoader(0, null, this);
+ }
+
+ @Override
+ public LogResult postLog(Geocache cache, LogType logType, Calendar date, String log, List<TrackableLog> trackableLogs) {
+
+ try {
+ final ImmutablePair<StatusCode, String> postResult = GCParser.postLog(cache.getGeocode(), cache.getCacheId(), viewstates, logType,
+ date.get(Calendar.YEAR), (date.get(Calendar.MONTH) + 1), date.get(Calendar.DATE),
+ log, trackableLogs);
+
+ return new LogResult(postResult.left, postResult.right);
+ } catch (Exception e) {
+ Log.e("GCLoggingManager.postLog", e);
+ }
+
+ return new LogResult(StatusCode.LOG_POST_ERROR, "");
+ }
+
+ @Override
+ public ImageResult postLogImage(String logId, String imageCaption, String imageDescription, Uri imageUri) {
+
+ if (StringUtils.isNotBlank(imageUri.getPath())) {
+
+ ImmutablePair<StatusCode, String> imageResult = GCParser.uploadLogImage(logId, imageCaption, imageDescription, imageUri);
+
+ return new ImageResult(imageResult.left, imageResult.right);
+ }
+
+ return new ImageResult(StatusCode.LOGIMAGE_POST_ERROR, "");
+ }
+
+ @Override
+ public boolean hasLoaderError() {
+ return hasLoaderError;
+ }
+
+ @Override
+ public List<TrackableLog> getTrackables() {
+ if (hasLoaderError) {
+ return Collections.emptyList();
+ }
+ return trackables;
+ }
+
+ @Override
+ public List<LogType> getPossibleLogTypes() {
+ if (hasLoaderError) {
+ return Collections.emptyList();
+ }
+ return possibleLogTypes;
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/connector/gc/GCMap.java b/main/src/cgeo/geocaching/connector/gc/GCMap.java
index 49f61ef..643caf5 100644
--- a/main/src/cgeo/geocaching/connector/gc/GCMap.java
+++ b/main/src/cgeo/geocaching/connector/gc/GCMap.java
@@ -92,7 +92,7 @@ public class GCMap {
JSONObject ownerObj = dataObject.getJSONObject("owner");
cache.setOwnerDisplayName(ownerObj.getString("text"));
- result.addCache(cache);
+ result.addAndPutInCache(cache);
}
} catch (JSONException e) {
@@ -231,13 +231,13 @@ public class GCMap {
exclude = true;
}
if (!exclude) {
- searchResult.addCache(cache);
+ searchResult.addAndPutInCache(cache);
}
}
Log.d("Retrieved " + searchResult.getCount() + " caches for tile " + tile.toString());
} catch (Exception e) {
- Log.e("GCBase.parseMapJSON", e);
+ Log.e("GCMap.parseMapJSON", e);
}
return searchResult;
@@ -283,7 +283,7 @@ public class GCMap {
* @return
*/
private static SearchResult searchByViewport(final Viewport viewport, final String[] tokens, Strategy strategy) {
- Log.d("GCBase.searchByViewport" + viewport.toString());
+ Log.d("GCMap.searchByViewport" + viewport.toString());
final SearchResult searchResult = new SearchResult();
searchResult.setUrl(GCConstants.URL_LIVE_MAP + "?ll=" + viewport.getCenter().getLatitude() + "," + viewport.getCenter().getLongitude());
@@ -330,11 +330,11 @@ public class GCMap {
String data = Tile.requestMapInfo(GCConstants.URL_MAP_INFO, params, GCConstants.URL_LIVE_MAP);
if (StringUtils.isEmpty(data)) {
- Log.w("GCBase.searchByViewport: No data from server for tile (" + tile.getX() + "/" + tile.getY() + ")");
+ Log.w("GCMap.searchByViewport: No data from server for tile (" + tile.getX() + "/" + tile.getY() + ")");
} else {
final SearchResult search = GCMap.parseMapJSON(data, tile, bitmap, strategy);
if (search == null || CollectionUtils.isEmpty(search.getGeocodes())) {
- Log.e("GCBase.searchByViewport: No cache parsed for viewport " + viewport);
+ Log.e("GCMap.searchByViewport: No cache parsed for viewport " + viewport);
}
else {
searchResult.addGeocodes(search.getGeocodes());
diff --git a/main/src/cgeo/geocaching/connector/gc/GCParser.java b/main/src/cgeo/geocaching/connector/gc/GCParser.java
index 6b456fd..3e26eb2 100644
--- a/main/src/cgeo/geocaching/connector/gc/GCParser.java
+++ b/main/src/cgeo/geocaching/connector/gc/GCParser.java
@@ -28,10 +28,10 @@ import cgeo.geocaching.loaders.RecaptchaReceiver;
import cgeo.geocaching.network.Network;
import cgeo.geocaching.network.Parameters;
import cgeo.geocaching.ui.DirectionImage;
-import cgeo.geocaching.utils.BaseUtils;
import cgeo.geocaching.utils.CancellableHandler;
import cgeo.geocaching.utils.Log;
import cgeo.geocaching.utils.MatcherWrapper;
+import cgeo.geocaching.utils.TextUtils;
import ch.boye.httpclientandroidlib.HttpResponse;
@@ -79,14 +79,14 @@ public abstract class GCParser {
// recaptcha
String recaptchaChallenge = null;
if (showCaptcha) {
- String recaptchaJsParam = BaseUtils.getMatch(page, GCConstants.PATTERN_SEARCH_RECAPTCHA, false, null);
+ final String recaptchaJsParam = TextUtils.getMatch(page, GCConstants.PATTERN_SEARCH_RECAPTCHA, false, null);
if (recaptchaJsParam != null) {
final Parameters params = new Parameters("k", recaptchaJsParam.trim());
final String recaptchaJs = Network.getResponseData(Network.getRequest("http://www.google.com/recaptcha/api/challenge", params));
if (StringUtils.isNotBlank(recaptchaJs)) {
- recaptchaChallenge = BaseUtils.getMatch(recaptchaJs, GCConstants.PATTERN_SEARCH_RECAPTCHACHALLENGE, true, 1, null, true);
+ recaptchaChallenge = TextUtils.getMatch(recaptchaJs, GCConstants.PATTERN_SEARCH_RECAPTCHACHALLENGE, true, 1, null, true);
}
}
if (thread != null && StringUtils.isNotBlank(recaptchaChallenge)) {
@@ -109,7 +109,7 @@ public abstract class GCParser {
page = page.substring(startPos); // cut on <table
startPos = page.indexOf('>');
- int endPos = page.indexOf("ctl00_ContentBody_UnitTxt");
+ final int endPos = page.indexOf("ctl00_ContentBody_UnitTxt");
if (startPos == -1 || endPos == -1) {
Log.e("GCParser.parseSearch: ID \"ctl00_ContentBody_UnitTxt\" not found on page");
return null;
@@ -122,7 +122,7 @@ public abstract class GCParser {
for (int z = 1; z < rows_count; z++) {
final Geocache cache = new Geocache();
- String row = rows[z];
+ final String row = rows[z];
// check for cache type presence
if (!row.contains("images/wpttypes")) {
@@ -150,7 +150,7 @@ public abstract class GCParser {
}
}
}
- } catch (Exception e) {
+ } catch (final Exception e) {
// failed to parse GUID and/or Disabled
Log.w("GCParser.parseSearch: Failed to parse GUID and/or Disabled data");
}
@@ -160,21 +160,21 @@ public abstract class GCParser {
continue;
}
- cache.setGeocode(BaseUtils.getMatch(row, GCConstants.PATTERN_SEARCH_GEOCODE, true, 1, cache.getGeocode(), true));
+ cache.setGeocode(TextUtils.getMatch(row, GCConstants.PATTERN_SEARCH_GEOCODE, true, 1, cache.getGeocode(), true));
// cache type
- cache.setType(CacheType.getByPattern(BaseUtils.getMatch(row, GCConstants.PATTERN_SEARCH_TYPE, true, 1, null, true)));
+ cache.setType(CacheType.getByPattern(TextUtils.getMatch(row, GCConstants.PATTERN_SEARCH_TYPE, true, 1, null, true)));
// cache direction - image
if (Settings.getLoadDirImg()) {
- final String direction = BaseUtils.getMatch(row, GCConstants.PATTERN_SEARCH_DIRECTION_DISTANCE, false, 1, null, false);
+ final String direction = TextUtils.getMatch(row, GCConstants.PATTERN_SEARCH_DIRECTION_DISTANCE, false, 1, null, false);
if (direction != null) {
cache.setDirectionImg(direction);
}
}
// cache distance - estimated distance for basic members
- final String distance = BaseUtils.getMatch(row, GCConstants.PATTERN_SEARCH_DIRECTION_DISTANCE, false, 2, null, false);
+ final String distance = TextUtils.getMatch(row, GCConstants.PATTERN_SEARCH_DIRECTION_DISTANCE, false, 2, null, false);
if (distance != null) {
cache.setDistance(DistanceParser.parseDistance(distance, Settings.isUseMetricUnits()));
}
@@ -193,7 +193,7 @@ public abstract class GCParser {
}
// size
- final String container = BaseUtils.getMatch(row, GCConstants.PATTERN_SEARCH_CONTAINER, false, 1, null, false);
+ final String container = TextUtils.getMatch(row, GCConstants.PATTERN_SEARCH_CONTAINER, false, 1, null, false);
cache.setSize(CacheSize.getById(container));
// cache inventory
@@ -203,7 +203,7 @@ public abstract class GCParser {
if (matcherTbs.groupCount() > 0) {
try {
cache.setInventoryItems(Integer.parseInt(matcherTbs.group(1)));
- } catch (NumberFormatException e) {
+ } catch (final NumberFormatException e) {
Log.e("Error parsing trackables count", e);
}
inventoryPre = matcherTbs.group(2);
@@ -229,7 +229,7 @@ public abstract class GCParser {
cache.setFound(row.contains("/images/icons/16/found.png"));
// id
- String result = BaseUtils.getMatch(row, GCConstants.PATTERN_SEARCH_ID, null);
+ String result = TextUtils.getMatch(row, GCConstants.PATTERN_SEARCH_ID, null);
if (null != result) {
cache.setCacheId(result);
cids.add(cache.getCacheId());
@@ -237,24 +237,24 @@ public abstract class GCParser {
// favorite count
try {
- result = BaseUtils.getMatch(row, GCConstants.PATTERN_SEARCH_FAVORITE, false, 1, null, true);
+ result = TextUtils.getMatch(row, GCConstants.PATTERN_SEARCH_FAVORITE, false, 1, null, true);
if (null != result) {
cache.setFavoritePoints(Integer.parseInt(result));
}
- } catch (NumberFormatException e) {
- Log.w("GCParser.parseSearch: Failed to parse favourite count");
+ } catch (final NumberFormatException e) {
+ Log.w("GCParser.parseSearch: Failed to parse favorite count");
}
- searchResult.addCache(cache);
+ searchResult.addAndPutInCache(cache);
}
// total caches found
try {
- String result = BaseUtils.getMatch(page, GCConstants.PATTERN_SEARCH_TOTALCOUNT, false, 1, null, true);
+ final String result = TextUtils.getMatch(page, GCConstants.PATTERN_SEARCH_TOTALCOUNT, false, 1, null, true);
if (null != result) {
searchResult.setTotal(Integer.parseInt(result));
}
- } catch (NumberFormatException e) {
+ } catch (final NumberFormatException e) {
Log.w("GCParser.parseSearch: Failed to parse cache count");
}
@@ -284,7 +284,7 @@ public abstract class GCParser {
params.put("__VIEWSTATEFIELDCOUNT", String.valueOf(searchResult.viewstates.length));
}
}
- for (String cid : cids) {
+ for (final String cid : cids) {
params.put("CID", cid);
}
@@ -308,7 +308,7 @@ public abstract class GCParser {
LocParser.parseLoc(searchResult, coordinates);
- } catch (Exception e) {
+ } catch (final Exception e) {
Log.e("GCParser.parseSearch.CIDs", e);
}
}
@@ -316,7 +316,7 @@ public abstract class GCParser {
// get direction images
if (Settings.getLoadDirImg()) {
final Set<Geocache> caches = searchResult.getCachesFromSearchResult(LoadFlags.LOAD_CACHE_OR_DB);
- for (Geocache cache : caches) {
+ for (final Geocache cache : caches) {
if (cache.getCoords() == null && StringUtils.isNotEmpty(cache.getDirectionImg())) {
DirectionImage.getDrawable(cache.getDirectionImg());
}
@@ -327,15 +327,17 @@ public abstract class GCParser {
}
private static Float parseStars(final String value) {
- float floatValue = Float.parseFloat(StringUtils.replaceChars(value, ',', '.'));
+ final float floatValue = Float.parseFloat(StringUtils.replaceChars(value, ',', '.'));
return floatValue >= 0.5 && floatValue <= 5.0 ? floatValue : null;
}
static SearchResult parseCache(final String page, final CancellableHandler handler) {
final SearchResult searchResult = parseCacheFromText(page, handler);
+ // attention: parseCacheFromText already stores implicitely through searchResult.addCache
if (searchResult != null && !searchResult.getGeocodes().isEmpty()) {
final Geocache cache = searchResult.getFirstCacheFromResult(LoadFlags.LOAD_CACHE_OR_DB);
getExtraOnlineInfo(cache, page, handler);
+ // too late: it is already stored through parseCacheFromText
cache.setDetailedUpdatedNow();
if (CancellableHandler.isCancelled(handler)) {
return null;
@@ -372,7 +374,7 @@ public abstract class GCParser {
return searchResult;
}
- final String cacheName = Html.fromHtml(BaseUtils.getMatch(page, GCConstants.PATTERN_NAME, true, "")).toString();
+ final String cacheName = Html.fromHtml(TextUtils.getMatch(page, GCConstants.PATTERN_NAME, true, "")).toString();
if (GCConstants.STRING_UNKNOWN_ERROR.equalsIgnoreCase(cacheName)) {
searchResult.setError(StatusCode.UNKNOWN_ERROR);
return searchResult;
@@ -383,30 +385,30 @@ public abstract class GCParser {
cache.setArchived(page.contains(GCConstants.STRING_ARCHIVED));
- cache.setPremiumMembersOnly(BaseUtils.matches(page, GCConstants.PATTERN_PREMIUMMEMBERS));
+ cache.setPremiumMembersOnly(TextUtils.matches(page, GCConstants.PATTERN_PREMIUMMEMBERS));
- cache.setFavorite(BaseUtils.matches(page, GCConstants.PATTERN_FAVORITE));
+ cache.setFavorite(TextUtils.matches(page, GCConstants.PATTERN_FAVORITE));
// cache geocode
- cache.setGeocode(BaseUtils.getMatch(page, GCConstants.PATTERN_GEOCODE, true, cache.getGeocode()));
+ cache.setGeocode(TextUtils.getMatch(page, GCConstants.PATTERN_GEOCODE, true, cache.getGeocode()));
// cache id
- cache.setCacheId(BaseUtils.getMatch(page, GCConstants.PATTERN_CACHEID, true, cache.getCacheId()));
+ cache.setCacheId(TextUtils.getMatch(page, GCConstants.PATTERN_CACHEID, true, cache.getCacheId()));
// cache guid
- cache.setGuid(BaseUtils.getMatch(page, GCConstants.PATTERN_GUID, true, cache.getGuid()));
+ cache.setGuid(TextUtils.getMatch(page, GCConstants.PATTERN_GUID, true, cache.getGuid()));
// name
cache.setName(cacheName);
// owner real name
- cache.setOwnerUserId(Network.decode(BaseUtils.getMatch(page, GCConstants.PATTERN_OWNER_USERID, true, cache.getOwnerUserId())));
+ cache.setOwnerUserId(Network.decode(TextUtils.getMatch(page, GCConstants.PATTERN_OWNER_USERID, true, cache.getOwnerUserId())));
cache.setUserModifiedCoords(false);
String tableInside = page;
- int pos = tableInside.indexOf(GCConstants.STRING_CACHEDETAILS);
+ final int pos = tableInside.indexOf(GCConstants.STRING_CACHEDETAILS);
if (pos == -1) {
Log.e("GCParser.parseCache: ID \"cacheDetails\" not found on page");
return null;
@@ -416,96 +418,96 @@ public abstract class GCParser {
if (StringUtils.isNotBlank(tableInside)) {
// cache terrain
- String result = BaseUtils.getMatch(tableInside, GCConstants.PATTERN_TERRAIN, true, null);
+ String result = TextUtils.getMatch(tableInside, GCConstants.PATTERN_TERRAIN, true, null);
if (result != null) {
try {
cache.setTerrain(Float.parseFloat(StringUtils.replaceChars(result, '_', '.')));
- } catch (NumberFormatException e) {
+ } catch (final NumberFormatException e) {
Log.e("Error parsing terrain value", e);
}
}
// cache difficulty
- result = BaseUtils.getMatch(tableInside, GCConstants.PATTERN_DIFFICULTY, true, null);
+ result = TextUtils.getMatch(tableInside, GCConstants.PATTERN_DIFFICULTY, true, null);
if (result != null) {
try {
cache.setDifficulty(Float.parseFloat(StringUtils.replaceChars(result, '_', '.')));
- } catch (NumberFormatException e) {
+ } catch (final NumberFormatException e) {
Log.e("Error parsing difficulty value", e);
}
}
// owner
- cache.setOwnerDisplayName(StringEscapeUtils.unescapeHtml4(BaseUtils.getMatch(tableInside, GCConstants.PATTERN_OWNER_DISPLAYNAME, true, cache.getOwnerDisplayName())));
+ cache.setOwnerDisplayName(StringEscapeUtils.unescapeHtml4(TextUtils.getMatch(tableInside, GCConstants.PATTERN_OWNER_DISPLAYNAME, true, cache.getOwnerDisplayName())));
// hidden
try {
- String hiddenString = BaseUtils.getMatch(tableInside, GCConstants.PATTERN_HIDDEN, true, null);
+ String hiddenString = TextUtils.getMatch(tableInside, GCConstants.PATTERN_HIDDEN, true, null);
if (StringUtils.isNotBlank(hiddenString)) {
cache.setHidden(Login.parseGcCustomDate(hiddenString));
}
if (cache.getHiddenDate() == null) {
// event date
- hiddenString = BaseUtils.getMatch(tableInside, GCConstants.PATTERN_HIDDENEVENT, true, null);
+ hiddenString = TextUtils.getMatch(tableInside, GCConstants.PATTERN_HIDDENEVENT, true, null);
if (StringUtils.isNotBlank(hiddenString)) {
cache.setHidden(Login.parseGcCustomDate(hiddenString));
}
}
- } catch (ParseException e) {
+ } catch (final ParseException e) {
// failed to parse cache hidden date
Log.w("GCParser.parseCache: Failed to parse cache hidden (event) date");
}
- // favourite
+ // favorite
try {
- cache.setFavoritePoints(Integer.parseInt(BaseUtils.getMatch(tableInside, GCConstants.PATTERN_FAVORITECOUNT, true, "0")));
- } catch (NumberFormatException e) {
- Log.e("Error parsing favourite count", e);
+ cache.setFavoritePoints(Integer.parseInt(TextUtils.getMatch(tableInside, GCConstants.PATTERN_FAVORITECOUNT, true, "0")));
+ } catch (final NumberFormatException e) {
+ Log.e("Error parsing favorite count", e);
}
// cache size
- cache.setSize(CacheSize.getById(BaseUtils.getMatch(tableInside, GCConstants.PATTERN_SIZE, true, CacheSize.NOT_CHOSEN.id)));
+ cache.setSize(CacheSize.getById(TextUtils.getMatch(tableInside, GCConstants.PATTERN_SIZE, true, CacheSize.NOT_CHOSEN.id)));
}
// cache found
- cache.setFound(BaseUtils.matches(page, GCConstants.PATTERN_FOUND) || BaseUtils.matches(page, GCConstants.PATTERN_FOUND_ALTERNATIVE));
+ cache.setFound(TextUtils.matches(page, GCConstants.PATTERN_FOUND) || TextUtils.matches(page, GCConstants.PATTERN_FOUND_ALTERNATIVE));
// cache found date
try {
- final String foundDateString = BaseUtils.getMatch(page, GCConstants.PATTERN_FOUND_DATE, true, null);
+ final String foundDateString = TextUtils.getMatch(page, GCConstants.PATTERN_FOUND_DATE, true, null);
if (StringUtils.isNotBlank(foundDateString)) {
cache.setVisitedDate(Login.parseGcCustomDate(foundDateString).getTime());
}
- } catch (ParseException e) {
+ } catch (final ParseException e) {
// failed to parse cache found date
Log.w("GCParser.parseCache: Failed to parse cache found date");
}
// cache type
- cache.setType(CacheType.getByPattern(BaseUtils.getMatch(page, GCConstants.PATTERN_TYPE, true, cache.getType().id)));
+ cache.setType(CacheType.getByPattern(TextUtils.getMatch(page, GCConstants.PATTERN_TYPE, true, cache.getType().id)));
// on watchlist
- cache.setOnWatchlist(BaseUtils.matches(page, GCConstants.PATTERN_WATCHLIST));
+ cache.setOnWatchlist(TextUtils.matches(page, GCConstants.PATTERN_WATCHLIST));
// latitude and longitude. Can only be retrieved if user is logged in
- String latlon = BaseUtils.getMatch(page, GCConstants.PATTERN_LATLON, true, "");
+ String latlon = TextUtils.getMatch(page, GCConstants.PATTERN_LATLON, true, "");
if (StringUtils.isNotEmpty(latlon)) {
try {
cache.setCoords(new Geopoint(latlon));
cache.setReliableLatLon(true);
- } catch (Geopoint.GeopointException e) {
+ } catch (final Geopoint.GeopointException e) {
Log.w("GCParser.parseCache: Failed to parse cache coordinates", e);
}
}
// cache location
- cache.setLocation(BaseUtils.getMatch(page, GCConstants.PATTERN_LOCATION, true, ""));
+ cache.setLocation(TextUtils.getMatch(page, GCConstants.PATTERN_LOCATION, true, ""));
// cache hint
- String result = BaseUtils.getMatch(page, GCConstants.PATTERN_HINT, false, null);
+ final String result = TextUtils.getMatch(page, GCConstants.PATTERN_HINT, false, null);
if (result != null) {
// replace linebreak and paragraph tags
- String hint = GCConstants.PATTERN_LINEBREAK.matcher(result).replaceAll("\n");
+ final String hint = GCConstants.PATTERN_LINEBREAK.matcher(result).replaceAll("\n");
if (hint != null) {
cache.setHint(StringUtils.replace(hint, "</p>", "").trim());
}
@@ -514,17 +516,17 @@ public abstract class GCParser {
cache.checkFields();
// cache personal note
- cache.setPersonalNote(BaseUtils.getMatch(page, GCConstants.PATTERN_PERSONALNOTE, true, cache.getPersonalNote()));
+ cache.setPersonalNote(TextUtils.getMatch(page, GCConstants.PATTERN_PERSONALNOTE, true, cache.getPersonalNote()));
// cache short description
- cache.setShortDescription(BaseUtils.getMatch(page, GCConstants.PATTERN_SHORTDESC, true, ""));
+ cache.setShortDescription(TextUtils.getMatch(page, GCConstants.PATTERN_SHORTDESC, true, ""));
// cache description
- cache.setDescription(BaseUtils.getMatch(page, GCConstants.PATTERN_DESC, true, ""));
+ cache.setDescription(TextUtils.getMatch(page, GCConstants.PATTERN_DESC, true, ""));
// cache attributes
try {
- final String attributesPre = BaseUtils.getMatch(page, GCConstants.PATTERN_ATTRIBUTES, true, null);
+ final String attributesPre = TextUtils.getMatch(page, GCConstants.PATTERN_ATTRIBUTES, true, null);
if (null != attributesPre) {
final MatcherWrapper matcherAttributesInside = new MatcherWrapper(GCConstants.PATTERN_ATTRIBUTESINSIDE, attributesPre);
@@ -537,8 +539,8 @@ public abstract class GCParser {
// if the image name can be recognized, use the image name as attribute
final String imageName = matcherAttributesInside.group(1).trim();
if (StringUtils.isNotEmpty(imageName)) {
- int start = imageName.lastIndexOf('/');
- int end = imageName.lastIndexOf('.');
+ final int start = imageName.lastIndexOf('/');
+ final int end = imageName.lastIndexOf('.');
if (start >= 0 && end >= 0) {
attribute = imageName.substring(start + 1, end).replace('-', '_').toLowerCase(Locale.US);
}
@@ -548,7 +550,7 @@ public abstract class GCParser {
}
cache.setAttributes(attributes);
}
- } catch (Exception e) {
+ } catch (final Exception e) {
// failed to parse cache attributes
Log.w("GCParser.parseCache: Failed to parse cache attributes");
}
@@ -565,7 +567,7 @@ public abstract class GCParser {
while (matcherSpoilersInside.find()) {
// the original spoiler URL (include .../display/... contains a low-resolution image
// if we shorten the URL we get the original-resolution image
- String url = matcherSpoilersInside.group(1).replace("/display", "");
+ final String url = matcherSpoilersInside.group(1).replace("/display", "");
String title = null;
if (matcherSpoilersInside.group(3) != null) {
@@ -577,7 +579,7 @@ public abstract class GCParser {
}
cache.addSpoiler(new Image(url, title, description));
}
- } catch (Exception e) {
+ } catch (final Exception e) {
// failed to parse cache spoilers
Log.w("GCParser.parseCache: Failed to parse cache spoilers");
}
@@ -611,20 +613,20 @@ public abstract class GCParser {
}
}
}
- } catch (Exception e) {
+ } catch (final Exception e) {
// failed to parse cache inventory
Log.w("GCParser.parseCache: Failed to parse cache inventory (2)");
}
// cache logs counts
try {
- final String countlogs = BaseUtils.getMatch(page, GCConstants.PATTERN_COUNTLOGS, true, null);
+ final String countlogs = TextUtils.getMatch(page, GCConstants.PATTERN_COUNTLOGS, true, null);
if (null != countlogs) {
final MatcherWrapper matcherLog = new MatcherWrapper(GCConstants.PATTERN_COUNTLOG, countlogs);
while (matcherLog.find()) {
- String typeStr = matcherLog.group(1);
- String countStr = matcherLog.group(2).replaceAll("[.,]", "");
+ final String typeStr = matcherLog.group(1);
+ final String countStr = matcherLog.group(2).replaceAll("[.,]", "");
if (StringUtils.isNotBlank(typeStr)
&& LogType.UNKNOWN != LogType.getByIconName(typeStr)
@@ -633,7 +635,7 @@ public abstract class GCParser {
}
}
}
- } catch (Exception e) {
+ } catch (final Exception e) {
// failed to parse logs
Log.w("GCParser.parseCache: Failed to parse cache log count");
}
@@ -643,7 +645,7 @@ public abstract class GCParser {
// add waypoint for original coordinates in case of user-modified listing-coordinates
try {
- final String originalCoords = BaseUtils.getMatch(page, GCConstants.PATTERN_LATLON_ORIG, false, null);
+ final String originalCoords = TextUtils.getMatch(page, GCConstants.PATTERN_LATLON_ORIG, false, null);
if (null != originalCoords) {
final Waypoint waypoint = new Waypoint(cgeoapplication.getInstance().getString(R.string.cache_coordinates_original), WaypointType.ORIGINAL, false);
@@ -651,7 +653,7 @@ public abstract class GCParser {
cache.addOrChangeWaypoint(waypoint, false);
cache.setUserModifiedCoords(true);
}
- } catch (Geopoint.GeopointException e) {
+ } catch (final Geopoint.GeopointException e) {
}
int wpBegin = page.indexOf("<table class=\"Table\" id=\"ctl00_ContentBody_Waypoints\">");
@@ -685,21 +687,21 @@ public abstract class GCParser {
// waypoint name
// res is null during the unit tests
- final String name = BaseUtils.getMatch(wp[6], GCConstants.PATTERN_WPNAME, true, 1, cgeoapplication.getInstance().getString(R.string.waypoint), true);
+ final String name = TextUtils.getMatch(wp[6], GCConstants.PATTERN_WPNAME, true, 1, cgeoapplication.getInstance().getString(R.string.waypoint), true);
// waypoint type
- final String resulttype = BaseUtils.getMatch(wp[3], GCConstants.PATTERN_WPTYPE, null);
+ final String resulttype = TextUtils.getMatch(wp[3], GCConstants.PATTERN_WPTYPE, null);
final Waypoint waypoint = new Waypoint(name, WaypointType.findById(resulttype), false);
// waypoint prefix
- waypoint.setPrefix(BaseUtils.getMatch(wp[4], GCConstants.PATTERN_WPPREFIXORLOOKUPORLATLON, true, 2, waypoint.getPrefix(), false));
+ waypoint.setPrefix(TextUtils.getMatch(wp[4], GCConstants.PATTERN_WPPREFIXORLOOKUPORLATLON, true, 2, waypoint.getPrefix(), false));
// waypoint lookup
- waypoint.setLookup(BaseUtils.getMatch(wp[5], GCConstants.PATTERN_WPPREFIXORLOOKUPORLATLON, true, 2, waypoint.getLookup(), false));
+ waypoint.setLookup(TextUtils.getMatch(wp[5], GCConstants.PATTERN_WPPREFIXORLOOKUPORLATLON, true, 2, waypoint.getLookup(), false));
// waypoint latitude and logitude
- latlon = Html.fromHtml(BaseUtils.getMatch(wp[7], GCConstants.PATTERN_WPPREFIXORLOOKUPORLATLON, false, 2, "", false)).toString().trim();
+ latlon = Html.fromHtml(TextUtils.getMatch(wp[7], GCConstants.PATTERN_WPPREFIXORLOOKUPORLATLON, false, 2, "", false)).toString().trim();
if (!StringUtils.startsWith(latlon, "???")) {
waypoint.setLatlon(latlon);
waypoint.setCoords(new Geopoint(latlon));
@@ -711,7 +713,7 @@ public abstract class GCParser {
}
// waypoint note
- waypoint.setNote(BaseUtils.getMatch(wp[3], GCConstants.PATTERN_WPNOTE, waypoint.getNote()));
+ waypoint.setNote(TextUtils.getMatch(wp[3], GCConstants.PATTERN_WPNOTE, waypoint.getNote()));
cache.addOrChangeWaypoint(waypoint, false);
}
@@ -729,7 +731,8 @@ public abstract class GCParser {
return searchResult;
}
- searchResult.addCache(cache);
+ cache.setDetailedUpdatedNow();
+ searchResult.addAndPutInCache(cache);
return searchResult;
}
@@ -782,7 +785,7 @@ public abstract class GCParser {
// save to application
search.setError(searchResult.getError());
search.setViewstates(searchResult.viewstates);
- for (String geocode : searchResult.getGeocodes()) {
+ for (final String geocode : searchResult.getGeocodes()) {
search.addGeocode(geocode);
}
return search;
@@ -893,7 +896,7 @@ public abstract class GCParser {
return null;
}
try {
- JSONObject response = Network.requestJSON("http://www.geocaching.com/api/geocode", new Parameters("q", address));
+ final JSONObject response = Network.requestJSON("http://www.geocaching.com/api/geocode", new Parameters("q", address));
if (response == null) {
return null;
}
@@ -903,12 +906,12 @@ public abstract class GCParser {
if (!response.has("data")) {
return null;
}
- JSONObject data = response.getJSONObject("data");
+ final JSONObject data = response.getJSONObject("data");
if (data == null) {
return null;
}
return searchByCoords(new Geopoint(data.getDouble("lat"), data.getDouble("lng")), cacheType, showCaptcha, recaptchaReceiver);
- } catch (JSONException e) {
+ } catch (final JSONException e) {
Log.w("GCParser.searchByAddress", e);
}
@@ -1005,7 +1008,7 @@ public abstract class GCParser {
final String uri = new Uri.Builder().scheme("http").authority("www.geocaching.com").path("/seek/log.aspx").encodedQuery("ID=" + cacheid).build().toString();
String page = Login.postRequestLogged(uri, params);
if (!Login.getLoginStatus(page)) {
- Log.e("GCParser.postLogTrackable: Can not log in geocaching");
+ Log.e("GCParser.postLog: Cannot log in geocaching");
return new ImmutablePair<StatusCode, String>(StatusCode.NOT_LOGGED_IN, "");
}
@@ -1033,7 +1036,7 @@ public abstract class GCParser {
if (trackables != null && !trackables.isEmpty()) { // we have some trackables to proceed
final StringBuilder hdnSelected = new StringBuilder();
- for (TrackableLog tb : trackables) {
+ for (final TrackableLog tb : trackables) {
final String action = Integer.toString(tb.id) + tb.action.action;
final StringBuilder paramText = new StringBuilder("ctl00$ContentBody$LogBookPanel1$uxTrackables$repTravelBugs$ctl");
@@ -1054,7 +1057,7 @@ public abstract class GCParser {
page = Network.getResponseData(Network.postRequest(uri, params));
}
- } catch (Exception e) {
+ } catch (final Exception e) {
Log.e("GCParser.postLog.confim", e);
}
@@ -1074,11 +1077,11 @@ public abstract class GCParser {
Login.setActualCachesFound(Login.getActualCachesFound() + 1);
}
- final String logID = BaseUtils.getMatch(page, GCConstants.PATTERN_LOG_IMAGE_UPLOAD, "");
+ final String logID = TextUtils.getMatch(page, GCConstants.PATTERN_LOG_IMAGE_UPLOAD, "");
return new ImmutablePair<StatusCode, String>(StatusCode.NO_ERROR, logID);
}
- } catch (Exception e) {
+ } catch (final Exception e) {
Log.e("GCParser.postLog.check", e);
}
@@ -1099,20 +1102,13 @@ public abstract class GCParser {
* the URI for the image to be uploaded
* @return status code to indicate success or failure
*/
- public static StatusCode uploadLogImage(final String logId, final String caption, final String description, final Uri imageUri) {
- final String uri = new Uri.Builder().scheme("http").authority("www.geocaching.com").path("/seek/upload.aspx").encodedQuery("LID=" + logId).build().toString();
-
- String page = Network.getResponseData(Network.getRequest(uri));
+ public static ImmutablePair<StatusCode, String> uploadLogImage(final String logId, final String caption, final String description, final Uri imageUri) {
+ final String uri = new Uri.Builder().scheme("http").authority("www.geocaching.com").path("/seek/upload.aspx").build().toString();
- if (!Login.getLoginStatus(page)) {
- // Login.isActualLoginStatus() was wrong, we are not logged in
- final StatusCode loginState = Login.login();
- if (loginState == StatusCode.NO_ERROR) {
- page = Network.getResponseData(Network.getRequest(uri));
- } else {
- Log.e("Image upload: No login (error: " + loginState + ')');
- return StatusCode.NOT_LOGGED_IN;
- }
+ final String page = Login.getRequestLogged(uri, new Parameters("LID=", logId));
+ if (StringUtils.isBlank(page)) {
+ Log.e("GCParser.uploadLogImage: No data from server");
+ return new ImmutablePair<StatusCode, String>(StatusCode.UNKNOWN_ERROR, null);
}
final String[] viewstates = Login.getViewstates(page);
@@ -1128,18 +1124,23 @@ public abstract class GCParser {
final File image = new File(imageUri.getPath());
final String response = Network.getResponseData(Network.postRequest(uri, uploadParams, "ctl00$ContentBody$ImageUploadControl1$uxFileUpload", "image/jpeg", image));
- MatcherWrapper matcherOK = new MatcherWrapper(GCConstants.PATTERN_OK_IMAGEUPLOAD, response);
+ final MatcherWrapper matcherUrl = new MatcherWrapper(GCConstants.PATTERN_IMAGE_UPLOAD_URL, response);
- if (matcherOK.find()) {
+ if (matcherUrl.find()) {
Log.i("Logimage successfully uploaded.");
-
- return StatusCode.NO_ERROR;
+ final String uploadedImageUrl = matcherUrl.group(1);
+ return ImmutablePair.of(StatusCode.NO_ERROR, uploadedImageUrl);
}
Log.e("GCParser.uploadLogIMage: Failed to upload image because of unknown error");
- return StatusCode.LOGIMAGE_POST_ERROR;
+ return ImmutablePair.of(StatusCode.LOGIMAGE_POST_ERROR, null);
}
+ /**
+ * Post a log to GC.com.
+ *
+ * @return status code of the upload and ID of the log
+ */
public static StatusCode postLogTrackable(final String tbid, final String trackingCode, final String[] viewstates,
final LogType logType, final int year, final int month, final int day, final String log) {
if (Login.isEmpty(viewstates)) {
@@ -1187,7 +1188,7 @@ public abstract class GCParser {
final String uri = new Uri.Builder().scheme("http").authority("www.geocaching.com").path("/track/log.aspx").encodedQuery("wid=" + tbid).build().toString();
final String page = Login.postRequestLogged(uri, params);
if (!Login.getLoginStatus(page)) {
- Log.e("GCParser.postLogTrackable: Can not log in geocaching");
+ Log.e("GCParser.postLogTrackable: Cannot log in geocaching");
return StatusCode.NOT_LOGGED_IN;
}
@@ -1198,7 +1199,7 @@ public abstract class GCParser {
Log.i("Log successfully posted to trackable #" + trackingCode);
return StatusCode.NO_ERROR;
}
- } catch (Exception e) {
+ } catch (final Exception e) {
Log.e("GCParser.postLogTrackable.check", e);
}
@@ -1215,14 +1216,14 @@ public abstract class GCParser {
*/
static boolean addToWatchlist(final Geocache cache) {
final String uri = "http://www.geocaching.com/my/watchlist.aspx?w=" + cache.getCacheId();
- String page = Login.postRequestLogged(uri, null);
+ final String page = Login.postRequestLogged(uri, null);
if (StringUtils.isBlank(page)) {
Log.e("GCParser.addToWatchlist: No data from server");
return false; // error
}
- boolean guidOnPage = cache.isGuidContainedInPage(page);
+ final boolean guidOnPage = cache.isGuidContainedInPage(page);
if (guidOnPage) {
Log.i("GCParser.addToWatchlist: cache is on watchlist");
cache.setOnWatchlist(true);
@@ -1256,7 +1257,7 @@ public abstract class GCParser {
Login.transferViewstates(page, params);
page = Network.getResponseData(Network.postRequest(uri, params));
- boolean guidOnPage = cache.isGuidContainedInPage(page);
+ final boolean guidOnPage = cache.isGuidContainedInPage(page);
if (!guidOnPage) {
Log.i("GCParser.removeFromWatchlist: cache removed from watchlist");
cache.setOnWatchlist(false);
@@ -1294,14 +1295,14 @@ public abstract class GCParser {
private static boolean changeFavorite(final Geocache cache, final boolean add) {
final String page = requestHtmlPage(cache.getGeocode(), null, "n", "0");
- final String userToken = BaseUtils.getMatch(page, GCConstants.PATTERN_USERTOKEN, "");
+ final String userToken = TextUtils.getMatch(page, GCConstants.PATTERN_USERTOKEN, "");
if (StringUtils.isEmpty(userToken)) {
return false;
}
final String uri = "http://www.geocaching.com/datastore/favorites.svc/update?u=" + userToken + "&f=" + Boolean.toString(add);
- HttpResponse response = Network.postRequest(uri, null);
+ final HttpResponse response = Network.postRequest(uri, null);
if (response != null && response.getStatusLine().getStatusCode() == 200) {
Log.i("GCParser.changeFavorite: cache added/removed to/from favorites");
@@ -1330,7 +1331,7 @@ public abstract class GCParser {
* Parse a trackable HTML description into a Trackable object
*
* @param page
- * the HTML page to parse, already processed through {@link BaseUtils#replaceWhitespace}
+ * the HTML page to parse, already processed through {@link TextUtils#replaceWhitespace}
* @return the parsed trackable, or null if none could be parsed
*/
static Trackable parseTrackable(final String page, final String possibleTrackingcode) {
@@ -1346,20 +1347,20 @@ public abstract class GCParser {
final Trackable trackable = new Trackable();
// trackable geocode
- trackable.setGeocode(BaseUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_GEOCODE, true, trackable.getGeocode()));
+ trackable.setGeocode(TextUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_GEOCODE, true, StringUtils.upperCase(possibleTrackingcode)));
// trackable id
- trackable.setGuid(BaseUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_GUID, true, trackable.getGuid()));
+ trackable.setGuid(TextUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_GUID, true, trackable.getGuid()));
// trackable icon
- trackable.setIconUrl(BaseUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_ICON, true, trackable.getIconUrl()));
+ trackable.setIconUrl(TextUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_ICON, true, trackable.getIconUrl()));
// trackable name
- trackable.setName(Html.fromHtml(BaseUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_NAME, true, "")).toString());
+ trackable.setName(Html.fromHtml(TextUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_NAME, true, "")).toString());
// trackable type
if (StringUtils.isNotBlank(trackable.getName())) {
- trackable.setType(BaseUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_TYPE, true, trackable.getType()));
+ trackable.setType(TextUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_TYPE, true, trackable.getType()));
}
// trackable owner name
@@ -1369,13 +1370,13 @@ public abstract class GCParser {
trackable.setOwnerGuid(matcherOwner.group(1));
trackable.setOwner(matcherOwner.group(2).trim());
}
- } catch (Exception e) {
+ } catch (final Exception e) {
// failed to parse trackable owner name
Log.w("GCParser.parseTrackable: Failed to parse trackable owner name");
}
// trackable origin
- trackable.setOrigin(BaseUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_ORIGIN, true, trackable.getOrigin()));
+ trackable.setOrigin(TextUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_ORIGIN, true, trackable.getOrigin()));
// trackable spotted
try {
@@ -1393,39 +1394,43 @@ public abstract class GCParser {
trackable.setSpottedType(Trackable.SPOTTED_USER);
}
- if (BaseUtils.matches(page, GCConstants.PATTERN_TRACKABLE_SPOTTEDUNKNOWN)) {
+ if (TextUtils.matches(page, GCConstants.PATTERN_TRACKABLE_SPOTTEDUNKNOWN)) {
trackable.setSpottedType(Trackable.SPOTTED_UNKNOWN);
}
- if (BaseUtils.matches(page, GCConstants.PATTERN_TRACKABLE_SPOTTEDOWNER)) {
+ if (TextUtils.matches(page, GCConstants.PATTERN_TRACKABLE_SPOTTEDOWNER)) {
trackable.setSpottedType(Trackable.SPOTTED_OWNER);
}
- } catch (Exception e) {
+ } catch (final Exception e) {
// failed to parse trackable last known place
Log.w("GCParser.parseTrackable: Failed to parse trackable last known place");
}
// released date - can be missing on the page
try {
- String releaseString = BaseUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_RELEASES, false, null);
+ final String releaseString = TextUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_RELEASES, false, null);
if (releaseString != null) {
trackable.setReleased(dateTbIn1.parse(releaseString));
if (trackable.getReleased() == null) {
trackable.setReleased(dateTbIn2.parse(releaseString));
}
}
- } catch (ParseException e1) {
+ } catch (final ParseException e1) {
trackable.setReleased(null);
}
// trackable distance
- final String distance = BaseUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_DISTANCE, false, null);
+ final String distance = TextUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_DISTANCE, false, null);
if (null != distance) {
- trackable.setDistance(DistanceParser.parseDistance(distance, Settings.isUseMetricUnits()));
+ try {
+ trackable.setDistance(DistanceParser.parseDistance(distance, Settings.isUseMetricUnits()));
+ } catch (final NumberFormatException e) {
+ Log.e("GCParser.parseTrackable: Failed to parse distance", e);
+ }
}
// trackable goal
- trackable.setGoal(convertLinks(BaseUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_GOAL, true, trackable.getGoal())));
+ trackable.setGoal(convertLinks(TextUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_GOAL, true, trackable.getGoal())));
// trackable details & image
try {
@@ -1441,10 +1446,13 @@ public abstract class GCParser {
trackable.setDetails(convertLinks(details));
}
}
- } catch (Exception e) {
+ } catch (final Exception e) {
// failed to parse trackable details & image
Log.w("GCParser.parseTrackable: Failed to parse trackable details & image");
}
+ if (StringUtils.isEmpty(trackable.getDetails()) && page.contains(GCConstants.ERROR_TB_NOT_ACTIVATED)) {
+ trackable.setDetails(cgeoapplication.getInstance().getString(R.string.trackable_not_activated));
+ }
// trackable logs
try {
@@ -1462,7 +1470,7 @@ public abstract class GCParser {
long date = 0;
try {
date = Login.parseGcCustomDate(matcherLogs.group(2)).getTime();
- } catch (ParseException e) {
+ } catch (final ParseException e) {
}
final LogEntry logDone = new LogEntry(
@@ -1490,7 +1498,7 @@ public abstract class GCParser {
trackable.getLogs().add(logDone);
}
- } catch (Exception e) {
+ } catch (final Exception e) {
// failed to parse logs
Log.w("GCParser.parseCache: Failed to parse cache logs", e);
}
@@ -1560,10 +1568,10 @@ public abstract class GCParser {
}
} else {
// extract embedded JSON data from page
- rawResponse = BaseUtils.getMatch(page, GCConstants.PATTERN_LOGBOOK, "");
+ rawResponse = TextUtils.getMatch(page, GCConstants.PATTERN_LOGBOOK, "");
}
- List<LogEntry> logs = new ArrayList<LogEntry>();
+ final List<LogEntry> logs = new ArrayList<LogEntry>();
try {
final JSONObject resp = new JSONObject(rawResponse);
@@ -1584,7 +1592,7 @@ public abstract class GCParser {
long date = 0;
try {
date = Login.parseGcCustomDate(entry.getString("Visited")).getTime();
- } catch (ParseException e) {
+ } catch (final ParseException e) {
Log.e("GCParser.loadLogsFromDetails: failed to parse log date.");
}
@@ -1612,7 +1620,7 @@ public abstract class GCParser {
logs.add(logDone);
}
- } catch (JSONException e) {
+ } catch (final JSONException e) {
// failed to parse logs
Log.w("GCParser.loadLogsFromDetails: Failed to parse cache logs", e);
}
@@ -1628,30 +1636,26 @@ public abstract class GCParser {
final List<LogType> types = new ArrayList<LogType>();
final MatcherWrapper typeBoxMatcher = new MatcherWrapper(GCConstants.PATTERN_TYPEBOX, page);
- String typesText = null;
- if (typeBoxMatcher.find()) {
- if (typeBoxMatcher.groupCount() > 0) {
- typesText = typeBoxMatcher.group(1);
- }
- }
-
- if (typesText != null) {
-
+ if (typeBoxMatcher.find() && typeBoxMatcher.groupCount() > 0) {
+ final String typesText = typeBoxMatcher.group(1);
final MatcherWrapper typeMatcher = new MatcherWrapper(GCConstants.PATTERN_TYPE2, typesText);
while (typeMatcher.find()) {
if (typeMatcher.groupCount() > 1) {
try {
- int type = Integer.parseInt(typeMatcher.group(2));
+ final int type = Integer.parseInt(typeMatcher.group(2));
if (type > 0) {
types.add(LogType.getById(type));
}
- } catch (NumberFormatException e) {
+ } catch (final NumberFormatException e) {
Log.e("Error parsing log types", e);
}
}
}
}
+ // we don't support this log type
+ types.remove(LogType.UPDATE_COORDINATES);
+
return types;
}
@@ -1690,7 +1694,7 @@ public abstract class GCParser {
Log.i("Trackable in inventory (#" + entry.ctl + "/" + entry.id + "): " + entry.trackCode + " - " + entry.name);
trackableLogs.add(entry);
}
- } catch (NumberFormatException e) {
+ } catch (final NumberFormatException e) {
Log.e("GCParser.parseTrackableLog", e);
}
}
@@ -1719,10 +1723,10 @@ public abstract class GCParser {
//cache.setLogs(loadLogsFromDetails(page, cache, false));
if (Settings.isFriendLogsWanted()) {
CancellableHandler.sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_logs);
- List<LogEntry> allLogs = cache.getLogs();
- List<LogEntry> friendLogs = loadLogsFromDetails(page, cache, true, false);
+ final List<LogEntry> allLogs = cache.getLogs();
+ final List<LogEntry> friendLogs = loadLogsFromDetails(page, cache, true, false);
if (friendLogs != null) {
- for (LogEntry log : friendLogs) {
+ for (final LogEntry log : friendLogs) {
if (allLogs.contains(log)) {
allLogs.get(allLogs.indexOf(log)).friend = true;
} else {
@@ -1766,7 +1770,7 @@ public abstract class GCParser {
public static boolean editModifiedCoordinates(Geocache cache, Geopoint wpt) {
final String page = requestHtmlPage(cache.getGeocode(), null, "n", "0");
- final String userToken = BaseUtils.getMatch(page, GCConstants.PATTERN_USERTOKEN, "");
+ final String userToken = TextUtils.getMatch(page, GCConstants.PATTERN_USERTOKEN, "");
if (StringUtils.isEmpty(userToken)) {
return false;
}
@@ -1785,7 +1789,7 @@ public abstract class GCParser {
final String uriSuffix = wpt != null ? "SetUserCoordinate" : "ResetUserCoordinate";
final String uriPrefix = "http://www.geocaching.com/seek/cache_details.aspx/";
- HttpResponse response = Network.postJsonRequest(uriPrefix + uriSuffix, jo);
+ final HttpResponse response = Network.postJsonRequest(uriPrefix + uriSuffix, jo);
Log.i("Sending to " + uriPrefix + uriSuffix + " :" + jo.toString());
if (response != null && response.getStatusLine().getStatusCode() == 200) {
@@ -1793,11 +1797,42 @@ public abstract class GCParser {
return true;
}
- } catch (JSONException e) {
+ } catch (final JSONException e) {
Log.e("Unknown exception with json wrap code", e);
}
Log.e("GCParser.deleteModifiedCoordinates - cannot delete modified coords");
return false;
}
+ public static boolean uploadPersonalNote(Geocache cache) {
+ final String page = requestHtmlPage(cache.getGeocode(), null, "n", "0");
+ final String userToken = TextUtils.getMatch(page, GCConstants.PATTERN_USERTOKEN, "");
+ if (StringUtils.isEmpty(userToken)) {
+ return false;
+ }
+
+ try {
+ final JSONObject jo = new JSONObject()
+ .put("dto", (new JSONObject()
+ .put("et", cache.getPersonalNote())
+ .put("ut", userToken)));
+
+ final String uriSuffix = "SetUserCacheNote";
+
+ final String uriPrefix = "http://www.geocaching.com/seek/cache_details.aspx/";
+ final HttpResponse response = Network.postJsonRequest(uriPrefix + uriSuffix, jo);
+ Log.i("Sending to " + uriPrefix + uriSuffix + " :" + jo.toString());
+
+ if (response != null && response.getStatusLine().getStatusCode() == 200) {
+ Log.i("GCParser.uploadPersonalNote - uploaded to GC.com");
+ return true;
+ }
+
+ } catch (final JSONException e) {
+ Log.e("Unknown exception with json wrap code", e);
+ }
+ Log.e("GCParser.uploadPersonalNote - cannot upload personal note");
+ return false;
+ }
+
}
diff --git a/main/src/cgeo/geocaching/connector/gc/Login.java b/main/src/cgeo/geocaching/connector/gc/Login.java
index 7351311..3146712 100644
--- a/main/src/cgeo/geocaching/connector/gc/Login.java
+++ b/main/src/cgeo/geocaching/connector/gc/Login.java
@@ -8,9 +8,9 @@ import cgeo.geocaching.network.Cookies;
import cgeo.geocaching.network.HtmlImage;
import cgeo.geocaching.network.Network;
import cgeo.geocaching.network.Parameters;
-import cgeo.geocaching.utils.BaseUtils;
import cgeo.geocaching.utils.Log;
import cgeo.geocaching.utils.MatcherWrapper;
+import cgeo.geocaching.utils.TextUtils;
import ch.boye.httpclientandroidlib.HttpResponse;
@@ -52,9 +52,9 @@ public abstract class Login {
"dd/MM/yyyy"
};
- Map<String, SimpleDateFormat> map = new HashMap<String, SimpleDateFormat>();
+ final Map<String, SimpleDateFormat> map = new HashMap<String, SimpleDateFormat>();
- for (String format : formats) {
+ for (final String format : formats) {
map.put(format, new SimpleDateFormat(format, Locale.ENGLISH));
}
@@ -77,7 +77,7 @@ public abstract class Login {
Login.setActualStatus(cgeoapplication.getInstance().getString(R.string.init_login_popup_working));
HttpResponse loginResponse = Network.getRequest("https://www.geocaching.com/login/default.aspx");
String loginData = Network.getResponseData(loginResponse);
- if (loginResponse != null && loginResponse.getStatusLine().getStatusCode() == 503 && BaseUtils.matches(loginData, GCConstants.PATTERN_MAINTENANCE)) {
+ if (loginResponse != null && loginResponse.getStatusLine().getStatusCode() == 503 && TextUtils.matches(loginData, GCConstants.PATTERN_MAINTENANCE)) {
return StatusCode.MAINTENANCE;
}
@@ -147,9 +147,9 @@ public abstract class Login {
}
public static StatusCode logout() {
- HttpResponse logoutResponse = Network.getRequest("https://www.geocaching.com/login/default.aspx?RESET=Y&redir=http%3a%2f%2fwww.geocaching.com%2fdefault.aspx%3f");
- String logoutData = Network.getResponseData(logoutResponse);
- if (logoutResponse != null && logoutResponse.getStatusLine().getStatusCode() == 503 && BaseUtils.matches(logoutData, GCConstants.PATTERN_MAINTENANCE)) {
+ final HttpResponse logoutResponse = Network.getRequest("https://www.geocaching.com/login/default.aspx?RESET=Y&redir=http%3a%2f%2fwww.geocaching.com%2fdefault.aspx%3f");
+ final String logoutData = Network.getResponseData(logoutResponse);
+ if (logoutResponse != null && logoutResponse.getStatusLine().getStatusCode() == 503 && TextUtils.matches(logoutData, GCConstants.PATTERN_MAINTENANCE)) {
return StatusCode.MAINTENANCE;
}
@@ -205,17 +205,17 @@ public abstract class Login {
setActualStatus(cgeoapplication.getInstance().getString(R.string.init_login_popup_ok));
// on every page except login page
- setActualLoginStatus(BaseUtils.matches(page, GCConstants.PATTERN_LOGIN_NAME));
+ setActualLoginStatus(TextUtils.matches(page, GCConstants.PATTERN_LOGIN_NAME));
if (isActualLoginStatus()) {
- setActualUserName(BaseUtils.getMatch(page, GCConstants.PATTERN_LOGIN_NAME, true, "???"));
+ setActualUserName(TextUtils.getMatch(page, GCConstants.PATTERN_LOGIN_NAME, true, "???"));
int cachesCount = 0;
try {
- cachesCount = Integer.parseInt(BaseUtils.getMatch(page, GCConstants.PATTERN_CACHES_FOUND, true, "0").replaceAll("[,.]", ""));
- } catch (NumberFormatException e) {
+ cachesCount = Integer.parseInt(TextUtils.getMatch(page, GCConstants.PATTERN_CACHES_FOUND, true, "0").replaceAll("[,.]", ""));
+ } catch (final NumberFormatException e) {
Log.e("getLoginStatus: bad cache count", e);
}
setActualCachesFound(cachesCount);
- Settings.setMemberStatus(BaseUtils.getMatch(page, GCConstants.PATTERN_MEMBER_STATUS, true, null));
+ Settings.setMemberStatus(TextUtils.getMatch(page, GCConstants.PATTERN_MEMBER_STATUS, true, null));
if ( page.contains(GCConstants.MEMBER_STATUS_RENEW) ) {
Settings.setMemberStatus(GCConstants.MEMBER_STATUS_PM);
}
@@ -223,7 +223,7 @@ public abstract class Login {
}
// login page
- setActualLoginStatus(BaseUtils.matches(page, GCConstants.PATTERN_LOGIN_NAME_LOGIN_PAGE));
+ setActualLoginStatus(TextUtils.matches(page, GCConstants.PATTERN_LOGIN_NAME_LOGIN_PAGE));
if (isActualLoginStatus()) {
setActualUserName(Settings.getUsername());
// number of caches found is not part of this page
@@ -260,23 +260,23 @@ public abstract class Login {
public static BitmapDrawable downloadAvatarAndGetMemberStatus() {
try {
- final String profile = BaseUtils.replaceWhitespace(Network.getResponseData(Network.getRequest("http://www.geocaching.com/my/")));
+ final String profile = TextUtils.replaceWhitespace(Network.getResponseData(Network.getRequest("http://www.geocaching.com/my/")));
- Settings.setMemberStatus(BaseUtils.getMatch(profile, GCConstants.PATTERN_MEMBER_STATUS, true, null));
+ Settings.setMemberStatus(TextUtils.getMatch(profile, GCConstants.PATTERN_MEMBER_STATUS, true, null));
if (profile.contains(GCConstants.MEMBER_STATUS_RENEW)) {
Settings.setMemberStatus(GCConstants.MEMBER_STATUS_PM);
}
- setActualCachesFound(Integer.parseInt(BaseUtils.getMatch(profile, GCConstants.PATTERN_CACHES_FOUND, true, "-1").replaceAll("[,.]", "")));
+ setActualCachesFound(Integer.parseInt(TextUtils.getMatch(profile, GCConstants.PATTERN_CACHES_FOUND, true, "-1").replaceAll("[,.]", "")));
- final String avatarURL = BaseUtils.getMatch(profile, GCConstants.PATTERN_AVATAR_IMAGE_PROFILE_PAGE, false, null);
+ final String avatarURL = TextUtils.getMatch(profile, GCConstants.PATTERN_AVATAR_IMAGE_PROFILE_PAGE, false, null);
if (null != avatarURL) {
final HtmlImage imgGetter = new HtmlImage("", false, 0, false);
return imgGetter.getDrawable(avatarURL);
}
// No match? There may be no avatar set by user.
Log.d("No avatar set for user");
- } catch (Exception e) {
+ } catch (final Exception e) {
Log.w("Error when retrieving user avatar", e);
}
return null;
@@ -294,7 +294,7 @@ public abstract class Login {
return;
}
- String customDate = BaseUtils.getMatch(result, GCConstants.PATTERN_CUSTOMDATE, true, null);
+ final String customDate = TextUtils.getMatch(result, GCConstants.PATTERN_CUSTOMDATE, true, null);
if (null != customDate) {
Settings.setGcCustomDate(customDate);
}
@@ -310,14 +310,14 @@ public abstract class Login {
if (gcCustomDateFormats.containsKey(format)) {
try {
return gcCustomDateFormats.get(format).parse(trimmed);
- } catch (ParseException e) {
+ } catch (final ParseException e) {
}
}
- for (SimpleDateFormat sdf : gcCustomDateFormats.values()) {
+ for (final SimpleDateFormat sdf : gcCustomDateFormats.values()) {
try {
return sdf.parse(trimmed);
- } catch (ParseException e) {
+ } catch (final ParseException e) {
}
}
@@ -347,7 +347,7 @@ public abstract class Login {
return true;
}
- for (String s : a) {
+ for (final String s : a) {
if (StringUtils.isNotEmpty(s)) {
return false;
}
@@ -373,24 +373,24 @@ public abstract class Login {
if (matcherViewstateCount.find()) {
try {
count = Integer.parseInt(matcherViewstateCount.group(1));
- } catch (NumberFormatException e) {
+ } catch (final NumberFormatException e) {
Log.e("getViewStates", e);
}
}
- String[] viewstates = new String[count];
+ final String[] viewstates = new String[count];
// Get the viewstates
final MatcherWrapper matcherViewstates = new MatcherWrapper(GCConstants.PATTERN_VIEWSTATES, page);
while (matcherViewstates.find()) {
- String sno = matcherViewstates.group(1); // number of viewstate
+ final String sno = matcherViewstates.group(1); // number of viewstate
int no;
if (StringUtils.isEmpty(sno)) {
no = 0;
} else {
try {
no = Integer.parseInt(sno);
- } catch (NumberFormatException e) {
+ } catch (final NumberFormatException e) {
Log.e("getViewStates", e);
no = 0;
}
@@ -436,17 +436,17 @@ public abstract class Login {
* @return
*/
public static String postRequestLogged(final String uri, final Parameters params) {
- HttpResponse response = Network.postRequest(uri, params);
- String data = Network.getResponseData(response);
+ final String data = Network.getResponseData(Network.postRequest(uri, params));
- if (!getLoginStatus(data)) {
- if (login() == StatusCode.NO_ERROR) {
- response = Network.postRequest(uri, params);
- data = Network.getResponseData(response);
- } else {
- Log.i("Working as guest.");
- }
+ if (getLoginStatus(data)) {
+ return data;
}
+
+ if (login() == StatusCode.NO_ERROR) {
+ return Network.getResponseData(Network.postRequest(uri, params));
+ }
+
+ Log.i("Working as guest.");
return data;
}
@@ -476,8 +476,8 @@ public abstract class Login {
public static String[] getMapTokens() {
final HttpResponse response = Network.getRequest(GCConstants.URL_LIVE_MAP);
final String data = Network.getResponseData(response);
- final String userSession = BaseUtils.getMatch(data, GCConstants.PATTERN_USERSESSION, "");
- final String sessionToken = BaseUtils.getMatch(data, GCConstants.PATTERN_SESSIONTOKEN, "");
+ final String userSession = TextUtils.getMatch(data, GCConstants.PATTERN_USERSESSION, "");
+ final String sessionToken = TextUtils.getMatch(data, GCConstants.PATTERN_SESSIONTOKEN, "");
return new String[] { userSession, sessionToken };
}
}
diff --git a/main/src/cgeo/geocaching/connector/gc/SearchHandler.java b/main/src/cgeo/geocaching/connector/gc/SearchHandler.java
index 840cad1..45832e4 100644
--- a/main/src/cgeo/geocaching/connector/gc/SearchHandler.java
+++ b/main/src/cgeo/geocaching/connector/gc/SearchHandler.java
@@ -102,7 +102,7 @@ public class SearchHandler extends Handler {
imgHandler.sendEmptyMessage(0);
} catch (IOException e) {
- Log.e("Failed to download reCAPTCHA image");
+ Log.e("Failed to download reCAPTCHA image", e);
}
}
}
diff --git a/main/src/cgeo/geocaching/connector/gc/Tile.java b/main/src/cgeo/geocaching/connector/gc/Tile.java
index 0e5ffe7..dd7f352 100644
--- a/main/src/cgeo/geocaching/connector/gc/Tile.java
+++ b/main/src/cgeo/geocaching/connector/gc/Tile.java
@@ -243,7 +243,7 @@ public class Tile {
try {
return response != null ? BitmapFactory.decodeStream(response.getEntity().getContent()) : null;
} catch (IOException e) {
- Log.e("cgBase.requestMapTile() " + e.getMessage());
+ Log.e("Tile.requestMapTile() ", e);
}
return null;
}
diff --git a/main/src/cgeo/geocaching/connector/oc/AttributeParser.java b/main/src/cgeo/geocaching/connector/oc/AttributeParser.java
new file mode 100644
index 0000000..63bee77
--- /dev/null
+++ b/main/src/cgeo/geocaching/connector/oc/AttributeParser.java
@@ -0,0 +1,327 @@
+// This is a generated file, do not change manually!
+
+package cgeo.geocaching.connector.oc;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class AttributeParser {
+
+ private final static Map<String, Integer> attrMapDe;
+ private final static Map<String, Integer> attrMapPl;
+
+ static {
+ attrMapDe = new HashMap<String, Integer>();
+ attrMapPl = new HashMap<String, Integer>();
+
+ // last header line
+ attrMapDe.put("Listed at Opencaching only", 6);
+ attrMapDe.put("Dostępna tylko na Opencaching", 6);
+ attrMapDe.put("Nur bei Opencaching logbar", 6);
+ attrMapDe.put("Solo loggeable en Opencaching", 6);
+ attrMapDe.put("Loggabile solo su Opencaching", 6);
+ attrMapPl.put("Near a Survey Marker", 54);
+ attrMapPl.put("W pobliżu punktu geodezyjnego", 54);
+ attrMapPl.put("Whereigo Cache", 55);
+ attrMapPl.put("Whereigo Cache", 55);
+ attrMapPl.put("Whereigo Cache", 55);
+ attrMapDe.put("Letterbox Cache", 8);
+ attrMapPl.put("Letterbox Cache", 56);
+ attrMapDe.put("Skrzynka typu Letterbox", 8);
+ attrMapPl.put("Skrzynka typu Letterbox", 56);
+ attrMapDe.put("Letterbox (benötigt Stempel)", 8);
+ attrMapPl.put("Letterbox (benötigt Stempel)", 56);
+ attrMapDe.put("Letterbox (necesita un estampador)", 8);
+ attrMapPl.put("Letterbox (necesita un estampador)", 56);
+ attrMapDe.put("Letterbox (richiede un timbro)", 8);
+ attrMapPl.put("Letterbox (richiede un timbro)", 56);
+ attrMapPl.put("GeoHotel", 43);
+ attrMapPl.put("GeoHotel", 43);
+ attrMapPl.put("GeoHotel", 43);
+ attrMapPl.put("Magnetic cache", 49);
+ attrMapPl.put("Przyczepiona magnesem", 49);
+ attrMapPl.put("magnetischer Cache", 49);
+ attrMapPl.put("Description contains an audio file", 50);
+ attrMapPl.put("Opis zawiera plik audio", 50);
+ attrMapPl.put("Offset cache", 51);
+ attrMapPl.put("Offset cache", 51);
+ attrMapPl.put("Peilungscache", 51);
+ attrMapPl.put("Garmin's wireless beacon", 52);
+ attrMapPl.put("Beacon - Garmin Chirp", 52);
+ attrMapPl.put("Funksignal – Garmin Chirp", 52);
+ attrMapPl.put("Dead Drop USB cache", 53);
+ attrMapPl.put("Dead Drop USB skrzynka", 53);
+ attrMapDe.put("Has a moving target", 31);
+ attrMapDe.put("bewegliches Ziel", 31);
+ attrMapDe.put("Objetivo en movimiento", 31);
+ attrMapDe.put("Oggetto in movimento", 31);
+ attrMapDe.put("Webcam Cache", 32);
+ attrMapDe.put("Webcam Cache", 32);
+ attrMapDe.put("Webcam Cache", 32);
+ attrMapDe.put("Webcam Cache", 32);
+ attrMapDe.put("Other cache type", 57);
+ attrMapDe.put("sonstiger Cachetyp", 57);
+ attrMapDe.put("Otro tipo de cache", 57);
+ attrMapDe.put("Altro tipo di cache", 57);
+ attrMapDe.put("Investigation required", 54);
+ attrMapDe.put("Recherche", 54);
+ attrMapDe.put("Investigación", 54);
+ attrMapDe.put("Ricerca", 54);
+ attrMapDe.put("Puzzle / Mystery", 55);
+ attrMapDe.put("Rätsel", 55);
+ attrMapDe.put("Puzzle / Misterio", 55);
+ attrMapDe.put("Puzzle / Mystery", 55);
+ attrMapDe.put("Arithmetical problem", 56);
+ attrMapDe.put("Rechenaufgabe", 56);
+ attrMapDe.put("Problema matemático", 56);
+ attrMapDe.put("Problema matematico", 56);
+ attrMapDe.put("Ask owner for start conditions", 58);
+ attrMapDe.put("Startbedingungen beim Owner erfragen", 58);
+ attrMapDe.put("Ask owner for start conditions", 58);
+ attrMapDe.put("Ask owner for start conditions", 58);
+ attrMapPl.put("Wheelchair accessible", 44);
+ attrMapPl.put("Dostępna dla niepełnosprawnych", 44);
+ attrMapPl.put("rollstuhltauglich", 44);
+ attrMapDe.put("Near the parking area", 24);
+ attrMapDe.put("nahe beim Auto", 24);
+ attrMapDe.put("Cerca de un Parking", 24);
+ attrMapDe.put("Vicino all'area di parcheggio", 24);
+ attrMapPl.put("Access only by walk", 84);
+ attrMapPl.put("Dostępna tylko pieszo", 84);
+ attrMapDe.put("Long walk", 25);
+ attrMapDe.put("längere Wanderung", 25);
+ attrMapDe.put("Larga caminata", 25);
+ attrMapDe.put("Lunga camminata", 25);
+ attrMapDe.put("Swamp, marsh or wading", 26);
+ attrMapDe.put("sumpfig/matschiges Gelände / waten", 26);
+ attrMapDe.put("Pantano / terreno fangoso", 26);
+ attrMapDe.put("Palude o marcita", 26);
+ attrMapDe.put("Hilly area", 27);
+ attrMapDe.put("hügeliges Gelände", 27);
+ attrMapDe.put("Terreno montañoso", 27);
+ attrMapDe.put("Area collinare", 27);
+ attrMapDe.put("Some climbing (no gear needed)", 28);
+ attrMapDe.put("leichtes Klettern (ohne Ausrüstung)", 28);
+ attrMapDe.put("fácil de subir (sin equipo)", 28);
+ attrMapDe.put("Arrampicata (attrezzatura non necessaria)", 28);
+ attrMapDe.put("Swimming required", 29);
+ attrMapDe.put("Schwimmen erforderlich", 29);
+ attrMapDe.put("Requiere nadar", 29);
+ attrMapDe.put("Nuoto necessario", 29);
+ attrMapDe.put("Access or parking fee", 36);
+ attrMapDe.put("Zugangs- bzw. Parkentgelt", 36);
+ attrMapDe.put("Acceso o parking pagando", 36);
+ attrMapDe.put("Tassa di ingresso o di parcheggio", 36);
+ attrMapPl.put("Bikes allowed", 85);
+ attrMapPl.put("Dostępna rowerem", 85);
+ attrMapPl.put("Hidden in natural surroundings (forests, mountains, etc.)", 60);
+ attrMapPl.put("Umiejscowiona na łonie natury (lasy, góry, itp.)", 60);
+ attrMapPl.put("Historic site", 61);
+ attrMapPl.put("Miejsce historyczne", 61);
+ attrMapDe.put("Point of interest", 30);
+ attrMapDe.put("interessanter Ort", 30);
+ attrMapDe.put("Punto de interes", 30);
+ attrMapDe.put("Punto di interesse", 30);
+ attrMapDe.put("Hidden wihin enclosed rooms (caves, buildings etc.)", 33);
+ attrMapDe.put("in geschlossenen Räumen (Höhle, Gebäude, etc.)", 33);
+ attrMapDe.put("en espacios confinados (cuevas, edificios, etc)", 33);
+ attrMapDe.put("All'interno di stanze chiuse (caverne, edifici, ecc.)", 33);
+ attrMapDe.put("Hidden under water", 34);
+ attrMapDe.put("Im Wasser versteckt", 34);
+ attrMapDe.put("En el agua", 34);
+ attrMapDe.put("Nell'acqua", 34);
+ attrMapDe.put("Parking area nearby", 18);
+ attrMapDe.put("Parkplatz in der Nähe", 18);
+ attrMapDe.put("Parking cercano", 18);
+ attrMapDe.put("Parcheggio nei pressi", 18);
+ attrMapDe.put("Public transportation", 19);
+ attrMapDe.put("erreichbar mit ÖVM", 19);
+ attrMapDe.put("Transporte Público", 19);
+ attrMapDe.put("Trasporto pubblico", 19);
+ attrMapDe.put("Drinking water nearby", 20);
+ attrMapDe.put("Trinkwasser in der Nähe", 20);
+ attrMapDe.put("Agua potable en las cercanias", 20);
+ attrMapDe.put("Acqua potabile nei pressi", 20);
+ attrMapDe.put("Public restrooms nearby", 21);
+ attrMapDe.put("öffentliche Toilette in der Nähe", 21);
+ attrMapDe.put("Aseos públicos cercanos", 21);
+ attrMapDe.put("Bagni pubblici nei pressi", 21);
+ attrMapDe.put("Public phone nearby", 22);
+ attrMapDe.put("Telefon in der Nähe", 22);
+ attrMapDe.put("Teléfono Público en las cercanias", 22);
+ attrMapDe.put("Telefono pubblico nei pressi", 22);
+ attrMapDe.put("First aid available", 23);
+ attrMapDe.put("Erste Hilfe verfügbar", 23);
+ attrMapDe.put("Disponible socorro rapido", 23);
+ attrMapDe.put("Disponibile pronto soccorso", 23);
+ attrMapDe.put("Available 24/7", 38);
+ attrMapDe.put("rund um die Uhr machbar", 38);
+ attrMapDe.put("Disponible las 24 horas", 38);
+ attrMapDe.put("Disponibile 24 ore", 38);
+ attrMapDe.put("Not 24/7", 39);
+ attrMapPl.put("Not 24/7", 80);
+ attrMapDe.put("Dostępna w określonych godzinach", 39);
+ attrMapPl.put("Dostępna w określonych godzinach", 80);
+ attrMapDe.put("nur zu bestimmten Uhrzeiten", 39);
+ attrMapPl.put("nur zu bestimmten Uhrzeiten", 80);
+ attrMapDe.put("Sólo disponible a ciertas horas", 39);
+ attrMapPl.put("Sólo disponible a ciertas horas", 80);
+ attrMapDe.put("Disponibile solo in certi orari", 39);
+ attrMapPl.put("Disponibile solo in certi orari", 80);
+ attrMapDe.put("Not recommended at night", 40);
+ attrMapDe.put("nur tagüber", 40);
+ attrMapDe.put("solo por el día", 40);
+ attrMapDe.put("solo di giorno", 40);
+ attrMapPl.put("Recommended at night", 91);
+ attrMapPl.put("Zalecane szukanie nocÄ…", 91);
+ attrMapPl.put("am besten nachts findbar", 91);
+ attrMapDe.put("Only at night", 1);
+ attrMapDe.put("nur bei Nacht", 1);
+ attrMapDe.put("Sólo por la noche", 1);
+ attrMapDe.put("Solo di notte", 1);
+ attrMapDe.put("All seasons", 42);
+ attrMapDe.put("ganzjähig zugänglich", 42);
+ attrMapDe.put("Todas las temporadas", 42);
+ attrMapDe.put("Tutte le stagioni", 42);
+ attrMapDe.put("Only available during specified seasons", 60);
+ attrMapDe.put("Nur zu bestimmten Zeiten im Jahr", 60);
+ attrMapDe.put("Sólo disponible durante las estaciones especificadas", 60);
+ attrMapDe.put("Disponibile solo in certe stagioni", 60);
+ attrMapDe.put("Breeding season / protected nature", 43);
+ attrMapDe.put("Brutsaison / Naturschutz", 43);
+ attrMapDe.put("Temporada de reproducción / protección de la naturaleza", 43);
+ attrMapDe.put("Stagione di riproduzione / natura protetta", 43);
+ attrMapDe.put("Available during winter", 44);
+ attrMapDe.put("schneesicheres Versteck", 44);
+ attrMapDe.put("Nieve en el escondite", 44);
+ attrMapDe.put("Luogo a prova di neve", 44);
+ attrMapDe.put("Not at high water level", 41);
+ attrMapDe.put("nicht bei Hochwasser oder Flut", 41);
+ attrMapDe.put("Compass required", 47);
+ attrMapPl.put("Compass required", 47);
+ attrMapDe.put("Potrzebny kompas", 47);
+ attrMapPl.put("Potrzebny kompas", 47);
+ attrMapDe.put("Kompass", 47);
+ attrMapPl.put("Kompass", 47);
+ attrMapDe.put("Brújula", 47);
+ attrMapPl.put("Brújula", 47);
+ attrMapDe.put("Bussola", 47);
+ attrMapPl.put("Bussola", 47);
+ attrMapPl.put("Take something to write", 48);
+ attrMapPl.put("Weź coś do pisania", 48);
+ attrMapPl.put("You may need a shovel", 81);
+ attrMapPl.put("Potrzebna łopatka", 81);
+ attrMapDe.put("Flashlight required", 48);
+ attrMapPl.put("Flashlight required", 82);
+ attrMapDe.put("Potrzebna latarka", 48);
+ attrMapPl.put("Potrzebna latarka", 82);
+ attrMapDe.put("Taschenlampe", 48);
+ attrMapPl.put("Taschenlampe", 82);
+ attrMapDe.put("Linterna", 48);
+ attrMapPl.put("Linterna", 82);
+ attrMapDe.put("Lampada tascabile", 48);
+ attrMapPl.put("Lampada tascabile", 82);
+ attrMapDe.put("Climbing gear required", 49);
+ attrMapDe.put("Kletterzeug", 49);
+ attrMapDe.put("Equipo de escalada", 49);
+ attrMapDe.put("Attrezzatura per arrampicata", 49);
+ attrMapDe.put("Cave equipment required", 50);
+ attrMapDe.put("Höhlenzeug", 50);
+ attrMapDe.put("Equipación para cuevas", 50);
+ attrMapDe.put("Attrezzatura per grotta", 50);
+ attrMapDe.put("Diving equipment required", 51);
+ attrMapDe.put("Taucherausrüstung", 51);
+ attrMapDe.put("Diving equipment", 51);
+ attrMapDe.put("Equipo de buceo", 51);
+ attrMapDe.put("Special tools required", 46);
+ attrMapPl.put("Special tools required", 83);
+ attrMapDe.put("Wymagany dodatkowy sprzęt", 46);
+ attrMapPl.put("Wymagany dodatkowy sprzęt", 83);
+ attrMapDe.put("spezielle Ausrüstung", 46);
+ attrMapPl.put("spezielle Ausrüstung", 83);
+ attrMapDe.put("Equipamiento especial", 46);
+ attrMapPl.put("Equipamiento especial", 83);
+ attrMapDe.put("Equipaggiamento speciale", 46);
+ attrMapPl.put("Equipaggiamento speciale", 83);
+ attrMapDe.put("Requires a boat", 52);
+ attrMapPl.put("Requires a boat", 86);
+ attrMapDe.put("Wymaga sprzętu pływającego", 52);
+ attrMapPl.put("Wymaga sprzętu pływającego", 86);
+ attrMapDe.put("Wasserfahrzeug", 52);
+ attrMapPl.put("Wasserfahrzeug", 86);
+ attrMapDe.put("Barca", 52);
+ attrMapPl.put("Barca", 86);
+ attrMapDe.put("Barca", 52);
+ attrMapPl.put("Barca", 86);
+ attrMapDe.put("No GPS required", 35);
+ attrMapDe.put("ohne GPS findbar", 35);
+ attrMapDe.put("Sin GPS", 35);
+ attrMapDe.put("Senza GPS", 35);
+ attrMapDe.put("Dangerous area", 9);
+ attrMapPl.put("Dangerous area", 90);
+ attrMapDe.put("Skrzynka niebezpieczna", 9);
+ attrMapPl.put("Skrzynka niebezpieczna", 90);
+ attrMapDe.put("gefährliches Gebiet", 9);
+ attrMapPl.put("gefährliches Gebiet", 90);
+ attrMapDe.put("Zona Peligrosa", 9);
+ attrMapPl.put("Zona Peligrosa", 90);
+ attrMapDe.put("Area pericolosa", 9);
+ attrMapPl.put("Area pericolosa", 90);
+ attrMapDe.put("Active railway nearby", 10);
+ attrMapDe.put("aktive Eisenbahnlinie in der Nähe", 10);
+ attrMapDe.put("Cerca del ferrocarril activo", 10);
+ attrMapDe.put("Ferrovia attiva nei pressi", 10);
+ attrMapDe.put("Cliff / Rocks", 11);
+ attrMapDe.put("Klippen / Felsen", 11);
+ attrMapDe.put("Acantilado / Rocas", 11);
+ attrMapDe.put("Scogliera / Rocce", 11);
+ attrMapDe.put("Hunting", 12);
+ attrMapDe.put("Jagdgebiet", 12);
+ attrMapDe.put("Zona de Caza", 12);
+ attrMapDe.put("Caccia", 12);
+ attrMapDe.put("Thorns", 13);
+ attrMapDe.put("Dornen", 13);
+ attrMapDe.put("Espinas", 13);
+ attrMapDe.put("Spine", 13);
+ attrMapDe.put("Ticks", 14);
+ attrMapDe.put("Zecken", 14);
+ attrMapDe.put("Garrapatas", 14);
+ attrMapDe.put("Zecche", 14);
+ attrMapDe.put("Abandoned mines", 15);
+ attrMapDe.put("Folgen des Bergbaus", 15);
+ attrMapDe.put("Mina abandonada", 15);
+ attrMapDe.put("Miniere abbandonate", 15);
+ attrMapDe.put("Poisonous plants", 16);
+ attrMapDe.put("giftige Pflanzen", 16);
+ attrMapDe.put("Planta venenosa", 16);
+ attrMapDe.put("Piante velenose", 16);
+ attrMapDe.put("Dangerous animals", 17);
+ attrMapDe.put("giftige/gefährliche Tiere", 17);
+ attrMapDe.put("Animales Peligrosos", 17);
+ attrMapDe.put("Animali pericolosi", 17);
+ attrMapPl.put("Quick cache", 40);
+ attrMapPl.put("Szybka skrzynka", 40);
+ attrMapDe.put("Overnight stay necessary", 37);
+ attrMapDe.put("Übernachtung erforderlich", 37);
+ attrMapDe.put("Necesario pernoctar", 37);
+ attrMapDe.put("Necessario pernottamento", 37);
+ attrMapPl.put("Take your children", 41);
+ attrMapPl.put("Można zabrać dzieci", 41);
+ attrMapDe.put("Suited for children (10-12 yo)", 59);
+ attrMapDe.put("kindgerecht (10-12 Jahre)", 59);
+ attrMapDe.put("Apto para niños (10-12 años)", 59);
+ attrMapDe.put("Suited for children (10-12 anni)", 59);
+ // first trailer line
+
+ }
+
+ public static int getOcDeId(final String name) {
+
+ int result = 0;
+
+ if (attrMapDe.containsKey(name)) {
+ result = attrMapDe.get(name);
+ }
+ return result;
+ }
+}
diff --git a/main/src/cgeo/geocaching/connector/oc/OC11XMLParser.java b/main/src/cgeo/geocaching/connector/oc/OC11XMLParser.java
deleted file mode 100644
index 621032f..0000000
--- a/main/src/cgeo/geocaching/connector/oc/OC11XMLParser.java
+++ /dev/null
@@ -1,754 +0,0 @@
-package cgeo.geocaching.connector.oc;
-
-import cgeo.geocaching.Geocache;
-import cgeo.geocaching.Image;
-import cgeo.geocaching.LogEntry;
-import cgeo.geocaching.R;
-import cgeo.geocaching.Settings;
-import cgeo.geocaching.cgeoapplication;
-import cgeo.geocaching.connector.ConnectorFactory;
-import cgeo.geocaching.connector.IConnector;
-import cgeo.geocaching.connector.gc.GCConnector;
-import cgeo.geocaching.enumerations.CacheAttribute;
-import cgeo.geocaching.enumerations.CacheSize;
-import cgeo.geocaching.enumerations.CacheType;
-import cgeo.geocaching.enumerations.LogType;
-import cgeo.geocaching.geopoint.Geopoint;
-import cgeo.geocaching.utils.Log;
-
-import org.apache.commons.lang3.StringUtils;
-import org.xml.sax.Attributes;
-import org.xml.sax.SAXException;
-
-import android.content.res.Resources;
-import android.sax.Element;
-import android.sax.EndElementListener;
-import android.sax.EndTextElementListener;
-import android.sax.RootElement;
-import android.sax.StartElementListener;
-import android.util.Xml;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.Collection;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Locale;
-import java.util.Map;
-import java.util.TimeZone;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-public class OC11XMLParser {
-
- private static final String[] MARKUP = new String[] { "p", "span" };
- private static Pattern STRIP_DATE = Pattern.compile("\\+0([0-9]){1}\\:00");
- private static Pattern LOCAL_URL = Pattern.compile("href=\"(.*)\"");
- private static final int CACHE_PARSE_LIMIT = 250;
- private static final Resources res = cgeoapplication.getInstance().getResources();
-
- private static ImageHolder imageHolder = null;
-
- private static class CacheHolder {
- public Geocache cache;
- public String latitude;
- public String longitude;
- }
-
- private static class CacheLog {
- public String id;
- public String cacheId;
- public LogEntry logEntry;
- }
-
- private static class CacheDescription {
- public String cacheId;
- public String shortDesc;
- public String desc;
- public String hint;
- }
-
- private static class ImageHolder {
- public String url;
- public String objectId;
- protected String title;
- protected boolean isSpoiler = false;
- }
-
- private static Date parseFullDate(final String date) {
- final SimpleDateFormat ISO8601DATEFORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US);
- ISO8601DATEFORMAT.setTimeZone(TimeZone.getTimeZone("UTC"));
- final String strippedDate = STRIP_DATE.matcher(date).replaceAll("+0$100");
- try {
- return ISO8601DATEFORMAT.parse(strippedDate);
- } catch (ParseException e) {
- Log.e("OC11XMLParser.parseFullDate", e);
- }
- return null;
- }
-
- private static Date parseDayDate(final String date) {
- final SimpleDateFormat ISO8601DATEFORMAT = new SimpleDateFormat("yyyy-MM-dd", Locale.US);
- ISO8601DATEFORMAT.setTimeZone(TimeZone.getTimeZone("UTC"));
- final String strippedDate = STRIP_DATE.matcher(date).replaceAll("+0$100");
- try {
- return ISO8601DATEFORMAT.parse(strippedDate);
- } catch (ParseException e) {
- Log.e("OC11XMLParser.parseDayDate", e);
- }
- return null;
- }
-
- private static CacheSize getCacheSize(final String sizeId) {
- try {
- int size = Integer.parseInt(sizeId);
-
- switch (size) {
- case 1:
- return CacheSize.OTHER;
- case 2:
- return CacheSize.MICRO;
- case 3:
- return CacheSize.SMALL;
- case 4:
- return CacheSize.REGULAR;
- case 5:
- case 6:
- return CacheSize.LARGE;
- case 8:
- return CacheSize.VIRTUAL;
- default:
- break;
- }
- } catch (NumberFormatException e) {
- Log.e("OC11XMLParser.getCacheSize", e);
- }
- return CacheSize.NOT_CHOSEN;
- }
-
- private static CacheType getCacheType(final String typeId) {
- try {
- int type = Integer.parseInt(typeId);
- switch (type) {
- case 1: // Other/unbekannter Cachetyp
- return CacheType.UNKNOWN;
- case 2: // Trad./normaler Cache
- return CacheType.TRADITIONAL;
- case 3: // Multi/Multicache
- return CacheType.MULTI;
- case 4: // Virt./virtueller Cache
- return CacheType.VIRTUAL;
- case 5: // ICam./Webcam-Cache
- return CacheType.WEBCAM;
- case 6: // Event/Event-Cache
- return CacheType.EVENT;
- case 7: // Quiz/Rätselcache
- return CacheType.MYSTERY;
- case 8: // Math/Mathe-/Physikcache
- return CacheType.MYSTERY;
- case 9: // Moving/beweglicher Cache
- return CacheType.VIRTUAL;
- case 10: // Driv./Drive-In
- return CacheType.TRADITIONAL;
- default:
- return CacheType.UNKNOWN;
- }
- } catch (NumberFormatException e) {
- Log.e("OC11XMLParser.getCacheType", e);
- }
- return CacheType.UNKNOWN;
- }
-
- private static LogType getLogType(final int typeId) {
- switch (typeId) {
- case 1:
- return LogType.FOUND_IT;
- case 2:
- return LogType.DIDNT_FIND_IT;
- case 3:
- return LogType.NOTE;
- case 7:
- return LogType.ATTENDED;
- case 8:
- return LogType.WILL_ATTEND;
- default:
- return LogType.UNKNOWN;
- }
- }
-
- private static void setCacheStatus(final int statusId, final Geocache cache) {
- switch (statusId) {
- case 1:
- cache.setArchived(false);
- cache.setDisabled(false);
- break;
- case 2:
- cache.setArchived(false);
- cache.setDisabled(true);
- break;
- default:
- cache.setArchived(true);
- cache.setDisabled(false);
- break;
- }
- }
-
- private static void resetCache(final CacheHolder cacheHolder) {
- cacheHolder.cache = new Geocache(null);
- cacheHolder.cache.setReliableLatLon(true);
- cacheHolder.cache.setDescription(StringUtils.EMPTY);
- cacheHolder.latitude = "0.0";
- cacheHolder.longitude = "0.0";
- }
-
- private static void resetLog(final CacheLog log) {
- log.cacheId = StringUtils.EMPTY;
- log.logEntry = new LogEntry("", 0, LogType.UNKNOWN, "");
- }
-
- private static void resetDesc(final CacheDescription desc) {
- desc.cacheId = StringUtils.EMPTY;
- desc.shortDesc = StringUtils.EMPTY;
- desc.desc = StringUtils.EMPTY;
- desc.hint = StringUtils.EMPTY;
- }
-
- private static int attributeId;
-
- public static Collection<Geocache> parseCaches(final InputStream stream) throws IOException {
- // parse and return caches without filtering
- return parseCaches(stream, true);
- }
-
- public static Collection<Geocache> parseCachesFiltered(final InputStream stream) throws IOException {
- // parse caches and filter result
- return parseCaches(stream, false);
- }
-
- private static Collection<Geocache> parseCaches(final InputStream stream, boolean ignoreFiltersIn) throws IOException {
-
- final Map<String, Geocache> caches = new HashMap<String, Geocache>();
- final Map<String, LogEntry> logs = new HashMap<String, LogEntry>();
-
- final CacheHolder cacheHolder = new CacheHolder();
- final CacheLog logHolder = new CacheLog();
- final CacheDescription descHolder = new CacheDescription();
-
- final RootElement root = new RootElement("oc11xml");
- final Element cacheNode = root.getChild("cache");
-
- final boolean ignoreFilters = ignoreFiltersIn;
-
- // cache
- cacheNode.setStartElementListener(new StartElementListener() {
-
- @Override
- public void start(Attributes attributes) {
- resetCache(cacheHolder);
- }
-
- });
-
- cacheNode.setEndElementListener(new EndElementListener() {
-
- @Override
- public void end() {
- Geocache cache = cacheHolder.cache;
- Geopoint coords = new Geopoint(cacheHolder.latitude, cacheHolder.longitude);
- cache.setCoords(coords);
- if (caches.size() < CACHE_PARSE_LIMIT && isValid(cache) && (ignoreFilters || !isExcluded(cache))) {
- cache.setDetailedUpdatedNow();
- caches.put(cache.getCacheId(), cache);
- }
- }
-
- private boolean isExcluded(Geocache cache) {
- if (cache.isArchived()) {
- return true;
- }
- if (cache.isDisabled() && Settings.isExcludeDisabledCaches()) {
- return true;
- }
- if ((cache.isFound() || cache.isOwner()) && Settings.isExcludeMyCaches()) {
- return true;
- }
- return !Settings.getCacheType().contains(cache);
- }
-
- private boolean isValid(Geocache cache) {
- return StringUtils.isNotBlank(cache.getGeocode()) && !cache.getCoords().equals(Geopoint.ZERO);
- }
- });
-
- // cache.id
- cacheNode.getChild("id").setEndTextElementListener(new EndTextElementListener() {
-
- @Override
- public void end(String body) {
- cacheHolder.cache.setCacheId(body);
- }
- });
-
- // cache.longitude
- cacheNode.getChild("longitude").setEndTextElementListener(new EndTextElementListener() {
-
- @Override
- public void end(String body) {
- String longitude = body.trim();
- if (StringUtils.isNotBlank(longitude)) {
- cacheHolder.longitude = longitude;
- }
- }
- });
-
- // cache.latitude
- cacheNode.getChild("latitude").setEndTextElementListener(new EndTextElementListener() {
-
- @Override
- public void end(String body) {
- String latitude = body.trim();
- if (StringUtils.isNotBlank(latitude)) {
- cacheHolder.latitude = latitude;
- }
- }
- });
-
- // cache.name
- cacheNode.getChild("name").setEndTextElementListener(new EndTextElementListener() {
-
- @Override
- public void end(String body) {
- final String content = body.trim();
- cacheHolder.cache.setName(content);
- }
- });
-
- // cache.waypoints[oc]
- cacheNode.getChild("waypoints").setStartElementListener(new StartElementListener() {
-
- @Override
- public void start(Attributes attrs) {
- if (attrs.getIndex("oc") > -1) {
- cacheHolder.cache.setGeocode(attrs.getValue("oc"));
- }
- if (attrs.getIndex("gccom") > -1) {
- String gccode = attrs.getValue("gccom");
- if (!StringUtils.isBlank(gccode)) {
- cacheHolder.cache.setDescription(res.getString(R.string.cache_listed_on, GCConnector.getInstance().getName()) + ": <a href=\"http://coord.info/" + gccode + "\">" + gccode + "</a><br /><br />");
- }
- }
- }
- });
-
- // cache.type[id]
- cacheNode.getChild("type").setStartElementListener(new StartElementListener() {
-
- @Override
- public void start(Attributes attrs) {
- if (attrs.getIndex("id") > -1) {
- final String typeId = attrs.getValue("id");
- cacheHolder.cache.setType(getCacheType(typeId));
- }
- }
- });
-
- // cache.status[id]
- cacheNode.getChild("status").setStartElementListener(new StartElementListener() {
-
- @Override
- public void start(Attributes attrs) {
- if (attrs.getIndex("id") > -1) {
- try {
- final int statusId = Integer.parseInt(attrs.getValue("id"));
- setCacheStatus(statusId, cacheHolder.cache);
- } catch (NumberFormatException e) {
- Log.w(String.format("Failed to parse status of cache '%s'.", cacheHolder.cache.getGeocode()));
- }
- }
- }
- });
-
- // cache.size[id]
- cacheNode.getChild("size").setStartElementListener(new StartElementListener() {
-
- @Override
- public void start(Attributes attrs) {
- if (attrs.getIndex("id") > -1) {
- final String typeId = attrs.getValue("id");
- cacheHolder.cache.setSize(getCacheSize(typeId));
- }
- }
- });
-
- // cache.difficulty
- cacheNode.getChild("difficulty").setEndTextElementListener(new EndTextElementListener() {
-
- @Override
- public void end(String body) {
- final String content = body.trim();
- try {
- cacheHolder.cache.setDifficulty(Float.valueOf(content));
- } catch (NumberFormatException e) {
- Log.e("OC11XMLParser: unknown difficulty " + content, e);
- }
- }
- });
-
- // cache.terrain
- cacheNode.getChild("terrain").setEndTextElementListener(new EndTextElementListener() {
-
- @Override
- public void end(String body) {
- final String content = body.trim();
- try {
- cacheHolder.cache.setTerrain(Float.valueOf(content));
- } catch (NumberFormatException e) {
- Log.e("OC11XMLParser: unknown terrain " + content, e);
- }
- }
- });
-
- // cache.datehidden
- cacheNode.getChild("datehidden").setEndTextElementListener(new EndTextElementListener() {
-
- @Override
- public void end(String body) {
- final String content = body.trim();
- cacheHolder.cache.setHidden(parseFullDate(content));
- }
- });
-
- // cache.userid
- final Element useridNode = cacheNode.getChild("userid");
-
- useridNode.setStartElementListener(new StartElementListener() {
-
- @Override
- public void start(Attributes attributes) {
- if (attributes.getIndex("id") > -1) {
- cacheHolder.cache.setOwnerUserId(attributes.getValue("id"));
- }
- }
- });
-
- useridNode.setEndTextElementListener(new EndTextElementListener() {
-
- @Override
- public void end(String body) {
- cacheHolder.cache.setOwnerDisplayName(body);
- }
- });
-
- // cache.attributes.attribute
- final Element attributeNode = cacheNode.getChild("attributes").getChild("attribute");
-
- attributeNode.setStartElementListener(new StartElementListener() {
-
- @Override
- public void start(Attributes attributes) {
- if (attributes.getIndex("id") > -1) {
- try {
- attributeId = Integer.parseInt(attributes.getValue("id"));
- } catch (NumberFormatException e) {
- Log.w(String.format("Failed to parse attribute id of cache '%s'.", cacheHolder.cache.getGeocode()));
- }
- }
- }
- });
-
- attributeNode.setEndTextElementListener(new EndTextElementListener() {
- @Override
- public void end(String body) {
- CacheAttribute attribute = CacheAttribute.getByOcId(attributeId);
- if (attribute != null) {
- // semantic of attributes on opencaching is always "yes"
- cacheHolder.cache.getAttributes().add(attribute.getAttributeName(true));
- }
- else {
- if (StringUtils.isNotBlank(body)) {
- cacheHolder.cache.getAttributes().add(body.trim());
- }
- }
- }
- });
-
- // cachedesc
- final Element cacheDesc = root.getChild("cachedesc");
-
- cacheDesc.setStartElementListener(new StartElementListener() {
-
- @Override
- public void start(Attributes attributes) {
- resetDesc(descHolder);
- }
- });
-
- cacheDesc.setEndElementListener(new EndElementListener() {
-
- @Override
- public void end() {
- final Geocache cache = caches.get(descHolder.cacheId);
- if (cache != null) {
- cache.setShortDescription(descHolder.shortDesc);
- cache.setDescription(cache.getDescription() + descHolder.desc);
- cache.setHint(descHolder.hint);
- }
- }
- });
-
- // cachedesc.cacheid
- cacheDesc.getChild("cacheid").setEndTextElementListener(new EndTextElementListener() {
-
- @Override
- public void end(String body) {
- descHolder.cacheId = body;
- }
- });
-
- // cachedesc.desc
- cacheDesc.getChild("shortdesc").setEndTextElementListener(new EndTextElementListener() {
-
- @Override
- public void end(String body) {
- final String content = body.trim();
- descHolder.shortDesc = linkify(stripMarkup(content));
- }
- });
-
- // cachedesc.desc
- cacheDesc.getChild("desc").setEndTextElementListener(new EndTextElementListener() {
-
- @Override
- public void end(String body) {
- final String content = body.trim();
- descHolder.desc = linkify(stripMarkup(content));
- }
- });
-
- // cachedesc.hint
- cacheDesc.getChild("hint").setEndTextElementListener(new EndTextElementListener() {
-
- @Override
- public void end(String body) {
- descHolder.hint = body.trim();
- }
- });
-
- // cachelog
- final Element cacheLog = root.getChild("cachelog");
-
- cacheLog.setStartElementListener(new StartElementListener() {
-
- @Override
- public void start(Attributes attrs) {
- resetLog(logHolder);
- }
- });
-
- cacheLog.setEndElementListener(new EndElementListener() {
-
- @Override
- public void end() {
- final Geocache cache = caches.get(logHolder.cacheId);
- if (cache != null && logHolder.logEntry.type != LogType.UNKNOWN) {
- logs.put(logHolder.id, logHolder.logEntry);
- cache.getLogs().add(0, logHolder.logEntry);
- if ((logHolder.logEntry.type == LogType.FOUND_IT || logHolder.logEntry.type == LogType.ATTENDED)
- && StringUtils.equalsIgnoreCase(logHolder.logEntry.author, Settings.getOCConnectorUserName())) {
- cache.setFound(true);
- cache.setVisitedDate(logHolder.logEntry.date);
- }
- }
- }
- });
-
- // cachelog.id
- cacheLog.getChild("id").setEndTextElementListener(new EndTextElementListener() {
-
- @Override
- public void end(String body) {
- logHolder.id = StringUtils.trim(body);
- }
- });
-
- // cachelog.cacheid
- cacheLog.getChild("cacheid").setEndTextElementListener(new EndTextElementListener() {
-
- @Override
- public void end(String body) {
- logHolder.cacheId = body;
- }
- });
-
- // cachelog.date
- cacheLog.getChild("date").setEndTextElementListener(new EndTextElementListener() {
-
- @Override
- public void end(String body) {
- try {
- logHolder.logEntry.date = parseDayDate(body).getTime();
- } catch (NullPointerException e) {
- Log.w("Failed to parse log date", e);
- }
- }
- });
-
- // cachelog.logtype
- cacheLog.getChild("logtype").setStartElementListener(new StartElementListener() {
-
- @Override
- public void start(Attributes attrs) {
- if (attrs.getIndex("id") > -1) {
- final String id = attrs.getValue("id");
- try {
- final int typeId = Integer.parseInt(id);
- logHolder.logEntry.type = getLogType(typeId);
- } catch (NumberFormatException e) {
- Log.e("OC11XMLParser, unknown logtype " + id, e);
- }
- }
- }
- });
-
- // cachelog.userid
- cacheLog.getChild("userid").setEndTextElementListener(new EndTextElementListener() {
-
- @Override
- public void end(String finderName) {
- logHolder.logEntry.author = finderName;
- }
- });
-
- // cachelog.text
- cacheLog.getChild("text").setEndTextElementListener(new EndTextElementListener() {
-
- @Override
- public void end(String logText) {
- logHolder.logEntry.log = stripMarkup(logText);
- }
- });
-
- // pictures
- final Element picture = root.getChild("picture");
-
- picture.setStartElementListener(new StartElementListener() {
-
- @Override
- public void start(Attributes attrs) {
- imageHolder = new ImageHolder();
- }
- });
-
- picture.setEndElementListener(new EndElementListener() {
-
- @Override
- public void end() {
- if (imageHolder.isSpoiler) {
- final Geocache cache = caches.get(imageHolder.objectId);
- if (cache != null) {
- Image spoiler = new Image(imageHolder.url, imageHolder.title);
- cache.addSpoiler(spoiler);
- }
- }
- else {
- final LogEntry log = logs.get(imageHolder.objectId);
- if (log != null) {
- log.addLogImage(new Image(imageHolder.url, imageHolder.title));
- }
- }
- }
- });
-
- // picture.object
- picture.getChild("object").setEndTextElementListener(new EndTextElementListener() {
-
- @Override
- public void end(String body) {
- imageHolder.objectId = StringUtils.trim(body);
- }
- });
-
- // picture.title
- picture.getChild("title").setEndTextElementListener(new EndTextElementListener() {
-
- @Override
- public void end(String body) {
- imageHolder.title = StringUtils.trim(body);
- }
- });
-
- // picture.url
- picture.getChild("url").setEndTextElementListener(new EndTextElementListener() {
-
- @Override
- public void end(String body) {
- imageHolder.url = StringUtils.trim(body);
- }
- });
-
- // picture.attributes
- picture.getChild("attributes").setStartElementListener(new StartElementListener() {
-
- @Override
- public void start(Attributes attributes) {
- if (attributes.getIndex("spoiler") > -1) {
- String spoiler = attributes.getValue("spoiler");
- imageHolder.isSpoiler = ("1".equals(spoiler));
- }
- }
- });
-
- try {
- Xml.parse(stream, Xml.Encoding.UTF_8, root.getContentHandler());
- return caches.values();
- } catch (SAXException e) {
- Log.e("Cannot parse .gpx file as oc11xml: could not parse XML", e);
- return null;
- }
- }
-
- /**
- * Converts local links to absolute links targeting the OC website.
- */
- private static String linkify(String input) {
- String result = input;
- Matcher matcher = LOCAL_URL.matcher(result);
- while (matcher.find()) {
- String url = matcher.group(1);
- if (!url.contains(":/")) {
- IConnector ocConnector = ConnectorFactory.getConnector("OCXXX");
- String prefix = "http://" + ocConnector.getHost() + "/";
- result = StringUtils.replace(result, url, prefix + url);
- matcher = LOCAL_URL.matcher(result);
- }
- }
- return result;
- }
-
- /**
- * Removes unneeded markup. Log texts are typically encapsulated in paragraph tags which lead to more empty space on
- * rendering.
- */
- protected static String stripMarkup(String input) {
- if (!StringUtils.startsWith(input, "<")) {
- return input;
- }
- String result = input.trim();
- for (String tagName : MARKUP) {
- final String startTag = "<" + tagName + ">";
- if (StringUtils.startsWith(result, startTag)) {
- final String endTag = "</" + tagName + ">";
- if (StringUtils.endsWith(result, endTag)) {
- String inner = result.substring(startTag.length(), result.length() - endTag.length()).trim();
- String nested = stripMarkup(inner);
- if (!nested.contains(startTag)) {
- result = nested;
- }
- }
- }
- }
- return result;
- }
-} \ No newline at end of file
diff --git a/main/src/cgeo/geocaching/connector/oc/OCApiConnector.java b/main/src/cgeo/geocaching/connector/oc/OCApiConnector.java
index 69cf8a4..4f365ec 100644
--- a/main/src/cgeo/geocaching/connector/oc/OCApiConnector.java
+++ b/main/src/cgeo/geocaching/connector/oc/OCApiConnector.java
@@ -7,13 +7,31 @@ import cgeo.geocaching.network.Parameters;
import cgeo.geocaching.utils.CancellableHandler;
import cgeo.geocaching.utils.CryptUtils;
+import org.apache.commons.lang3.StringUtils;
+
public class OCApiConnector extends OCConnector implements ISearchByGeocode {
+ // Levels of Okapi we support
+ // oldapi is around rev 500
+ // current is from rev 798 onwards
+ public enum ApiSupport {
+ oldapi,
+ current
+ }
+
+ // Levels of OAuth-Authentication we support
+ public enum OAuthLevel {
+ Level1,
+ Level3
+ }
+
private final String cK;
+ private final ApiSupport apiSupport;
- public OCApiConnector(String name, String host, String prefix, String cK) {
+ public OCApiConnector(String name, String host, String prefix, String cK, ApiSupport apiSupport) {
super(name, host, prefix);
this.cK = cK;
+ this.apiSupport = apiSupport;
}
public void addAuthentication(final Parameters params) {
@@ -23,7 +41,7 @@ public class OCApiConnector extends OCConnector implements ISearchByGeocode {
@Override
public String getLicenseText(final Geocache cache) {
// NOT TO BE TRANSLATED
- return "<a href=\"" + getCacheUrl(cache) + "\">" + getName() + "</a> data licensed under the Creative Commons BY-SA 3.0 License";
+ return "© " + cache.getOwnerDisplayName() + ", <a href=\"" + getCacheUrl(cache) + "\">" + getName() + "</a>, CC-BY-NC-ND, alle Logeinträge © jeweiliger Autor";
}
@Override
@@ -40,4 +58,23 @@ public class OCApiConnector extends OCConnector implements ISearchByGeocode {
// currently always active, but only for details download
return true;
}
+
+ @SuppressWarnings("static-method")
+ public OAuthLevel getSupportedAuthLevel() {
+ return OAuthLevel.Level1;
+ }
+
+ public String getCK() {
+ return CryptUtils.rot13(cK);
+ }
+
+ @SuppressWarnings("static-method")
+ public String getCS() {
+ return StringUtils.EMPTY;
+ }
+
+ public ApiSupport getApiSupport() {
+ return apiSupport;
+ }
+
}
diff --git a/main/src/cgeo/geocaching/connector/oc/OCApiLiveConnector.java b/main/src/cgeo/geocaching/connector/oc/OCApiLiveConnector.java
new file mode 100644
index 0000000..4c6db97
--- /dev/null
+++ b/main/src/cgeo/geocaching/connector/oc/OCApiLiveConnector.java
@@ -0,0 +1,119 @@
+package cgeo.geocaching.connector.oc;
+
+import cgeo.geocaching.Geocache;
+import cgeo.geocaching.SearchResult;
+import cgeo.geocaching.Settings;
+import cgeo.geocaching.cgData;
+import cgeo.geocaching.cgeoapplication;
+import cgeo.geocaching.connector.ILoggingManager;
+import cgeo.geocaching.connector.capability.ISearchByCenter;
+import cgeo.geocaching.connector.capability.ISearchByViewPort;
+import cgeo.geocaching.connector.oc.OkapiClient.UserInfo;
+import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.geopoint.Viewport;
+import cgeo.geocaching.utils.CryptUtils;
+
+import org.apache.commons.lang3.StringUtils;
+
+import android.app.Activity;
+
+public class OCApiLiveConnector extends OCApiConnector implements ISearchByCenter, ISearchByViewPort {
+
+ private String cS;
+ private UserInfo userInfo = new UserInfo(StringUtils.EMPTY, 0, false);
+
+ public OCApiLiveConnector(String name, String host, String prefix, int cKResId, int cSResId, ApiSupport apiSupport) {
+ super(name, host, prefix, CryptUtils.rot13(cgeoapplication.getInstance().getResources().getString(cKResId)), apiSupport);
+
+ cS = CryptUtils.rot13(cgeoapplication.getInstance().getResources().getString(cSResId));
+ }
+
+ @Override
+ public boolean isActivated() {
+ return Settings.isOCConnectorActive();
+ }
+
+ @Override
+ public SearchResult searchByViewport(Viewport viewport, String[] tokens) {
+ return new SearchResult(OkapiClient.getCachesBBox(viewport, this));
+ }
+
+ @Override
+ public SearchResult searchByCenter(Geopoint center) {
+
+ return new SearchResult(OkapiClient.getCachesAround(center, this));
+ }
+
+ @Override
+ public OAuthLevel getSupportedAuthLevel() {
+ // TODO the tokens must be available connector specific
+ if (StringUtils.isNotBlank(Settings.getOCDETokenPublic()) && StringUtils.isNotBlank(Settings.getOCDETokenSecret())) {
+ return OAuthLevel.Level3;
+ }
+ return OAuthLevel.Level1;
+ }
+
+ @Override
+ public String getCS() {
+ return CryptUtils.rot13(cS);
+ }
+
+ @Override
+ public boolean supportsWatchList() {
+ return true;
+ }
+
+ @Override
+ public boolean addToWatchlist(Geocache cache) {
+ final boolean added = OkapiClient.setWatchState(cache, true, this);
+
+ if (added) {
+ cgData.saveChangedCache(cache);
+ }
+
+ return added;
+ }
+
+ @Override
+ public boolean removeFromWatchlist(Geocache cache) {
+ final boolean removed = OkapiClient.setWatchState(cache, false, this);
+
+ if (removed) {
+ cgData.saveChangedCache(cache);
+ }
+
+ return removed;
+ }
+
+ @Override
+ public boolean supportsLogging() {
+ return true;
+ }
+
+ @Override
+ public ILoggingManager getLoggingManager(Activity activity, Geocache cache) {
+ return new OkapiLoggingManager(activity, this, cache);
+ }
+
+ @Override
+ public boolean canLog(Geocache cache) {
+ return true;
+ }
+
+ public boolean supportsPersonalization() {
+ return getSupportedAuthLevel() == OAuthLevel.Level3;
+ }
+
+ public boolean retrieveUserInfo() {
+ userInfo = OkapiClient.getUserInfo(this);
+ return userInfo.isRetrieveSuccessful();
+ }
+
+ public Object getUserName() {
+ return userInfo.getName();
+ }
+
+ public int getCachesFound() {
+ return userInfo.getFinds();
+ }
+}
diff --git a/main/src/cgeo/geocaching/connector/oc/OCAuthorizationActivity.java b/main/src/cgeo/geocaching/connector/oc/OCAuthorizationActivity.java
new file mode 100644
index 0000000..779c1c5
--- /dev/null
+++ b/main/src/cgeo/geocaching/connector/oc/OCAuthorizationActivity.java
@@ -0,0 +1,109 @@
+package cgeo.geocaching.connector.oc;
+
+import cgeo.geocaching.R;
+import cgeo.geocaching.Settings;
+import cgeo.geocaching.cgeoapplication;
+import cgeo.geocaching.network.OAuthAuthorizationActivity;
+
+import org.apache.commons.lang3.tuple.ImmutablePair;
+
+public class OCAuthorizationActivity extends OAuthAuthorizationActivity {
+
+ private final int siteResId = R.string.auth_ocde;
+
+ public OCAuthorizationActivity() {
+ super("www.opencaching.de",
+ "/okapi/services/oauth/request_token",
+ "/okapi/services/oauth/authorize",
+ "/okapi/services/oauth/access_token",
+ false,
+ cgeoapplication.getInstance().getResources().getString(R.string.oc_de_okapi_consumer_key),
+ cgeoapplication.getInstance().getResources().getString(R.string.oc_de_okapi_consumer_secret));
+ }
+
+ @Override
+ protected ImmutablePair<String, String> getTempToken() {
+ return Settings.getTempOCDEToken();
+ }
+
+ @Override
+ protected void setTempTokens(String tokenPublic, String tokenSecret) {
+ Settings.setOCDETempTokens(tokenPublic, tokenSecret);
+ }
+
+ @Override
+ protected void setTokens(String tokenPublic, String tokenSecret, boolean enable) {
+ Settings.setOCDETokens(tokenPublic, tokenSecret, enable);
+ }
+
+ @Override
+ protected String getAuthTitle() {
+ return res.getString(siteResId);
+ }
+
+ @Override
+ protected String getAuthAgain() {
+ return res.getString(R.string.auth_again_oc);
+ }
+
+ @Override
+ protected String getErrAuthInitialize() {
+ return res.getString(R.string.err_auth_initialize);
+ }
+
+ @Override
+ protected String getAuthStart() {
+ return res.getString(R.string.auth_start_oc);
+ }
+
+ @Override
+ protected String getAuthDialogCompleted() {
+ return res.getString(R.string.auth_dialog_completed_oc, getAuthTitle());
+ }
+
+ @Override
+ protected String getErrAuthProcess() {
+ return res.getString(R.string.err_auth_process);
+ }
+
+ @Override
+ protected String getAuthDialogWait() {
+ return res.getString(R.string.auth_dialog_wait_oc, getAuthTitle());
+ }
+
+ @Override
+ protected String getAuthDialogPinTitle() {
+ return res.getString(R.string.auth_dialog_pin_title_oc);
+ }
+
+ @Override
+ protected String getAuthDialogPinMessage() {
+ return res.getString(R.string.auth_dialog_pin_message_oc, getAuthTitle());
+ }
+
+ @Override
+ protected String getAboutAuth1() {
+ return res.getString(R.string.about_auth_1_oc, getAuthTitle());
+ }
+
+ @Override
+ protected String getAboutAuth2() {
+ return res.getString(R.string.about_auth_2_oc, getAuthTitle(), getAuthTitle());
+ }
+
+ @Override
+ protected String getAuthAuthorize() {
+ return res.getString(R.string.auth_authorize_oc);
+ }
+
+ @Override
+ protected String getAuthPinHint() {
+ return res.getString(R.string.auth_pin_hint_oc, getAuthTitle());
+ }
+
+ @Override
+ protected String getAuthFinish() {
+ return res.getString(R.string.auth_finish_oc);
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/connector/oc/OCConnector.java b/main/src/cgeo/geocaching/connector/oc/OCConnector.java
index 62dfb4c..01738c0 100644
--- a/main/src/cgeo/geocaching/connector/oc/OCConnector.java
+++ b/main/src/cgeo/geocaching/connector/oc/OCConnector.java
@@ -2,8 +2,8 @@ package cgeo.geocaching.connector.oc;
import cgeo.geocaching.Geocache;
import cgeo.geocaching.ICache;
+import cgeo.geocaching.R;
import cgeo.geocaching.connector.AbstractConnector;
-import cgeo.geocaching.enumerations.CacheRealm;
import java.util.regex.Pattern;
@@ -59,8 +59,11 @@ public class OCConnector extends AbstractConnector {
}
@Override
- public CacheRealm getCacheRealm() {
- return CacheRealm.OC;
+ public int getCacheMapMarkerId(boolean disabled) {
+ if (disabled) {
+ return R.drawable.marker_disabled_oc;
+ }
+ return R.drawable.marker_oc;
}
}
diff --git a/main/src/cgeo/geocaching/connector/oc/OCXMLApiConnector.java b/main/src/cgeo/geocaching/connector/oc/OCXMLApiConnector.java
deleted file mode 100644
index 43fdcfc..0000000
--- a/main/src/cgeo/geocaching/connector/oc/OCXMLApiConnector.java
+++ /dev/null
@@ -1,67 +0,0 @@
-package cgeo.geocaching.connector.oc;
-
-import cgeo.geocaching.Geocache;
-import cgeo.geocaching.ICache;
-import cgeo.geocaching.SearchResult;
-import cgeo.geocaching.Settings;
-import cgeo.geocaching.connector.capability.ISearchByCenter;
-import cgeo.geocaching.connector.capability.ISearchByGeocode;
-import cgeo.geocaching.connector.capability.ISearchByViewPort;
-import cgeo.geocaching.geopoint.Geopoint;
-import cgeo.geocaching.geopoint.Viewport;
-import cgeo.geocaching.ui.Formatter;
-import cgeo.geocaching.utils.CancellableHandler;
-
-import org.apache.commons.lang3.StringUtils;
-
-public class OCXMLApiConnector extends OCConnector implements ISearchByGeocode, ISearchByCenter, ISearchByViewPort {
-
- private final static double SEARCH_DISTANCE_LIMIT = 15.0;
- private final static double NEARBY_SEARCH_DISTANCE = 5.0;
-
- public OCXMLApiConnector(String name, String host, String prefix) {
- super(name, host, prefix);
- }
-
- @Override
- public SearchResult searchByGeocode(final String geocode, final String guid, CancellableHandler handler) {
- final Geocache cache = OCXMLClient.getCache(geocode);
- if (cache == null) {
- return null;
- }
- return new SearchResult(cache);
- }
-
- @Override
- public SearchResult searchByCenter(final Geopoint center) {
- return new SearchResult(OCXMLClient.getCachesAround(center, NEARBY_SEARCH_DISTANCE));
- }
-
- @Override
- public SearchResult searchByViewport(final Viewport viewport, final String[] tokens) {
- final Geopoint center = viewport.getCenter();
- double distance = center.distanceTo(viewport.bottomLeft) * 1.15;
- if (distance > SEARCH_DISTANCE_LIMIT) {
- distance = SEARCH_DISTANCE_LIMIT;
- }
- return new SearchResult(OCXMLClient.getCachesAround(center, distance));
- }
-
- @Override
- public boolean isActivated() {
- // currently only tested and working with oc.de
- return Settings.isOCConnectorActive();
- }
-
- @Override
- public boolean isOwner(ICache cache) {
- return StringUtils.equalsIgnoreCase(cache.getOwnerDisplayName(), Settings.getOCConnectorUserName());
- }
-
- @Override
- public String getLicenseText(Geocache cache) {
- // not to be translated
- return "© " + cache.getOwnerDisplayName() + ", " + "<a href=\"" + getCacheUrl(cache) + "\">www.opencaching.de</a>, CC-BY-NC-ND, Stand: " + Formatter.formatFullDate(cache.getUpdated());
- }
-
-}
diff --git a/main/src/cgeo/geocaching/connector/oc/OCXMLClient.java b/main/src/cgeo/geocaching/connector/oc/OCXMLClient.java
deleted file mode 100644
index 6767b48..0000000
--- a/main/src/cgeo/geocaching/connector/oc/OCXMLClient.java
+++ /dev/null
@@ -1,115 +0,0 @@
-package cgeo.geocaching.connector.oc;
-
-import cgeo.geocaching.Geocache;
-import cgeo.geocaching.cgData;
-import cgeo.geocaching.connector.ConnectorFactory;
-import cgeo.geocaching.connector.IConnector;
-import cgeo.geocaching.enumerations.LoadFlags;
-import cgeo.geocaching.geopoint.Geopoint;
-import cgeo.geocaching.geopoint.GeopointFormatter;
-import cgeo.geocaching.network.Network;
-import cgeo.geocaching.network.Parameters;
-import cgeo.geocaching.utils.Log;
-
-import ch.boye.httpclientandroidlib.HttpResponse;
-
-import org.apache.commons.lang3.StringUtils;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Locale;
-import java.util.zip.GZIPInputStream;
-
-public class OCXMLClient {
-
- private static final String SERVICE_CACHE = "/xml/ocxml11.php";
-
- // Url for single cache requests
- // http://www.opencaching.de/xml/ocxml11.php?modifiedsince=20060320000000&user=0&cache=1&cachedesc=1&cachelog=1&picture=1&removedobject=0&session=0&doctype=0&charset=utf-8&wp=OCC9BE
-
- public static Geocache getCache(final String geoCode) {
- try {
- final Parameters params = getOCXmlQueryParameters(true, true, true);
- params.put("wp", geoCode);
- final InputStream data = request(ConnectorFactory.getConnector(geoCode), SERVICE_CACHE, params);
-
- if (data == null) {
- return null;
- }
-
- Collection<Geocache> caches = OC11XMLParser.parseCaches(new GZIPInputStream(data));
- if (caches.iterator().hasNext()) {
- Geocache cache = caches.iterator().next();
- cgData.saveCache(cache, LoadFlags.SAVE_ALL);
- return cache;
- }
- return null;
- } catch (IOException e) {
- Log.e("Error parsing cache '" + geoCode + "'", e);
- return null;
- }
- }
-
- public static Collection<Geocache> getCachesAround(final Geopoint center, final double distance) {
- try {
- final Parameters params = getOCXmlQueryParameters(false, false, false);
- params.put("lat", GeopointFormatter.format(GeopointFormatter.Format.LAT_DECDEGREE_RAW, center));
- params.put("lon", GeopointFormatter.format(GeopointFormatter.Format.LON_DECDEGREE_RAW, center));
- params.put("distance", String.format(Locale.US, "%f", distance));
- final InputStream data = request(ConnectorFactory.getConnector("OCXXX"), SERVICE_CACHE, params);
-
- if (data == null) {
- return Collections.emptyList();
- }
-
- return OC11XMLParser.parseCachesFiltered(new GZIPInputStream(data));
- } catch (IOException e) {
- Log.e("Error parsing nearby search result", e);
- return Collections.emptyList();
- }
- }
-
- private static InputStream request(final IConnector connector, final String service, final Parameters params) {
- if (connector == null) {
- return null;
- }
- if (!(connector instanceof OCXMLApiConnector)) {
- return null;
- }
-
- final String host = connector.getHost();
- if (StringUtils.isBlank(host)) {
- return null;
- }
-
- final String uri = "http://" + host + service;
- HttpResponse resp = Network.getRequest(uri, params);
- if (resp != null) {
- try {
- return resp.getEntity().getContent();
- } catch (IllegalStateException e) {
- // fall through and return null
- } catch (IOException e) {
- // fall through and return null
- }
- }
- return null;
- }
-
- private static Parameters getOCXmlQueryParameters(final boolean withDescription, final boolean withLogs, final boolean withImages) {
- return new Parameters("modifiedsince", "20000101000000",
- "user", "0",
- "cache", "1",
- "cachedesc", withDescription ? "1" : "0",
- "cachelog", withLogs ? "1" : "0",
- "picture", withImages ? "1" : "0",
- "removedobject", "0",
- "session", "0",
- "doctype", "0",
- "charset", "utf-8",
- "zip", "gzip",
- "picturefromcachelog", withImages ? "1" : "0");
- }
-}
diff --git a/main/src/cgeo/geocaching/connector/oc/OkapiClient.java b/main/src/cgeo/geocaching/connector/oc/OkapiClient.java
index 0673605..f818a7c 100644
--- a/main/src/cgeo/geocaching/connector/oc/OkapiClient.java
+++ b/main/src/cgeo/geocaching/connector/oc/OkapiClient.java
@@ -3,16 +3,29 @@ package cgeo.geocaching.connector.oc;
import cgeo.geocaching.Geocache;
import cgeo.geocaching.Image;
import cgeo.geocaching.LogEntry;
+import cgeo.geocaching.R;
+import cgeo.geocaching.Settings;
+import cgeo.geocaching.Waypoint;
import cgeo.geocaching.cgData;
+import cgeo.geocaching.cgeoapplication;
import cgeo.geocaching.connector.ConnectorFactory;
import cgeo.geocaching.connector.IConnector;
+import cgeo.geocaching.connector.LogResult;
+import cgeo.geocaching.connector.gc.GCConnector;
+import cgeo.geocaching.connector.oc.OCApiConnector.ApiSupport;
+import cgeo.geocaching.connector.oc.OCApiConnector.OAuthLevel;
+import cgeo.geocaching.enumerations.CacheAttribute;
import cgeo.geocaching.enumerations.CacheSize;
import cgeo.geocaching.enumerations.CacheType;
import cgeo.geocaching.enumerations.LoadFlags.SaveFlag;
import cgeo.geocaching.enumerations.LogType;
+import cgeo.geocaching.enumerations.StatusCode;
+import cgeo.geocaching.enumerations.WaypointType;
import cgeo.geocaching.geopoint.Geopoint;
import cgeo.geocaching.geopoint.GeopointFormatter;
+import cgeo.geocaching.geopoint.Viewport;
import cgeo.geocaching.network.Network;
+import cgeo.geocaching.network.OAuth;
import cgeo.geocaching.network.Parameters;
import cgeo.geocaching.utils.Log;
@@ -22,17 +35,42 @@ import org.json.JSONException;
import org.json.JSONObject;
import android.net.Uri;
-import android.text.Html;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collections;
import java.util.Date;
import java.util.EnumSet;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
+import java.util.Map;
+import java.util.TimeZone;
final public class OkapiClient {
+
+ private static final char SEPARATOR = '|';
+ private static final String SEPARATOR_STRING = Character.toString(SEPARATOR);
+ private static final SimpleDateFormat logDateFormat;
+
+ static {
+ logDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSZ", Locale.US);
+ logDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
+ }
+
+ private static final String CACHE_ATTRNAMES = "attrnames";
+ private static final String WPT_LOCATION = "location";
+ private static final String WPT_DESCRIPTION = "description";
+ private static final String WPT_TYPE = "type";
+ private static final String WPT_NAME = "name";
+ private static final String CACHE_IS_WATCHED = "is_watched";
+ private static final String CACHE_WPTS = "alt_wpts";
+ private static final String CACHE_STATUS_ARCHIVED = "Archived";
+ private static final String CACHE_STATUS_DISABLED = "Temporarily unavailable";
+ private static final String CACHE_IS_FOUND = "is_found";
private static final String CACHE_SIZE = "size";
private static final String CACHE_VOTES = "rating_votes";
private static final String CACHE_NOTFOUNDS = "notfounds";
@@ -62,15 +100,35 @@ final public class OkapiClient {
private static final String LOG_USER = "user";
private static final String USER_USERNAME = "username";
+ private static final String USER_CACHES_FOUND = "caches_found";
+ private static final String USER_INFO_FIELDS = "username|caches_found";
+
+ // the several realms of possible fields for cache retrieval:
+ // Core: for livemap requests (L3 - only with level 3 auth)
+ // Additional: additional fields for full cache (L3 - only for level 3 auth, current - only for connectors with current api)
+ private static final String SERVICE_CACHE_CORE_FIELDS = "code|name|location|type|status|difficulty|terrain|size";
+ private static final String SERVICE_CACHE_CORE_L3_FIELDS = "is_found";
+ private static final String SERVICE_CACHE_ADDITIONAL_FIELDS = "owner|founds|notfounds|rating|rating_votes|recommendations|description|hint|images|latest_logs|date_hidden|alt_wpts|attrnames";
+ private static final String SERVICE_CACHE_ADDITIONAL_CURRENT_FIELDS = "gc_code|attribution_note";
+ private static final String SERVICE_CACHE_ADDITIONAL_L3_FIELDS = "is_watched";
+
+ private static final String METHOD_SEARCH_NEAREST = "services/caches/search/nearest";
+ private static final String METHOD_SEARCH_BBOX = "services/caches/search/bbox";
+ private static final String METHOD_RETRIEVE_CACHES = "services/caches/geocaches";
- private static final String SERVICE_CACHE = "/okapi/services/caches/geocache";
- private static final String SERVICE_CACHE_FIELDS = "code|name|location|type|status|owner|founds|notfounds|size|difficulty|terrain|rating|rating_votes|recommendations|description|hint|images|latest_logs|date_hidden";
+ public static Geocache getCache(final String geoCode) {
+ final Parameters params = new Parameters("cache_code", geoCode);
+ final IConnector connector = ConnectorFactory.getConnector(geoCode);
+ if (!(connector instanceof OCApiConnector)) {
+ return null;
+ }
- private static final String SERVICE_NEAREST = "/okapi/services/caches/search/nearest";
+ final OCApiConnector ocapiConn = (OCApiConnector) connector;
- public static Geocache getCache(final String geoCode) {
- final Parameters params = new Parameters("cache_code", geoCode, "fields", SERVICE_CACHE_FIELDS);
- final JSONObject data = request(ConnectorFactory.getConnector(geoCode), SERVICE_CACHE, params);
+ params.add("fields", getFullFields(ocapiConn));
+ params.add("attribution_append", "none");
+
+ final JSONObject data = request(ocapiConn, OkapiService.SERVICE_CACHE, params);
if (data == null) {
return null;
@@ -79,57 +137,141 @@ final public class OkapiClient {
return parseCache(data);
}
- public static List<Geocache> getCachesAround(final Geopoint center, IConnector connector) {
- String centerString = GeopointFormatter.format(GeopointFormatter.Format.LAT_DECDEGREE_RAW, center) + "|" + GeopointFormatter.format(GeopointFormatter.Format.LON_DECDEGREE_RAW, center);
- final Parameters params = new Parameters("center", centerString);
- final JSONObject data = request(connector, SERVICE_NEAREST, params);
+ public static List<Geocache> getCachesAround(final Geopoint center, OCApiConnector connector) {
+ final String centerString = GeopointFormatter.format(GeopointFormatter.Format.LAT_DECDEGREE_RAW, center) + SEPARATOR + GeopointFormatter.format(GeopointFormatter.Format.LON_DECDEGREE_RAW, center);
+ final Parameters params = new Parameters("search_method", METHOD_SEARCH_NEAREST);
+ final Map<String, String> valueMap = new LinkedHashMap<String, String>();
+ valueMap.put("center", centerString);
+ valueMap.put("limit", "20");
+
+ return requestCaches(connector, params, valueMap);
+ }
+
+ private static List<Geocache> requestCaches(OCApiConnector connector, final Parameters params, final Map<String, String> valueMap) {
+ addFilterParams(valueMap, connector);
+ params.add("search_params", new JSONObject(valueMap).toString());
+ addRetrieveParams(params, connector);
+
+ final JSONObject data = request(connector, OkapiService.SERVICE_SEARCH_AND_RETRIEVE, params);
if (data == null) {
- return null;
+ return Collections.emptyList();
}
return parseCaches(data);
}
+ // Assumes level 3 OAuth
+ public static List<Geocache> getCachesBBox(final Viewport viewport, OCApiConnector connector) {
+
+ if (viewport.getLatitudeSpan() == 0 || viewport.getLongitudeSpan() == 0) {
+ return Collections.emptyList();
+ }
+
+ final String bboxString = GeopointFormatter.format(GeopointFormatter.Format.LAT_DECDEGREE_RAW, viewport.bottomLeft)
+ + SEPARATOR + GeopointFormatter.format(GeopointFormatter.Format.LON_DECDEGREE_RAW, viewport.bottomLeft)
+ + SEPARATOR + GeopointFormatter.format(GeopointFormatter.Format.LAT_DECDEGREE_RAW, viewport.topRight)
+ + SEPARATOR + GeopointFormatter.format(GeopointFormatter.Format.LON_DECDEGREE_RAW, viewport.topRight);
+ final Parameters params = new Parameters("search_method", METHOD_SEARCH_BBOX);
+ final Map<String, String> valueMap = new LinkedHashMap<String, String>();
+ valueMap.put("bbox", bboxString);
+
+ return requestCaches(connector, params, valueMap);
+ }
+
+ public static boolean setWatchState(final Geocache cache, final boolean watched, OCApiConnector connector) {
+ final Parameters params = new Parameters("cache_code", cache.getGeocode());
+ params.add("watched", watched ? "true" : "false");
+
+ final JSONObject data = request(connector, OkapiService.SERVICE_MARK_CACHE, params);
+
+ if (data == null) {
+ return false;
+ }
+
+ cache.setOnWatchlist(watched);
+
+ return true;
+ }
+
+ public static LogResult postLog(final Geocache cache, LogType logType, Calendar date, String log, OCApiConnector connector) {
+ final Parameters params = new Parameters("cache_code", cache.getGeocode());
+ params.add("logtype", logType.oc_type);
+ params.add("comment", log);
+ params.add("comment_format", "plaintext");
+ params.add("when", logDateFormat.format(date.getTime()));
+ if (logType.equals(LogType.NEEDS_MAINTENANCE)) {
+ params.add("needs_maintenance", "true");
+ }
+
+ final JSONObject data = request(connector, OkapiService.SERVICE_SUBMIT_LOG, params);
+
+ if (data == null) {
+ return new LogResult(StatusCode.LOG_POST_ERROR, "");
+ }
+
+ try {
+ if (data.getBoolean("success")) {
+ return new LogResult(StatusCode.NO_ERROR, data.getString("log_uuid"));
+ }
+
+ return new LogResult(StatusCode.LOG_POST_ERROR, "");
+ } catch (final JSONException e) {
+ Log.e("OkapiClient.postLog", e);
+ }
+ return new LogResult(StatusCode.LOG_POST_ERROR, "");
+ }
+
private static List<Geocache> parseCaches(final JSONObject response) {
try {
- final JSONArray cachesResponse = response.getJSONArray("results");
+ // Check for empty result
+ final String result = response.getString("results");
+ if (StringUtils.isBlank(result) || StringUtils.equals(result, "[]")) {
+ return Collections.emptyList();
+ }
+
+ // Get and iterate result list
+ final JSONObject cachesResponse = response.getJSONObject("results");
if (cachesResponse != null) {
- ArrayList<String> geocodes = new ArrayList<String>(cachesResponse.length());
- for (int i = 0; i < cachesResponse.length(); i++) {
- String geocode = cachesResponse.getString(i);
- if (StringUtils.isNotBlank(geocode)) {
- geocodes.add(geocode);
- }
- }
- List<Geocache> caches = new ArrayList<Geocache>(geocodes.size());
- for (String geocode : geocodes) {
- Geocache cache = getCache(geocode);
+ final List<Geocache> caches = new ArrayList<Geocache>(cachesResponse.length());
+ @SuppressWarnings("unchecked")
+ final
+ Iterator<String> keys = cachesResponse.keys();
+ while (keys.hasNext()) {
+ final String key = keys.next();
+ final Geocache cache = parseSmallCache(cachesResponse.getJSONObject(key));
if (cache != null) {
caches.add(cache);
}
}
return caches;
}
- } catch (JSONException e) {
- Log.e("OkapiClient.parseCaches", e);
+ } catch (final JSONException e) {
+ Log.e("OkapiClient.parseCachesResult", e);
}
- return null;
+ return Collections.emptyList();
+ }
+
+ private static Geocache parseSmallCache(final JSONObject response) {
+ final Geocache cache = new Geocache();
+ cache.setReliableLatLon(true);
+ try {
+
+ parseCoreCache(response, cache);
+
+ cgData.saveCache(cache, EnumSet.of(SaveFlag.SAVE_CACHE));
+ } catch (final JSONException e) {
+ Log.e("OkapiClient.parseSmallCache", e);
+ }
+ return cache;
}
private static Geocache parseCache(final JSONObject response) {
final Geocache cache = new Geocache();
cache.setReliableLatLon(true);
try {
- cache.setGeocode(response.getString(CACHE_CODE));
- cache.setName(response.getString(CACHE_NAME));
- // not used: names
- setLocation(cache, response.getString(CACHE_LOCATION));
- cache.setType(getCacheType(response.getString(CACHE_TYPE)));
- final String status = response.getString(CACHE_STATUS);
- cache.setDisabled(status.equalsIgnoreCase("Temporarily unavailable"));
- cache.setArchived(status.equalsIgnoreCase("Archived"));
+ parseCoreCache(response, cache);
// not used: url
final JSONObject owner = response.getJSONObject(CACHE_OWNER);
@@ -137,9 +279,7 @@ final public class OkapiClient {
cache.getLogCounts().put(LogType.FOUND_IT, response.getInt(CACHE_FOUNDS));
cache.getLogCounts().put(LogType.DIDNT_FIND_IT, response.getInt(CACHE_NOTFOUNDS));
- cache.setSize(getCacheSize(response));
- cache.setDifficulty((float) response.getDouble(CACHE_DIFFICULTY));
- cache.setTerrain((float) response.getDouble(CACHE_TERRAIN));
+
if (!response.isNull(CACHE_RATING)) {
cache.setRating((float) response.getDouble(CACHE_RATING));
}
@@ -147,14 +287,29 @@ final public class OkapiClient {
cache.setFavoritePoints(response.getInt(CACHE_RECOMMENDATIONS));
// not used: req_password
- cache.setDescription(response.getString(CACHE_DESCRIPTION));
- cache.setHint(Html.fromHtml(response.getString(CACHE_HINT)).toString());
+ // Prepend gc-link to description if available
+ final StringBuilder description = new StringBuilder(500);
+ if (!response.isNull("gc_code")) {
+ final String gccode = response.getString("gc_code");
+ description.append(cgeoapplication.getInstance().getResources()
+ .getString(R.string.cache_listed_on, GCConnector.getInstance().getName()))
+ .append(": <a href=\"http://coord.info/")
+ .append(gccode)
+ .append("\">")
+ .append(gccode)
+ .append("</a><br /><br />");
+ }
+ description.append(response.getString(CACHE_DESCRIPTION));
+ cache.setDescription(description.toString());
+
+ // currently the hint is delivered as HTML (contrary to OKAPI documentation), so we can store it directly
+ cache.setHint(response.getString(CACHE_HINT));
// not used: hints
final JSONArray images = response.getJSONArray(CACHE_IMAGES);
if (images != null) {
for (int i = 0; i < images.length(); i++) {
- JSONObject imageResponse = images.getJSONObject(i);
+ final JSONObject imageResponse = images.getJSONObject(i);
if (imageResponse.getBoolean(CACHE_IMAGE_IS_SPOILER)) {
final String title = imageResponse.getString(CACHE_IMAGE_CAPTION);
final String url = absoluteUrl(imageResponse.getString(CACHE_IMAGE_URL), cache.getGeocode());
@@ -163,19 +318,45 @@ final public class OkapiClient {
}
}
- // not used: attrnames
+ cache.setAttributes(parseAttributes(response.getJSONArray(CACHE_ATTRNAMES)));
cache.setLogs(parseLogs(response.getJSONArray(CACHE_LATEST_LOGS)));
cache.setHidden(parseDate(response.getString(CACHE_HIDDEN)));
+ //TODO: Store license per cache
+ //cache.setLicense(response.getString("attribution_note"));
+ cache.setWaypoints(parseWaypoints(response.getJSONArray(CACHE_WPTS)), false);
+ if (!response.isNull(CACHE_IS_WATCHED)) {
+ cache.setOnWatchlist(response.getBoolean(CACHE_IS_WATCHED));
+ }
cache.setDetailedUpdatedNow();
// save full detailed caches
cgData.saveCache(cache, EnumSet.of(SaveFlag.SAVE_DB));
- } catch (JSONException e) {
+ } catch (final JSONException e) {
Log.e("OkapiClient.parseCache", e);
}
return cache;
}
+ private static void parseCoreCache(final JSONObject response, final Geocache cache) throws JSONException {
+ cache.setGeocode(response.getString(CACHE_CODE));
+ cache.setName(response.getString(CACHE_NAME));
+ // not used: names
+ setLocation(cache, response.getString(CACHE_LOCATION));
+ cache.setType(getCacheType(response.getString(CACHE_TYPE)));
+
+ final String status = response.getString(CACHE_STATUS);
+ cache.setDisabled(status.equalsIgnoreCase(CACHE_STATUS_DISABLED));
+ cache.setArchived(status.equalsIgnoreCase(CACHE_STATUS_ARCHIVED));
+
+ cache.setSize(getCacheSize(response));
+ cache.setDifficulty((float) response.getDouble(CACHE_DIFFICULTY));
+ cache.setTerrain((float) response.getDouble(CACHE_TERRAIN));
+
+ if (!response.isNull(CACHE_IS_FOUND)) {
+ cache.setFound(response.getBoolean(CACHE_IS_FOUND));
+ }
+ }
+
private static String absoluteUrl(String url, String geocode) {
final Uri uri = Uri.parse(url);
@@ -197,8 +378,8 @@ final public class OkapiClient {
List<LogEntry> result = null;
for (int i = 0; i < logsJSON.length(); i++) {
try {
- JSONObject logResponse = logsJSON.getJSONObject(i);
- LogEntry log = new LogEntry(
+ final JSONObject logResponse = logsJSON.getJSONObject(i);
+ final LogEntry log = new LogEntry(
parseUser(logResponse.getJSONObject(LOG_USER)),
parseDate(logResponse.getString(LOG_DATE)).getTime(),
parseLogType(logResponse.getString(LOG_TYPE)),
@@ -207,13 +388,37 @@ final public class OkapiClient {
result = new ArrayList<LogEntry>();
}
result.add(log);
- } catch (JSONException e) {
+ } catch (final JSONException e) {
Log.e("OkapiClient.parseLogs", e);
}
}
return result;
}
+ private static List<Waypoint> parseWaypoints(JSONArray wptsJson) {
+ List<Waypoint> result = null;
+ for (int i = 0; i < wptsJson.length(); i++) {
+ try {
+ final JSONObject wptResponse = wptsJson.getJSONObject(i);
+ final Waypoint wpt = new Waypoint(wptResponse.getString(WPT_NAME),
+ parseWptType(wptResponse.getString(WPT_TYPE)),
+ false);
+ wpt.setNote(wptResponse.getString(WPT_DESCRIPTION));
+ final Geopoint pt = parseCoords(wptResponse.getString(WPT_LOCATION));
+ if (pt != null) {
+ wpt.setCoords(pt);
+ }
+ if (result == null) {
+ result = new ArrayList<Waypoint>();
+ }
+ result.add(wpt);
+ } catch (final JSONException e) {
+ Log.e("OkapiClient.parseWaypoints", e);
+ }
+ }
+ return result;
+ }
+
private static LogType parseLogType(String logType) {
if ("Found it".equalsIgnoreCase(logType)) {
return LogType.FOUND_IT;
@@ -224,20 +429,75 @@ final public class OkapiClient {
return LogType.NOTE;
}
+ private static WaypointType parseWptType(String wptType) {
+ if ("parking".equalsIgnoreCase(wptType)) {
+ return WaypointType.PARKING;
+ }
+ if ("path".equalsIgnoreCase(wptType)) {
+ return WaypointType.TRAILHEAD;
+ }
+ if ("stage".equalsIgnoreCase(wptType)) {
+ return WaypointType.STAGE;
+ }
+ if ("physical-stage".equalsIgnoreCase(wptType)) {
+ return WaypointType.STAGE;
+ }
+ if ("virtual-stage".equalsIgnoreCase(wptType)) {
+ return WaypointType.PUZZLE;
+ }
+ if ("final".equalsIgnoreCase(wptType)) {
+ return WaypointType.FINAL;
+ }
+ if ("poi".equalsIgnoreCase(wptType)) {
+ return WaypointType.TRAILHEAD;
+ }
+ return WaypointType.WAYPOINT;
+ }
+
private static Date parseDate(final String date) {
final SimpleDateFormat ISO8601DATEFORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.getDefault());
final String strippedDate = date.replaceAll("\\+0([0-9]){1}\\:00", "+0$100");
try {
return ISO8601DATEFORMAT.parse(strippedDate);
- } catch (ParseException e) {
+ } catch (final ParseException e) {
Log.e("OkapiClient.parseDate", e);
}
return null;
}
+ private static Geopoint parseCoords(final String location) {
+ final String latitude = StringUtils.substringBefore(location, SEPARATOR_STRING);
+ final String longitude = StringUtils.substringAfter(location, SEPARATOR_STRING);
+ if (StringUtils.isNotBlank(latitude) && StringUtils.isNotBlank(longitude)) {
+ return new Geopoint(latitude, longitude);
+ }
+
+ return null;
+ }
+
+ private static List<String> parseAttributes(JSONArray nameList) {
+
+ final List<String> result = new ArrayList<String>();
+
+ for (int i = 0; i < nameList.length(); i++) {
+ try {
+ final String name = nameList.getString(i);
+ final CacheAttribute attr = CacheAttribute.getByOcId(AttributeParser.getOcDeId(name));
+
+ if (attr != null) {
+ result.add(attr.rawName);
+ }
+ } catch (final JSONException e) {
+ Log.e("OkapiClient.parseAttributes", e);
+ }
+ }
+
+ return result;
+ }
+
private static void setLocation(final Geocache cache, final String location) {
- final String latitude = StringUtils.substringBefore(location, "|");
- final String longitude = StringUtils.substringAfter(location, "|");
+ final String latitude = StringUtils.substringBefore(location, SEPARATOR_STRING);
+ final String longitude = StringUtils.substringAfter(location, SEPARATOR_STRING);
cache.setCoords(new Geopoint(latitude, longitude));
}
@@ -248,7 +508,7 @@ final public class OkapiClient {
double size = 0;
try {
size = response.getDouble(CACHE_SIZE);
- } catch (JSONException e) {
+ } catch (final JSONException e) {
Log.e("OkapiClient.getCacheSize", e);
}
switch ((int) Math.round(size)) {
@@ -281,14 +541,57 @@ final public class OkapiClient {
if (cacheType.equalsIgnoreCase("Virtual")) {
return CacheType.VIRTUAL;
}
+ if (cacheType.equalsIgnoreCase("Event")) {
+ return CacheType.EVENT;
+ }
+ if (cacheType.equalsIgnoreCase("Webcam")) {
+ return CacheType.WEBCAM;
+ }
+ if (cacheType.equalsIgnoreCase("Math/Physics")) {
+ return CacheType.MYSTERY;
+ }
+ if (cacheType.equalsIgnoreCase("Drive-In")) {
+ return CacheType.TRADITIONAL;
+ }
return CacheType.UNKNOWN;
}
- private static JSONObject request(final IConnector connector, final String service, final Parameters params) {
+ private static String getCoreFields(OCApiConnector connector) {
if (connector == null) {
- return null;
+ Log.e("OkapiClient.getCoreFields called with invalid connector");
+ return StringUtils.EMPTY;
}
- if (!(connector instanceof OCApiConnector)) {
+
+ if (connector.getSupportedAuthLevel() == OAuthLevel.Level3) {
+ return SERVICE_CACHE_CORE_FIELDS + SEPARATOR + SERVICE_CACHE_CORE_L3_FIELDS;
+ }
+
+ return SERVICE_CACHE_CORE_FIELDS;
+ }
+
+ private static String getFullFields(OCApiConnector connector) {
+ if (connector == null) {
+ Log.e("OkapiClient.getFullFields called with invalid connector");
+ return StringUtils.EMPTY;
+ }
+
+ final StringBuilder res = new StringBuilder(500);
+
+ res.append(SERVICE_CACHE_CORE_FIELDS);
+ res.append(SEPARATOR).append(SERVICE_CACHE_ADDITIONAL_FIELDS);
+ if (connector.getSupportedAuthLevel() == OAuthLevel.Level3) {
+ res.append(SEPARATOR).append(SERVICE_CACHE_CORE_L3_FIELDS);
+ res.append(SEPARATOR).append(SERVICE_CACHE_ADDITIONAL_L3_FIELDS);
+ }
+ if (connector.getApiSupport() == ApiSupport.current) {
+ res.append(SEPARATOR).append(SERVICE_CACHE_ADDITIONAL_CURRENT_FIELDS);
+ }
+
+ return res.toString();
+ }
+
+ private static JSONObject request(final OCApiConnector connector, final OkapiService service, final Parameters params) {
+ if (connector == null) {
return null;
}
@@ -297,10 +600,15 @@ final public class OkapiClient {
return null;
}
- ((OCApiConnector) connector).addAuthentication(params);
params.add("langpref", getPreferredLanguage());
- final String uri = "http://" + host + service;
+ if (connector.getSupportedAuthLevel() == OAuthLevel.Level3) {
+ OAuth.signOAuth(host, service.methodName, "GET", false, params, Settings.getOCDETokenPublic(), Settings.getOCDETokenSecret(), connector.getCK(), connector.getCS());
+ } else {
+ connector.addAuthentication(params);
+ }
+
+ final String uri = "http://" + host + service.methodName;
return Network.requestJSON(uri, params);
}
@@ -311,4 +619,106 @@ final public class OkapiClient {
}
return "en";
}
+
+ private static void addFilterParams(final Map<String, String> valueMap, OCApiConnector connector) {
+ if (!Settings.isExcludeDisabledCaches()) {
+ valueMap.put("status", "Available|Temporarily unavailable");
+ }
+ if (Settings.isExcludeMyCaches() && connector.getSupportedAuthLevel() == OAuthLevel.Level3) {
+ valueMap.put("exclude_my_own", "true");
+ valueMap.put("found_status", "notfound_only");
+ }
+ if (Settings.getCacheType() != CacheType.ALL) {
+ valueMap.put("type", getFilterFromType(Settings.getCacheType()));
+ }
+ }
+
+ private static void addRetrieveParams(final Parameters params, OCApiConnector connector) {
+ params.add("retr_method", METHOD_RETRIEVE_CACHES);
+ params.add("retr_params", "{\"fields\": \"" + getCoreFields(connector) + "\"}");
+ params.add("wrap", "true");
+ }
+
+ private static String getFilterFromType(CacheType cacheType) {
+ switch (cacheType) {
+ case EVENT:
+ return "Event";
+ case MULTI:
+ return "Multi";
+ case MYSTERY:
+ return "Quiz";
+ case TRADITIONAL:
+ return "Traditional";
+ case VIRTUAL:
+ return "Virtual";
+ case WEBCAM:
+ return "Webcam";
+ default:
+ return "";
+ }
+ }
+
+ public static UserInfo getUserInfo(OCApiLiveConnector connector) {
+ final Parameters params = new Parameters("fields", USER_INFO_FIELDS);
+
+ final JSONObject data = request(connector, OkapiService.SERVICE_USER, params);
+
+ if (data == null) {
+ return new UserInfo(StringUtils.EMPTY, 0, false);
+ }
+
+ String name = StringUtils.EMPTY;
+ int finds = 0;
+ boolean success = true;
+
+ if (!data.isNull(USER_USERNAME)) {
+ try {
+ name = data.getString(USER_USERNAME);
+ } catch (final JSONException e) {
+ Log.e("OkapiClient.getUserInfo - name", e);
+ success = false;
+ }
+ } else {
+ success = false;
+ }
+
+ if (!data.isNull(USER_CACHES_FOUND)) {
+ try {
+ finds = data.getInt(USER_CACHES_FOUND);
+ } catch (final JSONException e) {
+ Log.e("OkapiClient.getUserInfo - finds", e);
+ success = false;
+ }
+ } else {
+ success = false;
+ }
+
+ return new UserInfo(name, finds, success);
+ }
+
+ public static class UserInfo {
+
+ private final String name;
+ private final int finds;
+ private final boolean retrieveSuccessful;
+
+ UserInfo(String name, int finds, boolean retrieveSuccessful) {
+ this.name = name;
+ this.finds = finds;
+ this.retrieveSuccessful = retrieveSuccessful;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public int getFinds() {
+ return finds;
+ }
+
+ public boolean isRetrieveSuccessful() {
+ return retrieveSuccessful;
+ }
+ }
+
}
diff --git a/main/src/cgeo/geocaching/connector/oc/OkapiLoggingManager.java b/main/src/cgeo/geocaching/connector/oc/OkapiLoggingManager.java
new file mode 100644
index 0000000..8a94218
--- /dev/null
+++ b/main/src/cgeo/geocaching/connector/oc/OkapiLoggingManager.java
@@ -0,0 +1,68 @@
+package cgeo.geocaching.connector.oc;
+
+import cgeo.geocaching.Geocache;
+import cgeo.geocaching.TrackableLog;
+import cgeo.geocaching.LogCacheActivity;
+import cgeo.geocaching.connector.ILoggingManager;
+import cgeo.geocaching.connector.ImageResult;
+import cgeo.geocaching.connector.LogResult;
+import cgeo.geocaching.enumerations.LogType;
+import cgeo.geocaching.enumerations.StatusCode;
+
+import android.app.Activity;
+import android.net.Uri;
+
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.List;
+
+public class OkapiLoggingManager implements ILoggingManager {
+
+ private final OCApiConnector connector;
+ private final Geocache cache;
+ private LogCacheActivity activity;
+
+ private final static List<LogType> standardLogTypes = Arrays.asList(LogType.FOUND_IT, LogType.DIDNT_FIND_IT, LogType.NOTE, LogType.NEEDS_MAINTENANCE);
+ private final static List<LogType> eventLogTypes = Arrays.asList(LogType.WILL_ATTEND, LogType.ATTENDED, LogType.NOTE);
+
+ public OkapiLoggingManager(Activity activity, OCApiConnector connector, Geocache cache) {
+ this.connector = connector;
+ this.cache = cache;
+ this.activity = (LogCacheActivity) activity;
+ }
+
+ @Override
+ public void init() {
+ activity.onLoadFinished();
+ }
+
+ @Override
+ public LogResult postLog(Geocache cache, LogType logType, Calendar date, String log, List<TrackableLog> trackableLogs) {
+ return OkapiClient.postLog(cache, logType, date, log, connector);
+ }
+
+ @Override
+ public ImageResult postLogImage(String logId, String imageCaption, String imageDescription, Uri imageUri) {
+ return new ImageResult(StatusCode.LOG_POST_ERROR, "");
+ }
+
+ @Override
+ public boolean hasLoaderError() {
+ return false;
+ }
+
+ @Override
+ public List<TrackableLog> getTrackables() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public List<LogType> getPossibleLogTypes() {
+ if (cache.isEventCache()) {
+ return eventLogTypes;
+ }
+
+ return standardLogTypes;
+ }
+}
diff --git a/main/src/cgeo/geocaching/connector/oc/OkapiService.java b/main/src/cgeo/geocaching/connector/oc/OkapiService.java
new file mode 100644
index 0000000..ec09527
--- /dev/null
+++ b/main/src/cgeo/geocaching/connector/oc/OkapiService.java
@@ -0,0 +1,21 @@
+package cgeo.geocaching.connector.oc;
+
+import cgeo.geocaching.connector.oc.OCApiConnector.OAuthLevel;
+
+
+enum OkapiService {
+ SERVICE_CACHE("/okapi/services/caches/geocache", OAuthLevel.Level1),
+ SERVICE_SEARCH_AND_RETRIEVE("/okapi/services/caches/shortcuts/search_and_retrieve", OAuthLevel.Level1),
+ SERVICE_MARK_CACHE("/okapi/services/caches/mark", OAuthLevel.Level3),
+ SERVICE_SUBMIT_LOG("/okapi/services/logs/submit", OAuthLevel.Level3),
+ SERVICE_USER("/okapi/services/users/user", OAuthLevel.Level1);
+
+ final String methodName;
+ final OAuthLevel level;
+
+ OkapiService(final String methodName, final OAuthLevel level) {
+ this.methodName = methodName;
+ this.level = level;
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/connector/trackable/AbstractTrackableConnector.java b/main/src/cgeo/geocaching/connector/trackable/AbstractTrackableConnector.java
new file mode 100644
index 0000000..cd32d87
--- /dev/null
+++ b/main/src/cgeo/geocaching/connector/trackable/AbstractTrackableConnector.java
@@ -0,0 +1,10 @@
+package cgeo.geocaching.connector.trackable;
+
+
+public abstract class AbstractTrackableConnector implements TrackableConnector {
+
+ @Override
+ public boolean isLoggable() {
+ return false;
+ }
+}
diff --git a/main/src/cgeo/geocaching/connector/trackable/GeokretyConnector.java b/main/src/cgeo/geocaching/connector/trackable/GeokretyConnector.java
new file mode 100644
index 0000000..8387076
--- /dev/null
+++ b/main/src/cgeo/geocaching/connector/trackable/GeokretyConnector.java
@@ -0,0 +1,42 @@
+package cgeo.geocaching.connector.trackable;
+
+import cgeo.geocaching.Trackable;
+import cgeo.geocaching.network.Network;
+import cgeo.geocaching.utils.Log;
+
+import java.util.regex.Pattern;
+
+public class GeokretyConnector extends AbstractTrackableConnector {
+
+ private static final Pattern PATTERN_GK_CODE = Pattern.compile("GK[0-9A-F]{4,}");
+
+ @Override
+ public boolean canHandleTrackable(String geocode) {
+ return geocode != null && PATTERN_GK_CODE.matcher(geocode).matches();
+ }
+
+ @Override
+ public String getUrl(Trackable trackable) {
+ return "http://geokrety.org/konkret.php?id=" + getId(trackable.getGeocode());
+ }
+
+ @Override
+ public Trackable searchTrackable(String geocode, String guid, String id) {
+ final String page = Network.getResponseData(Network.getRequest("http://geokrety.org/export2.php?gkid=" + getId(geocode)));
+ if (page == null) {
+ return null;
+ }
+ return GeokretyParser.parse(page);
+ }
+
+ private static int getId(String geocode) {
+ try {
+ final String hex = geocode.substring(2);
+ return Integer.parseInt(hex, 16);
+ } catch (final NumberFormatException e) {
+ Log.e("Trackable.getUrl", e);
+ }
+ return -1;
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/connector/trackable/GeokretyParser.java b/main/src/cgeo/geocaching/connector/trackable/GeokretyParser.java
new file mode 100644
index 0000000..66ca5f7
--- /dev/null
+++ b/main/src/cgeo/geocaching/connector/trackable/GeokretyParser.java
@@ -0,0 +1,82 @@
+package cgeo.geocaching.connector.trackable;
+
+import cgeo.geocaching.R;
+import cgeo.geocaching.Trackable;
+import cgeo.geocaching.cgeoapplication;
+import cgeo.geocaching.utils.Log;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+import android.sax.Element;
+import android.sax.EndTextElementListener;
+import android.sax.RootElement;
+import android.sax.StartElementListener;
+import android.util.Xml;
+
+public class GeokretyParser {
+
+ public static Trackable parse(final String page) {
+ final Trackable trackable = new Trackable();
+
+ final RootElement root = new RootElement("gkxml");
+ final Element geokret = root.getChild("geokrety").getChild("geokret");
+
+ geokret.setEndTextElementListener(new EndTextElementListener() {
+
+ @Override
+ public void end(String name) {
+ trackable.setName(name);
+ }
+ });
+
+ geokret.setStartElementListener(new StartElementListener() {
+
+ @Override
+ public void start(Attributes attributes) {
+ try {
+ if (attributes.getIndex("id") > -1) {
+ trackable.setGeocode(geocode(Integer.valueOf(attributes.getValue("id"))));
+ }
+ if (attributes.getIndex("dist") > -1) {
+ trackable.setDistance(Float.valueOf(attributes.getValue("dist")));
+ }
+ if (attributes.getIndex("type") > -1) {
+ trackable.setType(getType(Integer.valueOf(attributes.getValue("type"))));
+ }
+ } catch (final NumberFormatException e) {
+ Log.e("Parsing geokret", e);
+ }
+ }
+ });
+
+ try {
+ Xml.parse(page, root.getContentHandler());
+ return trackable;
+ } catch (final SAXException e) {
+ Log.w("Cannot parse geokrety", e);
+ }
+
+ return null;
+ }
+
+ protected static String getType(int type) {
+ switch (type) {
+ case 0:
+ return cgeoapplication.getInstance().getString(R.string.geokret_type_traditional);
+ case 1:
+ return cgeoapplication.getInstance().getString(R.string.geokret_type_book_or_media);
+ case 2:
+ return cgeoapplication.getInstance().getString(R.string.geokret_type_human);
+ case 3:
+ return cgeoapplication.getInstance().getString(R.string.geokret_type_coin);
+ case 4:
+ return cgeoapplication.getInstance().getString(R.string.geokret_type_post);
+ }
+ return null;
+ }
+
+ protected static String geocode(final int id) {
+ return String.format("GK%04X", id);
+ }
+}
diff --git a/main/src/cgeo/geocaching/connector/trackable/TrackableConnector.java b/main/src/cgeo/geocaching/connector/trackable/TrackableConnector.java
new file mode 100644
index 0000000..c09dc07
--- /dev/null
+++ b/main/src/cgeo/geocaching/connector/trackable/TrackableConnector.java
@@ -0,0 +1,19 @@
+package cgeo.geocaching.connector.trackable;
+
+import cgeo.geocaching.Trackable;
+
+/**
+ * Methods to be implemented by any connector for handling trackables
+ *
+ */
+public interface TrackableConnector {
+
+ public boolean canHandleTrackable(final String geocode);
+
+ public String getUrl(final Trackable trackable);
+
+ public boolean isLoggable();
+
+ public Trackable searchTrackable(String geocode, String guid, String id);
+
+}
diff --git a/main/src/cgeo/geocaching/connector/trackable/TravelBugConnector.java b/main/src/cgeo/geocaching/connector/trackable/TravelBugConnector.java
new file mode 100644
index 0000000..9cae016
--- /dev/null
+++ b/main/src/cgeo/geocaching/connector/trackable/TravelBugConnector.java
@@ -0,0 +1,34 @@
+package cgeo.geocaching.connector.trackable;
+
+import cgeo.geocaching.Trackable;
+import cgeo.geocaching.connector.gc.GCParser;
+
+import java.util.regex.Pattern;
+
+public class TravelBugConnector extends AbstractTrackableConnector {
+
+ /**
+ * TB codes really start with TB1, there is no padding or minimum length
+ */
+ private final static Pattern PATTERN_TB_CODE = Pattern.compile("(TB[0-9A-Z]+)|([0-9A-Z]{6})", Pattern.CASE_INSENSITIVE);
+
+ @Override
+ public boolean canHandleTrackable(String geocode) {
+ return TravelBugConnector.PATTERN_TB_CODE.matcher(geocode).matches();
+ }
+
+ @Override
+ public String getUrl(Trackable trackable) {
+ return "http://www.geocaching.com//track/details.aspx?tracker=" + trackable.getGeocode();
+ }
+
+ @Override
+ public boolean isLoggable() {
+ return true;
+ }
+
+ @Override
+ public Trackable searchTrackable(String geocode, String guid, String id) {
+ return GCParser.searchTrackable(geocode, guid, id);
+ }
+} \ No newline at end of file
diff --git a/main/src/cgeo/geocaching/connector/trackable/UnknownTrackableConnector.java b/main/src/cgeo/geocaching/connector/trackable/UnknownTrackableConnector.java
new file mode 100644
index 0000000..0295927
--- /dev/null
+++ b/main/src/cgeo/geocaching/connector/trackable/UnknownTrackableConnector.java
@@ -0,0 +1,24 @@
+package cgeo.geocaching.connector.trackable;
+
+import cgeo.geocaching.Trackable;
+
+import org.apache.commons.lang3.StringUtils;
+
+public class UnknownTrackableConnector extends AbstractTrackableConnector {
+
+ @Override
+ public boolean canHandleTrackable(String geocode) {
+ return false;
+ }
+
+ @Override
+ public String getUrl(Trackable trackable) {
+ return StringUtils.EMPTY;
+ }
+
+ @Override
+ public Trackable searchTrackable(String geocode, String guid, String id) {
+ return null;
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/enumerations/CacheAttribute.java b/main/src/cgeo/geocaching/enumerations/CacheAttribute.java
index 530869f..243f63d 100644
--- a/main/src/cgeo/geocaching/enumerations/CacheAttribute.java
+++ b/main/src/cgeo/geocaching/enumerations/CacheAttribute.java
@@ -12,8 +12,8 @@ import java.util.HashMap;
import java.util.Map;
public enum CacheAttribute {
- // THIS LIST IS GENERATED: don't change anything here but in
- // project/attributes/makeEnum.sh
+ // THIS LIST IS GENERATED: don't change anything here but read
+ // project/attributes/readme.txt
DOGS(1, -1, "dogs", R.drawable.attribute_dogs, R.string.attribute_dogs_yes, R.string.attribute_dogs_no),
BICYCLES(32, -1, "bicycles", R.drawable.attribute_bicycles, R.string.attribute_bicycles_yes, R.string.attribute_bicycles_no),
MOTORCYCLES(33, -1, "motorcycles", R.drawable.attribute_motorcycles, R.string.attribute_motorcycles_yes, R.string.attribute_motorcycles_no),
@@ -27,7 +27,7 @@ public enum CacheAttribute {
ONEHOUR(7, -1, "onehour", R.drawable.attribute_onehour, R.string.attribute_onehour_yes, R.string.attribute_onehour_no),
SCENIC(8, -1, "scenic", R.drawable.attribute_scenic, R.string.attribute_scenic_yes, R.string.attribute_scenic_no),
HIKING(9, 25, "hiking", R.drawable.attribute_hiking, R.string.attribute_hiking_yes, R.string.attribute_hiking_no),
- CLIMBING(10, 28, "climbing", R.drawable.attribute_climbing, R.string.attribute_climbing_yes, R.string.attribute_climbing_no),
+ CLIMBING(10, -1, "climbing", R.drawable.attribute_climbing, R.string.attribute_climbing_yes, R.string.attribute_climbing_no),
WADING(11, -1, "wading", R.drawable.attribute_wading, R.string.attribute_wading_yes, R.string.attribute_wading_no),
SWIMMING(12, 29, "swimming", R.drawable.attribute_swimming, R.string.attribute_swimming_yes, R.string.attribute_swimming_no),
AVAILABLE(13, 38, "available", R.drawable.attribute_available, R.string.attribute_available_yes, R.string.attribute_available_no),
@@ -86,6 +86,7 @@ public enum CacheAttribute {
SYRINGE(-1, 23, "syringe", R.drawable.attribute_syringe, R.string.attribute_syringe_yes, R.string.attribute_syringe_no),
SWAMP(-1, 26, "swamp", R.drawable.attribute_swamp, R.string.attribute_swamp_yes, R.string.attribute_swamp_no),
HILLS(-1, 27, "hills", R.drawable.attribute_hills, R.string.attribute_hills_yes, R.string.attribute_hills_no),
+ EASY_CLIMBING(-1, 28, "easy_climbing", R.drawable.attribute_easy_climbing, R.string.attribute_easy_climbing_yes, R.string.attribute_easy_climbing_no),
POI(-1, 30, "poi", R.drawable.attribute_poi, R.string.attribute_poi_yes, R.string.attribute_poi_no),
MOVING_TARGET(-1, 31, "moving_target", R.drawable.attribute_moving_target, R.string.attribute_moving_target_yes, R.string.attribute_moving_target_no),
WEBCAM(-1, 32, "webcam", R.drawable.attribute_webcam, R.string.attribute_webcam_yes, R.string.attribute_webcam_no),
@@ -107,9 +108,10 @@ public enum CacheAttribute {
ARITHMETIC(-1, 56, "arithmetic", R.drawable.attribute_arithmetic, R.string.attribute_arithmetic_yes, R.string.attribute_arithmetic_no),
OTHER_CACHE(-1, 57, "other_cache", R.drawable.attribute_other_cache, R.string.attribute_other_cache_yes, R.string.attribute_other_cache_no),
ASK_OWNER(-1, 58, "ask_owner", R.drawable.attribute_ask_owner, R.string.attribute_ask_owner_yes, R.string.attribute_ask_owner_no),
- UNKNOWN(-1, -1, "unknown", R.drawable.attribute_unknown, R.string.attribute_unknown_yes, R.string.attribute_unknown_no);
- // THIS LIST IS GENERATED: don't change anything here but in
- // project/attributes/makeEnum.sh
+ UNKNOWN(-1, -1, "unknown", R.drawable.attribute_unknown, R.string.attribute_unknown_yes, R.string.attribute_unknown_no),
+ GEOTOUR(67, -1, "geotour", R.drawable.attribute_geotour, R.string.attribute_geotour_yes, R.string.attribute_geotour_no);
+ // THIS LIST IS GENERATED: don't change anything here but read
+ // project/attributes/readme.txt
private static final String INTERNAL_YES = "_yes";
private static final String INTERNAL_NO = "_no";
@@ -146,30 +148,20 @@ public enum CacheAttribute {
}
private final static Map<String, CacheAttribute> FIND_BY_GCRAWNAME;
+ private final static SparseArray<CacheAttribute> FIND_BY_GCID = new SparseArray<CacheAttribute>();
+ private final static SparseArray<CacheAttribute> FIND_BY_OCID = new SparseArray<CacheAttribute>();
static {
final HashMap<String, CacheAttribute> mapGcRawNames = new HashMap<String, CacheAttribute>();
for (CacheAttribute attr : values()) {
mapGcRawNames.put(attr.rawName, attr);
- }
- FIND_BY_GCRAWNAME = Collections.unmodifiableMap(mapGcRawNames);
- }
-
- private final static SparseArray<CacheAttribute> FIND_BY_GCID = new SparseArray<CacheAttribute>();
- static {
- for (CacheAttribute attr : values()) {
if (attr.gcid != NO_ID) {
FIND_BY_GCID.put(attr.gcid, attr);
}
- }
- }
-
- private final static SparseArray<CacheAttribute> FIND_BY_OCID = new SparseArray<CacheAttribute>();
- static {
- for (CacheAttribute attr : values()) {
if (attr.ocid != NO_ID) {
FIND_BY_OCID.put(attr.ocid, attr);
}
}
+ FIND_BY_GCRAWNAME = Collections.unmodifiableMap(mapGcRawNames);
}
public static CacheAttribute getByRawName(final String rawName) {
diff --git a/main/src/cgeo/geocaching/enumerations/CacheRealm.java b/main/src/cgeo/geocaching/enumerations/CacheRealm.java
deleted file mode 100644
index 5a203ab..0000000
--- a/main/src/cgeo/geocaching/enumerations/CacheRealm.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package cgeo.geocaching.enumerations;
-
-import cgeo.geocaching.R;
-
-public enum CacheRealm {
-
- GC("gc", "geocaching.com", R.drawable.marker, R.drawable.marker_disabled),
- OC("oc", "OpenCaching Network", R.drawable.marker_oc, R.drawable.marker_disabled_oc),
- OTHER("other", "Other", R.drawable.marker_other, R.drawable.marker_disabled_other);
-
- public final String id;
- public final String name;
- public final int markerId;
- public final int markerDisabledId;
-
- CacheRealm(String id, String name, int markerId, int markerDisabledId) {
- this.id = id;
- this.name = name;
- this.markerId = markerId;
- this.markerDisabledId = markerDisabledId;
- }
-}
diff --git a/main/src/cgeo/geocaching/enumerations/CacheType.java b/main/src/cgeo/geocaching/enumerations/CacheType.java
index 528d3fa..8dbadfd 100644
--- a/main/src/cgeo/geocaching/enumerations/CacheType.java
+++ b/main/src/cgeo/geocaching/enumerations/CacheType.java
@@ -29,6 +29,7 @@ public enum CacheType {
PROJECT_APE("ape", "Project Ape Cache", "2555690d-b2bc-4b55-b5ac-0cb704c0b768", R.string.ape, R.drawable.type_ape),
GCHQ("gchq", "Groundspeak HQ", "416f2494-dc17-4b6a-9bab-1a29dd292d8c", R.string.gchq, R.drawable.type_hq),
GPS_EXHIBIT("gps", "GPS Cache Exhibit", "72e69af2-7986-4990-afd9-bc16cbbb4ce3", R.string.gps, R.drawable.type_traditional), // icon missing
+ BLOCK_PARTY("block", "Groundspeak Block Party", "bc2f3df2-1aab-4601-b2ff-b5091f6c02e3", R.string.block, R.drawable.type_event), // icon missing
UNKNOWN("unknown", "unknown", "", R.string.unknown, R.drawable.type_unknown),
/** No real cache type -> filter */
ALL("all", "display all caches", "9a79e6ce-3344-409c-bbe9-496530baf758", R.string.all_types, R.drawable.type_unknown);
@@ -88,7 +89,8 @@ public enum CacheType {
}
public boolean isEvent() {
- return CacheType.EVENT == this || CacheType.MEGA_EVENT == this || CacheType.CITO == this || CacheType.LOSTANDFOUND == this;
+ return CacheType.EVENT == this || CacheType.MEGA_EVENT == this || CacheType.CITO == this ||
+ CacheType.LOSTANDFOUND == this || CacheType.BLOCK_PARTY == this;
}
@Override
@@ -98,7 +100,7 @@ public enum CacheType {
/**
* Whether this type contains the given cache.
- *
+ *
* @param cache
* @return true if this is the ALL type or if this type equals the type of the cache.
*/
@@ -111,4 +113,12 @@ public enum CacheType {
}
return cache.getType() == this;
}
+
+ public boolean applyDistanceRule() {
+ return !isVirtual() && !isEvent();
+ }
+
+ public boolean isVirtual() {
+ return VIRTUAL == this || WEBCAM == this || EARTH == this;
+ }
}
diff --git a/main/src/cgeo/geocaching/enumerations/LogType.java b/main/src/cgeo/geocaching/enumerations/LogType.java
index 71a5146..9902d3f 100644
--- a/main/src/cgeo/geocaching/enumerations/LogType.java
+++ b/main/src/cgeo/geocaching/enumerations/LogType.java
@@ -15,50 +15,52 @@ import java.util.Map;
*/
public enum LogType {
- FOUND_IT(2, "2", "found it", R.string.log_found, R.drawable.mark_green),
- DIDNT_FIND_IT(3, "3", "didn't find it", R.string.log_dnf, R.drawable.mark_red),
- NOTE(4, "4", "write note", R.string.log_note),
- PUBLISH_LISTING(1003, "24", "publish listing", R.string.log_published, R.drawable.mark_green_more),
- ENABLE_LISTING(23, "23", "enable listing", R.string.log_enabled, R.drawable.mark_green_more),
- ARCHIVE(5, "5", "archive", R.string.log_archived, R.drawable.mark_red_more),
- UNARCHIVE(12, "12", "unarchive", R.string.log_unarchived, R.drawable.mark_green_more),
- TEMP_DISABLE_LISTING(22, "22", "temporarily disable listing", R.string.log_disabled, R.drawable.mark_red_more),
- NEEDS_ARCHIVE(7, "7", "needs archived", R.string.log_needs_archived, R.drawable.mark_red),
- WILL_ATTEND(9, "9", "will attend", R.string.log_attend),
- ATTENDED(10, "10", "attended", R.string.log_attended, R.drawable.mark_green),
- RETRIEVED_IT(13, "13", "retrieved it", R.string.log_retrieved, R.drawable.mark_green_more),
- PLACED_IT(14, "14", "placed it", R.string.log_placed, R.drawable.mark_green_more),
- GRABBED_IT(19, "19", "grabbed it", R.string.log_grabbed, R.drawable.mark_green_more),
- NEEDS_MAINTENANCE(45, "45", "needs maintenance", R.string.log_maintenance_needed, R.drawable.mark_red),
- OWNER_MAINTENANCE(46, "46", "owner maintenance", R.string.log_maintained, R.drawable.mark_green_more),
- UPDATE_COORDINATES(47, "47", "update coordinates", R.string.log_update),
- DISCOVERED_IT(48, "48", "discovered it", R.string.log_discovered, R.drawable.mark_green),
- POST_REVIEWER_NOTE(18, "68", "post reviewer note", R.string.log_reviewer),
- VISIT(1001, "75", "visit", R.string.log_tb_visit, R.drawable.mark_green),
- WEBCAM_PHOTO_TAKEN(11, "11", "webcam photo taken", R.string.log_webcam, R.drawable.mark_green),
- ANNOUNCEMENT(74, "74", "announcement", R.string.log_announcement),
- MOVE_COLLECTION(69, "69", "unused_collection", R.string.log_movecollection),
- MOVE_INVENTORY(70, "70", "unused_inventory", R.string.log_moveinventory),
- RETRACT(25, "25", "retract listing", R.string.log_retractlisting),
- MARKED_MISSING(16, "16", "marked missing", R.string.log_marked_missing, R.drawable.mark_red),
- UNKNOWN(0, "unknown", "", R.string.err_unknown, R.drawable.mark_red); // LogType not init. yet
+ FOUND_IT(2, "2", "found it", "Found it", R.string.log_found, R.drawable.mark_green),
+ DIDNT_FIND_IT(3, "3", "didn't find it", "Didn't find it", R.string.log_dnf, R.drawable.mark_red),
+ NOTE(4, "4", "write note", "Comment", R.string.log_note),
+ PUBLISH_LISTING(1003, "24", "publish listing", "", R.string.log_published, R.drawable.mark_green_more),
+ ENABLE_LISTING(23, "23", "enable listing", "", R.string.log_enabled, R.drawable.mark_green_more),
+ ARCHIVE(5, "5", "archive", "", R.string.log_archived, R.drawable.mark_red_more),
+ UNARCHIVE(12, "12", "unarchive", "", R.string.log_unarchived, R.drawable.mark_green_more),
+ TEMP_DISABLE_LISTING(22, "22", "temporarily disable listing", "", R.string.log_disabled, R.drawable.mark_red_more),
+ NEEDS_ARCHIVE(7, "7", "needs archived", "", R.string.log_needs_archived, R.drawable.mark_red),
+ WILL_ATTEND(9, "9", "will attend", "Will attend", R.string.log_attend),
+ ATTENDED(10, "10", "attended", "Attended", R.string.log_attended, R.drawable.mark_green),
+ RETRIEVED_IT(13, "13", "retrieved it", "", R.string.log_retrieved, R.drawable.mark_green_more),
+ PLACED_IT(14, "14", "placed it", "", R.string.log_placed, R.drawable.mark_green_more),
+ GRABBED_IT(19, "19", "grabbed it", "", R.string.log_grabbed, R.drawable.mark_green_more),
+ NEEDS_MAINTENANCE(45, "45", "needs maintenance", "Comment", R.string.log_maintenance_needed, R.drawable.mark_red),
+ OWNER_MAINTENANCE(46, "46", "owner maintenance", "", R.string.log_maintained, R.drawable.mark_green_more),
+ UPDATE_COORDINATES(47, "47", "update coordinates", "", R.string.log_update),
+ DISCOVERED_IT(48, "48", "discovered it", "", R.string.log_discovered, R.drawable.mark_green),
+ POST_REVIEWER_NOTE(18, "68", "post reviewer note", "", R.string.log_reviewer),
+ VISIT(1001, "75", "visit", "", R.string.log_tb_visit, R.drawable.mark_green),
+ WEBCAM_PHOTO_TAKEN(11, "11", "webcam photo taken", "", R.string.log_webcam, R.drawable.mark_green),
+ ANNOUNCEMENT(74, "74", "announcement", "", R.string.log_announcement),
+ MOVE_COLLECTION(69, "69", "unused_collection", "", R.string.log_movecollection),
+ MOVE_INVENTORY(70, "70", "unused_inventory", "", R.string.log_moveinventory),
+ RETRACT(25, "25", "retract listing", "", R.string.log_retractlisting),
+ MARKED_MISSING(16, "16", "marked missing", "", R.string.log_marked_missing, R.drawable.mark_red),
+ UNKNOWN(0, "unknown", "", "", R.string.err_unknown, R.drawable.mark_red); // LogType not init. yet
public final int id;
public final String iconName;
public final String type;
+ public final String oc_type;
private final int stringId;
public final int markerId;
- LogType(int id, String iconName, String type, int stringId, int markerId) {
+ LogType(int id, String iconName, String type, String oc_type, int stringId, int markerId) {
this.id = id;
this.iconName = iconName;
this.type = type;
+ this.oc_type = oc_type;
this.stringId = stringId;
this.markerId = markerId;
}
- LogType(int id, String iconName, String type, int stringId) {
- this(id, iconName, type, stringId, R.drawable.mark_gray);
+ LogType(int id, String iconName, String type, String oc_type, int stringId) {
+ this(id, iconName, type, oc_type, stringId, R.drawable.mark_gray);
}
private final static Map<String, LogType> FIND_BY_ICONNAME;
diff --git a/main/src/cgeo/geocaching/enumerations/WaypointType.java b/main/src/cgeo/geocaching/enumerations/WaypointType.java
index 748c432..79c8106 100644
--- a/main/src/cgeo/geocaching/enumerations/WaypointType.java
+++ b/main/src/cgeo/geocaching/enumerations/WaypointType.java
@@ -72,4 +72,8 @@ public enum WaypointType {
public final String toString() {
return getL10n();
}
+
+ public boolean applyDistanceRule() {
+ return (this == FINAL || this == STAGE);
+ }
}
diff --git a/main/src/cgeo/geocaching/export/AbstractExport.java b/main/src/cgeo/geocaching/export/AbstractExport.java
index 72ea544..e4ba5f0 100644
--- a/main/src/cgeo/geocaching/export/AbstractExport.java
+++ b/main/src/cgeo/geocaching/export/AbstractExport.java
@@ -1,5 +1,6 @@
package cgeo.geocaching.export;
+import cgeo.geocaching.R;
import cgeo.geocaching.cgeoapplication;
abstract class AbstractExport implements Export {
@@ -27,7 +28,7 @@ abstract class AbstractExport implements Export {
/**
* Generates a localized string from a resource id.
- *
+ *
* @param resourceId
* the resource id of the string
* @param params
@@ -43,4 +44,8 @@ abstract class AbstractExport implements Export {
// used in the array adapter of the dialog showing the exports
return getName();
}
+
+ protected String getProgressTitle() {
+ return getString(R.string.export) + ": " + getName();
+ }
}
diff --git a/main/src/cgeo/geocaching/export/FieldnoteExport.java b/main/src/cgeo/geocaching/export/FieldnoteExport.java
index 5e1805a..38b603c 100644
--- a/main/src/cgeo/geocaching/export/FieldnoteExport.java
+++ b/main/src/cgeo/geocaching/export/FieldnoteExport.java
@@ -5,11 +5,11 @@ import cgeo.geocaching.LogEntry;
import cgeo.geocaching.R;
import cgeo.geocaching.cgData;
import cgeo.geocaching.activity.ActivityMixin;
-import cgeo.geocaching.activity.Progress;
import cgeo.geocaching.connector.gc.Login;
import cgeo.geocaching.enumerations.StatusCode;
import cgeo.geocaching.network.Network;
import cgeo.geocaching.network.Parameters;
+import cgeo.geocaching.utils.AsyncTaskWithProgress;
import cgeo.geocaching.utils.IOUtils;
import cgeo.geocaching.utils.Log;
@@ -20,12 +20,12 @@ import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
-import android.os.AsyncTask;
import android.os.Environment;
import android.view.ContextThemeWrapper;
import android.view.View;
import android.widget.CheckBox;
+import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
@@ -57,22 +57,23 @@ class FieldnoteExport extends AbstractExport {
}
@Override
- public void export(final List<Geocache> caches, final Activity activity) {
+ public void export(final List<Geocache> cachesList, final Activity activity) {
+ final Geocache[] caches = cachesList.toArray(new Geocache[cachesList.size()]);
if (null == activity) {
// No activity given, so no user interaction possible.
// Start export with default parameters.
- new ExportTask(caches, null, false, false).execute((Void) null);
+ new ExportTask(null, false, false).execute(caches);
} else {
// Show configuration dialog
getExportOptionsDialog(caches, activity).show();
}
}
- private Dialog getExportOptionsDialog(final List<Geocache> caches, final Activity activity) {
- AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+ private Dialog getExportOptionsDialog(final Geocache[] caches, final Activity activity) {
+ final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
// AlertDialog has always dark style, so we have to apply it as well always
- View layout = View.inflate(new ContextThemeWrapper(activity, R.style.dark), R.layout.fieldnote_export_dialog, null);
+ final View layout = View.inflate(new ContextThemeWrapper(activity, R.style.dark), R.layout.fieldnote_export_dialog, null);
builder.setView(layout);
final CheckBox uploadOption = (CheckBox) layout.findViewById(R.id.upload);
@@ -91,32 +92,27 @@ class FieldnoteExport extends AbstractExport {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
new ExportTask(
- caches,
activity,
uploadOption.isChecked(),
onlyNewOption.isChecked())
- .execute((Void) null);
+ .execute(caches);
}
});
return builder.create();
}
- private class ExportTask extends AsyncTask<Void, Integer, Boolean> {
- private final List<Geocache> caches;
+ private class ExportTask extends AsyncTaskWithProgress<Geocache, Boolean> {
private final Activity activity;
private final boolean upload;
private final boolean onlyNew;
- private final Progress progress = new Progress();
private File exportFile;
private static final int STATUS_UPLOAD = -1;
/**
- * Instantiates and configurates the task for exporting field notes.
+ * Instantiates and configures the task for exporting field notes.
*
- * @param caches
- * The {@link List} of {@link cgeo.geocaching.Geocache} to be exported
* @param activity
* optional: Show a progress bar and toasts
* @param upload
@@ -124,32 +120,25 @@ class FieldnoteExport extends AbstractExport {
* @param onlyNew
* Upload/export only new logs since last export
*/
- public ExportTask(final List<Geocache> caches, final Activity activity, final boolean upload, final boolean onlyNew) {
- this.caches = caches;
+ public ExportTask(final Activity activity, final boolean upload, final boolean onlyNew) {
+ super(activity, getProgressTitle(), getString(R.string.export_fieldnotes_creating));
this.activity = activity;
this.upload = upload;
this.onlyNew = onlyNew;
}
@Override
- protected void onPreExecute() {
- if (null != activity) {
- progress.show(activity, getString(R.string.export) + ": " + getName(), getString(R.string.export_fieldnotes_creating), true, null);
- }
- }
-
- @Override
- protected Boolean doInBackground(Void... params) {
+ protected Boolean doInBackgroundInternal(Geocache[] caches) {
final StringBuilder fieldNoteBuffer = new StringBuilder();
try {
int i = 0;
- for (Geocache cache : caches) {
+ for (final Geocache cache : caches) {
if (cache.isLogOffline()) {
appendFieldNote(fieldNoteBuffer, cache, cgData.loadLogOffline(cache.getGeocode()));
publishProgress(++i);
}
}
- } catch (Exception e) {
+ } catch (final Exception e) {
Log.e("FieldnoteExport.ExportTask generation", e);
return false;
}
@@ -162,19 +151,22 @@ class FieldnoteExport extends AbstractExport {
exportLocation.mkdirs();
- SimpleDateFormat fileNameDateFormat = new SimpleDateFormat("yyyyMMddHHmmss", Locale.US);
+ final SimpleDateFormat fileNameDateFormat = new SimpleDateFormat("yyyyMMddHHmmss", Locale.US);
exportFile = new File(exportLocation.toString() + '/' + fileNameDateFormat.format(new Date()) + ".txt");
- Writer fw = null;
+ Writer fileWriter = null;
+ BufferedOutputStream buffer = null;
try {
- OutputStream os = new FileOutputStream(exportFile);
- fw = new OutputStreamWriter(os, CharEncoding.UTF_16);
- fw.write(fieldNoteBuffer.toString());
- } catch (IOException e) {
+ final OutputStream os = new FileOutputStream(exportFile);
+ buffer = new BufferedOutputStream(os);
+ fileWriter = new OutputStreamWriter(buffer, CharEncoding.UTF_16);
+ fileWriter.write(fieldNoteBuffer.toString());
+ } catch (final IOException e) {
Log.e("FieldnoteExport.ExportTask export", e);
return false;
} finally {
- IOUtils.closeQuietly(fw);
+ IOUtils.closeQuietly(fileWriter);
+ IOUtils.closeQuietly(buffer);
}
if (upload) {
@@ -189,17 +181,11 @@ class FieldnoteExport extends AbstractExport {
}
final String uri = "http://www.geocaching.com/my/uploadfieldnotes.aspx";
- String page = Network.getResponseData(Network.getRequest(uri));
+ final String page = Login.getRequestLogged(uri, null);
- if (!Login.getLoginStatus(page)) {
- // Login.isActualLoginStatus() was wrong, we are not logged in
- final StatusCode loginState = Login.login();
- if (loginState == StatusCode.NO_ERROR) {
- page = Network.getResponseData(Network.getRequest(uri));
- } else {
- Log.e("FieldnoteExport.ExportTask upload: No login (error: " + loginState + ')');
- return false;
- }
+ if (StringUtils.isBlank(page)) {
+ Log.e("FieldnoteExport.ExportTask get page: No data from server");
+ return false;
}
final String[] viewstates = Login.getViewstates(page);
@@ -227,10 +213,8 @@ class FieldnoteExport extends AbstractExport {
}
@Override
- protected void onPostExecute(Boolean result) {
+ protected void onPostExecuteInternal(Boolean result) {
if (null != activity) {
- progress.dismiss();
-
if (result) {
// if (onlyNew) {
// // update last export time in settings when doing it ourself (currently we use the date check from gc.com)
@@ -248,12 +232,12 @@ class FieldnoteExport extends AbstractExport {
}
@Override
- protected void onProgressUpdate(Integer... status) {
+ protected void onProgressUpdateInternal(int status) {
if (null != activity) {
- if (STATUS_UPLOAD == status[0]) {
- progress.setMessage(getString(R.string.export_fieldnotes_uploading));
+ if (STATUS_UPLOAD == status) {
+ setMessage(getString(R.string.export_fieldnotes_uploading));
} else {
- progress.setMessage(getString(R.string.export_fieldnotes_creating) + " (" + status[0] + ')');
+ setMessage(getString(R.string.export_fieldnotes_creating) + " (" + status + ')');
}
}
}
diff --git a/main/src/cgeo/geocaching/export/GpxExport.java b/main/src/cgeo/geocaching/export/GpxExport.java
index b22f80f..e6b52bc 100644
--- a/main/src/cgeo/geocaching/export/GpxExport.java
+++ b/main/src/cgeo/geocaching/export/GpxExport.java
@@ -1,52 +1,37 @@
package cgeo.geocaching.export;
import cgeo.geocaching.Geocache;
-import cgeo.geocaching.LogEntry;
import cgeo.geocaching.R;
import cgeo.geocaching.Settings;
-import cgeo.geocaching.Waypoint;
-import cgeo.geocaching.cgData;
+import cgeo.geocaching.cgeoapplication;
import cgeo.geocaching.activity.ActivityMixin;
-import cgeo.geocaching.activity.Progress;
-import cgeo.geocaching.enumerations.CacheAttribute;
-import cgeo.geocaching.enumerations.LoadFlags;
-import cgeo.geocaching.geopoint.Geopoint;
-import cgeo.geocaching.utils.BaseUtils;
+import cgeo.geocaching.utils.AsyncTaskWithProgress;
import cgeo.geocaching.utils.Log;
-import cgeo.geocaching.utils.XmlUtils;
-import cgeo.org.kxml2.io.KXmlSerializer;
-
-import org.apache.commons.lang3.StringUtils;
-import org.xmlpull.v1.XmlSerializer;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
-import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
-import android.os.AsyncTask;
import android.os.Environment;
import android.view.ContextThemeWrapper;
import android.view.View;
import android.widget.CheckBox;
import android.widget.TextView;
+import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Locale;
class GpxExport extends AbstractExport {
- private static final SimpleDateFormat dateFormatZ = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
- public static final String PREFIX_XSI = "http://www.w3.org/2001/XMLSchema-instance";
- public static final String PREFIX_GPX = "http://www.topografix.com/GPX/1/0";
- public static final String PREFIX_GROUNDSPEAK = "http://www.groundspeak.com/cache/1/0";
protected GpxExport() {
super(getString(R.string.export_gpx));
@@ -54,22 +39,23 @@ class GpxExport extends AbstractExport {
@Override
public void export(final List<Geocache> caches, final Activity activity) {
+ final String[] geocodes = getGeocodes(caches);
if (null == activity) {
// No activity given, so no user interaction possible.
// Start export with default parameters.
- new ExportTask(caches, null).execute((Void) null);
+ new ExportTask(null).execute(geocodes);
} else {
// Show configuration dialog
- getExportDialog(caches, activity).show();
+ getExportDialog(geocodes, activity).show();
}
}
- private Dialog getExportDialog(final List<Geocache> caches, final Activity activity) {
- AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+ private Dialog getExportDialog(final String[] geocodes, final Activity activity) {
+ final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
// AlertDialog has always dark style, so we have to apply it as well always
- View layout = View.inflate(new ContextThemeWrapper(activity, R.style.dark), R.layout.gpx_export_dialog, null);
+ final View layout = View.inflate(new ContextThemeWrapper(activity, R.style.dark), R.layout.gpx_export_dialog, null);
builder.setView(layout);
final TextView text = (TextView) layout.findViewById(R.id.info);
@@ -91,136 +77,68 @@ class GpxExport extends AbstractExport {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
- new ExportTask(caches, activity).execute((Void) null);
+ new ExportTask(activity).execute(geocodes);
}
});
return builder.create();
}
- protected class ExportTask extends AsyncTask<Void, Integer, File> {
- private final List<Geocache> caches;
+ private static String[] getGeocodes(final List<Geocache> caches) {
+ final ArrayList<String> allGeocodes = new ArrayList<String>(caches.size());
+ for (final Geocache geocache : caches) {
+ allGeocodes.add(geocache.getGeocode());
+ }
+ return allGeocodes.toArray(new String[allGeocodes.size()]);
+ }
+
+ protected class ExportTask extends AsyncTaskWithProgress<String, File> {
private final Activity activity;
- private final Progress progress = new Progress();
/**
* Instantiates and configures the task for exporting field notes.
*
- * @param caches
- * The {@link List} of {@link cgeo.geocaching.Geocache} to be exported
* @param activity
* optional: Show a progress bar and toasts
*/
- public ExportTask(final List<Geocache> caches, final Activity activity) {
- this.caches = caches;
+ public ExportTask(final Activity activity) {
+ super(activity, getProgressTitle());
this.activity = activity;
}
@Override
- protected void onPreExecute() {
- if (null != activity) {
- progress.show(activity, null, getString(R.string.export) + ": " + getName(), ProgressDialog.STYLE_HORIZONTAL, null);
- progress.setMaxProgressAndReset(caches.size());
- }
- }
-
- @Override
- protected File doInBackground(Void... params) {
+ protected File doInBackgroundInternal(String[] geocodes) {
// quick check for being able to write the GPX file
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
return null;
}
+ final List<String> allGeocodes = new ArrayList<String>(Arrays.asList(geocodes));
+
+ setMessage(cgeoapplication.getInstance().getResources().getQuantityString(R.plurals.cache_counts, allGeocodes.size(), allGeocodes.size()));
+
final SimpleDateFormat fileNameDateFormat = new SimpleDateFormat("yyyyMMddHHmmss", Locale.US);
final File exportFile = new File(Settings.getGpxExportDir() + File.separatorChar + "export_" + fileNameDateFormat.format(new Date()) + ".gpx");
- FileWriter writer = null;
+ BufferedWriter writer = null;
try {
final File exportLocation = new File(Settings.getGpxExportDir());
exportLocation.mkdirs();
- final XmlSerializer gpx = new KXmlSerializer();
- writer = new FileWriter(exportFile);
- gpx.setOutput(writer);
-
- gpx.startDocument("UTF-8", true);
- gpx.setPrefix("", PREFIX_GPX);
- gpx.setPrefix("xsi", PREFIX_XSI);
- gpx.setPrefix("groundspeak", PREFIX_GROUNDSPEAK);
- gpx.startTag(PREFIX_GPX, "gpx");
- gpx.attribute("", "version", "1.0");
- gpx.attribute("", "creator", "c:geo - http://www.cgeo.org/");
- gpx.attribute(PREFIX_XSI, "schemaLocation",
- PREFIX_GPX + " http://www.topografix.com/GPX/1/0/gpx.xsd " +
- PREFIX_GROUNDSPEAK + " http://www.groundspeak.com/cache/1/0/1/cache.xsd");
+ writer = new BufferedWriter(new FileWriter(exportFile));
+ new GpxSerializer().writeGPX(allGeocodes, writer, new GpxSerializer.ProgressListener() {
- for (int i = 0; i < caches.size(); i++) {
- final Geocache cache = cgData.loadCache(caches.get(i).getGeocode(), LoadFlags.LOAD_ALL_DB_ONLY);
-
- gpx.startTag(PREFIX_GPX, "wpt");
- gpx.attribute("", "lat", Double.toString(cache.getCoords().getLatitude()));
- gpx.attribute("", "lon", Double.toString(cache.getCoords().getLongitude()));
-
- final Date hiddenDate = cache.getHiddenDate();
- if (hiddenDate != null) {
- XmlUtils.simpleText(gpx, PREFIX_GPX, "time", dateFormatZ.format(hiddenDate));
+ @Override
+ public void publishProgress(int countExported) {
+ this.publishProgress(countExported);
}
-
- XmlUtils.multipleTexts(gpx, PREFIX_GPX,
- "name", cache.getGeocode(),
- "desc", cache.getName(),
- "url", cache.getUrl(),
- "urlname", cache.getName(),
- "sym", cache.isFound() ? "Geocache Found" : "Geocache",
- "type", "Geocache|" + cache.getType().pattern);
-
- gpx.startTag(PREFIX_GROUNDSPEAK, "cache");
- gpx.attribute("", "id", cache.getCacheId());
- gpx.attribute("", "available", !cache.isDisabled() ? "True" : "False");
- gpx.attribute("", "archives", cache.isArchived() ? "True" : "False");
-
- XmlUtils.multipleTexts(gpx, PREFIX_GROUNDSPEAK,
- "name", cache.getName(),
- "placed_by", cache.getOwnerDisplayName(),
- "owner", cache.getOwnerUserId(),
- "type", cache.getType().pattern,
- "container", cache.getSize().id,
- "difficulty", Float.toString(cache.getDifficulty()),
- "terrain", Float.toString(cache.getTerrain()),
- "country", cache.getLocation(),
- "state", "",
- "encoded_hints", cache.getHint());
-
- writeAttributes(gpx, cache);
-
- gpx.startTag(PREFIX_GROUNDSPEAK, "short_description");
- gpx.attribute("", "html", BaseUtils.containsHtml(cache.getShortDescription()) ? "True" : "False");
- gpx.text(cache.getShortDescription());
- gpx.endTag(PREFIX_GROUNDSPEAK, "short_description");
-
- gpx.startTag(PREFIX_GROUNDSPEAK, "long_description");
- gpx.attribute("", "html", BaseUtils.containsHtml(cache.getDescription()) ? "True" : "False");
- gpx.text(cache.getDescription());
- gpx.endTag(PREFIX_GROUNDSPEAK, "long_description");
-
- writeLogs(gpx, cache);
-
- gpx.endTag(PREFIX_GROUNDSPEAK, "cache");
- gpx.endTag(PREFIX_GPX, "wpt");
-
- writeWaypoints(gpx, cache);
-
- publishProgress(i + 1);
- }
-
- gpx.endTag(PREFIX_GPX, "gpx");
- gpx.endDocument();
- } catch (final IOException e) {
+ });
+ } catch (final Exception e) {
Log.e("GpxExport.ExportTask export", e);
if (writer != null) {
try {
writer.close();
- } catch (IOException e1) {
+ } catch (final IOException e1) {
// Ignore double error
}
}
@@ -235,124 +153,13 @@ class GpxExport extends AbstractExport {
return exportFile;
}
- private void writeWaypoints(final XmlSerializer gpx, final Geocache cache) throws IOException {
- List<Waypoint> waypoints = cache.getWaypoints();
- List<Waypoint> ownWaypoints = new ArrayList<Waypoint>(waypoints.size());
- List<Waypoint> originWaypoints = new ArrayList<Waypoint>(waypoints.size());
- for (Waypoint wp : cache.getWaypoints()) {
- if (wp.isUserDefined()) {
- ownWaypoints.add(wp);
- } else {
- originWaypoints.add(wp);
- }
- }
- int maxPrefix = 0;
- for (Waypoint wp : originWaypoints) {
- String prefix = wp.getPrefix();
- try {
- final int numericPrefix = Integer.parseInt(prefix);
- maxPrefix = Math.max(numericPrefix, maxPrefix);
- } catch (NumberFormatException ex) {
- // ignore non numeric prefix, as it should be unique in the list of non-own waypoints already
- }
- writeCacheWaypoint(gpx, wp, prefix);
- }
- // Prefixes must be unique. There use numeric strings as prefixes in OWN waypoints
- for (Waypoint wp : ownWaypoints) {
- maxPrefix++;
- String prefix = StringUtils.leftPad(String.valueOf(maxPrefix), 2, '0');
- writeCacheWaypoint(gpx, wp, prefix);
- }
- }
-
- /**
- * Writes one waypoint entry for cache waypoint.
- *
- * @param cache
- * The
- * @param wp
- * @param prefix
- * @throws IOException
- */
- private void writeCacheWaypoint(final XmlSerializer gpx, final Waypoint wp, final String prefix) throws IOException {
- final Geopoint coords = wp.getCoords();
- // TODO: create some extension to GPX to include waypoint without coords
- if (coords != null) {
- gpx.startTag(PREFIX_GPX, "wpt");
- gpx.attribute("", "lat", Double.toString(coords.getLatitude()));
- gpx.attribute("", "lon", Double.toString(coords.getLongitude()));
- XmlUtils.multipleTexts(gpx, PREFIX_GPX,
- "name", prefix + wp.getGeocode().substring(2),
- "cmt", wp.getNote(),
- "desc", wp.getName(),
- "sym", wp.getWaypointType().toString(), //TODO: Correct identifier string
- "type", "Waypoint|" + wp.getWaypointType().toString()); //TODO: Correct identifier string
- gpx.endTag(PREFIX_GPX, "wpt");
- }
- }
-
- private void writeLogs(final XmlSerializer gpx, final Geocache cache) throws IOException {
- if (cache.getLogs().isEmpty()) {
- return;
- }
- gpx.startTag(PREFIX_GROUNDSPEAK, "logs");
-
- for (LogEntry log : cache.getLogs()) {
- gpx.startTag(PREFIX_GROUNDSPEAK, "log");
- gpx.attribute("", "id", Integer.toString(log.id));
-
- XmlUtils.multipleTexts(gpx, PREFIX_GROUNDSPEAK,
- "date", dateFormatZ.format(new Date(log.date)),
- "type", log.type.type);
-
- gpx.startTag(PREFIX_GROUNDSPEAK, "finder");
- gpx.attribute("", "id", "");
- gpx.text(log.author);
- gpx.endTag(PREFIX_GROUNDSPEAK, "finder");
-
- gpx.startTag(PREFIX_GROUNDSPEAK, "text");
- gpx.attribute("", "encoded", "False");
- gpx.text(log.log);
- gpx.endTag(PREFIX_GROUNDSPEAK, "text");
-
- gpx.endTag(PREFIX_GROUNDSPEAK, "log");
- }
-
- gpx.endTag(PREFIX_GROUNDSPEAK, "logs");
- }
-
- private void writeAttributes(final XmlSerializer gpx, final Geocache cache) throws IOException {
- if (cache.getAttributes().isEmpty()) {
- return;
- }
- //TODO: Attribute conversion required: English verbose name, gpx-id
- gpx.startTag(PREFIX_GROUNDSPEAK, "attributes");
-
- for (String attribute : cache.getAttributes()) {
- final CacheAttribute attr = CacheAttribute.getByRawName(CacheAttribute.trimAttributeName(attribute));
- if (attr == null) {
- continue;
- }
- final boolean enabled = CacheAttribute.isEnabled(attribute);
-
- gpx.startTag(PREFIX_GROUNDSPEAK, "attribute");
- gpx.attribute("", "id", Integer.toString(attr.gcid));
- gpx.attribute("", "inc", enabled ? "1" : "0");
- gpx.text(attr.getL10n(enabled));
- gpx.endTag(PREFIX_GROUNDSPEAK, "attribute");
- }
-
- gpx.endTag(PREFIX_GROUNDSPEAK, "attributes");
- }
-
@Override
- protected void onPostExecute(final File exportFile) {
+ protected void onPostExecuteInternal(final File exportFile) {
if (null != activity) {
- progress.dismiss();
if (exportFile != null) {
ActivityMixin.showToast(activity, getName() + ' ' + getString(R.string.export_exportedto) + ": " + exportFile.toString());
if (Settings.getShareAfterExport()) {
- Intent shareIntent = new Intent();
+ final Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(exportFile));
shareIntent.setType("application/xml");
@@ -364,11 +171,5 @@ class GpxExport extends AbstractExport {
}
}
- @Override
- protected void onProgressUpdate(Integer... status) {
- if (null != activity) {
- progress.setProgress(status[0]);
- }
- }
}
}
diff --git a/main/src/cgeo/geocaching/export/GpxSerializer.java b/main/src/cgeo/geocaching/export/GpxSerializer.java
new file mode 100644
index 0000000..2c50721
--- /dev/null
+++ b/main/src/cgeo/geocaching/export/GpxSerializer.java
@@ -0,0 +1,256 @@
+package cgeo.geocaching.export;
+
+import cgeo.geocaching.Geocache;
+import cgeo.geocaching.LogEntry;
+import cgeo.geocaching.Waypoint;
+import cgeo.geocaching.cgData;
+import cgeo.geocaching.enumerations.CacheAttribute;
+import cgeo.geocaching.enumerations.LoadFlags;
+import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.utils.TextUtils;
+import cgeo.geocaching.utils.XmlUtils;
+import cgeo.org.kxml2.io.KXmlSerializer;
+
+import org.apache.commons.lang3.StringUtils;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+import java.util.Set;
+
+public final class GpxSerializer {
+
+ private static final SimpleDateFormat dateFormatZ = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
+ public static final String PREFIX_XSI = "http://www.w3.org/2001/XMLSchema-instance";
+ public static final String PREFIX_GPX = "http://www.topografix.com/GPX/1/0";
+ public static final String PREFIX_GROUNDSPEAK = "http://www.groundspeak.com/cache/1/0";
+
+ /**
+ * During the export, only this number of geocaches is fully loaded into memory.
+ */
+ public static final int CACHES_PER_BATCH = 100;
+
+ /**
+ * counter for exported caches, used for progress reporting
+ */
+ private int countExported;
+ private ProgressListener progressListener;
+ private XmlSerializer gpx;
+
+ protected static interface ProgressListener {
+
+ void publishProgress(int countExported);
+
+ }
+
+ public void writeGPX(List<String> allGeocodesIn, Writer writer, final ProgressListener progressListener) throws IOException {
+ // create a copy of the geocode list, as we need to modify it, but it might be immutable
+ final ArrayList<String> allGeocodes = new ArrayList<String>(allGeocodesIn);
+
+ this.progressListener = progressListener;
+ gpx = new KXmlSerializer();
+ gpx.setOutput(writer);
+
+ gpx.startDocument("UTF-8", true);
+ gpx.setPrefix("", PREFIX_GPX);
+ gpx.setPrefix("xsi", PREFIX_XSI);
+ gpx.setPrefix("groundspeak", PREFIX_GROUNDSPEAK);
+ gpx.startTag(PREFIX_GPX, "gpx");
+ gpx.attribute("", "version", "1.0");
+ gpx.attribute("", "creator", "c:geo - http://www.cgeo.org/");
+ gpx.attribute(PREFIX_XSI, "schemaLocation",
+ PREFIX_GPX + " http://www.topografix.com/GPX/1/0/gpx.xsd " +
+ PREFIX_GROUNDSPEAK + " http://www.groundspeak.com/cache/1/0/1/cache.xsd");
+
+ // Split the overall set of geocodes into small chunks. That is a compromise between memory efficiency (because
+ // we don't load all caches fully into memory) and speed (because we don't query each cache separately).
+ while (!allGeocodes.isEmpty()) {
+ final List<String> batch = allGeocodes.subList(0, Math.min(CACHES_PER_BATCH, allGeocodes.size()));
+ exportBatch(gpx, batch);
+ batch.clear();
+ }
+
+ gpx.endTag(PREFIX_GPX, "gpx");
+ gpx.endDocument();
+ }
+
+ private void exportBatch(final XmlSerializer gpx, Collection<String> geocodesOfBatch) throws IOException {
+ final Set<Geocache> caches = cgData.loadCaches(geocodesOfBatch, LoadFlags.LOAD_ALL_DB_ONLY);
+ for (final Geocache cache : caches) {
+ gpx.startTag(PREFIX_GPX, "wpt");
+ gpx.attribute("", "lat", Double.toString(cache.getCoords().getLatitude()));
+ gpx.attribute("", "lon", Double.toString(cache.getCoords().getLongitude()));
+
+ final Date hiddenDate = cache.getHiddenDate();
+ if (hiddenDate != null) {
+ XmlUtils.simpleText(gpx, PREFIX_GPX, "time", dateFormatZ.format(hiddenDate));
+ }
+
+ XmlUtils.multipleTexts(gpx, PREFIX_GPX,
+ "name", cache.getGeocode(),
+ "desc", cache.getName(),
+ "url", cache.getUrl(),
+ "urlname", cache.getName(),
+ "sym", cache.isFound() ? "Geocache Found" : "Geocache",
+ "type", "Geocache|" + cache.getType().pattern);
+
+ gpx.startTag(PREFIX_GROUNDSPEAK, "cache");
+ gpx.attribute("", "id", cache.getCacheId());
+ gpx.attribute("", "available", !cache.isDisabled() ? "True" : "False");
+ gpx.attribute("", "archives", cache.isArchived() ? "True" : "False");
+
+ XmlUtils.multipleTexts(gpx, PREFIX_GROUNDSPEAK,
+ "name", cache.getName(),
+ "placed_by", cache.getOwnerDisplayName(),
+ "owner", cache.getOwnerUserId(),
+ "type", cache.getType().pattern,
+ "container", cache.getSize().id,
+ "difficulty", Float.toString(cache.getDifficulty()),
+ "terrain", Float.toString(cache.getTerrain()),
+ "country", cache.getLocation(),
+ "state", "",
+ "encoded_hints", cache.getHint());
+
+ writeAttributes(cache);
+
+ gpx.startTag(PREFIX_GROUNDSPEAK, "short_description");
+ gpx.attribute("", "html", TextUtils.containsHtml(cache.getShortDescription()) ? "True" : "False");
+ gpx.text(cache.getShortDescription());
+ gpx.endTag(PREFIX_GROUNDSPEAK, "short_description");
+
+ gpx.startTag(PREFIX_GROUNDSPEAK, "long_description");
+ gpx.attribute("", "html", TextUtils.containsHtml(cache.getDescription()) ? "True" : "False");
+ gpx.text(cache.getDescription());
+ gpx.endTag(PREFIX_GROUNDSPEAK, "long_description");
+
+ writeLogs(cache);
+
+ gpx.endTag(PREFIX_GROUNDSPEAK, "cache");
+ gpx.endTag(PREFIX_GPX, "wpt");
+
+ writeWaypoints(cache);
+
+ countExported++;
+ if (progressListener != null) {
+ progressListener.publishProgress(countExported);
+ }
+ }
+ }
+
+ private void writeWaypoints(final Geocache cache) throws IOException {
+ final List<Waypoint> waypoints = cache.getWaypoints();
+ final List<Waypoint> ownWaypoints = new ArrayList<Waypoint>(waypoints.size());
+ final List<Waypoint> originWaypoints = new ArrayList<Waypoint>(waypoints.size());
+ for (final Waypoint wp : cache.getWaypoints()) {
+ if (wp.isUserDefined()) {
+ ownWaypoints.add(wp);
+ } else {
+ originWaypoints.add(wp);
+ }
+ }
+ int maxPrefix = 0;
+ for (final Waypoint wp : originWaypoints) {
+ final String prefix = wp.getPrefix();
+ try {
+ final int numericPrefix = Integer.parseInt(prefix);
+ maxPrefix = Math.max(numericPrefix, maxPrefix);
+ } catch (final NumberFormatException ex) {
+ // ignore non numeric prefix, as it should be unique in the list of non-own waypoints already
+ }
+ writeCacheWaypoint(wp, prefix);
+ }
+ // Prefixes must be unique. There use numeric strings as prefixes in OWN waypoints
+ for (final Waypoint wp : ownWaypoints) {
+ maxPrefix++;
+ final String prefix = StringUtils.leftPad(String.valueOf(maxPrefix), 2, '0');
+ writeCacheWaypoint(wp, prefix);
+ }
+ }
+
+ /**
+ * Writes one waypoint entry for cache waypoint.
+ *
+ * @param cache
+ * The
+ * @param wp
+ * @param prefix
+ * @throws IOException
+ */
+ private void writeCacheWaypoint(final Waypoint wp, final String prefix) throws IOException {
+ final Geopoint coords = wp.getCoords();
+ // TODO: create some extension to GPX to include waypoint without coords
+ if (coords != null) {
+ gpx.startTag(PREFIX_GPX, "wpt");
+ gpx.attribute("", "lat", Double.toString(coords.getLatitude()));
+ gpx.attribute("", "lon", Double.toString(coords.getLongitude()));
+ XmlUtils.multipleTexts(gpx, PREFIX_GPX,
+ "name", prefix + wp.getGeocode().substring(2),
+ "cmt", wp.getNote(),
+ "desc", wp.getName(),
+ "sym", wp.getWaypointType().toString(), //TODO: Correct identifier string
+ "type", "Waypoint|" + wp.getWaypointType().toString()); //TODO: Correct identifier string
+ gpx.endTag(PREFIX_GPX, "wpt");
+ }
+ }
+
+ private void writeLogs(final Geocache cache) throws IOException {
+ if (cache.getLogs().isEmpty()) {
+ return;
+ }
+ gpx.startTag(PREFIX_GROUNDSPEAK, "logs");
+
+ for (final LogEntry log : cache.getLogs()) {
+ gpx.startTag(PREFIX_GROUNDSPEAK, "log");
+ gpx.attribute("", "id", Integer.toString(log.id));
+
+ XmlUtils.multipleTexts(gpx, PREFIX_GROUNDSPEAK,
+ "date", dateFormatZ.format(new Date(log.date)),
+ "type", log.type.type);
+
+ gpx.startTag(PREFIX_GROUNDSPEAK, "finder");
+ gpx.attribute("", "id", "");
+ gpx.text(log.author);
+ gpx.endTag(PREFIX_GROUNDSPEAK, "finder");
+
+ gpx.startTag(PREFIX_GROUNDSPEAK, "text");
+ gpx.attribute("", "encoded", "False");
+ gpx.text(log.log);
+ gpx.endTag(PREFIX_GROUNDSPEAK, "text");
+
+ gpx.endTag(PREFIX_GROUNDSPEAK, "log");
+ }
+
+ gpx.endTag(PREFIX_GROUNDSPEAK, "logs");
+ }
+
+ private void writeAttributes(final Geocache cache) throws IOException {
+ if (cache.getAttributes().isEmpty()) {
+ return;
+ }
+ //TODO: Attribute conversion required: English verbose name, gpx-id
+ gpx.startTag(PREFIX_GROUNDSPEAK, "attributes");
+
+ for (final String attribute : cache.getAttributes()) {
+ final CacheAttribute attr = CacheAttribute.getByRawName(CacheAttribute.trimAttributeName(attribute));
+ if (attr == null) {
+ continue;
+ }
+ final boolean enabled = CacheAttribute.isEnabled(attribute);
+
+ gpx.startTag(PREFIX_GROUNDSPEAK, "attribute");
+ gpx.attribute("", "id", Integer.toString(attr.gcid));
+ gpx.attribute("", "inc", enabled ? "1" : "0");
+ gpx.text(attr.getL10n(enabled));
+ gpx.endTag(PREFIX_GROUNDSPEAK, "attribute");
+ }
+
+ gpx.endTag(PREFIX_GROUNDSPEAK, "attributes");
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/files/AbstractFileListActivity.java b/main/src/cgeo/geocaching/files/AbstractFileListActivity.java
index 5ff0d91..8b02eeb 100644
--- a/main/src/cgeo/geocaching/files/AbstractFileListActivity.java
+++ b/main/src/cgeo/geocaching/files/AbstractFileListActivity.java
@@ -89,7 +89,6 @@ public abstract class AbstractFileListActivity<T extends ArrayAdapter<File>> ext
setTheme();
setContentView(R.layout.gpx);
- setTitle();
Bundle extras = getIntent().getExtras();
if (extras != null) {
@@ -146,11 +145,6 @@ public abstract class AbstractFileListActivity<T extends ArrayAdapter<File>> ext
*/
protected abstract List<File> getBaseFolders();
- /**
- * Triggers the deriving class to set the title
- */
- protected abstract void setTitle();
-
private class SearchFilesThread extends Thread {
private final FileListSelector selector = new FileListSelector();
diff --git a/main/src/cgeo/geocaching/files/FileParser.java b/main/src/cgeo/geocaching/files/FileParser.java
index 50b65a1..f979d74 100644
--- a/main/src/cgeo/geocaching/files/FileParser.java
+++ b/main/src/cgeo/geocaching/files/FileParser.java
@@ -2,7 +2,9 @@ package cgeo.geocaching.files;
import cgeo.geocaching.Geocache;
import cgeo.geocaching.utils.CancellableHandler;
+import cgeo.geocaching.utils.IOUtils;
+import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
@@ -16,7 +18,7 @@ import java.util.concurrent.CancellationException;
public abstract class FileParser {
/**
* Parses caches from input stream.
- *
+ *
* @param stream
* @param progressHandler
* for reporting parsing progress (in bytes read from input stream)
@@ -38,11 +40,11 @@ public abstract class FileParser {
* @throws ParserException
*/
public Collection<Geocache> parse(final File file, final CancellableHandler progressHandler) throws IOException, ParserException {
- FileInputStream fis = new FileInputStream(file);
+ BufferedInputStream stream = new BufferedInputStream(new FileInputStream(file));
try {
- return parse(fis, progressHandler);
+ return parse(stream, progressHandler);
} finally {
- fis.close();
+ IOUtils.closeQuietly(stream);
}
}
@@ -59,7 +61,7 @@ public abstract class FileParser {
}
return buffer;
} finally {
- input.close();
+ IOUtils.closeQuietly(input);
}
}
diff --git a/main/src/cgeo/geocaching/files/GPXImporter.java b/main/src/cgeo/geocaching/files/GPXImporter.java
index b8dcbb3..34c4d02 100644
--- a/main/src/cgeo/geocaching/files/GPXImporter.java
+++ b/main/src/cgeo/geocaching/files/GPXImporter.java
@@ -1,458 +1,490 @@
-package cgeo.geocaching.files;
-
-import cgeo.geocaching.Geocache;
-import cgeo.geocaching.R;
-import cgeo.geocaching.SearchResult;
-import cgeo.geocaching.Settings;
-import cgeo.geocaching.StaticMapsProvider;
-import cgeo.geocaching.cgData;
-import cgeo.geocaching.activity.IAbstractActivity;
-import cgeo.geocaching.activity.Progress;
-import cgeo.geocaching.enumerations.LoadFlags;
-import cgeo.geocaching.utils.CancellableHandler;
-import cgeo.geocaching.utils.Log;
-
-import org.apache.commons.lang3.StringUtils;
-
-import android.app.Activity;
-import android.app.ProgressDialog;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.Resources;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.Message;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.concurrent.CancellationException;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipInputStream;
-
-public class GPXImporter {
- static final int IMPORT_STEP_START = 0;
- static final int IMPORT_STEP_READ_FILE = 1;
- static final int IMPORT_STEP_READ_WPT_FILE = 2;
- static final int IMPORT_STEP_STORE_STATIC_MAPS = 4;
- static final int IMPORT_STEP_FINISHED = 5;
- static final int IMPORT_STEP_FINISHED_WITH_ERROR = 6;
- static final int IMPORT_STEP_CANCEL = 7;
- static final int IMPORT_STEP_CANCELED = 8;
- static final int IMPORT_STEP_STATIC_MAPS_SKIPPED = 9;
-
- public static final String GPX_FILE_EXTENSION = ".gpx";
- public static final String ZIP_FILE_EXTENSION = ".zip";
- public static final String WAYPOINTS_FILE_SUFFIX = "-wpts";
- public static final String WAYPOINTS_FILE_SUFFIX_AND_EXTENSION = WAYPOINTS_FILE_SUFFIX + GPX_FILE_EXTENSION;
-
- private static final List<String> GPX_MIME_TYPES = Arrays.asList("text/xml", "application/xml");
- private static final List<String> ZIP_MIME_TYPES = Arrays.asList("application/zip", "application/x-compressed", "application/x-zip-compressed", "application/x-zip", "application/octet-stream");
-
- private Progress progress = new Progress(true);
-
- private Resources res;
- private int listId;
- private IAbstractActivity fromActivity;
- private Handler importFinishedHandler;
-
- public GPXImporter(final IAbstractActivity fromActivity, final int listId, final Handler importFinishedHandler) {
- this.listId = listId;
- this.fromActivity = fromActivity;
- res = ((Activity) fromActivity).getResources();
- this.importFinishedHandler = importFinishedHandler;
- }
-
- /**
- * Import GPX file. Currently supports *.gpx, *.zip (containing gpx files, e.g. PQ queries) or *.loc files.
- *
- * @param file
- * the file to import
- */
- public void importGPX(final File file) {
- if (StringUtils.endsWithIgnoreCase(file.getName(), GPX_FILE_EXTENSION)) {
- new ImportGpxFileThread(file, listId, importStepHandler, progressHandler).start();
- } else if (StringUtils.endsWithIgnoreCase(file.getName(), ZIP_FILE_EXTENSION)) {
- new ImportGpxZipFileThread(file, listId, importStepHandler, progressHandler).start();
- } else {
- new ImportLocFileThread(file, listId, importStepHandler, progressHandler).start();
- }
- }
-
- /**
- * Import GPX provided via intent of activity that instantiated this GPXImporter.
- */
- public void importGPX() {
- final ContentResolver contentResolver = ((Activity) fromActivity).getContentResolver();
- final Intent intent = ((Activity) fromActivity).getIntent();
- final Uri uri = intent.getData();
-
- String mimeType = intent.getType();
- // if mimetype can't be determined (e.g. for emulators email app), derive it from uri file extension
- // contentResolver.getType(uri) doesn't help but throws exception for emulators email app
- // Permission Denial: reading com.android.email.provider.EmailProvider uri
- // Google search says: there is no solution for this problem
- // Gmail doesn't work at all, see #967
- if (mimeType == null) {
- if (StringUtils.endsWithIgnoreCase(uri.getPath(), GPX_FILE_EXTENSION)) {
- mimeType = "application/xml";
- } else {
- // if we can't determine a better type, default to zip import
- // emulator email sends e.g. content://com.android.email.attachmentprovider/1/1/RAW, mimetype=null
- mimeType = "application/zip";
- }
- }
-
- Log.i("importGPX: " + uri + ", mimetype=" + mimeType);
- if (GPX_MIME_TYPES.contains(mimeType)) {
- new ImportGpxAttachmentThread(uri, contentResolver, listId, importStepHandler, progressHandler).start();
- } else if (ZIP_MIME_TYPES.contains(mimeType)) {
- new ImportGpxZipAttachmentThread(uri, contentResolver, listId, importStepHandler, progressHandler).start();
- } else {
- importFinished();
- }
- }
-
- static abstract class ImportThread extends Thread {
- final int listId;
- final Handler importStepHandler;
- final CancellableHandler progressHandler;
-
- protected ImportThread(int listId, Handler importStepHandler, CancellableHandler progressHandler) {
- this.listId = listId;
- this.importStepHandler = importStepHandler;
- this.progressHandler = progressHandler;
- }
-
- @Override
- public void run() {
- try {
- importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_START));
- final Collection<Geocache> caches = doImport();
- Log.i("Imported successfully " + caches.size() + " caches.");
-
- final SearchResult search = new SearchResult();
- for (Geocache cache : caches) {
- search.addCache(cache);
- }
-
- if (Settings.isStoreOfflineMaps() || Settings.isStoreOfflineWpMaps()) {
- importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_STORE_STATIC_MAPS, R.string.gpx_import_store_static_maps, search.getCount()));
- boolean finishedWithoutCancel = importStaticMaps(search);
- // Skip last message if static maps where canceled
- if (!finishedWithoutCancel) {
- return;
- }
- }
-
- importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_FINISHED, search.getCount(), 0, search));
- } catch (IOException e) {
- Log.i("Importing caches failed - error reading data: " + e.getMessage());
- importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_FINISHED_WITH_ERROR, R.string.gpx_import_error_io, 0, e.getLocalizedMessage()));
- } catch (ParserException e) {
- Log.i("Importing caches failed - data format error" + e.getMessage());
- importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_FINISHED_WITH_ERROR, R.string.gpx_import_error_parser, 0, e.getLocalizedMessage()));
- } catch (CancellationException e) {
- Log.i("Importing caches canceled");
- importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_CANCELED));
- } catch (Exception e) {
- Log.e("Importing caches failed - unknown error: ", e);
- importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_FINISHED_WITH_ERROR, R.string.gpx_import_error_unexpected, 0, e.getLocalizedMessage()));
- }
- }
-
- protected abstract Collection<Geocache> doImport() throws IOException, ParserException;
-
- private boolean importStaticMaps(final SearchResult importedCaches) {
- int storedCacheMaps = 0;
- for (String geocode : importedCaches.getGeocodes()) {
- Geocache cache = cgData.loadCache(geocode, LoadFlags.LOAD_WAYPOINTS);
- Log.d("GPXImporter.ImportThread.importStaticMaps start downloadMaps for cache " + geocode);
- StaticMapsProvider.downloadMaps(cache);
- storedCacheMaps++;
- if (progressHandler.isCancelled()) {
- return false;
- }
- progressHandler.sendMessage(progressHandler.obtainMessage(0, storedCacheMaps, 0));
- }
- return true;
- }
- }
-
- static class ImportLocFileThread extends ImportThread {
- private final File file;
-
- public ImportLocFileThread(final File file, int listId, Handler importStepHandler, CancellableHandler progressHandler) {
- super(listId, importStepHandler, progressHandler);
- this.file = file;
- }
-
- @Override
- protected Collection<Geocache> doImport() throws IOException, ParserException {
- Log.i("Import LOC file: " + file.getAbsolutePath());
- importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_READ_FILE, R.string.gpx_import_loading_caches, (int) file.length()));
- LocParser parser = new LocParser(listId);
- return parser.parse(file, progressHandler);
- }
- }
-
- static abstract class ImportGpxThread extends ImportThread {
-
- protected ImportGpxThread(int listId, Handler importStepHandler, CancellableHandler progressHandler) {
- super(listId, importStepHandler, progressHandler);
- }
-
- @Override
- protected Collection<Geocache> doImport() throws IOException, ParserException {
- try {
- // try to parse cache file as GPX 10
- return doImport(new GPX10Parser(listId));
- } catch (ParserException pe) {
- // didn't work -> lets try GPX11
- return doImport(new GPX11Parser(listId));
- }
- }
-
- protected abstract Collection<Geocache> doImport(GPXParser parser) throws IOException, ParserException;
- }
-
- static class ImportGpxFileThread extends ImportGpxThread {
- private final File cacheFile;
-
- public ImportGpxFileThread(final File file, int listId, Handler importStepHandler, CancellableHandler progressHandler) {
- super(listId, importStepHandler, progressHandler);
- this.cacheFile = file;
- }
-
- @Override
- protected Collection<Geocache> doImport(GPXParser parser) throws IOException, ParserException {
- Log.i("Import GPX file: " + cacheFile.getAbsolutePath());
- importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_READ_FILE, R.string.gpx_import_loading_caches, (int) cacheFile.length()));
- Collection<Geocache> caches = parser.parse(cacheFile, progressHandler);
-
- final String wptsFilename = getWaypointsFileNameForGpxFile(cacheFile);
- if (wptsFilename != null) {
- final File wptsFile = new File(cacheFile.getParentFile(), wptsFilename);
- if (wptsFile.canRead()) {
- Log.i("Import GPX waypoint file: " + wptsFile.getAbsolutePath());
- importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_READ_WPT_FILE, R.string.gpx_import_loading_waypoints, (int) wptsFile.length()));
- caches = parser.parse(wptsFile, progressHandler);
- }
- }
- return caches;
- }
- }
-
- static class ImportGpxAttachmentThread extends ImportGpxThread {
- private final Uri uri;
- private ContentResolver contentResolver;
-
- public ImportGpxAttachmentThread(Uri uri, ContentResolver contentResolver, int listId, Handler importStepHandler, CancellableHandler progressHandler) {
- super(listId, importStepHandler, progressHandler);
- this.uri = uri;
- this.contentResolver = contentResolver;
- }
-
- @Override
- protected Collection<Geocache> doImport(GPXParser parser) throws IOException, ParserException {
- Log.i("Import GPX from uri: " + uri);
- importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_READ_FILE, R.string.gpx_import_loading_caches, -1));
- InputStream is = contentResolver.openInputStream(uri);
- try {
- return parser.parse(is, progressHandler);
- } finally {
- is.close();
- }
- }
- }
-
- static abstract class ImportGpxZipThread extends ImportGpxThread {
-
- protected ImportGpxZipThread(int listId, Handler importStepHandler, CancellableHandler progressHandler) {
- super(listId, importStepHandler, progressHandler);
- }
-
- @Override
- protected Collection<Geocache> doImport(GPXParser parser) throws IOException, ParserException {
- Collection<Geocache> caches = Collections.emptySet();
- // can't assume that GPX file comes before waypoint file in zip -> so we need two passes
- // 1. parse GPX files
- ZipInputStream zis = new ZipInputStream(getInputStream());
- try {
- for (ZipEntry zipEntry = zis.getNextEntry(); zipEntry != null; zipEntry = zis.getNextEntry()) {
- if (StringUtils.endsWithIgnoreCase(zipEntry.getName(), GPX_FILE_EXTENSION)) {
- if (!StringUtils.endsWithIgnoreCase(zipEntry.getName(), WAYPOINTS_FILE_SUFFIX_AND_EXTENSION)) {
- importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_READ_FILE, R.string.gpx_import_loading_caches, (int) zipEntry.getSize()));
- caches = parser.parse(new NoCloseInputStream(zis), progressHandler);
- }
- } else {
- throw new ParserException("Imported zip is not a GPX zip file.");
- }
- zis.closeEntry();
- }
- } finally {
- zis.close();
- }
-
- // 2. parse waypoint files
- zis = new ZipInputStream(getInputStream());
- try {
- for (ZipEntry zipEntry = zis.getNextEntry(); zipEntry != null; zipEntry = zis.getNextEntry()) {
- if (StringUtils.endsWithIgnoreCase(zipEntry.getName(), WAYPOINTS_FILE_SUFFIX_AND_EXTENSION)) {
- importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_READ_WPT_FILE, R.string.gpx_import_loading_waypoints, (int) zipEntry.getSize()));
- caches = parser.parse(new NoCloseInputStream(zis), progressHandler);
- }
- zis.closeEntry();
- }
- } finally {
- zis.close();
- }
-
- return caches;
- }
-
- protected abstract InputStream getInputStream() throws IOException;
- }
-
- static class ImportGpxZipFileThread extends ImportGpxZipThread {
- private final File cacheFile;
-
- public ImportGpxZipFileThread(final File file, int listId, Handler importStepHandler, CancellableHandler progressHandler) {
- super(listId, importStepHandler, progressHandler);
- this.cacheFile = file;
- Log.i("Import zipped GPX: " + file);
- }
-
- @Override
- protected InputStream getInputStream() throws IOException {
- return new FileInputStream(cacheFile);
- }
- }
-
- static class ImportGpxZipAttachmentThread extends ImportGpxZipThread {
- private final Uri uri;
- private ContentResolver contentResolver;
-
- public ImportGpxZipAttachmentThread(Uri uri, ContentResolver contentResolver, int listId, Handler importStepHandler, CancellableHandler progressHandler) {
- super(listId, importStepHandler, progressHandler);
- this.uri = uri;
- this.contentResolver = contentResolver;
- Log.i("Import zipped GPX from uri: " + uri);
- }
-
- @Override
- protected InputStream getInputStream() throws IOException {
- return contentResolver.openInputStream(uri);
- }
- }
-
- final private CancellableHandler progressHandler = new CancellableHandler() {
- @Override
- public void handleRegularMessage(Message msg) {
- progress.setProgress(msg.arg1);
- }
- };
-
- final private Handler importStepHandler = new Handler() {
- private boolean showProgressAfterCancel = false;
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case IMPORT_STEP_START:
- Message cancelMessage = importStepHandler.obtainMessage(IMPORT_STEP_CANCEL);
- progress.show((Context) fromActivity, res.getString(R.string.gpx_import_title_reading_file), res.getString(R.string.gpx_import_loading_caches), ProgressDialog.STYLE_HORIZONTAL, cancelMessage);
- break;
-
- case IMPORT_STEP_READ_FILE:
- case IMPORT_STEP_READ_WPT_FILE:
- progress.setMessage(res.getString(msg.arg1));
- progress.setMaxProgressAndReset(msg.arg2);
- break;
-
- case IMPORT_STEP_STORE_STATIC_MAPS:
- progress.dismiss();
- Message skipMessage = importStepHandler.obtainMessage(IMPORT_STEP_STATIC_MAPS_SKIPPED, msg.arg2, 0);
- progress.show((Context) fromActivity, res.getString(R.string.gpx_import_title_static_maps), res.getString(R.string.gpx_import_store_static_maps), ProgressDialog.STYLE_HORIZONTAL, skipMessage);
- progress.setMaxProgressAndReset(msg.arg2);
- break;
-
- case IMPORT_STEP_STATIC_MAPS_SKIPPED:
- progress.dismiss();
- progressHandler.cancel();
- StringBuilder bufferSkipped = new StringBuilder(20);
- bufferSkipped.append(res.getString(R.string.gpx_import_static_maps_skipped)).append(", ").append(msg.arg1).append(' ').append(res.getString(R.string.gpx_import_caches_imported));
- fromActivity.helpDialog(res.getString(R.string.gpx_import_title_caches_imported), bufferSkipped.toString());
- importFinished();
- break;
-
- case IMPORT_STEP_FINISHED:
- progress.dismiss();
- fromActivity.helpDialog(res.getString(R.string.gpx_import_title_caches_imported), msg.arg1 + " " + res.getString(R.string.gpx_import_caches_imported));
- importFinished();
- break;
-
- case IMPORT_STEP_FINISHED_WITH_ERROR:
- progress.dismiss();
- fromActivity.helpDialog(res.getString(R.string.gpx_import_title_caches_import_failed), res.getString(msg.arg1) + "\n\n" + msg.obj);
- importFinished();
- break;
-
- case IMPORT_STEP_CANCEL:
- progress.dismiss();
- progressHandler.cancel();
- break;
-
- case IMPORT_STEP_CANCELED:
- StringBuilder bufferCanceled = new StringBuilder(20);
- bufferCanceled.append(res.getString(R.string.gpx_import_canceled));
- if (showProgressAfterCancel) {
- bufferCanceled.append(", ").append(progress.getProgress()).append(' ').append(res.getString(R.string.gpx_import_caches_imported));
- }
- fromActivity.showShortToast(bufferCanceled.toString());
- importFinished();
- break;
-
- default:
- break;
- }
- }
- };
-
- /**
- * @param gpxfile
- * the gpx file
- * @return the expected file name of the waypoints file
- */
- static String getWaypointsFileNameForGpxFile(final File gpxfile) {
- if (gpxfile == null || !gpxfile.canRead()) {
- return null;
- }
- final String gpxFileName = gpxfile.getName();
- File dir = gpxfile.getParentFile();
- String[] filenameList = dir.list();
- for (String filename : filenameList) {
- if (!StringUtils.containsIgnoreCase(filename, WAYPOINTS_FILE_SUFFIX)) {
- continue;
- }
- String expectedGpxFileName = StringUtils.substringBeforeLast(filename, WAYPOINTS_FILE_SUFFIX)
- + StringUtils.substringAfterLast(filename, WAYPOINTS_FILE_SUFFIX);
- if (gpxFileName.equals(expectedGpxFileName)) {
- return filename;
- }
- }
- return null;
- }
-
- protected void importFinished() {
- if (importFinishedHandler != null) {
- importFinishedHandler.sendEmptyMessage(0);
- }
- }
-}
+package cgeo.geocaching.files;
+
+import cgeo.geocaching.Geocache;
+import cgeo.geocaching.R;
+import cgeo.geocaching.SearchResult;
+import cgeo.geocaching.Settings;
+import cgeo.geocaching.StaticMapsProvider;
+import cgeo.geocaching.cgData;
+import cgeo.geocaching.activity.IAbstractActivity;
+import cgeo.geocaching.activity.Progress;
+import cgeo.geocaching.enumerations.LoadFlags;
+import cgeo.geocaching.utils.CancellableHandler;
+import cgeo.geocaching.utils.Log;
+
+import org.apache.commons.lang3.StringUtils;
+
+import android.app.Activity;
+import android.app.ProgressDialog;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Message;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.CancellationException;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+public class GPXImporter {
+ static final int IMPORT_STEP_START = 0;
+ static final int IMPORT_STEP_READ_FILE = 1;
+ static final int IMPORT_STEP_READ_WPT_FILE = 2;
+ static final int IMPORT_STEP_STORE_STATIC_MAPS = 4;
+ static final int IMPORT_STEP_FINISHED = 5;
+ static final int IMPORT_STEP_FINISHED_WITH_ERROR = 6;
+ static final int IMPORT_STEP_CANCEL = 7;
+ static final int IMPORT_STEP_CANCELED = 8;
+ static final int IMPORT_STEP_STATIC_MAPS_SKIPPED = 9;
+
+ public static final String GPX_FILE_EXTENSION = ".gpx";
+ public static final String LOC_FILE_EXTENSION = ".loc";
+ public static final String ZIP_FILE_EXTENSION = ".zip";
+ public static final String WAYPOINTS_FILE_SUFFIX = "-wpts";
+ public static final String WAYPOINTS_FILE_SUFFIX_AND_EXTENSION = WAYPOINTS_FILE_SUFFIX + GPX_FILE_EXTENSION;
+
+ private static final List<String> GPX_MIME_TYPES = Arrays.asList("text/xml", "application/xml");
+ private static final List<String> ZIP_MIME_TYPES = Arrays.asList("application/zip", "application/x-compressed", "application/x-zip-compressed", "application/x-zip", "application/octet-stream");
+
+ private final Progress progress = new Progress(true);
+
+ private final Resources res;
+ private final int listId;
+ private final IAbstractActivity fromActivity;
+ private final Handler importFinishedHandler;
+
+ public GPXImporter(final IAbstractActivity fromActivity, final int listId, final Handler importFinishedHandler) {
+ this.listId = listId;
+ this.fromActivity = fromActivity;
+ res = ((Activity) fromActivity).getResources();
+ this.importFinishedHandler = importFinishedHandler;
+ }
+
+ /**
+ * Import GPX file. Currently supports *.gpx, *.zip (containing gpx files, e.g. PQ queries) or *.loc files.
+ *
+ * @param file
+ * the file to import
+ */
+ public void importGPX(final File file) {
+ if (StringUtils.endsWithIgnoreCase(file.getName(), GPX_FILE_EXTENSION)) {
+ new ImportGpxFileThread(file, listId, importStepHandler, progressHandler).start();
+ } else if (StringUtils.endsWithIgnoreCase(file.getName(), ZIP_FILE_EXTENSION)) {
+ new ImportGpxZipFileThread(file, listId, importStepHandler, progressHandler).start();
+ } else {
+ new ImportLocFileThread(file, listId, importStepHandler, progressHandler).start();
+ }
+ }
+
+ /**
+ * Import GPX provided via intent of activity that instantiated this GPXImporter.
+ */
+ public void importGPX() {
+ final ContentResolver contentResolver = ((Activity) fromActivity).getContentResolver();
+ final Intent intent = ((Activity) fromActivity).getIntent();
+ final Uri uri = intent.getData();
+
+ String mimeType = intent.getType();
+ // if mimetype can't be determined (e.g. for emulators email app), derive it from uri file extension
+ // contentResolver.getType(uri) doesn't help but throws exception for emulators email app
+ // Permission Denial: reading com.android.email.provider.EmailProvider uri
+ // Google search says: there is no solution for this problem
+ // Gmail doesn't work at all, see #967
+ if (mimeType == null) {
+ if (StringUtils.endsWithIgnoreCase(uri.getPath(), GPX_FILE_EXTENSION) || StringUtils.endsWithIgnoreCase(uri.getPath(), LOC_FILE_EXTENSION)) {
+ mimeType = "application/xml";
+ } else {
+ // if we can't determine a better type, default to zip import
+ // emulator email sends e.g. content://com.android.email.attachmentprovider/1/1/RAW, mimetype=null
+ mimeType = "application/zip";
+ }
+ }
+
+ Log.i("importGPX: " + uri + ", mimetype=" + mimeType);
+ if (GPX_MIME_TYPES.contains(mimeType)) {
+ if (StringUtils.endsWithIgnoreCase(uri.getPath(), LOC_FILE_EXTENSION)) {
+ new ImportLocAttachmentThread(uri, contentResolver, listId, importStepHandler, progressHandler).start();
+ } else {
+ new ImportGpxAttachmentThread(uri, contentResolver, listId, importStepHandler, progressHandler).start();
+ }
+ } else if (ZIP_MIME_TYPES.contains(mimeType)) {
+ new ImportGpxZipAttachmentThread(uri, contentResolver, listId, importStepHandler, progressHandler).start();
+ } else {
+ importFinished();
+ }
+ }
+
+ static abstract class ImportThread extends Thread {
+ final int listId;
+ final Handler importStepHandler;
+ final CancellableHandler progressHandler;
+
+ protected ImportThread(int listId, Handler importStepHandler, CancellableHandler progressHandler) {
+ this.listId = listId;
+ this.importStepHandler = importStepHandler;
+ this.progressHandler = progressHandler;
+ }
+
+ @Override
+ public void run() {
+ try {
+ importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_START));
+ final Collection<Geocache> caches = doImport();
+ Log.i("Imported successfully " + caches.size() + " caches.");
+
+ final SearchResult search = new SearchResult(caches);
+ // Do not put imported caches into the cachecache. That would consume lots of memory for no benefit.
+
+ if (Settings.isStoreOfflineMaps() || Settings.isStoreOfflineWpMaps()) {
+ importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_STORE_STATIC_MAPS, R.string.gpx_import_store_static_maps, search.getCount()));
+ final boolean finishedWithoutCancel = importStaticMaps(search);
+ // Skip last message if static maps where canceled
+ if (!finishedWithoutCancel) {
+ return;
+ }
+ }
+
+ importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_FINISHED, search.getCount(), 0, search));
+ } catch (final IOException e) {
+ Log.i("Importing caches failed - error reading data: ", e);
+ importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_FINISHED_WITH_ERROR, R.string.gpx_import_error_io, 0, e.getLocalizedMessage()));
+ } catch (final ParserException e) {
+ Log.i("Importing caches failed - data format error", e);
+ importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_FINISHED_WITH_ERROR, R.string.gpx_import_error_parser, 0, e.getLocalizedMessage()));
+ } catch (final CancellationException e) {
+ Log.i("Importing caches canceled");
+ importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_CANCELED));
+ } catch (final Exception e) {
+ Log.e("Importing caches failed - unknown error: ", e);
+ importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_FINISHED_WITH_ERROR, R.string.gpx_import_error_unexpected, 0, e.getLocalizedMessage()));
+ }
+ }
+
+ protected abstract Collection<Geocache> doImport() throws IOException, ParserException;
+
+ private boolean importStaticMaps(final SearchResult importedCaches) {
+ int storedCacheMaps = 0;
+ for (final String geocode : importedCaches.getGeocodes()) {
+ final Geocache cache = cgData.loadCache(geocode, LoadFlags.LOAD_WAYPOINTS);
+ if (cache != null) {
+ Log.d("GPXImporter.ImportThread.importStaticMaps start downloadMaps for cache " + geocode);
+ StaticMapsProvider.downloadMaps(cache);
+ } else {
+ Log.d("GPXImporter.ImportThread.importStaticMaps: no data found for " + geocode);
+ }
+ storedCacheMaps++;
+ if (progressHandler.isCancelled()) {
+ return false;
+ }
+ progressHandler.sendMessage(progressHandler.obtainMessage(0, storedCacheMaps, 0));
+ }
+ return true;
+ }
+ }
+
+ static class ImportLocFileThread extends ImportThread {
+ private final File file;
+
+ public ImportLocFileThread(final File file, int listId, Handler importStepHandler, CancellableHandler progressHandler) {
+ super(listId, importStepHandler, progressHandler);
+ this.file = file;
+ }
+
+ @Override
+ protected Collection<Geocache> doImport() throws IOException, ParserException {
+ Log.i("Import LOC file: " + file.getAbsolutePath());
+ importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_READ_FILE, R.string.gpx_import_loading_caches, (int) file.length()));
+ final LocParser parser = new LocParser(listId);
+ return parser.parse(file, progressHandler);
+ }
+ }
+
+ static class ImportLocAttachmentThread extends ImportThread {
+ private final Uri uri;
+ private final ContentResolver contentResolver;
+
+ public ImportLocAttachmentThread(Uri uri, ContentResolver contentResolver, int listId, Handler importStepHandler, CancellableHandler progressHandler) {
+ super(listId, importStepHandler, progressHandler);
+ this.uri = uri;
+ this.contentResolver = contentResolver;
+ }
+
+ @Override
+ protected Collection<Geocache> doImport() throws IOException, ParserException {
+ Log.i("Import LOC from uri: " + uri);
+ importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_READ_FILE, R.string.gpx_import_loading_caches, -1));
+ final InputStream is = contentResolver.openInputStream(uri);
+ final LocParser parser = new LocParser(listId);
+ try {
+ return parser.parse(is, progressHandler);
+ } finally {
+ is.close();
+ }
+ }
+ }
+
+ static abstract class ImportGpxThread extends ImportThread {
+
+ protected ImportGpxThread(int listId, Handler importStepHandler, CancellableHandler progressHandler) {
+ super(listId, importStepHandler, progressHandler);
+ }
+
+ @Override
+ protected Collection<Geocache> doImport() throws IOException, ParserException {
+ try {
+ // try to parse cache file as GPX 10
+ return doImport(new GPX10Parser(listId));
+ } catch (final ParserException pe) {
+ // didn't work -> lets try GPX11
+ return doImport(new GPX11Parser(listId));
+ }
+ }
+
+ protected abstract Collection<Geocache> doImport(GPXParser parser) throws IOException, ParserException;
+ }
+
+ static class ImportGpxFileThread extends ImportGpxThread {
+ private final File cacheFile;
+
+ public ImportGpxFileThread(final File file, int listId, Handler importStepHandler, CancellableHandler progressHandler) {
+ super(listId, importStepHandler, progressHandler);
+ this.cacheFile = file;
+ }
+
+ @Override
+ protected Collection<Geocache> doImport(GPXParser parser) throws IOException, ParserException {
+ Log.i("Import GPX file: " + cacheFile.getAbsolutePath());
+ importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_READ_FILE, R.string.gpx_import_loading_caches, (int) cacheFile.length()));
+ Collection<Geocache> caches = parser.parse(cacheFile, progressHandler);
+
+ final String wptsFilename = getWaypointsFileNameForGpxFile(cacheFile);
+ if (wptsFilename != null) {
+ final File wptsFile = new File(cacheFile.getParentFile(), wptsFilename);
+ if (wptsFile.canRead()) {
+ Log.i("Import GPX waypoint file: " + wptsFile.getAbsolutePath());
+ importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_READ_WPT_FILE, R.string.gpx_import_loading_waypoints, (int) wptsFile.length()));
+ caches = parser.parse(wptsFile, progressHandler);
+ }
+ }
+ return caches;
+ }
+ }
+
+ static class ImportGpxAttachmentThread extends ImportGpxThread {
+ private final Uri uri;
+ private final ContentResolver contentResolver;
+
+ public ImportGpxAttachmentThread(Uri uri, ContentResolver contentResolver, int listId, Handler importStepHandler, CancellableHandler progressHandler) {
+ super(listId, importStepHandler, progressHandler);
+ this.uri = uri;
+ this.contentResolver = contentResolver;
+ }
+
+ @Override
+ protected Collection<Geocache> doImport(GPXParser parser) throws IOException, ParserException {
+ Log.i("Import GPX from uri: " + uri);
+ importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_READ_FILE, R.string.gpx_import_loading_caches, -1));
+ final InputStream is = contentResolver.openInputStream(uri);
+ try {
+ return parser.parse(is, progressHandler);
+ } finally {
+ is.close();
+ }
+ }
+ }
+
+ static abstract class ImportGpxZipThread extends ImportGpxThread {
+
+ protected ImportGpxZipThread(int listId, Handler importStepHandler, CancellableHandler progressHandler) {
+ super(listId, importStepHandler, progressHandler);
+ }
+
+ @Override
+ protected Collection<Geocache> doImport(GPXParser parser) throws IOException, ParserException {
+ Collection<Geocache> caches = Collections.emptySet();
+ // can't assume that GPX file comes before waypoint file in zip -> so we need two passes
+ // 1. parse GPX files
+ ZipInputStream zis = new ZipInputStream(new BufferedInputStream(getInputStream()));
+ try {
+ for (ZipEntry zipEntry = zis.getNextEntry(); zipEntry != null; zipEntry = zis.getNextEntry()) {
+ if (StringUtils.endsWithIgnoreCase(zipEntry.getName(), GPX_FILE_EXTENSION)) {
+ if (!StringUtils.endsWithIgnoreCase(zipEntry.getName(), WAYPOINTS_FILE_SUFFIX_AND_EXTENSION)) {
+ importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_READ_FILE, R.string.gpx_import_loading_caches, (int) zipEntry.getSize()));
+ caches = parser.parse(new NoCloseInputStream(zis), progressHandler);
+ }
+ } else {
+ throw new ParserException("Imported zip is not a GPX zip file.");
+ }
+ zis.closeEntry();
+ }
+ } finally {
+ zis.close();
+ }
+
+ // 2. parse waypoint files
+ zis = new ZipInputStream(new BufferedInputStream(getInputStream()));
+ try {
+ for (ZipEntry zipEntry = zis.getNextEntry(); zipEntry != null; zipEntry = zis.getNextEntry()) {
+ if (StringUtils.endsWithIgnoreCase(zipEntry.getName(), WAYPOINTS_FILE_SUFFIX_AND_EXTENSION)) {
+ importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_READ_WPT_FILE, R.string.gpx_import_loading_waypoints, (int) zipEntry.getSize()));
+ caches = parser.parse(new NoCloseInputStream(zis), progressHandler);
+ }
+ zis.closeEntry();
+ }
+ } finally {
+ zis.close();
+ }
+
+ return caches;
+ }
+
+ protected abstract InputStream getInputStream() throws IOException;
+ }
+
+ static class ImportGpxZipFileThread extends ImportGpxZipThread {
+ private final File cacheFile;
+
+ public ImportGpxZipFileThread(final File file, int listId, Handler importStepHandler, CancellableHandler progressHandler) {
+ super(listId, importStepHandler, progressHandler);
+ this.cacheFile = file;
+ Log.i("Import zipped GPX: " + file);
+ }
+
+ @Override
+ protected InputStream getInputStream() throws IOException {
+ return new FileInputStream(cacheFile);
+ }
+ }
+
+ static class ImportGpxZipAttachmentThread extends ImportGpxZipThread {
+ private final Uri uri;
+ private final ContentResolver contentResolver;
+
+ public ImportGpxZipAttachmentThread(Uri uri, ContentResolver contentResolver, int listId, Handler importStepHandler, CancellableHandler progressHandler) {
+ super(listId, importStepHandler, progressHandler);
+ this.uri = uri;
+ this.contentResolver = contentResolver;
+ Log.i("Import zipped GPX from uri: " + uri);
+ }
+
+ @Override
+ protected InputStream getInputStream() throws IOException {
+ return contentResolver.openInputStream(uri);
+ }
+ }
+
+ final private CancellableHandler progressHandler = new CancellableHandler() {
+ @Override
+ public void handleRegularMessage(Message msg) {
+ progress.setProgress(msg.arg1);
+ }
+ };
+
+ final private Handler importStepHandler = new Handler() {
+ private final boolean showProgressAfterCancel = false;
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case IMPORT_STEP_START:
+ final Message cancelMessage = importStepHandler.obtainMessage(IMPORT_STEP_CANCEL);
+ progress.show((Context) fromActivity, res.getString(R.string.gpx_import_title_reading_file), res.getString(R.string.gpx_import_loading_caches), ProgressDialog.STYLE_HORIZONTAL, cancelMessage);
+ break;
+
+ case IMPORT_STEP_READ_FILE:
+ case IMPORT_STEP_READ_WPT_FILE:
+ progress.setMessage(res.getString(msg.arg1));
+ progress.setMaxProgressAndReset(msg.arg2);
+ break;
+
+ case IMPORT_STEP_STORE_STATIC_MAPS:
+ progress.dismiss();
+ final Message skipMessage = importStepHandler.obtainMessage(IMPORT_STEP_STATIC_MAPS_SKIPPED, msg.arg2, 0);
+ progress.show((Context) fromActivity, res.getString(R.string.gpx_import_title_static_maps), res.getString(R.string.gpx_import_store_static_maps), ProgressDialog.STYLE_HORIZONTAL, skipMessage);
+ progress.setMaxProgressAndReset(msg.arg2);
+ break;
+
+ case IMPORT_STEP_STATIC_MAPS_SKIPPED:
+ progress.dismiss();
+ progressHandler.cancel();
+ final StringBuilder bufferSkipped = new StringBuilder(20);
+ bufferSkipped.append(res.getString(R.string.gpx_import_static_maps_skipped)).append(", ").append(msg.arg1).append(' ').append(res.getString(R.string.gpx_import_caches_imported));
+ fromActivity.helpDialog(res.getString(R.string.gpx_import_title_caches_imported), bufferSkipped.toString());
+ importFinished();
+ break;
+
+ case IMPORT_STEP_FINISHED:
+ progress.dismiss();
+ fromActivity.helpDialog(res.getString(R.string.gpx_import_title_caches_imported), msg.arg1 + " " + res.getString(R.string.gpx_import_caches_imported));
+ importFinished();
+ break;
+
+ case IMPORT_STEP_FINISHED_WITH_ERROR:
+ progress.dismiss();
+ fromActivity.helpDialog(res.getString(R.string.gpx_import_title_caches_import_failed), res.getString(msg.arg1) + "\n\n" + msg.obj);
+ importFinished();
+ break;
+
+ case IMPORT_STEP_CANCEL:
+ progress.dismiss();
+ progressHandler.cancel();
+ break;
+
+ case IMPORT_STEP_CANCELED:
+ final StringBuilder bufferCanceled = new StringBuilder(20);
+ bufferCanceled.append(res.getString(R.string.gpx_import_canceled));
+ if (showProgressAfterCancel) {
+ bufferCanceled.append(", ").append(progress.getProgress()).append(' ').append(res.getString(R.string.gpx_import_caches_imported));
+ }
+ fromActivity.showShortToast(bufferCanceled.toString());
+ importFinished();
+ break;
+
+ default:
+ break;
+ }
+ }
+ };
+
+ /**
+ * @param gpxfile
+ * the gpx file
+ * @return the expected file name of the waypoints file
+ */
+ static String getWaypointsFileNameForGpxFile(final File gpxfile) {
+ if (gpxfile == null || !gpxfile.canRead()) {
+ return null;
+ }
+ final String gpxFileName = gpxfile.getName();
+ final File dir = gpxfile.getParentFile();
+ final String[] filenameList = dir.list();
+ for (final String filename : filenameList) {
+ if (!StringUtils.containsIgnoreCase(filename, WAYPOINTS_FILE_SUFFIX)) {
+ continue;
+ }
+ final String expectedGpxFileName = StringUtils.substringBeforeLast(filename, WAYPOINTS_FILE_SUFFIX)
+ + StringUtils.substringAfterLast(filename, WAYPOINTS_FILE_SUFFIX);
+ if (gpxFileName.equals(expectedGpxFileName)) {
+ return filename;
+ }
+ }
+ return null;
+ }
+
+ protected void importFinished() {
+ if (importFinishedHandler != null) {
+ importFinishedHandler.sendEmptyMessage(0);
+ }
+ }
+}
diff --git a/main/src/cgeo/geocaching/files/GPXParser.java b/main/src/cgeo/geocaching/files/GPXParser.java
index 96c90cc..f5ae381 100644
--- a/main/src/cgeo/geocaching/files/GPXParser.java
+++ b/main/src/cgeo/geocaching/files/GPXParser.java
@@ -183,6 +183,7 @@ public abstract class GPXParser extends FileParser {
R.string.attribute_treeclimbing_yes, // 64
R.string.attribute_frontyard_yes, // 65
R.string.attribute_teamwork_yes, // 66
+ R.string.attribute_geotour_yes, // 67
};
private static final String YES = "_yes";
private static final String NO = "_no";
@@ -205,7 +206,7 @@ public abstract class GPXParser extends FileParser {
String stringName;
try {
stringName = cgeoapplication.getInstance().getResources().getResourceName(stringId);
- } catch (NullPointerException e) {
+ } catch (final NullPointerException e) {
return null;
}
if (stringName == null) {
@@ -271,7 +272,7 @@ public abstract class GPXParser extends FileParser {
Double.valueOf(longitude)));
}
}
- } catch (Exception e) {
+ } catch (final Exception e) {
Log.w("Failed to parse waypoint's latitude and/or longitude.");
}
}
@@ -295,11 +296,7 @@ public abstract class GPXParser extends FileParser {
}
}
- if (StringUtils.isNotBlank(cache.getGeocode())
- && cache.getCoords() != null
- && ((type == null && sym == null)
- || StringUtils.contains(type, "geocache")
- || StringUtils.contains(sym, "geocache"))) {
+ if (isValidForImport()) {
fixCache(cache);
cache.setListId(listId);
cache.setDetailed(true);
@@ -316,6 +313,8 @@ public abstract class GPXParser extends FileParser {
// finally store the cache in the database
result.add(geocode);
cgData.saveCache(cache, EnumSet.of(SaveFlag.SAVE_DB));
+
+ // avoid the cachecache using lots of memory for caches which the user did not actually look at
cgData.removeAllFromCache();
showProgressMessage(progressHandler, progressStream.getProgress());
} else if (StringUtils.isNotBlank(cache.getName())
@@ -364,7 +363,7 @@ public abstract class GPXParser extends FileParser {
public void end(String body) {
try {
cache.setHidden(parseDate(body));
- } catch (Exception e) {
+ } catch (final Exception e) {
Log.w("Failed to parse cache date", e);
}
}
@@ -444,18 +443,29 @@ public abstract class GPXParser extends FileParser {
}
final MatcherWrapper matcherCode = new MatcherWrapper(patternUrlGeocode, url);
if (matcherCode.matches()) {
- String geocode = matcherCode.group(1);
+ final String geocode = matcherCode.group(1);
cache.setGeocode(geocode);
}
}
});
+ // waypoint.urlname (name for waymarks)
+ waypoint.getChild(namespace, "urlname").setEndTextElementListener(new EndTextElementListener() {
+
+ @Override
+ public void end(String urlName) {
+ if (cache.getName().equals(cache.getGeocode()) && StringUtils.startsWith(cache.getGeocode(), "WM")) {
+ cache.setName(StringUtils.trim(urlName));
+ }
+ }
+ });
+
// for GPX 1.0, cache info comes from waypoint node (so called private children,
// for GPX 1.1 from extensions node
final Element cacheParent = getCacheParent(waypoint);
// GSAK extensions
- for (String gsakNamespace : GSAK_NS) {
+ for (final String gsakNamespace : GSAK_NS) {
final Element gsak = cacheParent.getChild(gsakNamespace, "wptExtension");
gsak.getChild(gsakNamespace, "Watch").setEndTextElementListener(new EndTextElementListener() {
@@ -473,7 +483,7 @@ public abstract class GPXParser extends FileParser {
}
// 3 different versions of the GC schema
- for (String nsGC : nsGCList) {
+ for (final String nsGC : nsGCList) {
// waypoints.cache
final Element gcCache = cacheParent.getChild(nsGC, "cache");
@@ -491,7 +501,7 @@ public abstract class GPXParser extends FileParser {
if (attrs.getIndex("available") > -1) {
cache.setDisabled(!attrs.getValue("available").equalsIgnoreCase("true"));
}
- } catch (Exception e) {
+ } catch (final Exception e) {
Log.w("Failed to parse cache attributes.");
}
}
@@ -560,14 +570,14 @@ public abstract class GPXParser extends FileParser {
public void start(Attributes attrs) {
try {
if (attrs.getIndex("id") > -1 && attrs.getIndex("inc") > -1) {
- int attributeId = Integer.parseInt(attrs.getValue("id"));
- boolean attributeActive = Integer.parseInt(attrs.getValue("inc")) != 0;
- String internalId = CacheAttributeTranslator.getInternalId(attributeId, attributeActive);
+ final int attributeId = Integer.parseInt(attrs.getValue("id"));
+ final boolean attributeActive = Integer.parseInt(attrs.getValue("inc")) != 0;
+ final String internalId = CacheAttributeTranslator.getInternalId(attributeId, attributeActive);
if (internalId != null) {
cache.getAttributes().add(internalId);
}
}
- } catch (NumberFormatException e) {
+ } catch (final NumberFormatException e) {
// nothing
}
}
@@ -580,7 +590,7 @@ public abstract class GPXParser extends FileParser {
public void end(String body) {
try {
cache.setDifficulty(Float.parseFloat(body));
- } catch (NumberFormatException e) {
+ } catch (final NumberFormatException e) {
Log.w("Failed to parse difficulty", e);
}
}
@@ -593,7 +603,7 @@ public abstract class GPXParser extends FileParser {
public void end(String body) {
try {
cache.setTerrain(Float.parseFloat(body));
- } catch (NumberFormatException e) {
+ } catch (final NumberFormatException e) {
Log.w("Failed to parse terrain", e);
}
}
@@ -617,7 +627,7 @@ public abstract class GPXParser extends FileParser {
@Override
public void end(String state) {
- String trimmedState = state.trim();
+ final String trimmedState = state.trim();
if (StringUtils.isNotEmpty(trimmedState)) { // state can be completely empty
if (StringUtils.isBlank(cache.getLocation())) {
cache.setLocation(validate(state));
@@ -670,7 +680,7 @@ public abstract class GPXParser extends FileParser {
if (attrs.getIndex("ref") > -1) {
trackable.setGeocode(attrs.getValue("ref"));
}
- } catch (Exception e) {
+ } catch (final Exception e) {
// nothing
}
}
@@ -714,7 +724,7 @@ public abstract class GPXParser extends FileParser {
if (attrs.getIndex("id") > -1) {
log.id = Integer.parseInt(attrs.getValue("id"));
}
- } catch (Exception e) {
+ } catch (final Exception e) {
// nothing
}
}
@@ -737,7 +747,7 @@ public abstract class GPXParser extends FileParser {
public void end(String body) {
try {
log.date = parseDate(body).getTime();
- } catch (Exception e) {
+ } catch (final Exception e) {
Log.w("Failed to parse log date", e);
}
}
@@ -776,7 +786,7 @@ public abstract class GPXParser extends FileParser {
progressStream = new ProgressInputStream(stream);
Xml.parse(progressStream, Xml.Encoding.UTF_8, root.getContentHandler());
return cgData.loadCaches(result, EnumSet.of(LoadFlag.LOAD_DB_MINIMAL));
- } catch (SAXException e) {
+ } catch (final SAXException e) {
Log.w("Cannot parse .gpx file as GPX " + version + ": could not parse XML - ", e);
throw new ParserException("Cannot parse .gpx file as GPX " + version + ": could not parse XML", e);
}
@@ -823,7 +833,7 @@ public abstract class GPXParser extends FileParser {
return WaypointType.FINAL;
}
// this is not fully correct, but lets also look for localized waypoint types
- for (WaypointType waypointType : WaypointType.ALL_TYPES_EXCEPT_OWN_AND_ORIGINAL) {
+ for (final WaypointType waypointType : WaypointType.ALL_TYPES_EXCEPT_OWN_AND_ORIGINAL) {
final String localized = waypointType.getL10n();
if (StringUtils.isNotEmpty(localized)) {
if (localized.equalsIgnoreCase(sym)) {
@@ -891,4 +901,17 @@ public abstract class GPXParser extends FileParser {
}
}
}
+
+ private boolean isValidForImport() {
+ if (StringUtils.isBlank(cache.getGeocode())) {
+ return false;
+ }
+ if (cache.getCoords() == null) {
+ return false;
+ }
+ return ((type == null && sym == null)
+ || StringUtils.contains(type, "geocache")
+ || StringUtils.contains(sym, "geocache")
+ || StringUtils.containsIgnoreCase(sym, "waymark"));
+ }
}
diff --git a/main/src/cgeo/geocaching/files/LocParser.java b/main/src/cgeo/geocaching/files/LocParser.java
index fe290c3..1cfb2a3 100644
--- a/main/src/cgeo/geocaching/files/LocParser.java
+++ b/main/src/cgeo/geocaching/files/LocParser.java
@@ -27,19 +27,13 @@ import java.util.regex.Pattern;
public final class LocParser extends FileParser {
+ private static final String NAME_OWNER_SEPARATOR = " by ";
private static final Pattern patternGeocode = Pattern
.compile("name id=\"([^\"]+)\"");
private static final Pattern patternLat = Pattern
.compile("lat=\"([^\"]+)\"");
private static final Pattern patternLon = Pattern
.compile("lon=\"([^\"]+)\"");
- // premium only >>
- private static final Pattern patternDifficulty = Pattern
- .compile("<difficulty>([^<]+)</difficulty>");
- private static final Pattern patternTerrain = Pattern
- .compile("<terrain>([^<]+)</terrain>");
- private static final Pattern patternContainer = Pattern
- .compile("<container>([^<]+)</container>");
private static final Pattern patternName = Pattern.compile("CDATA\\[([^\\]]+)\\]");
private static final CacheSize[] SIZES = {
@@ -82,6 +76,7 @@ public final class LocParser extends FileParser {
if (StringUtils.isBlank(cache.getName())) {
cache.setName(coord.getName());
}
+ cache.setOwnerUserId(coord.getOwnerUserId());
}
static Map<String, Geocache> parseCoordinates(final String fileContent) {
@@ -110,7 +105,7 @@ public final class LocParser extends FileParser {
try {
return new Geopoint(Double.valueOf(latitude), Double.valueOf(longitude));
} catch (NumberFormatException e) {
- Log.e("LOC format has changed");
+ Log.e("LOC format has changed", e);
}
// fall back to parser, just in case the format changes
return new Geopoint(latitude, longitude);
@@ -156,7 +151,11 @@ public final class LocParser extends FileParser {
final MatcherWrapper matcherName = new MatcherWrapper(patternName, pointString);
if (matcherName.find()) {
final String name = matcherName.group(1).trim();
- cache.setName(StringUtils.substringBeforeLast(name, " by ").trim());
+ String ownerName = StringUtils.trim(StringUtils.substringAfterLast(name, NAME_OWNER_SEPARATOR));
+ if (StringUtils.isEmpty(cache.getOwnerUserId()) && StringUtils.isNotEmpty(ownerName)) {
+ cache.setOwnerUserId(ownerName);
+ }
+ cache.setName(StringUtils.substringBeforeLast(name, NAME_OWNER_SEPARATOR).trim());
} else {
cache.setName(cache.getGeocode());
}
@@ -167,20 +166,20 @@ public final class LocParser extends FileParser {
cache.setCoords(parsePoint(matcherLat.group(1).trim(), matcherLon.group(1).trim()));
}
- final MatcherWrapper matcherDifficulty = new MatcherWrapper(patternDifficulty, pointString);
+ final String difficulty = StringUtils.substringBetween(pointString, "<difficulty>", "</difficulty>");
+ final String terrain = StringUtils.substringBetween(pointString, "<terrain>", "</terrain>");
+ final String container = StringUtils.substringBetween(pointString, "<container>", "</container");
try {
- if (matcherDifficulty.find()) {
- cache.setDifficulty(Float.parseFloat(matcherDifficulty.group(1).trim()));
+ if (StringUtils.isNotBlank(difficulty)) {
+ cache.setDifficulty(Float.parseFloat(difficulty.trim()));
}
- final MatcherWrapper matcherTerrain = new MatcherWrapper(patternTerrain, pointString);
- if (matcherTerrain.find()) {
- cache.setTerrain(Float.parseFloat(matcherTerrain.group(1).trim()));
+ if (StringUtils.isNotBlank(terrain)) {
+ cache.setTerrain(Float.parseFloat(terrain.trim()));
}
- final MatcherWrapper matcherContainer = new MatcherWrapper(patternContainer, pointString);
- if (matcherContainer.find()) {
- final int size = Integer.parseInt(matcherContainer.group(1).trim());
+ if (StringUtils.isNotBlank(container)) {
+ final int size = Integer.parseInt(container.trim());
if (size >= 1 && size <= 8) {
cache.setSize(SIZES[size - 1]);
}
diff --git a/main/src/cgeo/geocaching/files/LocalStorage.java b/main/src/cgeo/geocaching/files/LocalStorage.java
index f59f15c..0f3e0e1 100644
--- a/main/src/cgeo/geocaching/files/LocalStorage.java
+++ b/main/src/cgeo/geocaching/files/LocalStorage.java
@@ -2,14 +2,18 @@ package cgeo.geocaching.files;
import cgeo.geocaching.cgeoapplication;
import cgeo.geocaching.utils.CryptUtils;
+import cgeo.geocaching.utils.IOUtils;
import cgeo.geocaching.utils.Log;
import ch.boye.httpclientandroidlib.Header;
import ch.boye.httpclientandroidlib.HttpResponse;
+
import org.apache.commons.lang3.StringUtils;
import android.os.Environment;
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
@@ -275,19 +279,14 @@ public class LocalStorage {
destination.getParentFile().mkdirs();
InputStream input = null;
- OutputStream output;
+ OutputStream output = null;
try {
- input = new FileInputStream(source);
- output = new FileOutputStream(destination);
+ input = new BufferedInputStream(new FileInputStream(source));
+ output = new BufferedOutputStream(new FileOutputStream(destination));
} catch (FileNotFoundException e) {
Log.e("LocalStorage.copy: could not open file", e);
- if (input != null) {
- try {
- input.close();
- } catch (IOException e1) {
- // ignore
- }
- }
+ IOUtils.closeQuietly(input);
+ IOUtils.closeQuietly(output);
return false;
}
diff --git a/main/src/cgeo/geocaching/files/SimpleDirChooser.java b/main/src/cgeo/geocaching/files/SimpleDirChooser.java
index 7520e2e..6b2366c 100644
--- a/main/src/cgeo/geocaching/files/SimpleDirChooser.java
+++ b/main/src/cgeo/geocaching/files/SimpleDirChooser.java
@@ -2,11 +2,11 @@ package cgeo.geocaching.files;
import cgeo.geocaching.Intents;
import cgeo.geocaching.R;
+import cgeo.geocaching.activity.AbstractListActivity;
import cgeo.geocaching.activity.ActivityMixin;
import org.apache.commons.lang3.StringUtils;
-import android.app.ListActivity;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
@@ -31,7 +31,7 @@ import java.util.List;
/**
* Dialog for choosing a file or directory.
*/
-public class SimpleDirChooser extends ListActivity {
+public class SimpleDirChooser extends AbstractListActivity {
private static final String PARENT_DIR = ".. ";
private File currentDir;
private FileArrayAdapter adapter;
@@ -46,7 +46,6 @@ public class SimpleDirChooser extends ListActivity {
ActivityMixin.setTheme(this);
setContentView(R.layout.simple_dir_chooser);
- setTitle(this.getResources().getString(R.string.simple_dir_chooser_title));
fill(currentDir);
@@ -106,13 +105,13 @@ public class SimpleDirChooser extends ListActivity {
public class FileArrayAdapter extends ArrayAdapter<Option> {
- private Context content;
+ private Context context;
private int id;
private List<Option> items;
public FileArrayAdapter(Context context, int simpleDirItemResId, List<Option> objects) {
super(context, simpleDirItemResId, objects);
- this.content = context;
+ this.context = context;
this.id = simpleDirItemResId;
this.items = objects;
}
@@ -126,7 +125,7 @@ public class SimpleDirChooser extends ListActivity {
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
- LayoutInflater vi = (LayoutInflater) content.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ LayoutInflater vi = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(id, null);
}
@@ -187,13 +186,12 @@ public class SimpleDirChooser extends ListActivity {
if (currentOption != lastOption) {
currentOption.setChecked(true);
lastPosition = position;
- okButton.setEnabled(true);
- okButton.setVisibility(View.VISIBLE);
} else {
lastPosition = -1;
- okButton.setEnabled(false);
- okButton.setVisibility(View.INVISIBLE);
}
+ final boolean enabled = currentOption.isChecked() && !currentOption.getName().equals(PARENT_DIR);
+ okButton.setEnabled(enabled);
+ okButton.setVisibility(enabled ? View.VISIBLE : View.INVISIBLE);
adapter.notifyDataSetChanged();
}
}
@@ -238,7 +236,7 @@ public class SimpleDirChooser extends ListActivity {
@Override
public boolean accept(File dir, String filename) {
File file = new File(dir, filename);
- return file.isDirectory();
+ return file.isDirectory() && file.canWrite();
}
}
diff --git a/main/src/cgeo/geocaching/filter/AttributeFilter.java b/main/src/cgeo/geocaching/filter/AttributeFilter.java
index 4b6f382..cadcf49 100644
--- a/main/src/cgeo/geocaching/filter/AttributeFilter.java
+++ b/main/src/cgeo/geocaching/filter/AttributeFilter.java
@@ -1,16 +1,16 @@
package cgeo.geocaching.filter;
-import cgeo.geocaching.R;
import cgeo.geocaching.Geocache;
+import cgeo.geocaching.R;
import cgeo.geocaching.cgData;
import cgeo.geocaching.cgeoapplication;
import cgeo.geocaching.enumerations.LoadFlags.LoadFlag;
-import org.apache.commons.lang3.StringUtils;
-
import android.content.res.Resources;
import java.util.EnumSet;
+import java.util.LinkedList;
+import java.util.List;
class AttributeFilter extends AbstractFilter {
@@ -24,13 +24,7 @@ class AttributeFilter extends AbstractFilter {
private static String getName(final String attribute, final Resources res, final String packageName) {
// dynamically search for a translation of the attribute
final int id = res.getIdentifier(attribute, "string", packageName);
- if (id > 0) {
- final String translated = res.getString(id);
- if (StringUtils.isNotBlank(translated)) {
- return translated;
- }
- }
- return attribute;
+ return id > 0 ? res.getString(id) : attribute;
}
@Override
@@ -45,14 +39,13 @@ class AttributeFilter extends AbstractFilter {
public static class Factory implements IFilterFactory {
@Override
- public IFilter[] getFilters() {
+ public List<IFilter> getFilters() {
final String packageName = cgeoapplication.getInstance().getBaseContext().getPackageName();
final Resources res = cgeoapplication.getInstance().getResources();
- final String[] ids = res.getStringArray(R.array.attribute_ids);
- final IFilter[] filters = new IFilter[ids.length];
- for (int i = 0; i < ids.length; i++) {
- filters[i] = new AttributeFilter(getName("attribute_" + ids[i], res, packageName), ids[i]);
+ final List<IFilter> filters = new LinkedList<IFilter>();
+ for (final String id: res.getStringArray(R.array.attribute_ids)) {
+ filters.add(new AttributeFilter(getName("attribute_" + id, res, packageName), id));
}
return filters;
}
diff --git a/main/src/cgeo/geocaching/filter/DifficultyFilter.java b/main/src/cgeo/geocaching/filter/DifficultyFilter.java
index c0ec61a..8099a51 100644
--- a/main/src/cgeo/geocaching/filter/DifficultyFilter.java
+++ b/main/src/cgeo/geocaching/filter/DifficultyFilter.java
@@ -4,6 +4,7 @@ import cgeo.geocaching.Geocache;
import cgeo.geocaching.R;
import java.util.ArrayList;
+import java.util.List;
class DifficultyFilter extends AbstractRangeFilter {
@@ -19,12 +20,12 @@ class DifficultyFilter extends AbstractRangeFilter {
public static class Factory implements IFilterFactory {
@Override
- public IFilter[] getFilters() {
+ public List<IFilter> getFilters() {
final ArrayList<IFilter> filters = new ArrayList<IFilter>(5);
for (int difficulty = 1; difficulty <= 5; difficulty++) {
filters.add(new DifficultyFilter(difficulty));
}
- return filters.toArray(new IFilter[filters.size()]);
+ return filters;
}
}
diff --git a/main/src/cgeo/geocaching/filter/FilterUserInterface.java b/main/src/cgeo/geocaching/filter/FilterUserInterface.java
index be63a08..a1d42cc 100644
--- a/main/src/cgeo/geocaching/filter/FilterUserInterface.java
+++ b/main/src/cgeo/geocaching/filter/FilterUserInterface.java
@@ -16,6 +16,7 @@ import android.widget.ArrayAdapter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
+import java.util.List;
public final class FilterUserInterface {
@@ -101,9 +102,9 @@ public final class FilterUserInterface {
}
private void selectFromFactory(final IFilterFactory factory, final String menuTitle, final RunnableWithArgument<IFilter> runAfterwards) {
- final IFilter[] filters = factory.getFilters();
- if (filters.length == 1) {
- runAfterwards.run(filters[0]);
+ final List<IFilter> filters = Collections.unmodifiableList(factory.getFilters());
+ if (filters.size() == 1) {
+ runAfterwards.run(filters.get(0));
return;
}
@@ -114,7 +115,7 @@ public final class FilterUserInterface {
builder.setAdapter(adapter, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int item) {
- runAfterwards.run(filters[item]);
+ runAfterwards.run(filters.get(item));
}
});
diff --git a/main/src/cgeo/geocaching/filter/IFilterFactory.java b/main/src/cgeo/geocaching/filter/IFilterFactory.java
index 3491fd7..e750639 100644
--- a/main/src/cgeo/geocaching/filter/IFilterFactory.java
+++ b/main/src/cgeo/geocaching/filter/IFilterFactory.java
@@ -1,5 +1,7 @@
package cgeo.geocaching.filter;
+import java.util.List;
+
interface IFilterFactory {
- public IFilter[] getFilters();
+ public List<? extends IFilter> getFilters();
}
diff --git a/main/src/cgeo/geocaching/filter/ModifiedFilter.java b/main/src/cgeo/geocaching/filter/ModifiedFilter.java
index f3e57de..74befda 100644
--- a/main/src/cgeo/geocaching/filter/ModifiedFilter.java
+++ b/main/src/cgeo/geocaching/filter/ModifiedFilter.java
@@ -4,6 +4,9 @@ import cgeo.geocaching.Geocache;
import cgeo.geocaching.R;
import cgeo.geocaching.cgeoapplication;
+import java.util.Collections;
+import java.util.List;
+
class ModifiedFilter extends AbstractFilter implements IFilterFactory {
public ModifiedFilter() {
@@ -17,7 +20,7 @@ class ModifiedFilter extends AbstractFilter implements IFilterFactory {
}
@Override
- public IFilter[] getFilters() {
- return new IFilter[] { this };
+ public List<ModifiedFilter> getFilters() {
+ return Collections.singletonList(this);
}
}
diff --git a/main/src/cgeo/geocaching/filter/OriginFilter.java b/main/src/cgeo/geocaching/filter/OriginFilter.java
index a880092..bd4e41e 100644
--- a/main/src/cgeo/geocaching/filter/OriginFilter.java
+++ b/main/src/cgeo/geocaching/filter/OriginFilter.java
@@ -7,6 +7,7 @@ import cgeo.geocaching.connector.IConnector;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
+import java.util.List;
public class OriginFilter extends AbstractFilter {
@@ -25,7 +26,7 @@ public class OriginFilter extends AbstractFilter {
public static final class Factory implements IFilterFactory {
@Override
- public IFilter[] getFilters() {
+ public List<OriginFilter> getFilters() {
final ArrayList<OriginFilter> filters = new ArrayList<OriginFilter>();
for (IConnector connector : ConnectorFactory.getConnectors()) {
filters.add(new OriginFilter(connector));
@@ -40,7 +41,7 @@ public class OriginFilter extends AbstractFilter {
}
});
- return filters.toArray(new OriginFilter[filters.size()]);
+ return filters;
}
}
diff --git a/main/src/cgeo/geocaching/filter/SizeFilter.java b/main/src/cgeo/geocaching/filter/SizeFilter.java
index 7a34c83..8ddc475 100644
--- a/main/src/cgeo/geocaching/filter/SizeFilter.java
+++ b/main/src/cgeo/geocaching/filter/SizeFilter.java
@@ -3,7 +3,8 @@ package cgeo.geocaching.filter;
import cgeo.geocaching.Geocache;
import cgeo.geocaching.enumerations.CacheSize;
-import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
class SizeFilter extends AbstractFilter {
private final CacheSize cacheSize;
@@ -26,15 +27,15 @@ class SizeFilter extends AbstractFilter {
public static class Factory implements IFilterFactory {
@Override
- public IFilter[] getFilters() {
+ public List<IFilter> getFilters() {
final CacheSize[] cacheSizes = CacheSize.values();
- final ArrayList<SizeFilter> filters = new ArrayList<SizeFilter>();
+ final List<IFilter> filters = new LinkedList<IFilter>();
for (CacheSize cacheSize : cacheSizes) {
if (cacheSize != CacheSize.UNKNOWN) {
filters.add(new SizeFilter(cacheSize));
}
}
- return filters.toArray(new SizeFilter[filters.size()]);
+ return filters;
}
}
diff --git a/main/src/cgeo/geocaching/filter/StateFilter.java b/main/src/cgeo/geocaching/filter/StateFilter.java
index 0df47c1..e18128d 100644
--- a/main/src/cgeo/geocaching/filter/StateFilter.java
+++ b/main/src/cgeo/geocaching/filter/StateFilter.java
@@ -9,6 +9,7 @@ import android.content.res.Resources;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
+import java.util.List;
abstract class StateFilter extends AbstractFilter {
@@ -86,17 +87,41 @@ abstract class StateFilter extends AbstractFilter {
}
}
+ static class StateStoredFilter extends StateFilter {
+ public StateStoredFilter() {
+ super(res.getString(R.string.cache_status_stored));
+ }
+
+ @Override
+ public boolean accepts(Geocache cache) {
+ return cache.isOffline();
+ }
+ }
+
+ static class StateNotStoredFilter extends StateFilter {
+ public StateNotStoredFilter() {
+ super(res.getString(R.string.cache_status_not_stored));
+ }
+
+ @Override
+ public boolean accepts(Geocache cache) {
+ return !cache.isOffline();
+ }
+ }
+
public static class Factory implements IFilterFactory {
@Override
- public IFilter[] getFilters() {
- final ArrayList<StateFilter> filters = new ArrayList<StateFilter>();
+ public List<StateFilter> getFilters() {
+ final List<StateFilter> filters = new ArrayList<StateFilter>(6);
filters.add(new StateFoundFilter());
filters.add(new StateArchivedFilter());
filters.add(new StateDisabledFilter());
filters.add(new StatePremiumFilter());
filters.add(new StateNonPremiumFilter());
filters.add(new StateOfflineLogFilter());
+ filters.add(new StateStoredFilter());
+ filters.add(new StateNotStoredFilter());
Collections.sort(filters, new Comparator<StateFilter>() {
@@ -106,7 +131,7 @@ abstract class StateFilter extends AbstractFilter {
}
});
- return filters.toArray(new StateFilter[filters.size()]);
+ return filters;
}
}
diff --git a/main/src/cgeo/geocaching/filter/TerrainFilter.java b/main/src/cgeo/geocaching/filter/TerrainFilter.java
index f7703d5..87372c6 100644
--- a/main/src/cgeo/geocaching/filter/TerrainFilter.java
+++ b/main/src/cgeo/geocaching/filter/TerrainFilter.java
@@ -1,10 +1,10 @@
package cgeo.geocaching.filter;
-
-import cgeo.geocaching.R;
import cgeo.geocaching.Geocache;
+import cgeo.geocaching.R;
import java.util.ArrayList;
+import java.util.List;
class TerrainFilter extends AbstractRangeFilter {
@@ -19,12 +19,12 @@ class TerrainFilter extends AbstractRangeFilter {
public static class Factory implements IFilterFactory {
@Override
- public IFilter[] getFilters() {
+ public List<IFilter> getFilters() {
final ArrayList<IFilter> filters = new ArrayList<IFilter>(5);
for (int terrain = 1; terrain <= 5; terrain++) {
filters.add(new TerrainFilter(terrain));
}
- return filters.toArray(new IFilter[filters.size()]);
+ return filters;
}
}
diff --git a/main/src/cgeo/geocaching/filter/TrackablesFilter.java b/main/src/cgeo/geocaching/filter/TrackablesFilter.java
index 3225daa..5eff8a7 100644
--- a/main/src/cgeo/geocaching/filter/TrackablesFilter.java
+++ b/main/src/cgeo/geocaching/filter/TrackablesFilter.java
@@ -1,9 +1,12 @@
package cgeo.geocaching.filter;
-import cgeo.geocaching.R;
import cgeo.geocaching.Geocache;
+import cgeo.geocaching.R;
import cgeo.geocaching.cgeoapplication;
+import java.util.Collections;
+import java.util.List;
+
class TrackablesFilter extends AbstractFilter implements IFilterFactory {
public TrackablesFilter() {
super(cgeoapplication.getInstance().getString(R.string.caches_filter_track));
@@ -15,8 +18,8 @@ class TrackablesFilter extends AbstractFilter implements IFilterFactory {
}
@Override
- public IFilter[] getFilters() {
- return new IFilter[] { this };
+ public List<TrackablesFilter> getFilters() {
+ return Collections.singletonList(this);
}
}
diff --git a/main/src/cgeo/geocaching/filter/TypeFilter.java b/main/src/cgeo/geocaching/filter/TypeFilter.java
index eeab552..ea0ccff 100644
--- a/main/src/cgeo/geocaching/filter/TypeFilter.java
+++ b/main/src/cgeo/geocaching/filter/TypeFilter.java
@@ -3,7 +3,8 @@ package cgeo.geocaching.filter;
import cgeo.geocaching.Geocache;
import cgeo.geocaching.enumerations.CacheType;
-import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
class TypeFilter extends AbstractFilter {
private final CacheType cacheType;
@@ -26,15 +27,15 @@ class TypeFilter extends AbstractFilter {
public static class Factory implements IFilterFactory {
@Override
- public IFilter[] getFilters() {
+ public List<IFilter> getFilters() {
final CacheType[] types = CacheType.values();
- final ArrayList<IFilter> filters = new ArrayList<IFilter>(types.length);
+ final List<IFilter> filters = new LinkedList<IFilter>();
for (CacheType cacheType : types) {
if (cacheType != CacheType.ALL) {
filters.add(new TypeFilter(cacheType));
}
}
- return filters.toArray(new IFilter[filters.size()]);
+ return filters;
}
}
diff --git a/main/src/cgeo/geocaching/gcvote/GCVote.java b/main/src/cgeo/geocaching/gcvote/GCVote.java
index a053f31..f6cfb84 100644
--- a/main/src/cgeo/geocaching/gcvote/GCVote.java
+++ b/main/src/cgeo/geocaching/gcvote/GCVote.java
@@ -173,12 +173,15 @@ public final class GCVote {
/**
* Transmit user vote to gcvote.com
- *
+ *
* @param cache
* @param vote
- * @return
+ * @return {@code true} if the rating was submitted successfully
*/
public static boolean setRating(Geocache cache, double vote) {
+ if (!Settings.isGCvoteLogin()) {
+ return false;
+ }
if (!cache.supportsGCVote()) {
return false;
}
diff --git a/main/src/cgeo/geocaching/geopoint/Geopoint.java b/main/src/cgeo/geocaching/geopoint/Geopoint.java
index dbe0aa4..1973b03 100644
--- a/main/src/cgeo/geocaching/geopoint/Geopoint.java
+++ b/main/src/cgeo/geocaching/geopoint/Geopoint.java
@@ -297,7 +297,7 @@ public final class Geopoint implements ICoordinates, Parcelable {
/**
* Returns formatted coordinates with default format.
* Default format is decimalminutes, e.g. N 52° 36.123 E 010° 03.456
- *
+ *
* @return formatted coordinates
*/
@Override
@@ -345,7 +345,7 @@ public final class Geopoint implements ICoordinates, Parcelable {
return result.getDouble("elevation");
}
} catch (Exception e) {
- Log.w("cgBase.getElevation", e);
+ Log.w("Geopoint.getElevation", e);
}
return null;
diff --git a/main/src/cgeo/geocaching/loaders/CoordsGeocacheListLoader.java b/main/src/cgeo/geocaching/loaders/CoordsGeocacheListLoader.java
index ca2461c..09ea459 100644
--- a/main/src/cgeo/geocaching/loaders/CoordsGeocacheListLoader.java
+++ b/main/src/cgeo/geocaching/loaders/CoordsGeocacheListLoader.java
@@ -19,7 +19,11 @@ public class CoordsGeocacheListLoader extends AbstractSearchLoader {
@Override
public SearchResult runSearch() {
- SearchResult search = GCParser.searchByCoords(coords, Settings.getCacheType(), Settings.isShowCaptcha(), this);
+
+ SearchResult search = new SearchResult();
+ if (Settings.isGCConnectorActive()) {
+ search = GCParser.searchByCoords(coords, Settings.getCacheType(), Settings.isShowCaptcha(), this);
+ }
for (ISearchByCenter centerConn : ConnectorFactory.getSearchByCenterConnectors()) {
if (centerConn.isActivated()) {
diff --git a/main/src/cgeo/geocaching/loaders/UrlLoader.java b/main/src/cgeo/geocaching/loaders/UrlLoader.java
index abafd5f..9f6c3d5 100644
--- a/main/src/cgeo/geocaching/loaders/UrlLoader.java
+++ b/main/src/cgeo/geocaching/loaders/UrlLoader.java
@@ -28,7 +28,7 @@ public class UrlLoader extends AsyncTaskLoader<String> {
try {
return Network.getResponseData(Network.getRequest(url, params));
} catch (final Exception e) {
- Log.w("cgeovisit.UrlLoader.loadInBackground", e);
+ Log.w("UrlLoader.loadInBackground", e);
return null;
}
}
diff --git a/main/src/cgeo/geocaching/maps/AbstractMap.java b/main/src/cgeo/geocaching/maps/AbstractMap.java
index c028e51..d9ee751 100644
--- a/main/src/cgeo/geocaching/maps/AbstractMap.java
+++ b/main/src/cgeo/geocaching/maps/AbstractMap.java
@@ -63,8 +63,6 @@ public abstract class AbstractMap {
public abstract void goHome(View view);
- public abstract void goManual(View view);
-
public abstract void onSaveInstanceState(final Bundle outState);
}
diff --git a/main/src/cgeo/geocaching/maps/CGeoMap.java b/main/src/cgeo/geocaching/maps/CGeoMap.java
index 30bbadf..c876192 100644
--- a/main/src/cgeo/geocaching/maps/CGeoMap.java
+++ b/main/src/cgeo/geocaching/maps/CGeoMap.java
@@ -86,7 +86,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
/** max. number of caches displayed in the Live Map */
public static final int MAX_CACHES = 500;
- /** Controls the behaviour of the map */
+ /** Controls the behavior of the map */
public enum MapMode {
/** Live Map */
LIVE,
@@ -116,24 +116,10 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
private static final String EXTRAS_MAP_MODE = "mapMode";
private static final String EXTRAS_LIVE_ENABLED = "liveEnabled";
- private static final int MENU_SELECT_MAPVIEW = 1;
- private static final int MENU_MAP_LIVE = 2;
- private static final int MENU_STORE_CACHES = 3;
- private static final int SUBMENU_MODES = 4;
- private static final int MENU_TRAIL_MODE = 81;
- private static final int MENU_THEME_MODE = 82;
- private static final int MENU_CIRCLE_MODE = 83;
- private static final int SUBMENU_STRATEGY = 5;
- private static final int MENU_STRATEGY_FASTEST = 51;
- private static final int MENU_STRATEGY_FAST = 52;
- private static final int MENU_STRATEGY_AUTO = 53;
- private static final int MENU_STRATEGY_DETAILED = 74;
-
- private static final int MENU_AS_LIST = 7;
-
private static final String BUNDLE_MAP_SOURCE = "mapSource";
private static final String BUNDLE_MAP_STATE = "mapState";
private static final String BUNDLE_LIVE_ENABLED = "liveEnabled";
+ private static final String BUNDLE_TRAIL_HISTORY = "trailHistory";
private Resources res = null;
private MapItemFactory mapItemFactory = null;
@@ -173,8 +159,6 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
private static final int[][] INSET_FOUND = { { 0, 0, 21, 28 }, { 0, 0, 25, 35 } }; // top left, 12x12 / 16x16
private static final int[][] INSET_USERMODIFIEDCOORDS = { { 21, 28, 0, 0 }, { 19, 25, 0, 0 } }; // bottom right, 12x12 / 26x26
private static final int[][] INSET_PERSONALNOTE = { { 0, 28, 21, 0 }, { 0, 25, 19, 0 } }; // bottom left, 12x12 / 26x26
- private static final int MENU_GROUP_MAP_SOURCES = 1;
- private static final int MENU_GROUP_MAP_STRATEGY = 2;
private SparseArray<LayerDrawable> overlaysCache = new SparseArray<LayerDrawable>();
/** Count of caches currently visible */
@@ -360,6 +344,9 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
outState.putInt(BUNDLE_MAP_SOURCE, currentSourceId);
outState.putIntArray(BUNDLE_MAP_STATE, currentMapState());
outState.putBoolean(BUNDLE_LIVE_ENABLED, isLiveEnabled);
+ if (overlayPosition != null) {
+ outState.putParcelableArrayList(BUNDLE_TRAIL_HISTORY, overlayPosition.getHistory());
+ }
}
@Override
@@ -382,9 +369,9 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
if (extras != null) {
mapMode = (MapMode) extras.get(EXTRAS_MAP_MODE);
isLiveEnabled = extras.getBoolean(EXTRAS_LIVE_ENABLED, false);
- searchIntent = (SearchResult) extras.getParcelable(EXTRAS_SEARCH);
+ searchIntent = extras.getParcelable(EXTRAS_SEARCH);
geocodeIntent = extras.getString(EXTRAS_GEOCODE);
- coordsIntent = (Geopoint) extras.getParcelable(EXTRAS_COORDS);
+ coordsIntent = extras.getParcelable(EXTRAS_COORDS);
waypointTypeIntent = WaypointType.findById(extras.getString(EXTRAS_WPTTYPE));
mapStateIntent = extras.getIntArray(EXTRAS_MAPSTATE);
mapTitle = extras.getString(EXTRAS_MAP_TITLE);
@@ -397,11 +384,14 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
mapTitle = res.getString(R.string.map_map);
}
+ ArrayList<Location> trailHistory = null;
+
// Get fresh map information from the bundle if any
if (savedInstanceState != null) {
currentSourceId = savedInstanceState.getInt(BUNDLE_MAP_SOURCE, Settings.getMapSource().getNumericalId());
mapStateIntent = savedInstanceState.getIntArray(BUNDLE_MAP_STATE);
isLiveEnabled = savedInstanceState.getBoolean(BUNDLE_LIVE_ENABLED, false);
+ trailHistory = savedInstanceState.getParcelableArrayList(BUNDLE_TRAIL_HISTORY);
} else {
currentSourceId = Settings.getMapSource().getNumericalId();
}
@@ -438,6 +428,9 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
if (overlayPosition == null) {
overlayPosition = mapView.createAddPositionOverlay(activity);
+ if (trailHistory != null) {
+ overlayPosition.setHistory(trailHistory);
+ }
}
if (overlayScale == null) {
@@ -541,36 +534,16 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
@Override
public boolean onCreateOptionsMenu(Menu menu) {
+ // menu inflation happens in Google/Mapsforge specific classes
+ super.onCreateOptionsMenu(menu);
- SubMenu submenu = menu.addSubMenu(0, MENU_SELECT_MAPVIEW, 0, res.getString(R.string.map_view_map)).setIcon(R.drawable.ic_menu_mapmode);
- addMapViewMenuItems(submenu);
-
- menu.add(0, MENU_MAP_LIVE, 0, res.getString(R.string.map_live_disable)).setIcon(R.drawable.ic_menu_refresh);
- menu.add(0, MENU_STORE_CACHES, 0, res.getString(R.string.caches_store_offline)).setIcon(R.drawable.ic_menu_set_as).setEnabled(false);
- SubMenu subMenuModes = menu.addSubMenu(0, SUBMENU_MODES, 0, res.getString(R.string.map_modes)).setIcon(R.drawable.ic_menu_mark);
- subMenuModes.add(0, MENU_TRAIL_MODE, 0, res.getString(R.string.map_trail_hide)).setIcon(R.drawable.ic_menu_trail);
- subMenuModes.add(0, MENU_CIRCLE_MODE, 0, res.getString(R.string.map_circles_hide)).setIcon(R.drawable.ic_menu_circle);
- subMenuModes.add(0, MENU_THEME_MODE, 0, res.getString(R.string.map_theme_select)).setIcon(R.drawable.ic_menu_preferences);
+ MapProviderFactory.addMapviewMenuItems(menu);
- Strategy strategy = Settings.getLiveMapStrategy();
- SubMenu subMenuStrategy = menu.addSubMenu(0, SUBMENU_STRATEGY, 0, res.getString(R.string.map_strategy)).setIcon(R.drawable.ic_menu_preferences);
+ final SubMenu subMenuStrategy = menu.findItem(R.id.submenu_strategy).getSubMenu();
subMenuStrategy.setHeaderTitle(res.getString(R.string.map_strategy_title));
- subMenuStrategy.add(MENU_GROUP_MAP_STRATEGY, MENU_STRATEGY_FASTEST, 0, Strategy.FASTEST.getL10n()).setCheckable(true).setChecked(strategy == Strategy.FASTEST);
- subMenuStrategy.add(MENU_GROUP_MAP_STRATEGY, MENU_STRATEGY_FAST, 0, Strategy.FAST.getL10n()).setCheckable(true).setChecked(strategy == Strategy.FAST);
- subMenuStrategy.add(MENU_GROUP_MAP_STRATEGY, MENU_STRATEGY_AUTO, 0, Strategy.AUTO.getL10n()).setCheckable(true).setChecked(strategy == Strategy.AUTO);
- subMenuStrategy.add(MENU_GROUP_MAP_STRATEGY, MENU_STRATEGY_DETAILED, 0, Strategy.DETAILED.getL10n()).setCheckable(true).setChecked(strategy == Strategy.DETAILED);
- subMenuStrategy.setGroupCheckable(MENU_GROUP_MAP_STRATEGY, true, true);
-
- menu.add(0, MENU_AS_LIST, 0, res.getString(R.string.map_as_list)).setIcon(R.drawable.ic_menu_agenda);
-
return true;
}
- private static void addMapViewMenuItems(final Menu menu) {
- MapProviderFactory.addMapviewMenuItems(menu, MENU_GROUP_MAP_SOURCES);
- menu.setGroupCheckable(MENU_GROUP_MAP_SOURCES, true, true);
- }
-
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
@@ -582,14 +555,14 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
}
try {
- MenuItem item = menu.findItem(MENU_TRAIL_MODE);
+ MenuItem item = menu.findItem(R.id.menu_trail_mode);
if (Settings.isMapTrail()) {
item.setTitle(res.getString(R.string.map_trail_hide));
} else {
item.setTitle(res.getString(R.string.map_trail_show));
}
- item = menu.findItem(MENU_MAP_LIVE); // live map
+ item = menu.findItem(R.id.menu_map_live); // live map
if (isLiveEnabled) {
item.setTitle(res.getString(R.string.map_live_disable));
} else {
@@ -597,23 +570,37 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
}
final Set<String> geocodesInViewport = getGeocodesForCachesInViewport();
- menu.findItem(MENU_STORE_CACHES).setEnabled(!isLoading() && CollectionUtils.isNotEmpty(geocodesInViewport) && new SearchResult(geocodesInViewport).hasUnsavedCaches());
+ menu.findItem(R.id.menu_store_caches).setEnabled(!isLoading() && CollectionUtils.isNotEmpty(geocodesInViewport) && new SearchResult(geocodesInViewport).hasUnsavedCaches());
- item = menu.findItem(MENU_CIRCLE_MODE); // show circles
+ item = menu.findItem(R.id.menu_circle_mode); // show circles
if (overlayCaches != null && overlayCaches.getCircles()) {
item.setTitle(res.getString(R.string.map_circles_hide));
} else {
item.setTitle(res.getString(R.string.map_circles_show));
}
- item = menu.findItem(MENU_THEME_MODE); // show theme selection
+ item = menu.findItem(R.id.menu_theme_mode); // show theme selection
item.setVisible(mapView.hasMapThemes());
- menu.findItem(MENU_AS_LIST).setEnabled(isLiveEnabled && !isLoading());
+ menu.findItem(R.id.menu_as_list).setEnabled(isLiveEnabled && !isLoading());
- menu.findItem(SUBMENU_STRATEGY).setEnabled(isLiveEnabled);
+ menu.findItem(R.id.submenu_strategy).setEnabled(isLiveEnabled);
+
+ switch (Settings.getLiveMapStrategy()) {
+ case FASTEST:
+ menu.findItem(R.id.menu_strategy_fastest).setChecked(true);
+ break;
+ case FAST:
+ menu.findItem(R.id.menu_strategy_fast).setChecked(true);
+ break;
+ case AUTO:
+ menu.findItem(R.id.menu_strategy_auto).setChecked(true);
+ break;
+ default: // DETAILED
+ menu.findItem(R.id.menu_strategy_detailed).setChecked(true);
+ }
} catch (Exception e) {
- Log.e("cgeomap.onPrepareOptionsMenu", e);
+ Log.e("CGeoMap.onPrepareOptionsMenu", e);
}
return true;
@@ -623,12 +610,12 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
public boolean onOptionsItemSelected(MenuItem item) {
final int id = item.getItemId();
switch (id) {
- case MENU_TRAIL_MODE:
+ case R.id.menu_trail_mode:
Settings.setMapTrail(!Settings.isMapTrail());
mapView.repaintRequired(overlayPosition);
ActivityMixin.invalidateOptionsMenu(activity);
return true;
- case MENU_MAP_LIVE:
+ case R.id.menu_map_live:
isLiveEnabled = !isLiveEnabled;
if (mapMode == MapMode.LIVE) {
Settings.setLiveMap(isLiveEnabled);
@@ -638,7 +625,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
searchIntent = null;
ActivityMixin.invalidateOptionsMenu(activity);
return true;
- case MENU_STORE_CACHES:
+ case R.id.menu_store_caches:
if (!isLoading()) {
final Set<String> geocodesInViewport = getGeocodesForCachesInViewport();
final List<String> geocodes = new ArrayList<String>();
@@ -672,7 +659,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
}
}
return true;
- case MENU_CIRCLE_MODE:
+ case R.id.menu_circle_mode:
if (overlayCaches == null) {
return false;
}
@@ -681,29 +668,29 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
mapView.repaintRequired(overlayCaches);
ActivityMixin.invalidateOptionsMenu(activity);
return true;
- case MENU_THEME_MODE:
+ case R.id.menu_theme_mode:
selectMapTheme();
return true;
- case MENU_AS_LIST: {
+ case R.id.menu_as_list: {
cgeocaches.startActivityMap(activity, new SearchResult(getGeocodesForCachesInViewport()));
return true;
}
- case MENU_STRATEGY_FASTEST: {
+ case R.id.menu_strategy_fastest: {
item.setChecked(true);
Settings.setLiveMapStrategy(Strategy.FASTEST);
return true;
}
- case MENU_STRATEGY_FAST: {
+ case R.id.menu_strategy_fast: {
item.setChecked(true);
Settings.setLiveMapStrategy(Strategy.FAST);
return true;
}
- case MENU_STRATEGY_AUTO: {
+ case R.id.menu_strategy_auto: {
item.setChecked(true);
Settings.setLiveMapStrategy(Strategy.AUTO);
return true;
}
- case MENU_STRATEGY_DETAILED: {
+ case R.id.menu_strategy_detailed: {
item.setChecked(true);
Settings.setLiveMapStrategy(Strategy.DETAILED);
return true;
@@ -751,9 +738,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
@Override
public void onClick(DialogInterface dialog, int newItem) {
- if (newItem == selectedItem) {
- // no change
- } else {
+ if (newItem != selectedItem) {
// Adjust index because of <default> selection
if (newItem > 0) {
Settings.setCustomRenderThemeFile(themeFiles[newItem - 1].getPath());
@@ -1055,7 +1040,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
yield();
} catch (Exception e) {
- Log.w("cgeomap.LoadTimer.run", e);
+ Log.w("CGeoMap.LoadTimer.run", e);
}
}
}
@@ -1179,7 +1164,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
searchResult = ConnectorFactory.searchByViewport(viewport.resize(0.8), tokens);
if (searchResult != null) {
downloaded = true;
- if (searchResult.getError() == StatusCode.NOT_LOGGED_IN) {
+ if (searchResult.getError() == StatusCode.NOT_LOGGED_IN && Settings.isGCConnectorActive()) {
Login.login();
tokens = null;
} else {
@@ -1351,7 +1336,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
geoDirUpdate.startDir();
} catch (Exception e) {
- Log.e("cgeocaches.onPrepareOptionsMenu.onCancel", e);
+ Log.e("CGeoMap.storeCaches.onCancel", e);
}
}
});
@@ -1429,7 +1414,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
Geocache.storeCache(null, geocode, listId, false, handler);
}
} catch (Exception e) {
- Log.e("cgeocaches.LoadDetails.run", e);
+ Log.e("CGeoMap.LoadDetails.run", e);
} finally {
// one more cache over
detailProgress++;
@@ -1578,12 +1563,6 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
ActivityMixin.goHome(activity);
}
- // open manual entry
- @Override
- public void goManual(View view) {
- ActivityMixin.goManual(activity, "c:geo-live-map");
- }
-
@Override
public View makeView() {
ImageView imageView = new ImageView(activity);
@@ -1645,13 +1624,13 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
}
private CachesOverlayItemImpl getCacheItem(final Geocache cache) {
- final CachesOverlayItemImpl item = mapItemFactory.getCachesOverlayItem(cache, cache.getType());
+ final CachesOverlayItemImpl item = mapItemFactory.getCachesOverlayItem(cache, cache.getType().applyDistanceRule());
final int hashcode = new HashCodeBuilder()
.append(cache.isReliableLatLon())
.append(cache.getType().id)
.append(cache.isDisabled() || cache.isArchived())
- .append(cache.getCacheRealm().id)
+ .append(cache.getMapMarkerId())
.append(cache.isOwner())
.append(cache.isFound())
.append(cache.hasUserModifiedCoords())
@@ -1660,18 +1639,21 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
.append(cache.getListId() > 0)
.toHashCode();
- final LayerDrawable ldFromCache = overlaysCache.get(hashcode);
- if (ldFromCache != null) {
- item.setMarker(ldFromCache);
- return item;
+ LayerDrawable drawable = overlaysCache.get(hashcode);
+ if (drawable == null) {
+ drawable = createCacheItem(cache, hashcode);
}
+ item.setMarker(drawable);
+ return item;
+ }
+ private LayerDrawable createCacheItem(final Geocache cache, final int hashcode) {
// Set initial capacities to the maximum of layers and insets to avoid dynamic reallocation
final ArrayList<Drawable> layers = new ArrayList<Drawable>(9);
final ArrayList<int[]> insets = new ArrayList<int[]>(8);
// background: disabled or not
- final Drawable marker = getResources().getDrawable(cache.isDisabled() || cache.isArchived() ? cache.getCacheRealm().markerDisabledId : cache.getCacheRealm().markerId);
+ final Drawable marker = getResources().getDrawable(cache.getMapMarkerId());
layers.add(marker);
final int resolution = marker.getIntrinsicWidth() > 40 ? 1 : 0;
// reliable or not
@@ -1719,13 +1701,11 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
}
overlaysCache.put(hashcode, ld);
-
- item.setMarker(ld);
- return item;
+ return ld;
}
private CachesOverlayItemImpl getWaypointItem(final Waypoint waypoint) {
- final CachesOverlayItemImpl item = mapItemFactory.getCachesOverlayItem(waypoint, null);
+ final CachesOverlayItemImpl item = mapItemFactory.getCachesOverlayItem(waypoint, waypoint.getWaypointType().applyDistanceRule());
Drawable marker = getResources().getDrawable(!waypoint.isVisited() ? R.drawable.marker : R.drawable.marker_transparent);
final Drawable[] layers = new Drawable[] {
marker,
diff --git a/main/src/cgeo/geocaching/maps/CachesOverlay.java b/main/src/cgeo/geocaching/maps/CachesOverlay.java
index 9bb4cef..f1dd9b3 100644
--- a/main/src/cgeo/geocaching/maps/CachesOverlay.java
+++ b/main/src/cgeo/geocaching/maps/CachesOverlay.java
@@ -1,11 +1,11 @@
package cgeo.geocaching.maps;
import cgeo.geocaching.CachePopup;
+import cgeo.geocaching.Geocache;
import cgeo.geocaching.IWaypoint;
import cgeo.geocaching.R;
import cgeo.geocaching.Settings;
import cgeo.geocaching.WaypointPopup;
-import cgeo.geocaching.Geocache;
import cgeo.geocaching.cgData;
import cgeo.geocaching.activity.Progress;
import cgeo.geocaching.connector.gc.GCMap;
@@ -58,14 +58,14 @@ public class CachesOverlay extends AbstractItemizedOverlay {
mapItemFactory = mapProvider.getMapItemFactory();
}
- public void updateItems(CachesOverlayItemImpl item) {
+ void updateItems(CachesOverlayItemImpl item) {
List<CachesOverlayItemImpl> itemsPre = new ArrayList<CachesOverlayItemImpl>();
itemsPre.add(item);
updateItems(itemsPre);
}
- public void updateItems(List<CachesOverlayItemImpl> itemsPre) {
+ void updateItems(List<CachesOverlayItemImpl> itemsPre) {
if (itemsPre == null) {
return;
}
@@ -86,11 +86,11 @@ public class CachesOverlay extends AbstractItemizedOverlay {
}
}
- public boolean getCircles() {
+ boolean getCircles() {
return displayCircles;
}
- public void switchCircles() {
+ void switchCircles() {
displayCircles = !displayCircles;
}
@@ -126,20 +126,17 @@ public class CachesOverlay extends AbstractItemizedOverlay {
final Point center = new Point();
for (CachesOverlayItemImpl item : items) {
- final Geopoint itemCoord = item.getCoord().getCoords();
- final GeoPointImpl itemGeo = mapItemFactory.getGeoPointBase(itemCoord);
- projection.toPixels(itemGeo, center);
+ if (item.applyDistanceRule()) {
+ final Geopoint itemCoord = item.getCoord().getCoords();
+ final GeoPointImpl itemGeo = mapItemFactory.getGeoPointBase(itemCoord);
+ projection.toPixels(itemGeo, center);
- final CacheType type = item.getType();
- if (type == null || type == CacheType.MULTI || type == CacheType.MYSTERY || type == CacheType.VIRTUAL || type.isEvent()) {
- blockedCircle.setColor(0x66000000);
- blockedCircle.setStyle(Style.STROKE);
- canvas.drawCircle(center.x, center.y, radius, blockedCircle);
- } else {
+ // dashed circle around the waypoint
blockedCircle.setColor(0x66BB0000);
blockedCircle.setStyle(Style.STROKE);
canvas.drawCircle(center.x, center.y, radius, blockedCircle);
+ // filling the circle area with a transparent color
blockedCircle.setColor(0x44BB0000);
blockedCircle.setStyle(Style.FILL);
canvas.drawCircle(center.x, center.y, radius, blockedCircle);
@@ -209,9 +206,9 @@ public class CachesOverlay extends AbstractItemizedOverlay {
progress.show(context, context.getResources().getString(R.string.map_live), context.getResources().getString(R.string.cache_dialog_loading_details), true, null);
+ CachesOverlayItemImpl item = null;
// prevent concurrent changes
getOverlayImpl().lock();
- CachesOverlayItemImpl item = null;
try {
if (index < items.size()) {
item = items.get(index);
@@ -247,7 +244,7 @@ public class CachesOverlay extends AbstractItemizedOverlay {
progress.dismiss();
} catch (Exception e) {
- Log.e("cgMapOverlay.onTap", e);
+ Log.e("CachesOverlay.onTap", e);
if (progress != null) {
progress.dismiss();
}
@@ -261,7 +258,7 @@ public class CachesOverlay extends AbstractItemizedOverlay {
try {
return items.get(index);
} catch (Exception e) {
- Log.e("cgMapOverlay.createItem", e);
+ Log.e("CachesOverlay.createItem", e);
}
return null;
@@ -272,7 +269,7 @@ public class CachesOverlay extends AbstractItemizedOverlay {
try {
return items.size();
} catch (Exception e) {
- Log.e("cgMapOverlay.size", e);
+ Log.e("CachesOverlay.size", e);
}
return 0;
diff --git a/main/src/cgeo/geocaching/maps/MapProviderFactory.java b/main/src/cgeo/geocaching/maps/MapProviderFactory.java
index 483189f..5ce8ab6 100644
--- a/main/src/cgeo/geocaching/maps/MapProviderFactory.java
+++ b/main/src/cgeo/geocaching/maps/MapProviderFactory.java
@@ -1,5 +1,6 @@
package cgeo.geocaching.maps;
+import cgeo.geocaching.R;
import cgeo.geocaching.Settings;
import cgeo.geocaching.maps.google.GoogleMapProvider;
import cgeo.geocaching.maps.interfaces.MapProvider;
@@ -7,6 +8,7 @@ import cgeo.geocaching.maps.interfaces.MapSource;
import cgeo.geocaching.maps.mapsforge.MapsforgeMapProvider;
import android.view.Menu;
+import android.view.SubMenu;
import java.util.ArrayList;
import java.util.List;
@@ -43,13 +45,16 @@ public class MapProviderFactory {
return provider1 == provider2 && provider1.isSameActivity(source1, source2);
}
- public static void addMapviewMenuItems(final Menu parentMenu, final int groupId) {
+ public static void addMapviewMenuItems(Menu menu) {
+ final SubMenu parentMenu = menu.findItem(R.id.menu_select_mapview).getSubMenu();
+
final int currentSource = Settings.getMapSource().getNumericalId();
for (int i = 0; i < mapSources.size(); i++) {
final MapSource mapSource = mapSources.get(i);
final int id = mapSource.getNumericalId();
- parentMenu.add(groupId, id, i, mapSource.getName()).setCheckable(true).setChecked(id == currentSource);
+ parentMenu.add(R.id.menu_group_map_sources, id, i, mapSource.getName()).setCheckable(true).setChecked(id == currentSource);
}
+ parentMenu.setGroupCheckable(R.id.menu_group_map_sources, true, true);
}
public static MapSource getMapSource(int id) {
diff --git a/main/src/cgeo/geocaching/maps/PositionOverlay.java b/main/src/cgeo/geocaching/maps/PositionOverlay.java
index fec67ef..08acd2f 100644
--- a/main/src/cgeo/geocaching/maps/PositionOverlay.java
+++ b/main/src/cgeo/geocaching/maps/PositionOverlay.java
@@ -22,7 +22,6 @@ import android.graphics.Point;
import android.location.Location;
import java.util.ArrayList;
-import java.util.List;
public class PositionOverlay implements GeneralOverlay {
private Location coordinates = null;
@@ -39,7 +38,7 @@ public class PositionOverlay implements GeneralOverlay {
private PaintFlagsDrawFilter setfil = null;
private PaintFlagsDrawFilter remfil = null;
private Location historyRecent = null;
- private List<Location> history = new ArrayList<Location>();
+ private ArrayList<Location> history = new ArrayList<Location>();
private Point historyPointN = new Point();
private Point historyPointP = new Point();
private Activity activity;
@@ -229,4 +228,12 @@ public class PositionOverlay implements GeneralOverlay {
public OverlayImpl getOverlayImpl() {
return this.ovlImpl;
}
+
+ public ArrayList<Location> getHistory() {
+ return history;
+ }
+
+ public void setHistory(ArrayList<Location> inHistory) {
+ history = inHistory;
+ }
}
diff --git a/main/src/cgeo/geocaching/maps/google/GoogleCacheOverlay.java b/main/src/cgeo/geocaching/maps/google/GoogleCacheOverlay.java
index 4868a30..21d78a0 100644
--- a/main/src/cgeo/geocaching/maps/google/GoogleCacheOverlay.java
+++ b/main/src/cgeo/geocaching/maps/google/GoogleCacheOverlay.java
@@ -73,12 +73,12 @@ public class GoogleCacheOverlay extends ItemizedOverlay<GoogleCacheOverlayItem>
@Override
public Drawable superBoundCenter(Drawable markerIn) {
- return super.boundCenter(markerIn);
+ return ItemizedOverlay.boundCenter(markerIn);
}
@Override
public Drawable superBoundCenterBottom(Drawable marker) {
- return super.boundCenterBottom(marker);
+ return ItemizedOverlay.boundCenterBottom(marker);
}
@Override
diff --git a/main/src/cgeo/geocaching/maps/google/GoogleCacheOverlayItem.java b/main/src/cgeo/geocaching/maps/google/GoogleCacheOverlayItem.java
index 2ac66af..b26654a 100644
--- a/main/src/cgeo/geocaching/maps/google/GoogleCacheOverlayItem.java
+++ b/main/src/cgeo/geocaching/maps/google/GoogleCacheOverlayItem.java
@@ -1,21 +1,20 @@
package cgeo.geocaching.maps.google;
import cgeo.geocaching.IWaypoint;
-import cgeo.geocaching.enumerations.CacheType;
import cgeo.geocaching.maps.interfaces.CachesOverlayItemImpl;
import com.google.android.maps.GeoPoint;
import com.google.android.maps.OverlayItem;
public class GoogleCacheOverlayItem extends OverlayItem implements CachesOverlayItemImpl {
- final private CacheType cacheType;
final private IWaypoint coord;
+ final private boolean applyDistanceRule;
- public GoogleCacheOverlayItem(final IWaypoint coordinate, final CacheType type) {
+ public GoogleCacheOverlayItem(final IWaypoint coordinate, boolean applyDistanceRule) {
super(new GeoPoint(coordinate.getCoords().getLatitudeE6(), coordinate.getCoords().getLongitudeE6()), coordinate.getName(), "");
- this.cacheType = type;
this.coord = coordinate;
+ this.applyDistanceRule = applyDistanceRule;
}
@Override
@@ -24,8 +23,8 @@ public class GoogleCacheOverlayItem extends OverlayItem implements CachesOverlay
}
@Override
- public CacheType getType() {
- return cacheType;
+ public boolean applyDistanceRule() {
+ return applyDistanceRule;
}
}
diff --git a/main/src/cgeo/geocaching/maps/google/GoogleMapActivity.java b/main/src/cgeo/geocaching/maps/google/GoogleMapActivity.java
index 5649d19..dcff363 100644
--- a/main/src/cgeo/geocaching/maps/google/GoogleMapActivity.java
+++ b/main/src/cgeo/geocaching/maps/google/GoogleMapActivity.java
@@ -1,5 +1,6 @@
package cgeo.geocaching.maps.google;
+import cgeo.geocaching.R;
import cgeo.geocaching.activity.FilteredActivity;
import cgeo.geocaching.maps.AbstractMap;
import cgeo.geocaching.maps.CGeoMap;
@@ -83,7 +84,9 @@ public class GoogleMapActivity extends MapActivity implements MapActivityImpl, F
@Override
public boolean superOnCreateOptionsMenu(Menu menu) {
- return super.onCreateOptionsMenu(menu);
+ final boolean result = super.onCreateOptionsMenu(menu);
+ getMenuInflater().inflate(R.menu.map_activity, menu);
+ return result;
}
@Override
@@ -122,12 +125,6 @@ public class GoogleMapActivity extends MapActivity implements MapActivityImpl, F
mapBase.goHome(view);
}
- // open manual entry
- @Override
- public void goManual(View view) {
- mapBase.goManual(view);
- }
-
@Override
public void showFilterMenu(View view) {
// do nothing, the filter bar only shows the global filter
diff --git a/main/src/cgeo/geocaching/maps/google/GoogleMapItemFactory.java b/main/src/cgeo/geocaching/maps/google/GoogleMapItemFactory.java
index f40c799..c708dc5 100644
--- a/main/src/cgeo/geocaching/maps/google/GoogleMapItemFactory.java
+++ b/main/src/cgeo/geocaching/maps/google/GoogleMapItemFactory.java
@@ -1,7 +1,6 @@
package cgeo.geocaching.maps.google;
import cgeo.geocaching.IWaypoint;
-import cgeo.geocaching.enumerations.CacheType;
import cgeo.geocaching.geopoint.Geopoint;
import cgeo.geocaching.maps.interfaces.CachesOverlayItemImpl;
import cgeo.geocaching.maps.interfaces.GeoPointImpl;
@@ -15,7 +14,7 @@ public class GoogleMapItemFactory implements MapItemFactory {
}
@Override
- public CachesOverlayItemImpl getCachesOverlayItem(final IWaypoint coordinate, final CacheType type) {
- return new GoogleCacheOverlayItem(coordinate, type);
+ public CachesOverlayItemImpl getCachesOverlayItem(final IWaypoint coordinate, boolean applyDistanceRule) {
+ return new GoogleCacheOverlayItem(coordinate, applyDistanceRule);
}
}
diff --git a/main/src/cgeo/geocaching/maps/interfaces/CachesOverlayItemImpl.java b/main/src/cgeo/geocaching/maps/interfaces/CachesOverlayItemImpl.java
index 5bf3ed2..03fa21f 100644
--- a/main/src/cgeo/geocaching/maps/interfaces/CachesOverlayItemImpl.java
+++ b/main/src/cgeo/geocaching/maps/interfaces/CachesOverlayItemImpl.java
@@ -1,7 +1,6 @@
package cgeo.geocaching.maps.interfaces;
import cgeo.geocaching.IWaypoint;
-import cgeo.geocaching.enumerations.CacheType;
/**
* Covers the common functions of the provider-specific
@@ -11,6 +10,5 @@ public interface CachesOverlayItemImpl extends OverlayItemImpl {
public IWaypoint getCoord();
- public CacheType getType();
-
+ public boolean applyDistanceRule();
}
diff --git a/main/src/cgeo/geocaching/maps/interfaces/MapActivityImpl.java b/main/src/cgeo/geocaching/maps/interfaces/MapActivityImpl.java
index dc7dca5..e7deebd 100644
--- a/main/src/cgeo/geocaching/maps/interfaces/MapActivityImpl.java
+++ b/main/src/cgeo/geocaching/maps/interfaces/MapActivityImpl.java
@@ -35,6 +35,4 @@ public interface MapActivityImpl {
public abstract void goHome(View view);
- public abstract void goManual(View view);
-
}
diff --git a/main/src/cgeo/geocaching/maps/interfaces/MapItemFactory.java b/main/src/cgeo/geocaching/maps/interfaces/MapItemFactory.java
index e02d472..22c6698 100644
--- a/main/src/cgeo/geocaching/maps/interfaces/MapItemFactory.java
+++ b/main/src/cgeo/geocaching/maps/interfaces/MapItemFactory.java
@@ -1,13 +1,12 @@
package cgeo.geocaching.maps.interfaces;
import cgeo.geocaching.IWaypoint;
-import cgeo.geocaching.enumerations.CacheType;
import cgeo.geocaching.geopoint.Geopoint;
public interface MapItemFactory {
public GeoPointImpl getGeoPointBase(final Geopoint coords);
- public CachesOverlayItemImpl getCachesOverlayItem(final IWaypoint iWaypoint, final CacheType type);
+ public CachesOverlayItemImpl getCachesOverlayItem(final IWaypoint iWaypoint, final boolean applyDistanceRule);
}
diff --git a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeCacheOverlay.java b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeCacheOverlay.java
index 0bd2484..9e14e36 100644
--- a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeCacheOverlay.java
+++ b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeCacheOverlay.java
@@ -71,12 +71,12 @@ public class MapsforgeCacheOverlay extends ItemizedOverlay<MapsforgeCacheOverlay
@Override
public Drawable superBoundCenter(Drawable markerIn) {
- return super.boundCenter(markerIn);
+ return ItemizedOverlay.boundCenter(markerIn);
}
@Override
public Drawable superBoundCenterBottom(Drawable marker) {
- return super.boundCenterBottom(marker);
+ return ItemizedOverlay.boundCenterBottom(marker);
}
@Override
diff --git a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeCacheOverlayItem.java b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeCacheOverlayItem.java
index 29f13b3..27ca664 100644
--- a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeCacheOverlayItem.java
+++ b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeCacheOverlayItem.java
@@ -1,7 +1,6 @@
package cgeo.geocaching.maps.mapsforge;
import cgeo.geocaching.IWaypoint;
-import cgeo.geocaching.enumerations.CacheType;
import cgeo.geocaching.maps.interfaces.CachesOverlayItemImpl;
import org.mapsforge.android.maps.overlay.OverlayItem;
@@ -10,14 +9,14 @@ import org.mapsforge.core.GeoPoint;
import android.graphics.drawable.Drawable;
public class MapsforgeCacheOverlayItem extends OverlayItem implements CachesOverlayItemImpl {
- final private CacheType cacheType;
final private IWaypoint coord;
+ final private boolean applyDistanceRule;
- public MapsforgeCacheOverlayItem(IWaypoint coordinate, final CacheType type) {
+ public MapsforgeCacheOverlayItem(IWaypoint coordinate, boolean applyDistanceRule) {
super(new GeoPoint(coordinate.getCoords().getLatitudeE6(), coordinate.getCoords().getLongitudeE6()), coordinate.getName(), "");
- this.cacheType = type;
this.coord = coordinate;
+ this.applyDistanceRule = applyDistanceRule;
}
@Override
@@ -26,13 +25,13 @@ public class MapsforgeCacheOverlayItem extends OverlayItem implements CachesOver
}
@Override
- public CacheType getType() {
- return cacheType;
+ public Drawable getMarker(int index) {
+ return getMarker();
}
@Override
- public Drawable getMarker(int index) {
- return getMarker();
+ public boolean applyDistanceRule() {
+ return applyDistanceRule;
}
}
diff --git a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapActivity.java b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapActivity.java
index f850402..232fe3c 100644
--- a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapActivity.java
+++ b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapActivity.java
@@ -1,5 +1,6 @@
package cgeo.geocaching.maps.mapsforge;
+import cgeo.geocaching.R;
import cgeo.geocaching.activity.FilteredActivity;
import cgeo.geocaching.maps.AbstractMap;
import cgeo.geocaching.maps.CGeoMap;
@@ -78,7 +79,9 @@ public class MapsforgeMapActivity extends MapActivity implements MapActivityImpl
@Override
public boolean superOnCreateOptionsMenu(Menu menu) {
- return super.onCreateOptionsMenu(menu);
+ final boolean result = super.onCreateOptionsMenu(menu);
+ getMenuInflater().inflate(R.menu.map_activity, menu);
+ return result;
}
@Override
@@ -117,12 +120,6 @@ public class MapsforgeMapActivity extends MapActivity implements MapActivityImpl
mapBase.goHome(view);
}
- // open manual entry
- @Override
- public void goManual(View view) {
- mapBase.goManual(view);
- }
-
@Override
public void showFilterMenu(View view) {
// do nothing, the filter bar only shows the global filter
diff --git a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapItemFactory.java b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapItemFactory.java
index 10fcb03..4ade09c 100644
--- a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapItemFactory.java
+++ b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapItemFactory.java
@@ -1,7 +1,6 @@
package cgeo.geocaching.maps.mapsforge;
import cgeo.geocaching.IWaypoint;
-import cgeo.geocaching.enumerations.CacheType;
import cgeo.geocaching.geopoint.Geopoint;
import cgeo.geocaching.maps.interfaces.CachesOverlayItemImpl;
import cgeo.geocaching.maps.interfaces.GeoPointImpl;
@@ -15,8 +14,8 @@ public class MapsforgeMapItemFactory implements MapItemFactory {
}
@Override
- public CachesOverlayItemImpl getCachesOverlayItem(final IWaypoint coordinate, final CacheType type) {
- return new MapsforgeCacheOverlayItem(coordinate, type);
+ public CachesOverlayItemImpl getCachesOverlayItem(final IWaypoint coordinate, boolean applyDistanceRule) {
+ return new MapsforgeCacheOverlayItem(coordinate, applyDistanceRule);
}
}
diff --git a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapProvider.java b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapProvider.java
index dc0dbf8..7cf18fb 100644
--- a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapProvider.java
+++ b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapProvider.java
@@ -68,7 +68,7 @@ public final class MapsforgeMapProvider extends AbstractMapProvider {
Collections.sort(mapFileList, String.CASE_INSENSITIVE_ORDER);
return mapFileList;
} catch (Exception e) {
- Log.e("Settings.getOfflineMaps: " + e);
+ Log.e("MapsforgeMapProvider.getOfflineMaps: ", e);
}
return Collections.emptyList();
}
@@ -167,7 +167,7 @@ public final class MapsforgeMapProvider extends AbstractMapProvider {
final List<String> offlineMaps = getOfflineMaps();
for (String mapFile : offlineMaps) {
final String mapName = StringUtils.capitalize(StringUtils.substringBeforeLast(new File(mapFile).getName(), "."));
- registerMapSource(new OfflineMapSource(mapFile, this, resources.getString(R.string.map_source_osm_offline) + " - " + mapName, MapGeneratorInternal.DATABASE_RENDERER));
+ registerMapSource(new OfflineMapSource(mapFile, this, mapName + " (" + resources.getString(R.string.map_source_osm_offline) + ")", MapGeneratorInternal.DATABASE_RENDERER));
}
// have a default entry, if no map files are available. otherwise we cannot select "offline" in the settings
if (offlineMaps.isEmpty()) {
diff --git a/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeCacheOverlay.java b/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeCacheOverlay.java
index 581548f..30355fd 100644
--- a/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeCacheOverlay.java
+++ b/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeCacheOverlay.java
@@ -71,12 +71,12 @@ public class MapsforgeCacheOverlay extends ItemizedOverlay<MapsforgeCacheOverlay
@Override
public Drawable superBoundCenter(Drawable markerIn) {
- return super.boundCenter(markerIn);
+ return ItemizedOverlay.boundCenter(markerIn);
}
@Override
public Drawable superBoundCenterBottom(Drawable marker) {
- return super.boundCenterBottom(marker);
+ return ItemizedOverlay.boundCenterBottom(marker);
}
@Override
diff --git a/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeCacheOverlayItem.java b/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeCacheOverlayItem.java
index 6b74de5..4e4a358 100644
--- a/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeCacheOverlayItem.java
+++ b/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeCacheOverlayItem.java
@@ -1,7 +1,6 @@
package cgeo.geocaching.maps.mapsforge.v024;
import cgeo.geocaching.IWaypoint;
-import cgeo.geocaching.enumerations.CacheType;
import cgeo.geocaching.maps.interfaces.CachesOverlayItemImpl;
import org.mapsforge.android.mapsold.GeoPoint;
@@ -10,14 +9,14 @@ import org.mapsforge.android.mapsold.OverlayItem;
import android.graphics.drawable.Drawable;
public class MapsforgeCacheOverlayItem extends OverlayItem implements CachesOverlayItemImpl {
- final private CacheType cacheType;
final private IWaypoint coord;
+ final private boolean applyDistanceRule;
- public MapsforgeCacheOverlayItem(IWaypoint coordinate, final CacheType type) {
+ public MapsforgeCacheOverlayItem(IWaypoint coordinate, boolean applyDistanceRule) {
super(new GeoPoint(coordinate.getCoords().getLatitudeE6(), coordinate.getCoords().getLongitudeE6()), coordinate.getName(), "");
- this.cacheType = type;
this.coord = coordinate;
+ this.applyDistanceRule = applyDistanceRule;
}
@Override
@@ -26,13 +25,13 @@ public class MapsforgeCacheOverlayItem extends OverlayItem implements CachesOver
}
@Override
- public CacheType getType() {
- return cacheType;
+ public Drawable getMarker(int index) {
+ return getMarker();
}
@Override
- public Drawable getMarker(int index) {
- return getMarker();
+ public boolean applyDistanceRule() {
+ return applyDistanceRule;
}
}
diff --git a/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapActivity024.java b/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapActivity024.java
index ed8a7bc..33ed30e 100644
--- a/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapActivity024.java
+++ b/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapActivity024.java
@@ -117,12 +117,6 @@ public class MapsforgeMapActivity024 extends MapActivity implements MapActivityI
mapBase.goHome(view);
}
- // open manual entry
- @Override
- public void goManual(View view) {
- mapBase.goManual(view);
- }
-
@Override
public void showFilterMenu(View view) {
// do nothing, the filter bar only shows the global filter
diff --git a/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapItemFactory024.java b/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapItemFactory024.java
index 5c64592..4f1d34c 100644
--- a/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapItemFactory024.java
+++ b/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapItemFactory024.java
@@ -1,7 +1,6 @@
package cgeo.geocaching.maps.mapsforge.v024;
import cgeo.geocaching.IWaypoint;
-import cgeo.geocaching.enumerations.CacheType;
import cgeo.geocaching.geopoint.Geopoint;
import cgeo.geocaching.maps.interfaces.CachesOverlayItemImpl;
import cgeo.geocaching.maps.interfaces.GeoPointImpl;
@@ -15,7 +14,7 @@ public class MapsforgeMapItemFactory024 implements MapItemFactory {
}
@Override
- public CachesOverlayItemImpl getCachesOverlayItem(final IWaypoint coordinate, final CacheType type) {
- return new MapsforgeCacheOverlayItem(coordinate, type);
+ public CachesOverlayItemImpl getCachesOverlayItem(final IWaypoint coordinate, boolean applyDistanceRule) {
+ return new MapsforgeCacheOverlayItem(coordinate, applyDistanceRule);
}
}
diff --git a/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapView024.java b/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapView024.java
index 85d61fe..cc8bc66 100644
--- a/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapView024.java
+++ b/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapView024.java
@@ -53,7 +53,7 @@ public class MapsforgeMapView024 extends MapView implements MapViewImpl {
super.draw(canvas);
} catch (Exception e) {
- Log.e("MapsforgeMapView.draw", e);
+ Log.e("MapsforgeMapView024.draw", e);
}
}
@@ -208,7 +208,7 @@ public class MapsforgeMapView024 extends MapView implements MapViewImpl {
}
} catch (Exception e) {
- Log.e("MapsforgeMapView.repaintRequired", e);
+ Log.e("MapsforgeMapView024.repaintRequired", e);
}
}
}
diff --git a/main/src/cgeo/geocaching/network/HtmlImage.java b/main/src/cgeo/geocaching/network/HtmlImage.java
index 38498d6..0649e12 100644
--- a/main/src/cgeo/geocaching/network/HtmlImage.java
+++ b/main/src/cgeo/geocaching/network/HtmlImage.java
@@ -6,7 +6,8 @@ import cgeo.geocaching.cgeoapplication;
import cgeo.geocaching.compatibility.Compatibility;
import cgeo.geocaching.connector.ConnectorFactory;
import cgeo.geocaching.files.LocalStorage;
-import cgeo.geocaching.utils.ImageHelper;
+import cgeo.geocaching.utils.IOUtils;
+import cgeo.geocaching.utils.ImageUtils;
import cgeo.geocaching.utils.Log;
import ch.boye.httpclientandroidlib.HttpResponse;
@@ -21,10 +22,10 @@ import android.graphics.drawable.BitmapDrawable;
import android.net.Uri;
import android.text.Html;
+import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
-import java.io.IOException;
import java.util.Date;
public class HtmlImage implements Html.ImageGetter {
@@ -42,7 +43,8 @@ public class HtmlImage implements Html.ImageGetter {
"hitwebcounter.com",
"kostenloser-counter.eu",
"trendcounter.com",
- "hit-counter-download.com"
+ "hit-counter-download.com",
+ "gcwetterau.de/counter"
};
public static final String SHARED = "shared";
@@ -66,6 +68,7 @@ public class HtmlImage implements Html.ImageGetter {
bfOptions = new BitmapFactory.Options();
bfOptions.inTempStorage = new byte[16 * 1024];
+ bfOptions.inPreferredConfig = Bitmap.Config.RGB_565;
Point displaySize = Compatibility.getDisplaySize();
this.maxWidth = displaySize.x - 25;
@@ -129,7 +132,7 @@ public class HtmlImage implements Html.ImageGetter {
}
}
- return imagePre != null ? ImageHelper.scaleBitmapToFitDisplay(imagePre) : null;
+ return imagePre != null ? ImageUtils.scaleBitmapToFitDisplay(imagePre) : null;
}
/**
@@ -194,7 +197,11 @@ public class HtmlImage implements Html.ImageGetter {
if (file.exists()) {
if (listId >= StoredList.STANDARD_LIST_ID || file.lastModified() > (new Date().getTime() - (24 * 60 * 60 * 1000)) || forceKeep) {
setSampleSize(file);
- return BitmapFactory.decodeFile(file.getPath(), bfOptions);
+ final Bitmap image = BitmapFactory.decodeFile(file.getPath(), bfOptions);
+ if (image == null) {
+ Log.e("Cannot decode bitmap from " + file.getPath());
+ }
+ return image;
}
}
return null;
@@ -205,20 +212,14 @@ public class HtmlImage implements Html.ImageGetter {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
- FileInputStream fis = null;
+ BufferedInputStream stream = null;
try {
- fis = new FileInputStream(file);
- BitmapFactory.decodeStream(fis, null, options);
+ stream = new BufferedInputStream(new FileInputStream(file));
+ BitmapFactory.decodeStream(stream, null, options);
} catch (FileNotFoundException e) {
Log.e("HtmlImage.setSampleSize", e);
} finally {
- if (fis != null) {
- try {
- fis.close();
- } catch (IOException e) {
- // ignore
- }
- }
+ IOUtils.closeQuietly(stream);
}
int scale = 1;
diff --git a/main/src/cgeo/geocaching/network/Network.java b/main/src/cgeo/geocaching/network/Network.java
index eb6a6ac..57196c5 100644
--- a/main/src/cgeo/geocaching/network/Network.java
+++ b/main/src/cgeo/geocaching/network/Network.java
@@ -2,7 +2,7 @@ package cgeo.geocaching.network;
import cgeo.geocaching.Settings;
import cgeo.geocaching.files.LocalStorage;
-import cgeo.geocaching.utils.BaseUtils;
+import cgeo.geocaching.utils.TextUtils;
import cgeo.geocaching.utils.Log;
import ch.boye.httpclientandroidlib.Header;
@@ -40,6 +40,9 @@ import org.apache.commons.lang3.StringUtils;
import org.json.JSONException;
import org.json.JSONObject;
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
import android.net.Uri;
import java.io.File;
@@ -415,7 +418,7 @@ public abstract class Network {
private static String getResponseDataNoError(final HttpResponse response, boolean replaceWhitespace) {
try {
String data = EntityUtils.toString(response.getEntity(), CharEncoding.UTF_8);
- return replaceWhitespace ? BaseUtils.replaceWhitespace(data) : data;
+ return replaceWhitespace ? TextUtils.replaceWhitespace(data) : data;
} catch (Exception e) {
Log.e("getResponseData", e);
return null;
@@ -425,7 +428,7 @@ public abstract class Network {
/**
* Get the body of a HTTP response.
*
- * {@link BaseUtils#replaceWhitespace(String)} will be called on the result
+ * {@link TextUtils#replaceWhitespace(String)} will be called on the result
*
* @param response a HTTP response, which can be null
* @return the body if the response comes from a successful HTTP request, <code>null</code> otherwise
@@ -438,7 +441,7 @@ public abstract class Network {
* Get the body of a HTTP response.
*
* @param response a HTTP response, which can be null
- * @param replaceWhitespace <code>true</code> if {@link BaseUtils#replaceWhitespace(String)}
+ * @param replaceWhitespace <code>true</code> if {@link TextUtils#replaceWhitespace(String)}
* should be called on the body
* @return the body if the response comes from a successful HTTP request, <code>null</code> otherwise
*/
@@ -471,4 +474,19 @@ public abstract class Network {
return null;
}
+ /**
+ * Checks if the device has network connection.
+ *
+ * @param context
+ * context of the application, cannot be null
+ *
+ * @return <code>true</code> if the device is connected to the network.
+ */
+ public static boolean isNetworkConnected(Context context) {
+ ConnectivityManager conMan = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
+ NetworkInfo activeNetwork = conMan.getActiveNetworkInfo();
+
+ return activeNetwork != null && activeNetwork.isConnected();
+ }
+
}
diff --git a/main/src/cgeo/geocaching/network/OAuth.java b/main/src/cgeo/geocaching/network/OAuth.java
index 0b7a261..6740096 100644
--- a/main/src/cgeo/geocaching/network/OAuth.java
+++ b/main/src/cgeo/geocaching/network/OAuth.java
@@ -1,9 +1,9 @@
package cgeo.geocaching.network;
-import cgeo.geocaching.Settings;
import cgeo.geocaching.utils.CryptUtils;
import ch.boye.httpclientandroidlib.NameValuePair;
+
import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList;
@@ -11,9 +11,17 @@ import java.util.Date;
import java.util.List;
public class OAuth {
- public static void signOAuth(final String host, final String path, final String method, final boolean https, final Parameters params, final String token, final String tokenSecret) {
+ public static void signOAuth(final String host,
+ final String path,
+ final String method,
+ final boolean https,
+ final Parameters params,
+ final String token,
+ final String tokenSecret,
+ final String consumerKey,
+ final String consumerSecret) {
params.put(
- "oauth_consumer_key", Settings.getKeyConsumerPublic(),
+ "oauth_consumer_key", consumerKey,
"oauth_nonce", CryptUtils.md5(Long.toString(System.currentTimeMillis())),
"oauth_signature_method", "HMAC-SHA1",
"oauth_timestamp", Long.toString(new Date().getTime() / 1000),
@@ -26,7 +34,7 @@ public class OAuth {
paramsEncoded.add(nameValue.getName() + "=" + Network.rfc3986URLEncode(nameValue.getValue()));
}
- final String keysPacked = Settings.getKeyConsumerSecret() + "&" + StringUtils.defaultString(tokenSecret); // both even if empty some of them!
+ final String keysPacked = consumerSecret + "&" + StringUtils.defaultString(tokenSecret); // both even if empty some of them!
final String requestPacked = method + "&" + Network.rfc3986URLEncode((https ? "https" : "http") + "://" + host + path) + "&" + Network.rfc3986URLEncode(StringUtils.join(paramsEncoded.toArray(), '&'));
params.put("oauth_signature", CryptUtils.base64Encode(CryptUtils.hashHmac(requestPacked, keysPacked)));
}
diff --git a/main/src/cgeo/geocaching/network/OAuthAuthorizationActivity.java b/main/src/cgeo/geocaching/network/OAuthAuthorizationActivity.java
new file mode 100644
index 0000000..751443e
--- /dev/null
+++ b/main/src/cgeo/geocaching/network/OAuthAuthorizationActivity.java
@@ -0,0 +1,326 @@
+package cgeo.geocaching.network;
+
+import cgeo.geocaching.R;
+import cgeo.geocaching.activity.AbstractActivity;
+import cgeo.geocaching.utils.Log;
+import cgeo.geocaching.utils.MatcherWrapper;
+
+import ch.boye.httpclientandroidlib.client.entity.UrlEncodedFormEntity;
+import ch.boye.httpclientandroidlib.util.EntityUtils;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.tuple.ImmutablePair;
+
+import android.app.ProgressDialog;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.view.View;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.TextView;
+
+import java.util.regex.Pattern;
+
+public abstract class OAuthAuthorizationActivity extends AbstractActivity {
+
+ private String host;
+ private String pathRequest;
+ private String pathAuthorize;
+ private String pathAccess;
+ private boolean https;
+ private String consumerKey;
+ private String consumerSecret;
+ private String OAtoken = null;
+ private String OAtokenSecret = null;
+ private final Pattern paramsPattern1 = Pattern.compile("oauth_token=([a-zA-Z0-9\\-\\_.]+)");
+ private final Pattern paramsPattern2 = Pattern.compile("oauth_token_secret=([a-zA-Z0-9\\-\\_.]+)");
+ private Button startButton = null;
+ private EditText pinEntry = null;
+ private Button pinEntryButton = null;
+ private ProgressDialog requestTokenDialog = null;
+ private ProgressDialog changeTokensDialog = null;
+ private Handler requestTokenHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ if (requestTokenDialog != null && requestTokenDialog.isShowing()) {
+ requestTokenDialog.dismiss();
+ }
+
+ startButton.setOnClickListener(new StartListener());
+ startButton.setEnabled(true);
+
+ if (msg.what == 1) {
+ startButton.setText(getAuthAgain());
+
+ pinEntry.setVisibility(View.VISIBLE);
+ pinEntryButton.setVisibility(View.VISIBLE);
+ pinEntryButton.setOnClickListener(new ConfirmPINListener());
+ } else {
+ showToast(getErrAuthInitialize());
+ startButton.setText(getAuthStart());
+ }
+ }
+
+ };
+ private Handler changeTokensHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ if (changeTokensDialog != null && changeTokensDialog.isShowing()) {
+ changeTokensDialog.dismiss();
+ }
+
+ pinEntryButton.setOnClickListener(new ConfirmPINListener());
+ pinEntryButton.setEnabled(true);
+
+ if (msg.what == 1) {
+ showToast(getAuthDialogCompleted());
+
+ pinEntryButton.setVisibility(View.GONE);
+
+ finish();
+ } else {
+ showToast(getErrAuthProcess());
+
+ pinEntry.setVisibility(View.GONE);
+ pinEntryButton.setVisibility(View.GONE);
+ startButton.setText(getAuthStart());
+ }
+ }
+ };
+
+ public OAuthAuthorizationActivity(String host,
+ String pathRequest,
+ String pathAuthorize,
+ String pathAccess,
+ boolean https,
+ String consumerKey,
+ String consumerSecret) {
+ this.host = host;
+ this.pathRequest = pathRequest;
+ this.pathAuthorize = pathAuthorize;
+ this.pathAccess = pathAccess;
+ this.https = https;
+ this.consumerKey = consumerKey;
+ this.consumerSecret = consumerSecret;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState, R.layout.authorization_activity);
+
+ setTitle(getAuthTitle());
+
+ init();
+ }
+
+ private void init() {
+ startButton = (Button) findViewById(R.id.start);
+ pinEntry = (EditText) findViewById(R.id.pin);
+ pinEntryButton = (Button) findViewById(R.id.pin_button);
+
+ TextView auth = (TextView) findViewById(R.id.auth_1);
+ auth.setText(getAboutAuth1());
+ auth = (TextView) findViewById(R.id.auth_2);
+ auth.setText(getAboutAuth2());
+
+ ImmutablePair<String, String> tempToken = getTempToken();
+ OAtoken = tempToken.left;
+ OAtokenSecret = tempToken.right;
+
+ startButton.setText(getAuthAuthorize());
+ pinEntryButton.setText(getAuthFinish());
+
+ startButton.setEnabled(true);
+ startButton.setOnClickListener(new StartListener());
+
+ if (StringUtils.isBlank(OAtoken) && StringUtils.isBlank(OAtokenSecret)) {
+ // start authorization process
+ startButton.setText(getAuthStart());
+ } else {
+ // already have temporary tokens, continue from pin
+ startButton.setText(getAuthAgain());
+
+ pinEntry.setHint(getAuthPinHint());
+ pinEntry.setVisibility(View.VISIBLE);
+ pinEntryButton.setVisibility(View.VISIBLE);
+ pinEntryButton.setOnClickListener(new ConfirmPINListener());
+ }
+ }
+
+ private void requestToken() {
+
+ int status = 0;
+ try {
+ final Parameters params = new Parameters();
+ params.put("oauth_callback", "oob");
+ final String method = "GET";
+ OAuth.signOAuth(host, pathRequest, method, https, params, null, null, consumerKey, consumerSecret);
+ final String line = Network.getResponseData(Network.getRequest(getUrlPrefix() + host + pathRequest, params));
+
+ if (StringUtils.isNotBlank(line)) {
+ final MatcherWrapper paramsMatcher1 = new MatcherWrapper(paramsPattern1, line);
+ if (paramsMatcher1.find()) {
+ OAtoken = paramsMatcher1.group(1);
+ }
+ final MatcherWrapper paramsMatcher2 = new MatcherWrapper(paramsPattern2, line);
+ if (paramsMatcher2.find()) {
+ OAtokenSecret = paramsMatcher2.group(1);
+ }
+
+ if (StringUtils.isNotBlank(OAtoken) && StringUtils.isNotBlank(OAtokenSecret)) {
+ setTempTokens(OAtoken, OAtokenSecret);
+ try {
+ final Parameters paramsBrowser = new Parameters();
+ paramsBrowser.put("oauth_token", OAtoken);
+ final String encodedParams = EntityUtils.toString(new UrlEncodedFormEntity(paramsBrowser));
+ startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(getUrlPrefix() + host + pathAuthorize + "?" + encodedParams)));
+ status = 1;
+ } catch (Exception e) {
+ Log.e("OAuthAuthorizationActivity.requestToken(2)", e);
+ }
+ }
+ }
+ } catch (Exception e) {
+ Log.e("OAuthAuthorizationActivity.requestToken(1)", e);
+ }
+
+ requestTokenHandler.sendEmptyMessage(status);
+ }
+
+ private void changeToken() {
+
+ int status = 0;
+
+ try {
+ final Parameters params = new Parameters("oauth_verifier", pinEntry.getText().toString());
+
+ final String method = "POST";
+ OAuth.signOAuth(host, pathAccess, method, https, params, OAtoken, OAtokenSecret, consumerKey, consumerSecret);
+ final String line = StringUtils.defaultString(Network.getResponseData(Network.postRequest(getUrlPrefix() + host + pathAccess, params)));
+
+ OAtoken = "";
+ OAtokenSecret = "";
+
+ final MatcherWrapper paramsMatcher1 = new MatcherWrapper(paramsPattern1, line);
+ if (paramsMatcher1.find()) {
+ OAtoken = paramsMatcher1.group(1);
+ }
+ final MatcherWrapper paramsMatcher2 = new MatcherWrapper(paramsPattern2, line);
+ if (paramsMatcher2.find() && paramsMatcher2.groupCount() > 0) {
+ OAtokenSecret = paramsMatcher2.group(1);
+ }
+
+ if (StringUtils.isBlank(OAtoken) && StringUtils.isBlank(OAtokenSecret)) {
+ OAtoken = "";
+ OAtokenSecret = "";
+ setTokens(null, null, false);
+ } else {
+ setTokens(OAtoken, OAtokenSecret, true);
+ status = 1;
+ }
+ } catch (Exception e) {
+ Log.e("OAuthAuthorizationActivity.changeToken", e);
+ }
+
+ changeTokensHandler.sendEmptyMessage(status);
+ }
+
+ private String getUrlPrefix() {
+ return https ? "https://" : "http://";
+ }
+
+ private class StartListener implements View.OnClickListener {
+
+ @Override
+ public void onClick(View arg0) {
+ if (requestTokenDialog == null) {
+ requestTokenDialog = new ProgressDialog(OAuthAuthorizationActivity.this);
+ requestTokenDialog.setCancelable(false);
+ requestTokenDialog.setMessage(getAuthDialogWait());
+ }
+ requestTokenDialog.show();
+ startButton.setEnabled(false);
+ startButton.setOnTouchListener(null);
+ startButton.setOnClickListener(null);
+
+ setTempTokens(null, null);
+ (new Thread() {
+
+ @Override
+ public void run() {
+ requestToken();
+ }
+ }).start();
+ }
+ }
+
+ private class ConfirmPINListener implements View.OnClickListener {
+
+ @Override
+ public void onClick(View arg0) {
+ if (StringUtils.isEmpty(((EditText) findViewById(R.id.pin)).getText().toString())) {
+ helpDialog(getAuthDialogPinTitle(), getAuthDialogPinMessage());
+ return;
+ }
+
+ if (changeTokensDialog == null) {
+ changeTokensDialog = new ProgressDialog(OAuthAuthorizationActivity.this);
+ changeTokensDialog.setCancelable(false);
+ changeTokensDialog.setMessage(getAuthDialogWait());
+ }
+ changeTokensDialog.show();
+ pinEntryButton.setEnabled(false);
+ pinEntryButton.setOnTouchListener(null);
+ pinEntryButton.setOnClickListener(null);
+
+ (new Thread() {
+
+ @Override
+ public void run() {
+ changeToken();
+ }
+ }).start();
+ }
+ }
+
+ protected abstract ImmutablePair<String, String> getTempToken();
+
+ protected abstract void setTempTokens(String tokenPublic, String tokenSecret);
+
+ protected abstract void setTokens(String tokenPublic, String tokenSecret, boolean enable);
+
+ // get resources from derived class
+
+ protected abstract String getAuthTitle();
+
+ protected abstract String getAuthAgain();
+
+ protected abstract String getErrAuthInitialize();
+
+ protected abstract String getAuthStart();
+
+ protected abstract String getAuthDialogCompleted();
+
+ protected abstract String getErrAuthProcess();
+
+ protected abstract String getAuthDialogWait();
+
+ protected abstract String getAuthDialogPinTitle();
+
+ protected abstract String getAuthDialogPinMessage();
+
+ protected abstract String getAboutAuth1();
+
+ protected abstract String getAboutAuth2();
+
+ protected abstract String getAuthAuthorize();
+
+ protected abstract String getAuthPinHint();
+
+ protected abstract String getAuthFinish();
+}
diff --git a/main/src/cgeo/geocaching/network/StatusUpdater.java b/main/src/cgeo/geocaching/network/StatusUpdater.java
index 93ae1ee..d54f706 100644
--- a/main/src/cgeo/geocaching/network/StatusUpdater.java
+++ b/main/src/cgeo/geocaching/network/StatusUpdater.java
@@ -3,6 +3,7 @@ package cgeo.geocaching.network;
import cgeo.geocaching.cgeoapplication;
import cgeo.geocaching.utils.MemorySubject;
import cgeo.geocaching.utils.PeriodicHandler;
+import cgeo.geocaching.utils.PeriodicHandler.PeriodicHandlerListener;
import cgeo.geocaching.utils.Version;
import org.json.JSONException;
@@ -14,7 +15,7 @@ import android.os.Looper;
import java.util.Locale;
-public class StatusUpdater extends MemorySubject<StatusUpdater.Status> implements Runnable {
+public class StatusUpdater extends MemorySubject<StatusUpdater.Status> implements Runnable, PeriodicHandlerListener {
static public class Status {
final public String message;
@@ -37,7 +38,8 @@ public class StatusUpdater extends MemorySubject<StatusUpdater.Status> implement
}
}
- private void requestUpdate() {
+ @Override
+ public void onPeriodic() {
final JSONObject response =
Network.requestJSON("http://status.cgeo.org/api/status.json",
new Parameters("version_code", String.valueOf(Version.getVersionCode(cgeoapplication.getInstance())),
@@ -59,12 +61,7 @@ public class StatusUpdater extends MemorySubject<StatusUpdater.Status> implement
@Override
public void run() {
Looper.prepare();
- new PeriodicHandler(1800000L) {
- @Override
- public void act() {
- requestUpdate();
- }
- }.start();
+ new PeriodicHandler(1800000L, this).start();
Looper.loop();
}
diff --git a/main/src/cgeo/geocaching/speech/SpeechService.java b/main/src/cgeo/geocaching/speech/SpeechService.java
new file mode 100644
index 0000000..7226014
--- /dev/null
+++ b/main/src/cgeo/geocaching/speech/SpeechService.java
@@ -0,0 +1,188 @@
+package cgeo.geocaching.speech;
+
+import cgeo.geocaching.DirectionProvider;
+import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.utils.GeoDirHandler;
+import cgeo.geocaching.utils.Log;
+
+import org.apache.commons.lang3.StringUtils;
+
+import android.app.Activity;
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+import android.speech.tts.TextToSpeech;
+import android.speech.tts.TextToSpeech.OnInitListener;
+
+import java.util.Locale;
+
+/**
+ * Service to speak the compass directions.
+ *
+ */
+public class SpeechService extends Service implements OnInitListener {
+
+ private static final int SPEECH_MINPAUSE_SECONDS = 5;
+ private static final int SPEECH_MAXPAUSE_SECONDS = 30;
+ private static final String EXTRA_TARGET_COORDS = "target";
+ private static Activity startingActivity;
+ private static boolean isRunning = false;
+ /**
+ * Text to speech API of Android
+ */
+ private TextToSpeech tts;
+ /**
+ * TTS has been initialized and we can speak.
+ */
+ private boolean initialized = false;
+ protected float direction;
+ protected Geopoint position;
+ protected boolean directionInitialized;
+ protected boolean positionInitialized;
+
+ GeoDirHandler geoHandler = new GeoDirHandler() {
+ @Override
+ protected void updateDirection(float newDirection) {
+ direction = DirectionProvider.getDirectionNow(startingActivity, newDirection);
+ directionInitialized = true;
+ updateCompass();
+ }
+
+ @Override
+ protected void updateGeoData(cgeo.geocaching.IGeoData newGeo) {
+ position = newGeo.getCoords();
+ positionInitialized = true;
+ if (newGeo.getSpeed() > 5) {
+ direction = newGeo.getBearing();
+ directionInitialized = true;
+ }
+ updateCompass();
+ }
+ };
+ /**
+ * remember when we talked the last time
+ */
+ private long lastSpeechTime = 0;
+ private float lastSpeechDistance = 0.0f;
+ private Geopoint target;
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+
+ protected void updateCompass() {
+ // make sure we have both sensor values before talking
+ if (!positionInitialized || !directionInitialized) {
+ return;
+ }
+
+ // avoid any calculation, if the delay since the last output is not long enough
+ final long now = System.currentTimeMillis();
+ if (now - lastSpeechTime <= SPEECH_MINPAUSE_SECONDS * 1000) {
+ return;
+ }
+
+ // to speak, we want max pause to have elapsed or distance to geopoint to have changed by a given amount
+ final float distance = position.distanceTo(target);
+ if (now - lastSpeechTime <= SPEECH_MAXPAUSE_SECONDS * 1000) {
+ if (Math.abs(lastSpeechDistance - distance) < getDeltaForDistance(distance)) {
+ return;
+ }
+ }
+
+ final String text = TextFactory.getText(position, target, direction);
+ if (StringUtils.isNotEmpty(text)) {
+ lastSpeechTime = System.currentTimeMillis();
+ lastSpeechDistance = distance;
+ speak(text);
+ }
+ }
+
+ /**
+ * Return distance required to be moved based on overall distance.<br>
+ *
+ * @param distance
+ * in km
+ * @return delta in km
+ */
+ private static float getDeltaForDistance(final float distance) {
+ if (distance > 1.0) {
+ return 0.2f;
+ } else if (distance > 0.05) {
+ return distance / 5.0f;
+ }
+
+ return 0f;
+ }
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ tts = new TextToSpeech(this, this);
+ }
+
+ @Override
+ public void onDestroy() {
+ geoHandler.stopGeoAndDir();
+ if (tts != null) {
+ tts.stop();
+ tts.shutdown();
+ }
+ super.onDestroy();
+ }
+
+ @Override
+ public void onInit(int status) {
+ // The text to speech system takes some time to initialize.
+ if (status != TextToSpeech.SUCCESS) {
+ Log.e("Text to speech cannot be initialized.");
+ return;
+ }
+
+ int switchLocale = tts.setLanguage(Locale.getDefault());
+
+ if (switchLocale == TextToSpeech.LANG_MISSING_DATA
+ || switchLocale == TextToSpeech.LANG_NOT_SUPPORTED) {
+ Log.e("Current languge not supported by text to speech.");
+ return;
+ }
+
+ initialized = true;
+
+ geoHandler.startGeoAndDir();
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ if (intent != null) {
+ target = intent.getParcelableExtra(EXTRA_TARGET_COORDS);
+ }
+ return START_NOT_STICKY;
+ }
+
+ private void speak(final String text) {
+ if (!initialized) {
+ return;
+ }
+ tts.speak(text, TextToSpeech.QUEUE_FLUSH, null);
+ }
+
+ public static void startService(final Activity activity, Geopoint dstCoords) {
+ isRunning = true;
+ startingActivity = activity;
+ Intent talkingService = new Intent(activity, SpeechService.class);
+ talkingService.putExtra(EXTRA_TARGET_COORDS, dstCoords);
+ activity.startService(talkingService);
+ }
+
+ public static void stopService(final Activity activity) {
+ isRunning = false;
+ activity.stopService(new Intent(activity, SpeechService.class));
+ }
+
+ public static boolean isRunning() {
+ return isRunning;
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/speech/TextFactory.java b/main/src/cgeo/geocaching/speech/TextFactory.java
new file mode 100644
index 0000000..d4f3a48
--- /dev/null
+++ b/main/src/cgeo/geocaching/speech/TextFactory.java
@@ -0,0 +1,101 @@
+package cgeo.geocaching.speech;
+
+import cgeo.geocaching.R;
+import cgeo.geocaching.Settings;
+import cgeo.geocaching.cgeoapplication;
+import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.geopoint.IConversion;
+import cgeo.geocaching.utils.AngleUtils;
+
+import java.util.Locale;
+
+/**
+ * Creates the output to be read by TTS.
+ *
+ */
+public class TextFactory {
+ public static String getText(Geopoint position, Geopoint target, float direction) {
+ if (position == null || target == null) {
+ return null;
+ }
+ return getDirection(position, target, direction) + ". " + getDistance(position, target);
+ }
+
+ private static String getDistance(Geopoint position, Geopoint target) {
+ float kilometers = position.distanceTo(target);
+
+ if (Settings.isUseMetricUnits()) {
+ return getDistance(kilometers, (int) (kilometers * 1000.0),
+ 5.0f, 1.0f, 50,
+ R.plurals.tts_kilometers, R.string.tts_one_kilometer,
+ R.plurals.tts_meters, R.string.tts_one_meter);
+ }
+ return getDistance(kilometers / IConversion.MILES_TO_KILOMETER,
+ (int) (kilometers * 1000.0 * IConversion.METERS_TO_FEET),
+ 3.0f, 0.2f, 300,
+ R.plurals.tts_miles, R.string.tts_one_mile,
+ R.plurals.tts_feet, R.string.tts_one_foot);
+ }
+
+ private static String getDistance(float farDistance, int nearDistance,
+ float farFarAway, float farNearAway, int nearFarAway,
+ int farId, int farOneId, int nearId, int nearOneId) {
+ if (farDistance >= farFarAway) {
+ // example: "5 kilometers" - always without decimal digits
+ int quantity = Math.round(farDistance);
+ if (quantity == 1) {
+ return getString(farOneId, quantity, String.valueOf(quantity));
+ }
+ return getQuantityString(farId, quantity, String.valueOf(quantity));
+ }
+ if (farDistance >= farNearAway) {
+ // example: "2.2 kilometers" - decimals if necessary
+ float precision1 = Math.round(farDistance * 10.0f) / 10.0f;
+ float precision0 = Math.round(farDistance);
+ if (precision1 == precision0) {
+ // this is an int - e.g. 2 kilometers
+ int quantity = (int) precision0;
+ if (quantity == 1) {
+ return getString(farOneId, quantity, String.valueOf(quantity));
+ }
+ return getQuantityString(farId, quantity, String.valueOf(quantity));
+ }
+ // this is no int - e.g. 1.7 kilometers
+ String digits = String.format(Locale.getDefault(), "%.1f", farDistance);
+ // always use the plural (9 leads to plural)
+ return getQuantityString(farId, 9, digits);
+ }
+ // example: "34 meters"
+ int quantity = nearDistance;
+ if (quantity > nearFarAway) {
+ // example: "120 meters" - rounded to 10 meters
+ quantity = (int) Math.round(quantity / 10.0) * 10;
+ }
+ if (quantity == 1) {
+ return getString(nearOneId, quantity, String.valueOf(quantity));
+ }
+ return getQuantityString(nearId, quantity, String.valueOf(quantity));
+ }
+
+ private static String getString(int resourceId, Object... formatArgs) {
+ return cgeoapplication.getInstance().getString(resourceId, formatArgs);
+ }
+
+ private static String getQuantityString(int resourceId, int quantity, Object... formatArgs) {
+ return cgeoapplication.getInstance().getResources().getQuantityString(resourceId, quantity, formatArgs);
+ }
+
+ private static String getDirection(Geopoint position, Geopoint target, float direction) {
+ final int bearing = (int) position.bearingTo(target);
+ int degrees = (int) AngleUtils.normalize(bearing - direction);
+
+ int hours = (degrees + 15) / 30;
+ if (hours == 0) {
+ hours = 12;
+ }
+ if (hours == 1) {
+ return getString(R.string.tts_one_oclock, String.valueOf(hours));
+ }
+ return getString(R.string.tts_oclock, String.valueOf(hours));
+ }
+}
diff --git a/main/src/cgeo/geocaching/twitter/Twitter.java b/main/src/cgeo/geocaching/twitter/Twitter.java
index f30830e..3f1f749 100644
--- a/main/src/cgeo/geocaching/twitter/Twitter.java
+++ b/main/src/cgeo/geocaching/twitter/Twitter.java
@@ -15,7 +15,10 @@ import cgeo.geocaching.utils.Log;
import ch.boye.httpclientandroidlib.HttpResponse;
+import org.apache.commons.lang3.StringUtils;
+
public final class Twitter {
+ private static final String HASH_PREFIX_WITH_BLANK = " #";
public static final int MAX_TWEET_SIZE = 140;
public static void postTweet(final cgeoapplication app, final String status, final Geopoint coords) {
@@ -35,7 +38,7 @@ public final class Twitter {
"display_coordinates", "true");
}
- OAuth.signOAuth("api.twitter.com", "/1/statuses/update.json", "POST", false, parameters, Settings.getTokenPublic(), Settings.getTokenSecret());
+ OAuth.signOAuth("api.twitter.com", "/1/statuses/update.json", "POST", false, parameters, Settings.getTokenPublic(), Settings.getTokenSecret(), Settings.getKeyConsumerPublic(), Settings.getKeyConsumerSecret());
final HttpResponse httpResponse = Network.postRequest("http://api.twitter.com/1/statuses/update.json", parameters);
if (httpResponse != null && httpResponse.getStatusLine().getStatusCode() == 200) {
Log.i("Tweet posted");
@@ -43,53 +46,60 @@ public final class Twitter {
Log.e("Tweet could not be posted");
}
} catch (Exception e) {
- Log.e("cgBase.postTweet", e);
+ Log.e("Twitter.postTweet", e);
}
}
- public static String appendHashTag(final String status, final String tag) {
- String result = status;
- if (result.length() + 2 + tag.length() <= 140) {
- result += " #" + tag;
+ public static void appendHashTag(final StringBuilder status, final String tag) {
+ if (status.length() + HASH_PREFIX_WITH_BLANK.length() + tag.length() <= MAX_TWEET_SIZE) {
+ final String tagWithPrefix = HASH_PREFIX_WITH_BLANK + tag;
+ if (status.indexOf(tagWithPrefix, 0) == -1) {
+ status.append(tagWithPrefix);
+ }
}
- return result;
}
public static void postTweetCache(String geocode) {
- final Geocache cache = cgData.loadCache(geocode, LoadFlags.LOAD_CACHE_OR_DB);
- String status;
- final String url = cache.getUrl();
- if (url.length() >= 100) {
- status = "I found " + url;
+ if (!Settings.isUseTwitter()) {
+ return;
}
- else {
- String name = cache.getName();
- status = "I found " + name + " (" + url + ")";
- if (status.length() > MAX_TWEET_SIZE) {
- name = name.substring(0, name.length() - (status.length() - MAX_TWEET_SIZE) - 1) + '…';
- }
- status = "I found " + name + " (" + url + ")";
- status = appendHashTag(status, "cgeo");
- status = appendHashTag(status, "geocaching");
+ if (!Settings.isTwitterLoginValid()) {
+ return;
}
+ final Geocache cache = cgData.loadCache(geocode, LoadFlags.LOAD_CACHE_OR_DB);
+ postTweet(cgeoapplication.getInstance(), getStatusMessage(cache), null);
+ }
+
+ static String getStatusMessage(Geocache cache) {
+ String name = cache.getName();
+ if (name.length() > 100) {
+ name = name.substring(0, 100) + '…';
+ }
+ final String url = StringUtils.defaultString(cache.getUrl());
+ return fillTemplate(Settings.getCacheTwitterMessage(), name, url);
+ }
- postTweet(cgeoapplication.getInstance(), status, null);
+ private static String fillTemplate(String template, String name, final String url) {
+ String result = StringUtils.replace(template, "[NAME]", name);
+ result = StringUtils.replace(result, "[URL]", url);
+ StringBuilder builder = new StringBuilder(result);
+ appendHashTag(builder, "cgeo");
+ appendHashTag(builder, "geocaching");
+ return builder.toString();
}
public static void postTweetTrackable(String geocode) {
final Trackable trackable = cgData.loadTrackable(geocode);
+ postTweet(cgeoapplication.getInstance(), getStatusMessage(trackable), null);
+ }
+
+ static String getStatusMessage(Trackable trackable) {
String name = trackable.getName();
if (name.length() > 82) {
name = name.substring(0, 81) + '…';
}
- StringBuilder builder = new StringBuilder("I touched ");
- builder.append(name);
- if (trackable.getUrl() != null) {
- builder.append(" (").append(trackable.getUrl()).append(')');
- }
- builder.append('!');
- String status = appendHashTag(builder.toString(), "cgeo");
- status = appendHashTag(status, "geocaching");
- postTweet(cgeoapplication.getInstance(), status, null);
+ String url = StringUtils.defaultString(trackable.getUrl());
+ String status = Settings.getTrackableTwitterMessage();
+ return fillTemplate(status, name, url);
}
}
diff --git a/main/src/cgeo/geocaching/twitter/TwitterAuthorizationActivity.java b/main/src/cgeo/geocaching/twitter/TwitterAuthorizationActivity.java
index 3d9f283..7146a62 100644
--- a/main/src/cgeo/geocaching/twitter/TwitterAuthorizationActivity.java
+++ b/main/src/cgeo/geocaching/twitter/TwitterAuthorizationActivity.java
@@ -2,268 +2,105 @@ package cgeo.geocaching.twitter;
import cgeo.geocaching.R;
import cgeo.geocaching.Settings;
-import cgeo.geocaching.activity.AbstractActivity;
-import cgeo.geocaching.network.Network;
-import cgeo.geocaching.network.OAuth;
-import cgeo.geocaching.network.Parameters;
-import cgeo.geocaching.utils.Log;
-import cgeo.geocaching.utils.MatcherWrapper;
+import cgeo.geocaching.network.OAuthAuthorizationActivity;
-import ch.boye.httpclientandroidlib.client.entity.UrlEncodedFormEntity;
-import ch.boye.httpclientandroidlib.util.EntityUtils;
-
-import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
-import android.app.ProgressDialog;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.view.View;
-import android.widget.Button;
-import android.widget.EditText;
-
-import java.util.regex.Pattern;
-
-public class TwitterAuthorizationActivity extends AbstractActivity {
- private String OAtoken = null;
- private String OAtokenSecret = null;
- private final Pattern paramsPattern1 = Pattern.compile("oauth_token=([a-zA-Z0-9\\-\\_.]+)");
- private final Pattern paramsPattern2 = Pattern.compile("oauth_token_secret=([a-zA-Z0-9\\-\\_.]+)");
- private Button startButton = null;
- private EditText pinEntry = null;
- private Button pinEntryButton = null;
- private ProgressDialog requestTokenDialog = null;
- private ProgressDialog changeTokensDialog = null;
- private Handler requestTokenHandler = new Handler() {
-
- @Override
- public void handleMessage(Message msg) {
- if (requestTokenDialog != null && requestTokenDialog.isShowing()) {
- requestTokenDialog.dismiss();
- }
-
- startButton.setOnClickListener(new StartListener());
- startButton.setEnabled(true);
-
- if (msg.what == 1) {
- startButton.setText(res.getString(R.string.auth_again));
-
- pinEntry.setVisibility(View.VISIBLE);
- pinEntryButton.setVisibility(View.VISIBLE);
- pinEntryButton.setOnClickListener(new ConfirmPINListener());
- } else {
- showToast(res.getString(R.string.err_auth_initialize));
- startButton.setText(res.getString(R.string.auth_start));
- }
- }
- };
- private Handler changeTokensHandler = new Handler() {
+public class TwitterAuthorizationActivity extends OAuthAuthorizationActivity {
- @Override
- public void handleMessage(Message msg) {
- if (changeTokensDialog != null && changeTokensDialog.isShowing()) {
- changeTokensDialog.dismiss();
- }
-
- pinEntryButton.setOnClickListener(new ConfirmPINListener());
- pinEntryButton.setEnabled(true);
-
- if (msg.what == 1) {
- showToast(res.getString(R.string.auth_dialog_completed));
-
- pinEntryButton.setVisibility(View.GONE);
-
- finish();
- } else {
- showToast(res.getString(R.string.err_auth_process));
-
- pinEntry.setVisibility(View.GONE);
- pinEntryButton.setVisibility(View.GONE);
- startButton.setText(res.getString(R.string.auth_start));
- }
- }
- };
+ public TwitterAuthorizationActivity() {
+ super("api.twitter.com",
+ "/oauth/request_token",
+ "/oauth/authorize",
+ "/oauth/access_token",
+ true,
+ Settings.getKeyConsumerPublic(),
+ Settings.getKeyConsumerSecret());
+ }
@Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- setTheme();
- setContentView(R.layout.twitter_authorization_activity);
- setTitle(res.getString(R.string.auth_twitter));
-
- init();
+ protected ImmutablePair<String, String> getTempToken() {
+ return Settings.getTempToken();
}
@Override
- public void onResume() {
- super.onResume();
-
+ protected void setTempTokens(String tokenPublic, String tokenSecret) {
+ Settings.setTwitterTempTokens(tokenPublic, tokenSecret);
}
- private void init() {
- startButton = (Button) findViewById(R.id.start);
- pinEntry = (EditText) findViewById(R.id.pin);
- pinEntryButton = (Button) findViewById(R.id.pin_button);
-
- ImmutablePair<String, String> tempToken = Settings.getTempToken();
- OAtoken = tempToken.left;
- OAtokenSecret = tempToken.right;
-
- startButton.setEnabled(true);
- startButton.setOnClickListener(new StartListener());
-
- if (StringUtils.isBlank(OAtoken) && StringUtils.isBlank(OAtokenSecret)) {
- // start authorization process
- startButton.setText(res.getString(R.string.auth_start));
- } else {
- // already have temporary tokens, continue from pin
- startButton.setText(res.getString(R.string.auth_again));
-
- pinEntry.setVisibility(View.VISIBLE);
- pinEntryButton.setVisibility(View.VISIBLE);
- pinEntryButton.setOnClickListener(new ConfirmPINListener());
- }
+ @Override
+ protected void setTokens(String tokenPublic, String tokenSecret, boolean enable) {
+ Settings.setTwitterTokens(tokenPublic, tokenSecret, enable);
}
- private void requestToken() {
-
- int status = 0;
- try {
- final Parameters params = new Parameters();
- final String method = "GET";
- final String pathRequest = "/oauth/request_token";
- final String host = "api.twitter.com";
- OAuth.signOAuth(host, pathRequest, method, true, params, null, null);
- final String line = Network.getResponseData(Network.getRequest("https://" + host + pathRequest, params));
-
-
- if (StringUtils.isNotBlank(line)) {
- final MatcherWrapper paramsMatcher1 = new MatcherWrapper(paramsPattern1, line);
- if (paramsMatcher1.find()) {
- OAtoken = paramsMatcher1.group(1);
- }
- final MatcherWrapper paramsMatcher2 = new MatcherWrapper(paramsPattern2, line);
- if (paramsMatcher2.find()) {
- OAtokenSecret = paramsMatcher2.group(1);
- }
-
- if (StringUtils.isNotBlank(OAtoken) && StringUtils.isNotBlank(OAtokenSecret)) {
- Settings.setTwitterTempTokens(OAtoken, OAtokenSecret);
- try {
- final Parameters paramsBrowser = new Parameters();
- paramsBrowser.put("oauth_callback", "oob");
- final String pathAuthorize = "/oauth/authorize";
- OAuth.signOAuth(host, pathAuthorize, "GET", true, paramsBrowser, OAtoken, OAtokenSecret);
- final String encodedParams = EntityUtils.toString(new UrlEncodedFormEntity(paramsBrowser));
- startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://" + host + pathAuthorize + "?" + encodedParams)));
- status = 1;
- } catch (Exception e) {
- Log.e("TwitterAuthorizationActivity.requestToken(2)", e);
- }
- }
- }
- } catch (Exception e) {
- Log.e("TwitterAuthorizationActivity.requestToken(1)", e);
- }
-
- requestTokenHandler.sendEmptyMessage(status);
+ @Override
+ protected String getAuthTitle() {
+ return res.getString(R.string.auth_twitter);
}
- private void changeToken() {
-
- int status = 0;
-
- try {
- final Parameters params = new Parameters("oauth_verifier", pinEntry.getText().toString());
-
- final String method = "POST";
- final String path = "/oauth/access_token";
- final String host = "api.twitter.com";
- OAuth.signOAuth(host, path, method, true, params, OAtoken, OAtokenSecret);
- final String line = StringUtils.defaultString(Network.getResponseData(Network.postRequest("https://" + host + path, params)));
-
- OAtoken = "";
- OAtokenSecret = "";
+ @Override
+ protected String getAuthAgain() {
+ return res.getString(R.string.auth_again);
+ }
- final MatcherWrapper paramsMatcher1 = new MatcherWrapper(paramsPattern1, line);
- if (paramsMatcher1.find()) {
- OAtoken = paramsMatcher1.group(1);
- }
- final MatcherWrapper paramsMatcher2 = new MatcherWrapper(paramsPattern2, line);
- if (paramsMatcher2.find() && paramsMatcher2.groupCount() > 0) {
- OAtokenSecret = paramsMatcher2.group(1);
- }
+ @Override
+ protected String getErrAuthInitialize() {
+ return res.getString(R.string.err_auth_initialize);
+ }
- if (StringUtils.isBlank(OAtoken) && StringUtils.isBlank(OAtokenSecret)) {
- OAtoken = "";
- OAtokenSecret = "";
- Settings.setTwitterTokens(null, null, false);
- } else {
- Settings.setTwitterTokens(OAtoken, OAtokenSecret, true);
- status = 1;
- }
- } catch (Exception e) {
- Log.e("TwitterAuthorizationActivity.changeToken", e);
- }
+ @Override
+ protected String getAuthStart() {
+ return res.getString(R.string.auth_start);
+ }
- changeTokensHandler.sendEmptyMessage(status);
+ @Override
+ protected String getAuthDialogCompleted() {
+ return res.getString(R.string.auth_dialog_completed);
}
- private class StartListener implements View.OnClickListener {
+ @Override
+ protected String getErrAuthProcess() {
+ return res.getString(R.string.err_auth_process);
+ }
- @Override
- public void onClick(View arg0) {
- if (requestTokenDialog == null) {
- requestTokenDialog = new ProgressDialog(TwitterAuthorizationActivity.this);
- requestTokenDialog.setCancelable(false);
- requestTokenDialog.setMessage(res.getString(R.string.auth_dialog_wait));
- }
- requestTokenDialog.show();
- startButton.setEnabled(false);
- startButton.setOnTouchListener(null);
- startButton.setOnClickListener(null);
+ @Override
+ protected String getAuthDialogWait() {
+ return res.getString(R.string.auth_dialog_wait);
+ }
- Settings.setTwitterTempTokens(null, null);
- (new Thread() {
+ @Override
+ protected String getAuthDialogPinTitle() {
+ return res.getString(R.string.auth_dialog_pin_title);
+ }
- @Override
- public void run() {
- requestToken();
- }
- }).start();
- }
+ @Override
+ protected String getAuthDialogPinMessage() {
+ return res.getString(R.string.auth_dialog_pin_message);
}
- private class ConfirmPINListener implements View.OnClickListener {
+ @Override
+ protected String getAboutAuth1() {
+ return res.getString(R.string.about_auth_1);
+ }
- @Override
- public void onClick(View arg0) {
- if (StringUtils.isEmpty(((EditText) findViewById(R.id.pin)).getText().toString())) {
- helpDialog(res.getString(R.string.auth_dialog_pin_title), res.getString(R.string.auth_dialog_pin_message));
- return;
- }
+ @Override
+ protected String getAboutAuth2() {
+ return res.getString(R.string.about_auth_2);
+ }
- if (changeTokensDialog == null) {
- changeTokensDialog = new ProgressDialog(TwitterAuthorizationActivity.this);
- changeTokensDialog.setCancelable(false);
- changeTokensDialog.setMessage(res.getString(R.string.auth_dialog_wait));
- }
- changeTokensDialog.show();
- pinEntryButton.setEnabled(false);
- pinEntryButton.setOnTouchListener(null);
- pinEntryButton.setOnClickListener(null);
+ @Override
+ protected String getAuthAuthorize() {
+ return res.getString(R.string.auth_authorize);
+ }
- (new Thread() {
+ @Override
+ protected String getAuthPinHint() {
+ return res.getString(R.string.auth_pin_hint);
+ }
- @Override
- public void run() {
- changeToken();
- }
- }).start();
- }
+ @Override
+ protected String getAuthFinish() {
+ return res.getString(R.string.auth_finish);
}
+
}
diff --git a/main/src/cgeo/geocaching/ui/AbstractUserClickListener.java b/main/src/cgeo/geocaching/ui/AbstractUserClickListener.java
new file mode 100644
index 0000000..b5e5c9a
--- /dev/null
+++ b/main/src/cgeo/geocaching/ui/AbstractUserClickListener.java
@@ -0,0 +1,77 @@
+package cgeo.geocaching.ui;
+
+import cgeo.geocaching.Geocache;
+import cgeo.geocaching.R;
+import cgeo.geocaching.cgeocaches;
+import cgeo.geocaching.activity.AbstractActivity;
+import cgeo.geocaching.network.Network;
+
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.net.Uri;
+import android.view.View;
+
+abstract class AbstractUserClickListener implements View.OnClickListener {
+
+ protected final Geocache cache;
+
+ public AbstractUserClickListener(final Geocache cache) {
+ this.cache = cache;
+ }
+
+ @Override
+ public void onClick(View view) {
+ if (view == null) {
+ return;
+ }
+ if (!cache.supportsUserActions()) {
+ return;
+ }
+
+ showUserActionsDialog(getUserName(view), view);
+ }
+
+ protected abstract CharSequence getUserName(View view);
+
+ /**
+ * Opens a dialog to do actions on an user name
+ */
+ protected static void showUserActionsDialog(final CharSequence name, final View view) {
+ final AbstractActivity context = (AbstractActivity) view.getContext();
+ final Resources res = context.getResources();
+ final CharSequence[] items = { res.getString(R.string.user_menu_view_hidden),
+ res.getString(R.string.user_menu_view_found),
+ res.getString(R.string.user_menu_open_browser),
+ res.getString(R.string.user_menu_send_message)
+ };
+
+ final AlertDialog.Builder builder = new AlertDialog.Builder(context);
+ builder.setTitle(res.getString(R.string.user_menu_title) + " " + name);
+ builder.setItems(items, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int item) {
+ switch (item) {
+ case 0:
+ cgeocaches.startActivityOwner(context, name.toString());
+ return;
+ case 1:
+ cgeocaches.startActivityUserName(context, name.toString());
+ return;
+ case 2:
+ context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.geocaching.com/profile/?u=" + Network.encode(name.toString()))));
+ return;
+ case 3:
+ context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.geocaching.com/email/?u=" + Network.encode(name.toString()))));
+ return;
+ default:
+ break;
+ }
+ }
+ });
+ final AlertDialog alert = builder.create();
+ alert.show();
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/ui/AbstractViewHolder.java b/main/src/cgeo/geocaching/ui/AbstractViewHolder.java
new file mode 100644
index 0000000..cc5cd4d
--- /dev/null
+++ b/main/src/cgeo/geocaching/ui/AbstractViewHolder.java
@@ -0,0 +1,19 @@
+package cgeo.geocaching.ui;
+
+import butterknife.Views;
+
+import android.view.View;
+
+/**
+ * Abstract super class for all view holders. It is responsible for the invocation of the view injection code and for
+ * the tagging of views.
+ *
+ */
+public abstract class AbstractViewHolder {
+
+ protected AbstractViewHolder(View view) {
+ Views.inject(this, view);
+ view.setTag(this);
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/ui/AddressListAdapter.java b/main/src/cgeo/geocaching/ui/AddressListAdapter.java
index eb8b516..736c036 100644
--- a/main/src/cgeo/geocaching/ui/AddressListAdapter.java
+++ b/main/src/cgeo/geocaching/ui/AddressListAdapter.java
@@ -1,5 +1,7 @@
package cgeo.geocaching.ui;
+import butterknife.InjectView;
+
import cgeo.geocaching.R;
import cgeo.geocaching.cgeoapplication;
import cgeo.geocaching.cgeocaches;
@@ -24,9 +26,13 @@ public class AddressListAdapter extends ArrayAdapter<Address> {
final private LayoutInflater inflater;
final private Geopoint location;
- private static final class ViewHolder {
- TextView label;
- TextView distance;
+ protected static final class ViewHolder extends AbstractViewHolder {
+ @InjectView(R.id.label) protected TextView label;
+ @InjectView(R.id.distance) protected TextView distance;
+
+ public ViewHolder(View view) {
+ super(view);
+ }
}
public AddressListAdapter(final Context context) {
@@ -44,13 +50,8 @@ public class AddressListAdapter extends ArrayAdapter<Address> {
// holder pattern implementation
final ViewHolder holder;
if (view == null) {
- view = inflater.inflate(R.layout.addresses_item, null);
-
- holder = new ViewHolder();
- holder.label = (TextView) view.findViewById(R.id.label);
- holder.distance = (TextView) view.findViewById(R.id.distance);
-
- view.setTag(holder);
+ view = inflater.inflate(R.layout.addresslist_item, null);
+ holder = new ViewHolder(view);
} else {
holder = (ViewHolder) view.getTag();
}
diff --git a/main/src/cgeo/geocaching/ui/CacheDetailsCreator.java b/main/src/cgeo/geocaching/ui/CacheDetailsCreator.java
index e98bd77..9059a6b 100644
--- a/main/src/cgeo/geocaching/ui/CacheDetailsCreator.java
+++ b/main/src/cgeo/geocaching/ui/CacheDetailsCreator.java
@@ -2,6 +2,7 @@ package cgeo.geocaching.ui;
import cgeo.geocaching.Geocache;
import cgeo.geocaching.R;
+import cgeo.geocaching.Waypoint;
import cgeo.geocaching.cgeoapplication;
import cgeo.geocaching.geopoint.Geopoint;
import cgeo.geocaching.geopoint.Units;
@@ -67,7 +68,7 @@ public final class CacheDetailsCreator {
final LayoutInflater inflater = LayoutInflater.from(activity);
for (int i = 0; i < 5; i++) {
- ImageView star = (ImageView) inflater.inflate(R.layout.star, null);
+ ImageView star = (ImageView) inflater.inflate(R.layout.star_image, null);
if (value - i >= 0.75) {
star.setImageResource(R.drawable.star_on);
} else if (value - i >= 0.25) {
@@ -154,4 +155,24 @@ public final class CacheDetailsCreator {
}
add(R.string.cache_distance, text);
}
+
+ public void addDistance(final Waypoint wpt, final TextView waypointDistanceView) {
+ Float distance = null;
+ if (wpt.getCoords() != null) {
+ final Geopoint currentCoords = cgeoapplication.getInstance().currentGeo().getCoords();
+ if (currentCoords != null) {
+ distance = currentCoords.distanceTo(wpt);
+ }
+ }
+ String text = "--";
+ if (distance != null) {
+ text = Units.getDistanceFromKilometers(distance);
+ }
+ else if (waypointDistanceView != null) {
+ // if there is already a distance in waypointDistance, use it instead of resetting to default.
+ // this prevents displaying "--" while waiting for a new position update (See bug #1468)
+ text = waypointDistanceView.getText().toString();
+ }
+ add(R.string.cache_distance, text);
+ }
}
diff --git a/main/src/cgeo/geocaching/ui/CacheListAdapter.java b/main/src/cgeo/geocaching/ui/CacheListAdapter.java
index 42b774e..d95363e 100644
--- a/main/src/cgeo/geocaching/ui/CacheListAdapter.java
+++ b/main/src/cgeo/geocaching/ui/CacheListAdapter.java
@@ -1,5 +1,7 @@
package cgeo.geocaching.ui;
+import butterknife.InjectView;
+
import cgeo.geocaching.CacheDetailActivity;
import cgeo.geocaching.Geocache;
import cgeo.geocaching.IGeoData;
@@ -77,13 +79,13 @@ public class CacheListAdapter extends ArrayAdapter<Geocache> {
private static final int[] RATING_BACKGROUND = new int[3];
static {
if (Settings.isLightSkin()) {
- RATING_BACKGROUND[0] = R.drawable.favourite_background_red_light;
- RATING_BACKGROUND[1] = R.drawable.favourite_background_orange_light;
- RATING_BACKGROUND[2] = R.drawable.favourite_background_green_light;
+ RATING_BACKGROUND[0] = R.drawable.favorite_background_red_light;
+ RATING_BACKGROUND[1] = R.drawable.favorite_background_orange_light;
+ RATING_BACKGROUND[2] = R.drawable.favorite_background_green_light;
} else {
- RATING_BACKGROUND[0] = R.drawable.favourite_background_red_dark;
- RATING_BACKGROUND[1] = R.drawable.favourite_background_orange_dark;
- RATING_BACKGROUND[2] = R.drawable.favourite_background_green_dark;
+ RATING_BACKGROUND[0] = R.drawable.favorite_background_red_dark;
+ RATING_BACKGROUND[1] = R.drawable.favorite_background_orange_dark;
+ RATING_BACKGROUND[2] = R.drawable.favorite_background_green_dark;
}
}
@@ -91,16 +93,20 @@ public class CacheListAdapter extends ArrayAdapter<Geocache> {
* view holder for the cache list adapter
*
*/
- private static class ViewHolder {
- CheckBox checkbox;
- ImageView logStatusMark;
- TextView text;
- TextView favourite;
- TextView info;
- ImageView inventory;
- DistanceView distance;
- CompassMiniView direction;
- ImageView dirImg;
+ protected static class ViewHolder extends AbstractViewHolder {
+ @InjectView(R.id.checkbox) protected CheckBox checkbox;
+ @InjectView(R.id.log_status_mark) protected ImageView logStatusMark;
+ @InjectView(R.id.text) protected TextView text;
+ @InjectView(R.id.distance) protected DistanceView distance;
+ @InjectView(R.id.favorite) protected TextView favorite;
+ @InjectView(R.id.info) protected TextView info;
+ @InjectView(R.id.inventory) protected ImageView inventory;
+ @InjectView(R.id.direction) protected CompassMiniView direction;
+ @InjectView(R.id.dirimg) protected ImageView dirImg;
+
+ public ViewHolder(View view) {
+ super(view);
+ }
}
public CacheListAdapter(final Activity activity, final List<Geocache> list, CacheListType cacheListType) {
@@ -348,20 +354,9 @@ public class CacheListAdapter extends ArrayAdapter<Geocache> {
final ViewHolder holder;
if (v == null) {
- v = inflater.inflate(R.layout.caches_item, null);
-
- holder = new ViewHolder();
- holder.checkbox = (CheckBox) v.findViewById(R.id.checkbox);
- holder.logStatusMark = (ImageView) v.findViewById(R.id.log_status_mark);
- holder.text = (TextView) v.findViewById(R.id.text);
- holder.distance = (DistanceView) v.findViewById(R.id.distance);
- holder.direction = (CompassMiniView) v.findViewById(R.id.direction);
- holder.dirImg = (ImageView) v.findViewById(R.id.dirimg);
- holder.inventory = (ImageView) v.findViewById(R.id.inventory);
- holder.favourite = (TextView) v.findViewById(R.id.favourite);
- holder.info = (TextView) v.findViewById(R.id.info);
-
- v.setTag(holder);
+ v = inflater.inflate(R.layout.cacheslist_item, null);
+
+ holder = new ViewHolder(v);
} else {
holder = (ViewHolder) v.getTag();
}
@@ -453,14 +448,14 @@ public class CacheListAdapter extends ArrayAdapter<Geocache> {
holder.direction.setVisibility(View.GONE);
}
- holder.favourite.setText(Integer.toString(cache.getFavoritePoints()));
+ holder.favorite.setText(Integer.toString(cache.getFavoritePoints()));
int favoriteBack;
// set default background, neither vote nor rating may be available
if (lightSkin) {
- favoriteBack = R.drawable.favourite_background_light;
+ favoriteBack = R.drawable.favorite_background_light;
} else {
- favoriteBack = R.drawable.favourite_background_dark;
+ favoriteBack = R.drawable.favorite_background_dark;
}
final float myVote = cache.getMyVote();
if (myVote > 0) { // use my own rating for display, if I have voted
@@ -481,7 +476,7 @@ public class CacheListAdapter extends ArrayAdapter<Geocache> {
favoriteBack = RATING_BACKGROUND[0];
}
}
- holder.favourite.setBackgroundResource(favoriteBack);
+ holder.favorite.setBackgroundResource(favoriteBack);
if (cacheListType == CacheListType.HISTORY && cache.getVisitedDate() > 0) {
holder.info.setText(Formatter.formatCacheInfoHistory(cache));
diff --git a/main/src/cgeo/geocaching/ui/CompassView.java b/main/src/cgeo/geocaching/ui/CompassView.java
index 0ef3a43..b73a2a9 100644
--- a/main/src/cgeo/geocaching/ui/CompassView.java
+++ b/main/src/cgeo/geocaching/ui/CompassView.java
@@ -3,6 +3,7 @@ package cgeo.geocaching.ui;
import cgeo.geocaching.R;
import cgeo.geocaching.utils.AngleUtils;
import cgeo.geocaching.utils.PeriodicHandler;
+import cgeo.geocaching.utils.PeriodicHandler.PeriodicHandlerListener;
import android.content.Context;
import android.graphics.Bitmap;
@@ -14,7 +15,7 @@ import android.util.AttributeSet;
import android.util.FloatMath;
import android.view.View;
-public class CompassView extends View {
+public class CompassView extends View implements PeriodicHandlerListener {
private Context context = null;
private Bitmap compassUnderlay = null;
@@ -48,7 +49,7 @@ public class CompassView extends View {
private int compassOverlayWidth = 0;
private int compassOverlayHeight = 0;
private boolean initialDisplay;
- private final RedrawHandler redrawHandler = new RedrawHandler();
+ private final PeriodicHandler redrawHandler = new PeriodicHandler(40, this);
public CompassView(Context contextIn) {
super(contextIn);
@@ -145,26 +146,18 @@ public class CompassView extends View {
return AngleUtils.normalize(actual + offset);
}
- private class RedrawHandler extends PeriodicHandler {
-
- public RedrawHandler() {
- super(40);
- }
-
- @Override
- public void act() {
- final float newAzimuthShown = smoothUpdate(northMeasured, azimuthShown);
- final float newCacheHeadingShown = smoothUpdate(cacheHeadingMeasured, cacheHeadingShown);
- if (Math.abs(AngleUtils.difference(azimuthShown, newAzimuthShown)) >= 2 ||
- Math.abs(AngleUtils.difference(cacheHeadingShown, newCacheHeadingShown)) >= 2) {
- synchronized(CompassView.this) {
- azimuthShown = newAzimuthShown;
- cacheHeadingShown = newCacheHeadingShown;
- }
- invalidate();
+ @Override
+ public void onPeriodic() {
+ final float newAzimuthShown = smoothUpdate(northMeasured, azimuthShown);
+ final float newCacheHeadingShown = smoothUpdate(cacheHeadingMeasured, cacheHeadingShown);
+ if (Math.abs(AngleUtils.difference(azimuthShown, newAzimuthShown)) >= 2 ||
+ Math.abs(AngleUtils.difference(cacheHeadingShown, newCacheHeadingShown)) >= 2) {
+ synchronized(this) {
+ azimuthShown = newAzimuthShown;
+ cacheHeadingShown = newCacheHeadingShown;
}
+ invalidate();
}
-
}
@Override
@@ -178,12 +171,12 @@ public class CompassView extends View {
headingDrawn = cacheHeadingShown;
}
- float azimuthTemp = azimuthDrawn;
+ final float azimuthTemp = azimuthDrawn;
final float azimuthRelative = AngleUtils.normalize(azimuthTemp - headingDrawn);
// compass margins
- int canvasCenterX = (compassRoseWidth / 2) + ((getWidth() - compassRoseWidth) / 2);
- int canvasCenterY = (compassRoseHeight / 2) + ((getHeight() - compassRoseHeight) / 2);
+ final int canvasCenterX = (compassRoseWidth / 2) + ((getWidth() - compassRoseWidth) / 2);
+ final int canvasCenterY = (compassRoseHeight / 2) + ((getHeight() - compassRoseHeight) / 2);
super.onDraw(canvas);
@@ -224,38 +217,36 @@ public class CompassView extends View {
}
private int measureWidth(int measureSpec) {
- int result;
- int specMode = MeasureSpec.getMode(measureSpec);
- int specSize = MeasureSpec.getSize(measureSpec);
+ final int specMode = MeasureSpec.getMode(measureSpec);
+ final int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.EXACTLY) {
- result = specSize;
- } else {
- result = compassArrow.getWidth() + getPaddingLeft() + getPaddingRight();
+ return specSize;
+ }
- if (specMode == MeasureSpec.AT_MOST) {
- result = Math.min(result, specSize);
- }
+ final int desired = compassArrow.getWidth() + getPaddingLeft() + getPaddingRight();
+ if (specMode == MeasureSpec.AT_MOST) {
+ return Math.min(desired, specSize);
}
- return result;
+ return desired;
}
private int measureHeight(int measureSpec) {
- int result;
- int specMode = MeasureSpec.getMode(measureSpec);
- int specSize = MeasureSpec.getSize(measureSpec);
+ // The duplicated code in measureHeight and measureWidth cannot be avoided.
+ // Those methods must be efficient, therefore we cannot extract the code differences and unify the remainder.
+ final int specMode = MeasureSpec.getMode(measureSpec);
+ final int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.EXACTLY) {
- result = specSize;
- } else {
- result = compassArrow.getHeight() + getPaddingTop() + getPaddingBottom();
+ return specSize;
+ }
- if (specMode == MeasureSpec.AT_MOST) {
- result = Math.min(result, specSize);
- }
+ final int desired = compassArrow.getHeight() + getPaddingTop() + getPaddingBottom();
+ if (specMode == MeasureSpec.AT_MOST) {
+ return Math.min(desired, specSize);
}
- return result;
+ return desired;
}
}
diff --git a/main/src/cgeo/geocaching/ui/CoordinatesFormatSwitcher.java b/main/src/cgeo/geocaching/ui/CoordinatesFormatSwitcher.java
new file mode 100644
index 0000000..afadb33
--- /dev/null
+++ b/main/src/cgeo/geocaching/ui/CoordinatesFormatSwitcher.java
@@ -0,0 +1,38 @@
+package cgeo.geocaching.ui;
+
+import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.geopoint.GeopointFormatter;
+
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.TextView;
+
+/**
+ * view click listener to automatically switch different coordinate formats
+ *
+ */
+public class CoordinatesFormatSwitcher implements OnClickListener {
+
+ private static GeopointFormatter.Format[] availableFormats = new GeopointFormatter.Format[] {
+ GeopointFormatter.Format.LAT_LON_DECMINUTE,
+ GeopointFormatter.Format.LAT_LON_DECSECOND,
+ GeopointFormatter.Format.LAT_LON_DECDEGREE
+ };
+
+ private int position = 0;
+
+ private final Geopoint coordinates;
+
+ public CoordinatesFormatSwitcher(final Geopoint coordinates) {
+ this.coordinates = coordinates;
+ }
+
+ @Override
+ public void onClick(View view) {
+ position = (position + 1) % availableFormats.length;
+ TextView textView = (TextView) view;
+ // rotate coordinate formats on click
+ textView.setText(coordinates.format(availableFormats[position]));
+ }
+
+} \ No newline at end of file
diff --git a/main/src/cgeo/geocaching/ui/DecryptTextClickListener.java b/main/src/cgeo/geocaching/ui/DecryptTextClickListener.java
index 4ba88ae..f10e13a 100644
--- a/main/src/cgeo/geocaching/ui/DecryptTextClickListener.java
+++ b/main/src/cgeo/geocaching/ui/DecryptTextClickListener.java
@@ -16,6 +16,12 @@ public class DecryptTextClickListener implements View.OnClickListener {
try {
final TextView logView = (TextView) view;
+
+ // do not run the click listener if a link was clicked
+ if (logView.getSelectionStart() != -1 || logView.getSelectionEnd() != -1) {
+ return;
+ }
+
CharSequence text = logView.getText();
if (text instanceof Spannable) {
Spannable span = (Spannable) text;
diff --git a/main/src/cgeo/geocaching/ui/EditNoteDialog.java b/main/src/cgeo/geocaching/ui/EditNoteDialog.java
new file mode 100644
index 0000000..bbf0618
--- /dev/null
+++ b/main/src/cgeo/geocaching/ui/EditNoteDialog.java
@@ -0,0 +1,70 @@
+package cgeo.geocaching.ui;
+
+import cgeo.geocaching.R;
+import cgeo.geocaching.R.string;
+
+import android.os.Bundle;
+import android.support.v4.app.DialogFragment;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager.LayoutParams;
+import android.view.inputmethod.EditorInfo;
+import android.widget.EditText;
+import android.widget.TextView;
+import android.widget.TextView.OnEditorActionListener;
+
+public class EditNoteDialog extends DialogFragment implements OnEditorActionListener {
+
+ public interface EditNoteDialogListener {
+ void onFinishEditNoteDialog(final String inputText);
+ }
+
+ public static final String ARGUMENT_INITIAL_NOTE = "initialNote";
+
+ private EditText mEditText;
+ private String initialNote;
+
+ public static EditNoteDialog newInstance(final String initialNote) {
+ EditNoteDialog dialog = new EditNoteDialog();
+
+ Bundle arguments = new Bundle();
+ arguments.putString(EditNoteDialog.ARGUMENT_INITIAL_NOTE, initialNote);
+ dialog.setArguments(arguments);
+
+ return dialog;
+ }
+
+ @Override
+ public View onCreateView(final LayoutInflater inflater, final ViewGroup container,
+ final Bundle savedInstanceState) {
+ View view = inflater.inflate(R.layout.fragment_edit_note, container);
+ mEditText = (EditText) view.findViewById(R.id.note);
+ initialNote = getArguments().getString(ARGUMENT_INITIAL_NOTE);
+ if (initialNote != null) {
+ mEditText.setText(initialNote);
+ initialNote = null;
+ }
+ getDialog().setTitle(string.cache_personal_note);
+ mEditText.requestFocus();
+ getDialog().getWindow().setSoftInputMode(
+ LayoutParams.SOFT_INPUT_STATE_VISIBLE);
+ mEditText.setOnEditorActionListener(this);
+
+ return view;
+ }
+
+ @Override
+ public boolean onEditorAction(final TextView v, final int actionId, final KeyEvent event) {
+ if (EditorInfo.IME_ACTION_DONE == actionId) {
+ final EditNoteDialogListener activity = (EditNoteDialogListener) getActivity();
+ activity.onFinishEditNoteDialog(mEditText.getText().toString());
+ dismiss();
+ return true;
+ }
+ return false;
+ }
+
+
+}
diff --git a/main/src/cgeo/geocaching/ui/FileSelectionListAdapter.java b/main/src/cgeo/geocaching/ui/FileSelectionListAdapter.java
index 1db3f21..c325f50 100644
--- a/main/src/cgeo/geocaching/ui/FileSelectionListAdapter.java
+++ b/main/src/cgeo/geocaching/ui/FileSelectionListAdapter.java
@@ -1,5 +1,7 @@
package cgeo.geocaching.ui;
+import butterknife.InjectView;
+
import cgeo.geocaching.R;
import cgeo.geocaching.files.IFileSelectionView;
import cgeo.geocaching.utils.Log;
@@ -17,23 +19,20 @@ import java.util.List;
public class FileSelectionListAdapter extends ArrayAdapter<File> {
- private IFileSelectionView parentView;
- private LayoutInflater inflater;
+ private final IFileSelectionView parentView;
+ private final LayoutInflater inflater;
public FileSelectionListAdapter(IFileSelectionView parentIn, List<File> listIn) {
super(parentIn.getContext(), 0, listIn);
parentView = parentIn;
+ inflater = ((Activity) getContext()).getLayoutInflater();
}
@Override
public View getView(final int position, final View rowView, final ViewGroup parent) {
- if (inflater == null) {
- inflater = ((Activity) getContext()).getLayoutInflater();
- }
-
if (position > getCount()) {
- Log.w("cgGPXListAdapter.getView: Attempt to access missing item #" + position);
+ Log.w("FileSelectionListAdapter.getView: Attempt to access missing item #" + position);
return null;
}
@@ -44,12 +43,7 @@ public class FileSelectionListAdapter extends ArrayAdapter<File> {
ViewHolder holder;
if (v == null) {
v = inflater.inflate(R.layout.mapfile_item, null);
-
- holder = new ViewHolder();
- holder.filepath = (TextView) v.findViewById(R.id.mapfilepath);
- holder.filename = (TextView) v.findViewById(R.id.mapfilename);
-
- v.setTag(holder);
+ holder = new ViewHolder(v);
} else {
holder = (ViewHolder) v.getTag();
}
@@ -85,8 +79,12 @@ public class FileSelectionListAdapter extends ArrayAdapter<File> {
}
}
- private static final class ViewHolder {
- TextView filepath;
- TextView filename;
+ protected static final class ViewHolder extends AbstractViewHolder {
+ @InjectView(R.id.mapfilepath) protected TextView filepath;
+ @InjectView(R.id.mapfilename) protected TextView filename;
+
+ public ViewHolder(View view) {
+ super(view);
+ }
}
}
diff --git a/main/src/cgeo/geocaching/ui/GPXListAdapter.java b/main/src/cgeo/geocaching/ui/GPXListAdapter.java
index 9f6c14c..7f3c33f 100644
--- a/main/src/cgeo/geocaching/ui/GPXListAdapter.java
+++ b/main/src/cgeo/geocaching/ui/GPXListAdapter.java
@@ -1,7 +1,9 @@
package cgeo.geocaching.ui;
-import cgeo.geocaching.R;
+import butterknife.InjectView;
+
import cgeo.geocaching.GpxFileListActivity;
+import cgeo.geocaching.R;
import cgeo.geocaching.files.GPXImporter;
import cgeo.geocaching.utils.Log;
@@ -18,28 +20,29 @@ import java.io.File;
import java.util.List;
public class GPXListAdapter extends ArrayAdapter<File> {
- private GpxFileListActivity activity = null;
- private LayoutInflater inflater = null;
+ private final GpxFileListActivity activity;
+ private final LayoutInflater inflater;
- private static class ViewHolder {
- TextView filepath;
- TextView filename;
+ protected static class ViewHolder extends AbstractViewHolder {
+ @InjectView(R.id.filepath) protected TextView filepath;
+ @InjectView(R.id.filename) protected TextView filename;
+
+ public ViewHolder(View view) {
+ super(view);
+ }
}
public GPXListAdapter(GpxFileListActivity parentIn, List<File> listIn) {
super(parentIn, 0, listIn);
activity = parentIn;
+ inflater = ((Activity) getContext()).getLayoutInflater();
}
@Override
public View getView(final int position, final View rowView, final ViewGroup parent) {
- if (inflater == null) {
- inflater = ((Activity) getContext()).getLayoutInflater();
- }
-
if (position > getCount()) {
- Log.w("cgGPXListAdapter.getView: Attempt to access missing item #" + position);
+ Log.w("GPXListAdapter.getView: Attempt to access missing item #" + position);
return null;
}
@@ -50,12 +53,7 @@ public class GPXListAdapter extends ArrayAdapter<File> {
final ViewHolder holder;
if (view == null) {
view = inflater.inflate(R.layout.gpx_item, null);
-
- holder = new ViewHolder();
- holder.filepath = (TextView) view.findViewById(R.id.filepath);
- holder.filename = (TextView) view.findViewById(R.id.filename);
-
- view.setTag(holder);
+ holder = new ViewHolder(view);
} else {
holder = (ViewHolder) view.getTag();
}
diff --git a/main/src/cgeo/geocaching/ui/ImagesList.java b/main/src/cgeo/geocaching/ui/ImagesList.java
index 9464114..0f860c4 100644
--- a/main/src/cgeo/geocaching/ui/ImagesList.java
+++ b/main/src/cgeo/geocaching/ui/ImagesList.java
@@ -11,7 +11,6 @@ import cgeo.geocaching.utils.Log;
import org.apache.commons.lang3.StringUtils;
import android.app.Activity;
-import android.app.ProgressDialog;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Bitmap;
@@ -31,6 +30,7 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
+import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.util.Collection;
@@ -39,23 +39,18 @@ import java.util.List;
public class ImagesList {
- private static final int MENU_FILE = 201;
- private static final int MENU_BROWSER = 202;
-
private BitmapDrawable currentDrawable;
private Image currentImage;
public enum ImageType {
- LogImages(R.string.cache_log_images_title, R.string.cache_log_images_loading),
- SpoilerImages(R.string.cache_spoiler_images_title, R.string.cache_spoiler_images_loading),
- AllImages(R.string.cache_images_title, R.string.cache_images_loading);
+ LogImages(R.string.cache_log_images_title),
+ SpoilerImages(R.string.cache_spoiler_images_title),
+ AllImages(R.string.cache_images_title);
private final int titleResId;
- private final int loadingResId;
- ImageType(final int title, final int loading) {
+ ImageType(final int title) {
this.titleResId = title;
- this.loadingResId = loading;
}
public int getTitle() {
@@ -64,9 +59,6 @@ public class ImagesList {
}
private LayoutInflater inflater = null;
- private ProgressDialog progressDialog = null;
- private int count = 0;
- private int countDone = 0;
private final Activity activity;
// We could use a Set here, but we will insert no duplicates, so there is no need to check for uniqueness.
private final Collection<Bitmap> bitmaps = new LinkedList<Bitmap>();
@@ -83,18 +75,10 @@ public class ImagesList {
inflater = activity.getLayoutInflater();
}
- public void loadImages(final View parentView, final List<Image> images, ImageType imageType, final boolean offline) {
+ public void loadImages(final View parentView, final List<Image> images, final boolean offline) {
imagesView = (LinearLayout) parentView.findViewById(R.id.spoiler_list);
- count = images.size();
- progressDialog = new ProgressDialog(activity);
- progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
- progressDialog.setMessage(activity.getString(imageType.loadingResId));
- progressDialog.setCancelable(true);
- progressDialog.setMax(count);
- progressDialog.show();
-
for (final Image img : images) {
LinearLayout rowView = (LinearLayout) inflater.inflate(R.layout.cache_image_item, null);
@@ -154,19 +138,12 @@ public class ImagesList {
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setLayoutParams(new LayoutParams(bounds.width(), bounds.height()));
+ view.findViewById(R.id.progress_bar).setVisibility(View.GONE);
view.addView(imageView);
imageView.setId(image.hashCode());
images.put(imageView.getId(), img);
}
-
- synchronized (activity) {
- countDone++;
- progressDialog.setProgress(countDone);
- if (progressDialog.getProgress() >= count) {
- progressDialog.dismiss();
- }
- }
}
}
@@ -179,10 +156,9 @@ public class ImagesList {
}
public void onCreateContextMenu(ContextMenu menu, View v) {
+ activity.getMenuInflater().inflate(R.menu.images_list_context, menu);
final Resources res = activity.getResources();
menu.setHeaderTitle(res.getString(R.string.cache_image));
- menu.add(0, MENU_FILE, 0, res.getString(R.string.cache_image_open_file));
- menu.add(0, MENU_BROWSER, 0, res.getString(R.string.cache_image_open_browser));
final ImageView view = (ImageView) v;
currentDrawable = (BitmapDrawable) view.getDrawable();
currentImage = images.get(view.getId());
@@ -190,10 +166,10 @@ public class ImagesList {
public boolean onContextItemSelected(MenuItem item) {
switch (item.getItemId()) {
- case MENU_FILE:
+ case R.id.image_open_file:
viewImageInStandardApp(currentDrawable);
return true;
- case MENU_BROWSER:
+ case R.id.image_open_browser:
if (currentImage != null) {
currentImage.openInBrowser(activity);
}
@@ -205,15 +181,15 @@ public class ImagesList {
private void viewImageInStandardApp(final BitmapDrawable image) {
final File file = LocalStorage.getStorageFile(null, "temp.jpg", false, true);
- FileOutputStream fos = null;
+ BufferedOutputStream stream = null;
try {
- fos = new FileOutputStream(file);
- image.getBitmap().compress(CompressFormat.JPEG, 100, fos);
+ stream = new BufferedOutputStream(new FileOutputStream(file));
+ image.getBitmap().compress(CompressFormat.JPEG, 100, stream);
} catch (Exception e) {
- Log.e("ImagesActivity.handleMessage.onClick", e);
+ Log.e("ImagesList.viewImageInStandardApp", e);
return;
} finally {
- IOUtils.closeQuietly(fos);
+ IOUtils.closeQuietly(stream);
}
final Intent intent = new Intent();
diff --git a/main/src/cgeo/geocaching/ui/LoggingUI.java b/main/src/cgeo/geocaching/ui/LoggingUI.java
index 2615947..ac74dd3 100644
--- a/main/src/cgeo/geocaching/ui/LoggingUI.java
+++ b/main/src/cgeo/geocaching/ui/LoggingUI.java
@@ -61,31 +61,12 @@ public class LoggingUI extends AbstractUIFactory {
}
}
- private static final int MENU_ICON_LOG_VISIT = R.drawable.ic_menu_edit;
- private static final int MENU_LOG_VISIT = 100;
- private static final int MENU_LOG_VISIT_OFFLINE = 101;
-
- public static void addMenuItems(final Menu menu, final Geocache cache) {
- if (cache == null) {
- return;
- }
- if (!cache.supportsLogging()) {
- return;
- }
- if (Settings.getLogOffline()) {
- menu.add(0, MENU_LOG_VISIT_OFFLINE, 0, res.getString(R.string.cache_menu_visit_offline)).setIcon(MENU_ICON_LOG_VISIT);
- }
- else {
- menu.add(0, MENU_LOG_VISIT, 0, res.getString(R.string.cache_menu_visit)).setIcon(MENU_ICON_LOG_VISIT);
- }
- }
-
public static boolean onMenuItemSelected(final MenuItem item, IAbstractActivity activity, Geocache cache) {
switch (item.getItemId()) {
- case MENU_LOG_VISIT:
+ case R.id.menu_log_visit:
cache.logVisit(activity);
return true;
- case MENU_LOG_VISIT_OFFLINE:
+ case R.id.menu_log_visit_offline:
showOfflineMenu(cache, (Activity) activity);
return true;
default:
@@ -123,7 +104,7 @@ public class LoggingUI extends AbstractUIFactory {
break;
case CLEAR_LOG:
- cgData.clearLogOffline(cache.getGeocode());
+ cache.clearOfflineLog();
break;
}
} else {
@@ -136,10 +117,17 @@ public class LoggingUI extends AbstractUIFactory {
}
- public static void onPrepareOptionsMenu(Menu menu) {
- final MenuItem item = menu.findItem(MENU_LOG_VISIT);
- if (item != null) {
- item.setEnabled(Settings.isLogin());
- }
+ public static void onPrepareOptionsMenu(Menu menu, Geocache cache) {
+ final MenuItem itemLog = menu.findItem(R.id.menu_log_visit);
+ itemLog.setVisible(cache.supportsLogging() && !Settings.getLogOffline());
+ itemLog.setEnabled(Settings.isLogin());
+
+ final MenuItem itemOffline = menu.findItem(R.id.menu_log_visit_offline);
+ itemOffline.setVisible(cache.supportsLogging() && Settings.getLogOffline());
+ }
+
+ public static void addMenuItems(Activity activity, Menu menu, Geocache cache) {
+ activity.getMenuInflater().inflate(R.menu.logging_ui, menu);
+ onPrepareOptionsMenu(menu, cache);
}
}
diff --git a/main/src/cgeo/geocaching/ui/OwnerActionsClickListener.java b/main/src/cgeo/geocaching/ui/OwnerActionsClickListener.java
new file mode 100644
index 0000000..e7b04a5
--- /dev/null
+++ b/main/src/cgeo/geocaching/ui/OwnerActionsClickListener.java
@@ -0,0 +1,28 @@
+package cgeo.geocaching.ui;
+
+import cgeo.geocaching.Geocache;
+
+import org.apache.commons.lang3.StringUtils;
+
+import android.view.View;
+import android.widget.TextView;
+
+/**
+ * Listener for clicks on owner name
+ */
+public class OwnerActionsClickListener extends AbstractUserClickListener {
+
+ public OwnerActionsClickListener(Geocache cache) {
+ super(cache);
+ }
+
+ @Override
+ protected String getUserName(View view) {
+ // Use real owner name vice the one owner chose to display
+ if (StringUtils.isNotBlank(cache.getOwnerUserId())) {
+ return cache.getOwnerUserId();
+ }
+ return ((TextView) view).getText().toString();
+ }
+}
+
diff --git a/main/src/cgeo/geocaching/ui/UserActionsClickListener.java b/main/src/cgeo/geocaching/ui/UserActionsClickListener.java
new file mode 100644
index 0000000..8235446
--- /dev/null
+++ b/main/src/cgeo/geocaching/ui/UserActionsClickListener.java
@@ -0,0 +1,22 @@
+package cgeo.geocaching.ui;
+
+import cgeo.geocaching.Geocache;
+
+import android.view.View;
+import android.widget.TextView;
+
+/**
+ * Listener for clicks on user name
+ */
+public class UserActionsClickListener extends AbstractUserClickListener {
+
+ public UserActionsClickListener(Geocache cache) {
+ super(cache);
+ }
+
+ @Override
+ protected CharSequence getUserName(View view) {
+ return ((TextView) view).getText().toString();
+ }
+}
+
diff --git a/main/src/cgeo/geocaching/ui/dialog/CoordinatesInputDialog.java b/main/src/cgeo/geocaching/ui/dialog/CoordinatesInputDialog.java
index dada8fd..60116f9 100644
--- a/main/src/cgeo/geocaching/ui/dialog/CoordinatesInputDialog.java
+++ b/main/src/cgeo/geocaching/ui/dialog/CoordinatesInputDialog.java
@@ -13,13 +13,10 @@ import cgeo.geocaching.geopoint.GeopointFormatter;
import org.apache.commons.lang3.StringUtils;
-import android.app.Dialog;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.View;
-import android.view.ViewGroup.LayoutParams;
-import android.view.Window;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
@@ -28,7 +25,7 @@ import android.widget.EditText;
import android.widget.Spinner;
import android.widget.TextView;
-public class CoordinatesInputDialog extends Dialog {
+public class CoordinatesInputDialog extends NoTitleDialog {
final private AbstractActivity context;
final private IGeoData geo;
@@ -47,7 +44,7 @@ public class CoordinatesInputDialog extends Dialog {
private coordInputFormatEnum currentFormat = null;
public CoordinatesInputDialog(final AbstractActivity context, final Geocache cache, final Geopoint gp, final IGeoData geo) {
- super(context, ActivityMixin.getTheme());
+ super(context, ActivityMixin.getDialogTheme());
this.context = context;
this.geo = geo;
this.cache = cache;
@@ -65,22 +62,7 @@ public class CoordinatesInputDialog extends Dialog {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- try {
- requestWindowFeature(Window.FEATURE_NO_TITLE);
- getWindow().setLayout(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
- } catch (Exception e) {
- // nothing
- }
-
- setContentView(R.layout.coords);
-
- findViewById(R.id.actionBarManualbutton).setOnClickListener(new View.OnClickListener() {
-
- @Override
- public void onClick(View view) {
- ActivityMixin.goManual(context, "c:geo-geocoordinate-input");
- }
- });
+ setContentView(R.layout.coordinatesinput_dialog);
final Spinner spinner = (Spinner) findViewById(R.id.spinnerCoordinateFormats);
final ArrayAdapter<CharSequence> adapter =
@@ -346,7 +328,7 @@ public class CoordinatesInputDialog extends Dialog {
if (currentFormat == coordInputFormatEnum.Plain) {
try {
gp = new Geopoint(eLat.getText().toString(), eLon.getText().toString());
- } catch (Geopoint.ParseException e) {
+ } catch (final Geopoint.ParseException e) {
if (signalError) {
context.showToast(context.getResources().getString(R.string.err_parse_lat_lon));
}
@@ -355,20 +337,20 @@ public class CoordinatesInputDialog extends Dialog {
return true;
}
- String latDir = bLat.getText().toString();
- String lonDir = bLon.getText().toString();
- String latDeg = eLatDeg.getText().toString();
- String lonDeg = eLonDeg.getText().toString();
- String latDegFrac = eLatMin.getText().toString();
- String lonDegFrac = eLonMin.getText().toString();
- String latMin = eLatMin.getText().toString();
- String lonMin = eLonMin.getText().toString();
- String latMinFrac = eLatSec.getText().toString();
- String lonMinFrac = eLonSec.getText().toString();
- String latSec = eLatSec.getText().toString();
- String lonSec = eLonSec.getText().toString();
- String latSecFrac = eLatSub.getText().toString();
- String lonSecFrac = eLonSub.getText().toString();
+ final String latDir = bLat.getText().toString();
+ final String lonDir = bLon.getText().toString();
+ final String latDeg = eLatDeg.getText().toString();
+ final String lonDeg = eLonDeg.getText().toString();
+ final String latDegFrac = eLatMin.getText().toString();
+ final String lonDegFrac = eLonMin.getText().toString();
+ final String latMin = eLatMin.getText().toString();
+ final String lonMin = eLonMin.getText().toString();
+ final String latMinFrac = eLatSec.getText().toString();
+ final String lonMinFrac = eLonSec.getText().toString();
+ final String latSec = eLatSec.getText().toString();
+ final String lonSec = eLonSec.getText().toString();
+ final String latSecFrac = eLatSub.getText().toString();
+ final String lonSecFrac = eLonSub.getText().toString();
switch (currentFormat) {
case Deg:
diff --git a/main/src/cgeo/geocaching/ui/dialog/CustomProgressDialog.java b/main/src/cgeo/geocaching/ui/dialog/CustomProgressDialog.java
index c2b722c..e80c446 100644
--- a/main/src/cgeo/geocaching/ui/dialog/CustomProgressDialog.java
+++ b/main/src/cgeo/geocaching/ui/dialog/CustomProgressDialog.java
@@ -19,7 +19,7 @@ import java.lang.reflect.Method;
public class CustomProgressDialog extends ProgressDialog {
public CustomProgressDialog(Context context) {
- super(context, ActivityMixin.getTheme());
+ super(context, ActivityMixin.getDialogTheme());
}
@Override
diff --git a/main/src/cgeo/geocaching/ui/dialog/DateDialog.java b/main/src/cgeo/geocaching/ui/dialog/DateDialog.java
index a9c579c..18f8e2e 100644
--- a/main/src/cgeo/geocaching/ui/dialog/DateDialog.java
+++ b/main/src/cgeo/geocaching/ui/dialog/DateDialog.java
@@ -3,15 +3,12 @@ package cgeo.geocaching.ui.dialog;
import cgeo.geocaching.R;
import android.app.Activity;
-import android.app.Dialog;
import android.os.Bundle;
-import android.view.ViewGroup.LayoutParams;
-import android.view.Window;
import android.widget.DatePicker;
import java.util.Calendar;
-public class DateDialog extends Dialog {
+public class DateDialog extends NoTitleDialog {
public interface DateDialogParent {
abstract public void setDate(final Calendar date);
@@ -32,13 +29,6 @@ public class DateDialog extends Dialog {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- try {
- requestWindowFeature(Window.FEATURE_NO_TITLE);
- getWindow().setLayout(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
- } catch (Exception e) {
- // nothing
- }
-
setContentView(R.layout.date);
final DatePicker picker = (DatePicker) findViewById(R.id.picker);
diff --git a/main/src/cgeo/geocaching/ui/dialog/EditorDialog.java b/main/src/cgeo/geocaching/ui/dialog/EditorDialog.java
deleted file mode 100644
index 4db69e5..0000000
--- a/main/src/cgeo/geocaching/ui/dialog/EditorDialog.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package cgeo.geocaching.ui.dialog;
-
-import cgeo.geocaching.CacheDetailActivity;
-import cgeo.geocaching.R;
-import cgeo.geocaching.activity.ActivityMixin;
-
-import android.app.Dialog;
-import android.os.Bundle;
-import android.view.View;
-import android.view.ViewGroup.LayoutParams;
-import android.view.Window;
-import android.widget.Button;
-import android.widget.EditText;
-
-public class EditorDialog extends Dialog {
-
- private CharSequence editorText;
- private EditorUpdate editorUpdate;
-
- public EditorDialog(CacheDetailActivity cacheDetailActivity, CharSequence editable) {
- super(cacheDetailActivity, ActivityMixin.getTheme());
- this.editorText = editable;
- }
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- requestWindowFeature(Window.FEATURE_NO_TITLE);
- setContentView(R.layout.editor);
-
- final EditText editText = (EditText) findViewById(R.id.editorEditText);
- editText.setText(editorText);
-
- final Button buttonSave = (Button) findViewById(R.id.editorSave);
- buttonSave.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- editorUpdate.update(editText.getEditableText());
- EditorDialog.this.hide();
- }
- });
- }
-
- public interface EditorUpdate {
- public void update(CharSequence editorText);
- }
-
- public void setOnEditorUpdate(EditorUpdate editorUpdate) {
- this.editorUpdate = editorUpdate;
-
- }
-
- @Override
- public void show() {
- super.show();
- getWindow().setLayout(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
- }
-
-}
diff --git a/main/src/cgeo/geocaching/ui/dialog/NoTitleDialog.java b/main/src/cgeo/geocaching/ui/dialog/NoTitleDialog.java
new file mode 100644
index 0000000..fc5ebe6
--- /dev/null
+++ b/main/src/cgeo/geocaching/ui/dialog/NoTitleDialog.java
@@ -0,0 +1,30 @@
+package cgeo.geocaching.ui.dialog;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.ViewGroup.LayoutParams;
+import android.view.Window;
+
+public abstract class NoTitleDialog extends Dialog {
+
+ public NoTitleDialog(Context context) {
+ super(context);
+ }
+
+ public NoTitleDialog(Context context, int theme) {
+ super(context, theme);
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ try {
+ requestWindowFeature(Window.FEATURE_NO_TITLE);
+ getWindow().setLayout(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
+ } catch (final Exception e) {
+ // nothing
+ }
+ }
+}
diff --git a/main/src/cgeo/geocaching/utils/AngleUtils.java b/main/src/cgeo/geocaching/utils/AngleUtils.java
index 6e59a91..fdd9a9d 100644
--- a/main/src/cgeo/geocaching/utils/AngleUtils.java
+++ b/main/src/cgeo/geocaching/utils/AngleUtils.java
@@ -1,6 +1,6 @@
package cgeo.geocaching.utils;
-public class AngleUtils {
+public final class AngleUtils {
private AngleUtils() {
// Do not instantiate
@@ -8,7 +8,7 @@ public class AngleUtils {
/**
* Return the angle to turn of to go from an angle to the other
- *
+ *
* @param from
* the origin angle in degrees
* @param to
diff --git a/main/src/cgeo/geocaching/utils/AsyncTaskWithProgress.java b/main/src/cgeo/geocaching/utils/AsyncTaskWithProgress.java
new file mode 100644
index 0000000..7526d92
--- /dev/null
+++ b/main/src/cgeo/geocaching/utils/AsyncTaskWithProgress.java
@@ -0,0 +1,139 @@
+package cgeo.geocaching.utils;
+
+import cgeo.geocaching.activity.Progress;
+
+import android.app.Activity;
+import android.app.ProgressDialog;
+import android.os.AsyncTask;
+
+/**
+ * AsyncTask which automatically shows a progress dialog. Use it like the {@code AsyncTask} class, but leave away the
+ * middle template parameter. Override {@link #doInBackgroundInternal(Object[])} and related methods.
+ * <p>
+ * If no style is given, the progress dialog uses "determinate" style with known maximum. The progress maximum is
+ * automatically derived from the number of {@code Params} given to the task in {@link #execute(Object...)}.
+ * </p>
+ *
+ * @param <Params>
+ * @param <Result>
+ */
+public abstract class AsyncTaskWithProgress<Params, Result> extends AsyncTask<Params, Integer, Result> {
+
+ private final Progress progress = new Progress();
+ private final Activity activity;
+ private final String progressTitle;
+ private final String progressMessage;
+ private boolean indeterminate = false;
+
+ /**
+ * Creates an AsyncTask with progress dialog.
+ *
+ * @param activity
+ * @param progressTitle
+ * @param progressMessage
+ */
+ public AsyncTaskWithProgress(final Activity activity, final String progressTitle, final String progressMessage) {
+ this(activity, progressTitle, progressMessage, false);
+ }
+
+ /**
+ * Creates an AsyncTask with progress dialog.
+ *
+ * @param activity
+ * @param progressTitle
+ */
+ public AsyncTaskWithProgress(final Activity activity, final String progressTitle) {
+ this(activity, progressTitle, null);
+ }
+
+ /**
+ * Creates an AsyncTask with progress dialog.
+ *
+ * @param activity
+ * @param progressTitle
+ * @param progressMessage
+ */
+ public AsyncTaskWithProgress(final Activity activity, final String progressTitle, final String progressMessage, boolean indeterminate) {
+ this.activity = activity;
+ this.progressTitle = progressTitle;
+ this.progressMessage = progressMessage;
+ this.indeterminate = indeterminate;
+ }
+
+ /**
+ * Creates an AsyncTask with progress dialog.
+ *
+ * @param activity
+ * @param progressTitle
+ */
+ public AsyncTaskWithProgress(final Activity activity, final String progressTitle, boolean indeterminate) {
+ this(activity, progressTitle, null, indeterminate);
+ }
+
+ @Override
+ protected final void onPreExecute() {
+ if (null != activity) {
+ if (indeterminate) {
+ progress.show(activity, progressTitle, progressMessage, true, null);
+ }
+ else {
+ progress.show(activity, progressTitle, progressMessage, ProgressDialog.STYLE_HORIZONTAL, null);
+ }
+ }
+ onPreExecuteInternal();
+ }
+
+ /**
+ * This method should typically be overridden by sub classes instead of {@link #onPreExecute()}.
+ */
+ protected void onPreExecuteInternal() {
+ // empty by default
+ }
+
+ @Override
+ protected final void onPostExecute(Result result) {
+ onPostExecuteInternal(result);
+ if (null != activity) {
+ progress.dismiss();
+ }
+ }
+
+ /**
+ * This method should typically be overridden by sub classes instead of {@link #onPostExecute(Object)}.
+ *
+ * @param result
+ */
+ protected void onPostExecuteInternal(Result result) {
+ // empty by default
+ }
+
+ @Override
+ protected final void onProgressUpdate(Integer... status) {
+ final int progressValue = status[0];
+ if (null != activity && progressValue >= 0) {
+ progress.setProgress(progressValue);
+ }
+ onProgressUpdateInternal(progressValue);
+ }
+
+ /**
+ * This method should by overridden by sub classes instead of {@link #onProgressUpdate(Integer...)}.
+ */
+ protected void onProgressUpdateInternal(@SuppressWarnings("unused") int progress) {
+ // empty by default
+ }
+
+ protected void setMessage(final String message) {
+ progress.setMessage(message);
+ }
+
+ @Override
+ protected final Result doInBackground(Params... params) {
+ if (params != null) {
+ progress.setMaxProgressAndReset(params.length);
+ }
+ return doInBackgroundInternal(params);
+ }
+
+ protected abstract Result doInBackgroundInternal(Params[] params);
+}
diff --git a/main/src/cgeo/geocaching/utils/ClipboardUtils.java b/main/src/cgeo/geocaching/utils/ClipboardUtils.java
index e6779ad..67069b2 100644
--- a/main/src/cgeo/geocaching/utils/ClipboardUtils.java
+++ b/main/src/cgeo/geocaching/utils/ClipboardUtils.java
@@ -3,7 +3,6 @@ package cgeo.geocaching.utils;
import cgeo.geocaching.cgeoapplication;
import android.content.Context;
-import android.text.ClipboardManager;
/**
* Clipboard Utilities. Functions to copy data to the Android clipboard.
@@ -13,6 +12,10 @@ import android.text.ClipboardManager;
@SuppressWarnings("deprecation")
public final class ClipboardUtils {
+ private ClipboardUtils() {
+ // utility class
+ }
+
/**
* Places the text passed in onto the clipboard as text
*
@@ -20,7 +23,8 @@ public final class ClipboardUtils {
* The text to place in the clipboard.
*/
public static void copyToClipboard(final CharSequence text) {
- final ClipboardManager clipboard = (ClipboardManager) cgeoapplication.getInstance().getSystemService(Context.CLIPBOARD_SERVICE);
+ // fully qualified name used here to avoid buggy deprecation warning (of javac) on the import statement
+ final android.text.ClipboardManager clipboard = (android.text.ClipboardManager) cgeoapplication.getInstance().getSystemService(Context.CLIPBOARD_SERVICE);
clipboard.setText(text);
}
diff --git a/main/src/cgeo/geocaching/utils/CryptUtils.java b/main/src/cgeo/geocaching/utils/CryptUtils.java
index df2baa0..18a337d 100644
--- a/main/src/cgeo/geocaching/utils/CryptUtils.java
+++ b/main/src/cgeo/geocaching/utils/CryptUtils.java
@@ -12,6 +12,10 @@ import javax.crypto.spec.SecretKeySpec;
public final class CryptUtils {
+ private CryptUtils() {
+ // utility class
+ }
+
private static char[] base64map1 = new char[64];
private static byte[] base64map2 = new byte[128];
@@ -37,28 +41,36 @@ public final class CryptUtils {
}
}
+ private static class Rot13Encryption {
+ private boolean plaintext = false;
+
+ char getNextEncryptedCharacter(final char c) {
+ int result = c;
+ if (result == '[') {
+ plaintext = true;
+ } else if (result == ']') {
+ plaintext = false;
+ } else if (!plaintext) {
+ int capitalized = result & 32;
+ result &= ~capitalized;
+ result = ((result >= 'A') && (result <= 'Z') ? ((result - 'A' + 13) % 26 + 'A') : result)
+ | capitalized;
+ }
+ return (char) result;
+ }
+ }
+
public static String rot13(String text) {
if (text == null) {
return "";
}
final StringBuilder result = new StringBuilder();
- // plaintext flag (do not convert)
- boolean plaintext = false;
+ Rot13Encryption rot13 = new Rot13Encryption();
final int length = text.length();
for (int index = 0; index < length; index++) {
- int c = text.charAt(index);
- if (c == '[') {
- plaintext = true;
- } else if (c == ']') {
- plaintext = false;
- } else if (!plaintext) {
- int capitalized = c & 32;
- c &= ~capitalized;
- c = ((c >= 'A') && (c <= 'Z') ? ((c - 'A' + 13) % 26 + 'A') : c)
- | capitalized;
- }
- result.append((char) c);
+ char c = text.charAt(index);
+ result.append(rot13.getNextEncryptedCharacter(c));
}
return result.toString();
}
@@ -71,7 +83,7 @@ public final class CryptUtils {
digest.update(text.getBytes(), 0, text.length());
hashed = new BigInteger(1, digest.digest()).toString(16);
} catch (Exception e) {
- Log.e("cgBase.md5", e);
+ Log.e("CryptUtils.md5", e);
}
return hashed;
@@ -85,7 +97,7 @@ public final class CryptUtils {
digest.update(text.getBytes(), 0, text.length());
hashed = new BigInteger(1, digest.digest()).toString(16);
} catch (Exception e) {
- Log.e("cgBase.sha1", e);
+ Log.e("CryptUtils.sha1", e);
}
return hashed;
@@ -100,7 +112,7 @@ public final class CryptUtils {
mac.init(secretKeySpec);
macBytes = mac.doFinal(text.getBytes());
} catch (Exception e) {
- Log.e("cgBase.hashHmac", e);
+ Log.e("CryptUtils.hashHmac", e);
}
return macBytes;
@@ -111,22 +123,12 @@ public final class CryptUtils {
// a SpannableStringBuilder instead of the pure text and we must replace each character inline.
// Otherwise we loose all the images, colors and so on...
final SpannableStringBuilder buffer = new SpannableStringBuilder(span);
- boolean plaintext = false;
+ Rot13Encryption rot13 = new Rot13Encryption();
final int length = span.length();
for (int index = 0; index < length; index++) {
- int c = span.charAt(index);
- if (c == '[') {
- plaintext = true;
- } else if (c == ']') {
- plaintext = false;
- } else if (!plaintext) {
- int capitalized = c & 32;
- c &= ~capitalized;
- c = ((c >= 'A') && (c <= 'Z') ? ((c - 'A' + 13) % 26 + 'A') : c)
- | capitalized;
- }
- buffer.replace(index, index + 1, String.valueOf((char) c));
+ char c = span.charAt(index);
+ buffer.replace(index, index + 1, String.valueOf(rot13.getNextEncryptedCharacter(c)));
}
return buffer;
}
diff --git a/main/src/cgeo/geocaching/utils/DateUtils.java b/main/src/cgeo/geocaching/utils/DateUtils.java
index fd5ef4a..b148979 100644
--- a/main/src/cgeo/geocaching/utils/DateUtils.java
+++ b/main/src/cgeo/geocaching/utils/DateUtils.java
@@ -2,7 +2,12 @@ package cgeo.geocaching.utils;
import java.util.Calendar;
-public class DateUtils {
+public final class DateUtils {
+
+ private DateUtils() {
+ // utility class
+ }
+
public static int daysSince(long date) {
final Calendar logDate = Calendar.getInstance();
logDate.setTimeInMillis(date);
diff --git a/main/src/cgeo/geocaching/utils/EditUtils.java b/main/src/cgeo/geocaching/utils/EditUtils.java
index f2f89e7..d975df9 100644
--- a/main/src/cgeo/geocaching/utils/EditUtils.java
+++ b/main/src/cgeo/geocaching/utils/EditUtils.java
@@ -8,6 +8,10 @@ import android.widget.TextView;
public final class EditUtils {
+ private EditUtils() {
+ // utility class
+ }
+
public static void setActionListener(final EditText editText, final Runnable runnable) {
editText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
diff --git a/main/src/cgeo/geocaching/utils/FileUtils.java b/main/src/cgeo/geocaching/utils/FileUtils.java
index 6fefc02..5ab8fcc 100644
--- a/main/src/cgeo/geocaching/utils/FileUtils.java
+++ b/main/src/cgeo/geocaching/utils/FileUtils.java
@@ -9,12 +9,16 @@ import java.io.File;
import java.util.List;
/**
- * Utiliy class for files
+ * Utility class for files
*
* @author rsudev
*
*/
-public class FileUtils {
+public final class FileUtils {
+
+ private FileUtils() {
+ // utility class
+ }
public static void listDir(List<File> result, File directory, FileSelector chooser, Handler feedBackHandler) {
diff --git a/main/src/cgeo/geocaching/utils/GeoDirHandler.java b/main/src/cgeo/geocaching/utils/GeoDirHandler.java
index 21b2562..78455c4 100644
--- a/main/src/cgeo/geocaching/utils/GeoDirHandler.java
+++ b/main/src/cgeo/geocaching/utils/GeoDirHandler.java
@@ -9,10 +9,19 @@ import android.os.Message;
/**
* GeoData and Direction handler. Manipulating geodata and direction information
- * through a GeoDirHandler ensures that all listeners are registered from a
- * {@link android.os.Looper} thread.
+ * through a GeoDirHandler ensures that all listeners are registered from a {@link android.os.Looper} thread.
+ * <p>
+ * To use this class, override at least one of {@link #updateDirection(float)} or {@link #updateGeoData(IGeoData)}. You
+ * need to start the handler using one of
+ * <ul>
+ * <li>{@link #startDir()}</li>
+ * <li>{@link #startGeo()}</li>
+ * <li>{@link #startGeoAndDir()}</li>
+ * </ul>
+ * A good place might be the {@code onResume} method of the Activity. Stop the Handler accordingly in {@code onPause}.
+ * </p>
*/
-public class GeoDirHandler extends Handler implements IObserver<Object> {
+public abstract class GeoDirHandler extends Handler implements IObserver<Object> {
private static final int OBSERVABLE = 1 << 1;
private static final int START_GEO = 1 << 2;
@@ -57,7 +66,8 @@ public class GeoDirHandler extends Handler implements IObserver<Object> {
/**
* Update method called when new IGeoData is available.
*
- * @param data the new data
+ * @param data
+ * the new data
*/
protected void updateGeoData(final IGeoData data) {
// Override this in children
@@ -66,7 +76,8 @@ public class GeoDirHandler extends Handler implements IObserver<Object> {
/**
* Update method called when new direction data is available.
*
- * @param direction the new direction
+ * @param direction
+ * the new direction
*/
protected void updateDirection(final float direction) {
// Override this in children
@@ -118,4 +129,3 @@ public class GeoDirHandler extends Handler implements IObserver<Object> {
sendEmptyMessage(STOP_GEO | STOP_DIR);
}
}
-
diff --git a/main/src/cgeo/geocaching/utils/HtmlUtils.java b/main/src/cgeo/geocaching/utils/HtmlUtils.java
index 8d4eed1..5717a37 100644
--- a/main/src/cgeo/geocaching/utils/HtmlUtils.java
+++ b/main/src/cgeo/geocaching/utils/HtmlUtils.java
@@ -10,7 +10,11 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
-public class HtmlUtils {
+public final class HtmlUtils {
+
+ private HtmlUtils() {
+ // utility class
+ }
/**
* Extract the text from a HTML based string. This is similar to what HTML.fromHtml(...) does, but this method also
@@ -20,6 +24,9 @@ public class HtmlUtils {
* @return
*/
public static String extractText(CharSequence html) {
+ if (StringUtils.isBlank(html)) {
+ return StringUtils.EMPTY;
+ }
String result = html.toString();
// recognize images in textview HTML contents
diff --git a/main/src/cgeo/geocaching/utils/ImageHelper.java b/main/src/cgeo/geocaching/utils/ImageUtils.java
index 98cad64..ea7d3ff 100644
--- a/main/src/cgeo/geocaching/utils/ImageHelper.java
+++ b/main/src/cgeo/geocaching/utils/ImageUtils.java
@@ -8,10 +8,13 @@ import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
-public class ImageHelper {
+import java.io.BufferedOutputStream;
+import java.io.FileOutputStream;
- // Do not let this class be instantiated, this is a utility class.
- private ImageHelper() {
+public final class ImageUtils {
+
+ private ImageUtils() {
+ // Do not let this class be instantiated, this is a utility class.
}
/**
@@ -22,11 +25,21 @@ public class ImageHelper {
* @return BitmapDrawable The scaled image
*/
public static BitmapDrawable scaleBitmapToFitDisplay(final Bitmap image) {
- final cgeoapplication app = cgeoapplication.getInstance();
Point displaySize = Compatibility.getDisplaySize();
final int maxWidth = displaySize.x - 25;
final int maxHeight = displaySize.y - 25;
+ return scaleBitmapTo(image, maxWidth, maxHeight);
+ }
+ /**
+ * Scales a bitmap to the given bounds if it is larger, otherwise returns the original bitmap.
+ *
+ * @param image
+ * The bitmap to scale
+ * @return BitmapDrawable The scaled image
+ */
+ public static BitmapDrawable scaleBitmapTo(final Bitmap image, final int maxWidth, final int maxHeight) {
+ final cgeoapplication app = cgeoapplication.getInstance();
Bitmap result = image;
int width = image.getWidth();
int height = image.getHeight();
@@ -43,4 +56,27 @@ public class ImageHelper {
return resultDrawable;
}
+ /**
+ * Store a bitmap to file.
+ *
+ * @param bitmap
+ * The bitmap to store
+ * @param format
+ * The image format
+ * @param quality
+ * The image quality
+ * @param pathOfOutputImage
+ * Path to store to
+ */
+ public static void storeBitmap(final Bitmap bitmap, final Bitmap.CompressFormat format, final int quality, final String pathOfOutputImage) {
+ try {
+ FileOutputStream out = new FileOutputStream(pathOfOutputImage);
+ BufferedOutputStream bos = new BufferedOutputStream(out);
+ bitmap.compress(format, quality, bos);
+ bos.flush();
+ bos.close();
+ } catch (Exception e) {
+ Log.e("ImageHelper.storeBitmap", e);
+ }
+ }
}
diff --git a/main/src/cgeo/geocaching/utils/LeastRecentlyUsedSet.java b/main/src/cgeo/geocaching/utils/LeastRecentlyUsedSet.java
index 698d38a..708dff0 100644
--- a/main/src/cgeo/geocaching/utils/LeastRecentlyUsedSet.java
+++ b/main/src/cgeo/geocaching/utils/LeastRecentlyUsedSet.java
@@ -10,13 +10,13 @@ import java.util.List;
/**
* Synchronized set wrapper for the LeastRecentlyUsedMap.
*
- * This code is heavily based on the HashSet code that represent Map as a Set.
+ * This code is heavily based on the HashSet code that represents Map as a Set.
* Unfortunately HashSet does not allow to use a custom Map as its Storage.
* Therefore overriding removeEldestEntry() is impossible for a normal LinkedHashSet.
*
* Synchronization is added to guard against concurrent modification. Iterator
* access has to be guarded externally or the synchronized getAsList method can be used
- * to get a clone for iteration
+ * to get a clone for iteration.
*/
public class LeastRecentlyUsedSet<E> extends AbstractSet<E>
implements Cloneable, java.io.Serializable {
@@ -28,7 +28,7 @@ public class LeastRecentlyUsedSet<E> extends AbstractSet<E>
public LeastRecentlyUsedSet(int maxEntries, int initialCapacity, float loadFactor) {
// because we don't use any Map.get() methods from the Set, BOUNDED and LRU_CACHE have the exact same Behaviour
- // So we useLRU_CACHE mode because it should perform a bit better (as it doesn't re-add explicitly)
+ // So we use LRU_CACHE mode because it should perform a bit better (as it doesn't re-add explicitly)
map = new LeastRecentlyUsedMap.LruCache<E, Object>(maxEntries, initialCapacity, loadFactor);
}
diff --git a/main/src/cgeo/geocaching/utils/Log.java b/main/src/cgeo/geocaching/utils/Log.java
index 6d57b75..f912ddd 100644
--- a/main/src/cgeo/geocaching/utils/Log.java
+++ b/main/src/cgeo/geocaching/utils/Log.java
@@ -2,6 +2,7 @@ package cgeo.geocaching.utils;
import android.os.Environment;
+import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
@@ -100,12 +101,14 @@ final public class Log {
first = false;
file.delete();
}
+ Writer writer = null;
try {
- final Writer writer = new FileWriter(file, true);
+ writer = new BufferedWriter(new FileWriter(file, true));
writer.write(msg);
- writer.close();
} catch (final IOException e) {
Log.e("logToFile: cannot write to " + file, e);
+ } finally {
+ IOUtils.closeQuietly(writer);
}
}
}
diff --git a/main/src/cgeo/geocaching/utils/LogTemplateProvider.java b/main/src/cgeo/geocaching/utils/LogTemplateProvider.java
index 0a8e547..2576e64 100644
--- a/main/src/cgeo/geocaching/utils/LogTemplateProvider.java
+++ b/main/src/cgeo/geocaching/utils/LogTemplateProvider.java
@@ -188,7 +188,7 @@ public class LogTemplateProvider {
}
try {
- return Integer.parseInt(BaseUtils.getMatch(page, GCConstants.PATTERN_CACHES_FOUND, true, "-1").replaceAll("[,.]", ""));
+ return Integer.parseInt(TextUtils.getMatch(page, GCConstants.PATTERN_CACHES_FOUND, true, "-1").replaceAll("[,.]", ""));
} catch (NumberFormatException e) {
Log.e("parseFindCount", e);
return -1;
diff --git a/main/src/cgeo/geocaching/utils/PeriodicHandler.java b/main/src/cgeo/geocaching/utils/PeriodicHandler.java
index 2759580..288bbb0 100644
--- a/main/src/cgeo/geocaching/utils/PeriodicHandler.java
+++ b/main/src/cgeo/geocaching/utils/PeriodicHandler.java
@@ -3,16 +3,26 @@ package cgeo.geocaching.utils;
import android.os.Handler;
import android.os.Message;
+import java.lang.ref.WeakReference;
+
/**
* A PeriodicHandler class helps with the implementation of a periodic
* action embedded in a thread with a looper such as the UI thread.
- * The act() method will be called periodically. The clock may drift
- * as the implementation does not target real-time actions.
+ * The onPeriodic() method of the listener will be called periodically.
+ * The clock may drift as the implementation does not target real-time
+ * actions.
*
* The handler will be interrupted if the device goes to sleep.
*
+ * The handler only keeps a weak reference to the listener. If the listener
+ * is garbage-collected without having stopped the timer, the handler will
+ * stop itself.
*/
-abstract public class PeriodicHandler extends Handler {
+final public class PeriodicHandler extends Handler {
+
+ public static interface PeriodicHandlerListener {
+ public void onPeriodic();
+ }
final static private int START = 0;
final static private int STOP = 1;
@@ -20,21 +30,19 @@ abstract public class PeriodicHandler extends Handler {
final private long period;
+ final private WeakReference<PeriodicHandlerListener> listenerRef;
+
/**
* Create a new PeriodicHandler object.
*
* @param period
* The period in milliseconds.
*/
- protected PeriodicHandler(final long period) {
+ public PeriodicHandler(final long period, final PeriodicHandlerListener listener) {
this.period = period;
+ listenerRef = new WeakReference<PeriodicHandlerListener>(listener);
}
- /**
- * Subclasses of PeriodicHandler must implement this method.
- */
- abstract public void act();
-
@Override
public void handleMessage(final Message msg) {
switch (msg.what) {
@@ -46,8 +54,11 @@ abstract public class PeriodicHandler extends Handler {
removeMessages(ACT);
break;
case ACT:
- sendEmptyMessageDelayed(ACT, period);
- act();
+ final PeriodicHandlerListener listener = listenerRef.get();
+ if (listener != null) {
+ sendEmptyMessageDelayed(ACT, period);
+ listener.onPeriodic();
+ }
break;
default:
throw new UnsupportedOperationException();
diff --git a/main/src/cgeo/geocaching/utils/ProcessUtils.java b/main/src/cgeo/geocaching/utils/ProcessUtils.java
index 53991fb..1c05e84 100644
--- a/main/src/cgeo/geocaching/utils/ProcessUtils.java
+++ b/main/src/cgeo/geocaching/utils/ProcessUtils.java
@@ -3,14 +3,37 @@ package cgeo.geocaching.utils;
import cgeo.geocaching.cgeoapplication;
import android.content.Intent;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
-public class ProcessUtils {
+import java.util.List;
+
+public final class ProcessUtils {
+
+ private ProcessUtils() {
+ // utility class
+ }
public static boolean isInstalled(final String packageName) {
- return getLaunchIntent(packageName) != null;
+ return (getLaunchIntent(packageName) != null) || hasPackageInstalled(packageName);
+ }
+
+ /**
+ * This will find installed applications even without launch intent (e.g. the streetview plugin).
+ */
+ private static boolean hasPackageInstalled(final String packageName) {
+ final List<PackageInfo> packs = cgeoapplication.getInstance().getPackageManager().getInstalledPackages(0);
+ for (final PackageInfo packageInfo : packs) {
+ if (packageName.equals(packageInfo.packageName)) {
+ return true;
+ }
+ }
+ return false;
}
+ /**
+ * This will find applications, which can be launched.
+ */
public static Intent getLaunchIntent(final String packageName) {
if (packageName == null) {
return null;
@@ -20,7 +43,7 @@ public class ProcessUtils {
// This can throw an exception where the exception type is only defined on API Level > 3
// therefore surround with try-catch
return packageManager.getLaunchIntentForPackage(packageName);
- } catch (Exception e) {
+ } catch (final Exception e) {
return null;
}
}
diff --git a/main/src/cgeo/geocaching/utils/BaseUtils.java b/main/src/cgeo/geocaching/utils/TextUtils.java
index 82e48cb..68ac595 100644
--- a/main/src/cgeo/geocaching/utils/BaseUtils.java
+++ b/main/src/cgeo/geocaching/utils/TextUtils.java
@@ -9,10 +9,14 @@ import java.util.regex.Pattern;
/**
* Misc. utils. All methods don't use Android specific stuff to use these methods in plain JUnit tests.
*/
-public final class BaseUtils {
+public final class TextUtils {
private static final Pattern PATTERN_REMOVE_NONPRINTABLE = Pattern.compile("\\p{Cntrl}");
+ private TextUtils() {
+ // utility class
+ }
+
/**
* Searches for the pattern p in the data. If the pattern is not found defaultValue is returned
*
@@ -69,7 +73,7 @@ public final class BaseUtils {
* @return defaultValue or the first group if the pattern matches (trimmed if wanted)
*/
public static String getMatch(final String data, final Pattern p, final boolean trim, final String defaultValue) {
- return BaseUtils.getMatch(data, p, trim, 1, defaultValue, false);
+ return TextUtils.getMatch(data, p, trim, 1, defaultValue, false);
}
/**
@@ -84,7 +88,7 @@ public final class BaseUtils {
* @return defaultValue or the first group if the pattern matches (trimmed)
*/
public static String getMatch(final String data, final Pattern p, final String defaultValue) {
- return BaseUtils.getMatch(data, p, true, 1, defaultValue, false);
+ return TextUtils.getMatch(data, p, true, 1, defaultValue, false);
}
/**
@@ -137,10 +141,11 @@ public final class BaseUtils {
}
/**
- * Quick and naive check for possible html-content of a string.
+ * Quick and naive check for possible rich HTML content in a string.
*
- * @param str
- * @return True, if <code>str</code> could contain html
+ * @param str A string containing HTML code.
+ * @return <tt>true</tt> if <tt>str</tt> contains HTML code that needs to go through a HTML renderer before
+ * being displayed, <tt>false</tt> if it can be displayed as-is without any loss
*/
public static boolean containsHtml(final String str) {
return str.indexOf('<') != -1 || str.indexOf('&') != -1;
diff --git a/main/src/cgeo/geocaching/utils/TranslationUtils.java b/main/src/cgeo/geocaching/utils/TranslationUtils.java
index 4d318f0..05045ee 100644
--- a/main/src/cgeo/geocaching/utils/TranslationUtils.java
+++ b/main/src/cgeo/geocaching/utils/TranslationUtils.java
@@ -19,6 +19,10 @@ public final class TranslationUtils {
public static final int translationTextLengthToWarn = 500;
private static final String TRANSLATION_APP = "com.google.android.apps.translate";
+ private TranslationUtils() {
+ // utility class
+ }
+
/**
* Build a URI for Google Translate
*
diff --git a/main/src/cgeo/geocaching/utils/XmlUtils.java b/main/src/cgeo/geocaching/utils/XmlUtils.java
index 4e08f42..2d85950 100644
--- a/main/src/cgeo/geocaching/utils/XmlUtils.java
+++ b/main/src/cgeo/geocaching/utils/XmlUtils.java
@@ -4,7 +4,7 @@ import org.xmlpull.v1.XmlSerializer;
import java.io.IOException;
-public class XmlUtils {
+public final class XmlUtils {
private XmlUtils() {
// Do not instantiate
diff --git a/main/src/cgeo/org/kxml2/io/KXmlSerializer.java b/main/src/cgeo/org/kxml2/io/KXmlSerializer.java
deleted file mode 100644
index 027ff53..0000000
--- a/main/src/cgeo/org/kxml2/io/KXmlSerializer.java
+++ /dev/null
@@ -1,605 +0,0 @@
-/*
- * Copyright (c) 2002,2003, Stefan Haustein, Oberhausen, Rhld., Germany
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-
-package cgeo.org.kxml2.io;
-
-import org.apache.commons.lang3.StringUtils;
-import org.xmlpull.v1.XmlSerializer;
-
-import java.io.BufferedWriter;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.io.Writer;
-import java.util.Locale;
-
-public class KXmlSerializer implements XmlSerializer {
-
- // static final String UNDEFINED = ":";
-
- // BEGIN android-added
- /** size (in characters) for the write buffer */
- private static final int WRITE_BUFFER_SIZE = 500;
- // END android-added
-
- // BEGIN android-changed
- // (Guarantee that the writer is always buffered.)
- private BufferedWriter writer;
- // END android-changed
-
- private boolean pending;
- private int auto;
- private int depth;
-
- private String[] elementStack = new String[12];
- //nsp/prefix/name
- private int[] nspCounts = new int[4];
- private String[] nspStack = new String[8];
- //prefix/nsp; both empty are ""
- private boolean[] indent = new boolean[4];
- private boolean unicode;
- private String encoding;
-
- private final void check(boolean close) throws IOException {
- if (!pending) {
- return;
- }
-
- depth++;
- pending = false;
-
- if (indent.length <= depth) {
- boolean[] hlp = new boolean[depth + 4];
- System.arraycopy(indent, 0, hlp, 0, depth);
- indent = hlp;
- }
- indent[depth] = indent[depth - 1];
-
- for (int i = nspCounts[depth - 1]; i < nspCounts[depth]; i++) {
- writer.write(' ');
- writer.write("xmlns");
- if (!StringUtils.isEmpty(nspStack[i * 2])) {
- writer.write(':');
- writer.write(nspStack[i * 2]);
- }
- else if (StringUtils.isEmpty(getNamespace()) && !StringUtils.isEmpty(nspStack[i * 2 + 1])) {
- throw new IllegalStateException("Cannot set default namespace for elements in no namespace");
- }
- writer.write("=\"");
- writeEscaped(nspStack[i * 2 + 1], '"');
- writer.write('"');
- }
-
- if (nspCounts.length <= depth + 1) {
- int[] hlp = new int[depth + 8];
- System.arraycopy(nspCounts, 0, hlp, 0, depth + 1);
- nspCounts = hlp;
- }
-
- nspCounts[depth + 1] = nspCounts[depth];
- // nspCounts[depth + 2] = nspCounts[depth];
-
- writer.write(close ? " />" : ">");
- }
-
- private final void writeEscaped(String s, int quot) throws IOException {
- for (int i = 0; i < s.length(); i++) {
- char c = s.charAt(i);
- switch (c) {
- case '\n':
- case '\r':
- case '\t':
- if (quot == -1) {
- writer.write(c);
- } else {
- writer.write("&#"+((int) c)+';');
- }
- break;
- case '&':
- writer.write("&amp;");
- break;
- case '>':
- writer.write("&gt;");
- break;
- case '<':
- writer.write("&lt;");
- break;
- default:
- if (c == quot) {
- writer.write(c == '"' ? "&quot;" : "&apos;");
- break;
- }
- // BEGIN android-changed: refuse to output invalid characters
- // See http://www.w3.org/TR/REC-xml/#charsets for definition.
- // Corrected for c:geo to handle utf-16 codepoint surrogates correctly
- // See http://en.wikipedia.org/wiki/UTF-16#Code_points_U.2B10000_to_U.2B10FFFF
- // Note: tab, newline, and carriage return have already been
- // handled above.
- // Check for lead surrogate
- if (c >= 0xd800 && c <= 0xdbff) {
-
- if (i + 1 < s.length()) {
- writer.write(s.substring(i, i + 1));
- i++;
- break;
- }
- // if the lead surrogate is at the string end, it's not valid utf-16
- reportInvalidCharacter(c);
- }
- boolean valid = (c >= 0x20 && c <= 0xd7ff) || (c >= 0xe000 && c <= 0xfffd);
- if (!valid) {
- reportInvalidCharacter(c);
- }
- if (unicode || c < 127) {
- writer.write(c);
- } else {
- writer.write("&#" + ((int) c) + ";");
- }
- // END android-changed
- }
- }
- }
-
- // BEGIN android-added
- private static void reportInvalidCharacter(char ch) {
- throw new IllegalArgumentException("Illegal character (" + Integer.toHexString((int) ch) + ")");
- }
- // END android-added
-
- /*
- * private final void writeIndent() throws IOException {
- * writer.write("\r\n");
- * for (int i = 0; i < depth; i++)
- * writer.write(' ');
- * }
- */
-
- public void docdecl(String dd) throws IOException {
- writer.write("<!DOCTYPE");
- writer.write(dd);
- writer.write(">");
- }
-
- public void endDocument() throws IOException {
- while (depth > 0) {
- endTag(elementStack[depth * 3 - 3], elementStack[depth * 3 - 1]);
- }
- flush();
- }
-
- public void entityRef(String name) throws IOException {
- check(false);
- writer.write('&');
- writer.write(name);
- writer.write(';');
- }
-
- public boolean getFeature(String name) {
- //return false;
- return ("http://xmlpull.org/v1/doc/features.html#indent-output"
- .equals(
- name))
- ? indent[depth]
- : false;
- }
-
- public String getPrefix(String namespace, boolean create) {
- try {
- return getPrefix(namespace, false, create);
- } catch (IOException e) {
- throw new RuntimeException(e.toString());
- }
- }
-
- private final String getPrefix(
- String namespace,
- boolean includeDefault,
- boolean create)
- throws IOException {
-
- for (int i = nspCounts[depth + 1] * 2 - 2; i >= 0; i -= 2) {
- if (nspStack[i + 1].equals(namespace)
- && (includeDefault || !StringUtils.isEmpty(nspStack[i]))) {
- String cand = nspStack[i];
- for (int j = i + 2; j < nspCounts[depth + 1] * 2; j++) {
- if (nspStack[j].equals(cand)) {
- cand = null;
- break;
- }
- }
- if (cand != null) {
- return cand;
- }
- }
- }
-
- if (!create) {
- return null;
- }
-
- String prefix;
-
- if (StringUtils.isEmpty(namespace)) {
- prefix = "";
- } else {
- do {
- prefix = "n" + (auto++);
- for (int i = nspCounts[depth + 1] * 2 - 2; i >= 0; i -= 2) {
- if (prefix.equals(nspStack[i])) {
- prefix = null;
- break;
- }
- }
- } while (prefix == null);
- }
-
- boolean p = pending;
- pending = false;
- setPrefix(prefix, namespace);
- pending = p;
- return prefix;
- }
-
- public Object getProperty(String name) {
- throw new RuntimeException("Unsupported property");
- }
-
- public void ignorableWhitespace(String s)
- throws IOException {
- text(s);
- }
-
- public void setFeature(String name, boolean value) {
- if ("http://xmlpull.org/v1/doc/features.html#indent-output"
- .equals(name)) {
- indent[depth] = value;
- } else {
- throw new RuntimeException("Unsupported Feature");
- }
- }
-
- public void setProperty(String name, Object value) {
- throw new RuntimeException(
- "Unsupported Property:" + value);
- }
-
- public void setPrefix(String prefix, String namespace)
- throws IOException {
-
- check(false);
- if (prefix == null) {
- prefix = "";
- }
- if (namespace == null) {
- namespace = "";
- }
-
- String defined = getPrefix(namespace, true, false);
-
- // boil out if already defined
-
- if (prefix.equals(defined)) {
- return;
- }
-
- int pos = (nspCounts[depth + 1]++) << 1;
-
- if (nspStack.length < pos + 1) {
- String[] hlp = new String[nspStack.length + 16];
- System.arraycopy(nspStack, 0, hlp, 0, pos);
- nspStack = hlp;
- }
-
- nspStack[pos++] = prefix;
- nspStack[pos] = namespace;
- }
-
- public void setOutput(Writer writer) {
- // BEGIN android-changed
- // Guarantee that the writer is always buffered.
- if (writer instanceof BufferedWriter) {
- this.writer = (BufferedWriter) writer;
- } else {
- this.writer = new BufferedWriter(writer, WRITE_BUFFER_SIZE);
- }
- // END android-changed
-
- // elementStack = new String[12]; //nsp/prefix/name
- //nspCounts = new int[4];
- //nspStack = new String[8]; //prefix/nsp
- //indent = new boolean[4];
-
- nspCounts[0] = 2;
- nspCounts[1] = 2;
- nspStack[0] = "";
- nspStack[1] = "";
- nspStack[2] = "xml";
- nspStack[3] = "http://www.w3.org/XML/1998/namespace";
- pending = false;
- auto = 0;
- depth = 0;
-
- unicode = false;
- }
-
- public void setOutput(OutputStream os, String encoding)
- throws IOException {
- if (os == null) {
- throw new IllegalArgumentException("os == null");
- }
- setOutput(encoding == null
- ? new OutputStreamWriter(os)
- : new OutputStreamWriter(os, encoding));
- this.encoding = encoding;
- if (encoding != null && encoding.toLowerCase(Locale.US).startsWith("utf")) {
- unicode = true;
- }
- }
-
- public void startDocument(String encoding, Boolean standalone) throws IOException {
- writer.write("<?xml version='1.0' ");
-
- if (encoding != null) {
- this.encoding = encoding;
- if (encoding.toLowerCase(Locale.US).startsWith("utf")) {
- unicode = true;
- }
- }
-
- if (this.encoding != null) {
- writer.write("encoding='");
- writer.write(this.encoding);
- writer.write("' ");
- }
-
- if (standalone != null) {
- writer.write("standalone='");
- writer.write(
- standalone.booleanValue() ? "yes" : "no");
- writer.write("' ");
- }
- writer.write("?>");
- }
-
- public XmlSerializer startTag(String namespace, String name)
- throws IOException {
- check(false);
-
- // if (namespace == null)
- // namespace = "";
-
- if (indent[depth]) {
- writer.write("\r\n");
- for (int i = 0; i < depth; i++) {
- writer.write(" ");
- }
- }
-
- int esp = depth * 3;
-
- if (elementStack.length < esp + 3) {
- String[] hlp = new String[elementStack.length + 12];
- System.arraycopy(elementStack, 0, hlp, 0, esp);
- elementStack = hlp;
- }
-
- String prefix =
- namespace == null
- ? ""
- : getPrefix(namespace, true, true);
-
- if (namespace != null && StringUtils.isEmpty(namespace)) {
- for (int i = nspCounts[depth]; i < nspCounts[depth + 1]; i++) {
- if (StringUtils.isEmpty(nspStack[i * 2]) && !StringUtils.isEmpty(nspStack[i * 2 + 1])) {
- throw new IllegalStateException("Cannot set default namespace for elements in no namespace");
- }
- }
- }
-
- elementStack[esp++] = namespace;
- elementStack[esp++] = prefix;
- elementStack[esp] = name;
-
- writer.write('<');
- if (!StringUtils.isEmpty(prefix)) {
- writer.write(prefix);
- writer.write(':');
- }
-
- writer.write(name);
-
- pending = true;
-
- return this;
- }
-
- public XmlSerializer attribute(
- String namespace,
- String name,
- String value)
- throws IOException {
- if (!pending) {
- throw new IllegalStateException("illegal position for attribute");
- }
-
- // int cnt = nspCounts[depth];
-
- if (namespace == null) {
- namespace = "";
- }
-
- // depth--;
- // pending = false;
-
- String prefix =
- StringUtils.isEmpty(namespace)
- ? ""
- : getPrefix(namespace, false, true);
-
- // pending = true;
- // depth++;
-
- /*
- * if (cnt != nspCounts[depth]) {
- * writer.write(' ');
- * writer.write("xmlns");
- * if (nspStack[cnt * 2] != null) {
- * writer.write(':');
- * writer.write(nspStack[cnt * 2]);
- * }
- * writer.write("=\"");
- * writeEscaped(nspStack[cnt * 2 + 1], '"');
- * writer.write('"');
- * }
- */
-
- writer.write(' ');
- if (!StringUtils.isEmpty(prefix)) {
- writer.write(prefix);
- writer.write(':');
- }
- writer.write(name);
- writer.write('=');
- char q = value.indexOf('"') == -1 ? '"' : '\'';
- writer.write(q);
- writeEscaped(value, q);
- writer.write(q);
-
- return this;
- }
-
- public void flush() throws IOException {
- check(false);
- writer.flush();
- }
-
- /*
- * public void close() throws IOException {
- * check();
- * writer.close();
- * }
- */
- public XmlSerializer endTag(String namespace, String name)
- throws IOException {
-
- if (!pending)
- {
- depth--;
- // if (namespace == null)
- // namespace = "";
- }
-
- if ((namespace == null
- && elementStack[depth * 3] != null)
- || (namespace != null
- && !namespace.equals(elementStack[depth * 3]))
- || !elementStack[depth * 3 + 2].equals(name)) {
- throw new IllegalArgumentException("</{"+namespace+"}"+name+"> does not match start");
- }
-
- if (pending) {
- check(true);
- depth--;
- }
- else {
- if (indent[depth + 1]) {
- writer.write("\r\n");
- for (int i = 0; i < depth; i++) {
- writer.write(" ");
- }
- }
-
- writer.write("</");
- String prefix = elementStack[depth * 3 + 1];
- if (!StringUtils.isEmpty(prefix)) {
- writer.write(prefix);
- writer.write(':');
- }
- writer.write(name);
- writer.write('>');
- }
-
- nspCounts[depth + 1] = nspCounts[depth];
- return this;
- }
-
- public String getNamespace() {
- return getDepth() == 0 ? null : elementStack[getDepth() * 3 - 3];
- }
-
- public String getName() {
- return getDepth() == 0 ? null : elementStack[getDepth() * 3 - 1];
- }
-
- public int getDepth() {
- return pending ? depth + 1 : depth;
- }
-
- public XmlSerializer text(String text) throws IOException {
- check(false);
- indent[depth] = false;
- writeEscaped(text, -1);
- return this;
- }
-
- public XmlSerializer text(char[] text, int start, int len)
- throws IOException {
- text(new String(text, start, len));
- return this;
- }
-
- public void cdsect(String data) throws IOException {
- check(false);
- // BEGIN android-changed: ]]> is not allowed within a CDATA,
- // so break and start a new one when necessary.
- data = data.replace("]]>", "]]]]><![CDATA[>");
- char[] chars = data.toCharArray();
- // We also aren't allowed any invalid characters.
- for (char ch : chars) {
- boolean valid = (ch >= 0x20 && ch <= 0xd7ff) ||
- (ch == '\t' || ch == '\n' || ch == '\r') ||
- (ch >= 0xe000 && ch <= 0xfffd);
- if (!valid) {
- reportInvalidCharacter(ch);
- }
- }
- writer.write("<![CDATA[");
- writer.write(chars, 0, chars.length);
- writer.write("]]>");
- // END android-changed
- }
-
- public void comment(String comment) throws IOException {
- check(false);
- writer.write("<!--");
- writer.write(comment);
- writer.write("-->");
- }
-
- public void processingInstruction(String pi)
- throws IOException {
- check(false);
- writer.write("<?");
- writer.write(pi);
- writer.write("?>");
- }
-} \ No newline at end of file
diff --git a/main/src/com/viewpagerindicator/PageIndicator.java b/main/src/com/viewpagerindicator/PageIndicator.java
deleted file mode 100644
index 26414d8..0000000
--- a/main/src/com/viewpagerindicator/PageIndicator.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2011 Patrik Akerfeldt
- * Copyright (C) 2011 Jake Wharton
- *
- * 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.viewpagerindicator;
-
-import android.support.v4.view.ViewPager;
-
-/**
- * A PageIndicator is responsible to show an visual indicator on the total views
- * number and the current visible view.
- */
-public interface PageIndicator extends ViewPager.OnPageChangeListener {
- /**
- * Bind the indicator to a ViewPager.
- *
- * @param view
- */
- public void setViewPager(ViewPager view);
-
- /**
- * Bind the indicator to a ViewPager.
- *
- * @param view
- * @param initialPosition
- */
- public void setViewPager(ViewPager view, int initialPosition);
-
- /**
- * <p>Set the current page of both the ViewPager and indicator.</p>
- *
- * <p>This <strong>must</strong> be used if you need to set the page before
- * the views are drawn on screen (e.g., default start page).</p>
- *
- * @param item
- */
- public void setCurrentItem(int item);
-
- /**
- * Set a page change listener which will receive forwarded events.
- *
- * @param listener
- */
- public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener);
-
- /**
- * Notify the indicator that the fragment list has changed.
- */
- public void notifyDataSetChanged();
-}
diff --git a/main/src/com/viewpagerindicator/TitlePageIndicator.java b/main/src/com/viewpagerindicator/TitlePageIndicator.java
deleted file mode 100644
index 94ac962..0000000
--- a/main/src/com/viewpagerindicator/TitlePageIndicator.java
+++ /dev/null
@@ -1,771 +0,0 @@
-/*
- * Copyright (C) 2011 Patrik Akerfeldt
- * Copyright (C) 2011 Francisco Figueiredo Jr.
- * Copyright (C) 2011 Jake Wharton
- *
- * 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.viewpagerindicator;
-
-import cgeo.geocaching.R;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.RectF;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.support.v4.view.MotionEventCompat;
-import android.support.v4.view.PagerAdapter;
-import android.support.v4.view.ViewConfigurationCompat;
-import android.support.v4.view.ViewPager;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewConfiguration;
-
-import java.util.ArrayList;
-
-/**
- * A TitlePageIndicator is a PageIndicator which displays the title of left view
- * (if exist), the title of the current select view (centered) and the title of
- * the right view (if exist). When the user scrolls the ViewPager then titles are
- * also scrolled.
- */
-public class TitlePageIndicator extends View implements PageIndicator {
- /**
- * Percentage indicating what percentage of the screen width away from
- * center should the underline be fully faded. A value of 0.25 means that
- * halfway between the center of the screen and an edge.
- */
- private static final float SELECTION_FADE_PERCENTAGE = 0.25f;
-
- /**
- * Percentage indicating what percentage of the screen width away from
- * center should the selected text bold turn off. A value of 0.05 means
- * that 10% between the center and an edge.
- */
- private static final float BOLD_FADE_PERCENTAGE = 0.05f;
-
- public enum IndicatorStyle {
- None(0), Triangle(1), Underline(2);
-
- public final int value;
-
- IndicatorStyle(int value) {
- this.value = value;
- }
-
- public static IndicatorStyle fromValue(int value) {
- for (IndicatorStyle style : IndicatorStyle.values()) {
- if (style.value == value) {
- return style;
- }
- }
- return null;
- }
- }
-
- private ViewPager mViewPager;
- private ViewPager.OnPageChangeListener mListener;
- private TitleProvider mTitleProvider;
- private int mCurrentPage;
- private int mCurrentOffset;
- private int mScrollState;
- private final Paint mPaintText;
- private boolean mBoldText;
- private int mColorText;
- private int mColorSelected;
- private Path mPath = new Path();
- private final Paint mPaintFooterLine;
- private IndicatorStyle mFooterIndicatorStyle;
- private final Paint mPaintFooterIndicator;
- private float mFooterIndicatorHeight;
- private float mFooterIndicatorUnderlinePadding;
- private float mFooterPadding;
- private float mTitlePadding;
- private float mTopPadding;
- /** Left and right side padding for not active view titles. */
- private float mClipPadding;
- private float mFooterLineHeight;
-
- private static final int INVALID_POINTER = -1;
-
- private int mTouchSlop;
- private float mLastMotionX = -1;
- private int mActivePointerId = INVALID_POINTER;
- private boolean mIsDragging;
-
-
- public TitlePageIndicator(Context context) {
- this(context, null);
- }
-
- public TitlePageIndicator(Context context, AttributeSet attrs) {
- this(context, attrs, R.attr.vpiTitlePageIndicatorStyle);
- }
-
- public TitlePageIndicator(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
-
- //Load defaults from resources
- final Resources res = getResources();
- final int defaultFooterColor = res.getColor(R.color.default_title_indicator_footer_color);
- final float defaultFooterLineHeight = res.getDimension(R.dimen.default_title_indicator_footer_line_height);
- final int defaultFooterIndicatorStyle = res.getInteger(R.integer.default_title_indicator_footer_indicator_style);
- final float defaultFooterIndicatorHeight = res.getDimension(R.dimen.default_title_indicator_footer_indicator_height);
- final float defaultFooterIndicatorUnderlinePadding = res.getDimension(R.dimen.default_title_indicator_footer_indicator_underline_padding);
- final float defaultFooterPadding = res.getDimension(R.dimen.default_title_indicator_footer_padding);
- final int defaultSelectedColor = res.getColor(R.color.default_title_indicator_selected_color);
- final boolean defaultSelectedBold = res.getBoolean(R.bool.default_title_indicator_selected_bold);
- final int defaultTextColor = res.getColor(R.color.default_title_indicator_text_color);
- final float defaultTextSize = res.getDimension(R.dimen.default_title_indicator_text_size);
- final float defaultTitlePadding = res.getDimension(R.dimen.default_title_indicator_title_padding);
- final float defaultClipPadding = res.getDimension(R.dimen.default_title_indicator_clip_padding);
- final float defaultTopPadding = res.getDimension(R.dimen.default_title_indicator_top_padding);
-
- //Retrieve styles attributes
- TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TitlePageIndicator, defStyle, R.style.Widget_TitlePageIndicator);
-
- //Retrieve the colors to be used for this view and apply them.
- mFooterLineHeight = a.getDimension(R.styleable.TitlePageIndicator_footerLineHeight, defaultFooterLineHeight);
- mFooterIndicatorStyle = IndicatorStyle.fromValue(a.getInteger(R.styleable.TitlePageIndicator_footerIndicatorStyle, defaultFooterIndicatorStyle));
- mFooterIndicatorHeight = a.getDimension(R.styleable.TitlePageIndicator_footerIndicatorHeight, defaultFooterIndicatorHeight);
- mFooterIndicatorUnderlinePadding = a.getDimension(R.styleable.TitlePageIndicator_footerIndicatorUnderlinePadding, defaultFooterIndicatorUnderlinePadding);
- mFooterPadding = a.getDimension(R.styleable.TitlePageIndicator_footerPadding, defaultFooterPadding);
- mTopPadding = a.getDimension(R.styleable.TitlePageIndicator_topPadding, defaultTopPadding);
- mTitlePadding = a.getDimension(R.styleable.TitlePageIndicator_titlePadding, defaultTitlePadding);
- mClipPadding = a.getDimension(R.styleable.TitlePageIndicator_clipPadding, defaultClipPadding);
- mColorSelected = a.getColor(R.styleable.TitlePageIndicator_selectedColor, defaultSelectedColor);
- mColorText = a.getColor(R.styleable.TitlePageIndicator_textColor, defaultTextColor);
- mBoldText = a.getBoolean(R.styleable.TitlePageIndicator_selectedBold, defaultSelectedBold);
-
- final float textSize = a.getDimension(R.styleable.TitlePageIndicator_textSize, defaultTextSize);
- final int footerColor = a.getColor(R.styleable.TitlePageIndicator_footerColor, defaultFooterColor);
- mPaintText = new Paint();
- mPaintText.setTextSize(textSize);
- mPaintText.setAntiAlias(true);
- mPaintFooterLine = new Paint();
- mPaintFooterLine.setStyle(Paint.Style.FILL_AND_STROKE);
- mPaintFooterLine.setStrokeWidth(mFooterLineHeight);
- mPaintFooterLine.setColor(footerColor);
- mPaintFooterIndicator = new Paint();
- mPaintFooterIndicator.setStyle(Paint.Style.FILL_AND_STROKE);
- mPaintFooterIndicator.setColor(footerColor);
-
- a.recycle();
-
- final ViewConfiguration configuration = ViewConfiguration.get(context);
- mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(configuration);
- }
-
-
- public int getFooterColor() {
- return mPaintFooterLine.getColor();
- }
-
- public void setFooterColor(int footerColor) {
- mPaintFooterLine.setColor(footerColor);
- mPaintFooterIndicator.setColor(footerColor);
- invalidate();
- }
-
- public float getFooterLineHeight() {
- return mFooterLineHeight;
- }
-
- public void setFooterLineHeight(float footerLineHeight) {
- mFooterLineHeight = footerLineHeight;
- mPaintFooterLine.setStrokeWidth(mFooterLineHeight);
- invalidate();
- }
-
- public float getFooterIndicatorHeight() {
- return mFooterIndicatorHeight;
- }
-
- public void setFooterIndicatorHeight(float footerTriangleHeight) {
- mFooterIndicatorHeight = footerTriangleHeight;
- invalidate();
- }
-
- public float getFooterIndicatorPadding() {
- return mFooterPadding;
- }
-
- public void setFooterIndicatorPadding(float footerIndicatorPadding) {
- mFooterPadding = footerIndicatorPadding;
- invalidate();
- }
-
- public IndicatorStyle getFooterIndicatorStyle() {
- return mFooterIndicatorStyle;
- }
-
- public void setFooterIndicatorStyle(IndicatorStyle indicatorStyle) {
- mFooterIndicatorStyle = indicatorStyle;
- invalidate();
- }
-
- public int getSelectedColor() {
- return mColorSelected;
- }
-
- public void setSelectedColor(int selectedColor) {
- mColorSelected = selectedColor;
- invalidate();
- }
-
- public boolean isSelectedBold() {
- return mBoldText;
- }
-
- public void setSelectedBold(boolean selectedBold) {
- mBoldText = selectedBold;
- invalidate();
- }
-
- public int getTextColor() {
- return mColorText;
- }
-
- public void setTextColor(int textColor) {
- mPaintText.setColor(textColor);
- mColorText = textColor;
- invalidate();
- }
-
- public float getTextSize() {
- return mPaintText.getTextSize();
- }
-
- public void setTextSize(float textSize) {
- mPaintText.setTextSize(textSize);
- invalidate();
- }
-
- public float getTitlePadding() {
- return this.mTitlePadding;
- }
-
- public void setTitlePadding(float titlePadding) {
- mTitlePadding = titlePadding;
- invalidate();
- }
-
- public float getTopPadding() {
- return this.mTopPadding;
- }
-
- public void setTopPadding(float topPadding) {
- mTopPadding = topPadding;
- invalidate();
- }
-
- public float getClipPadding() {
- return this.mClipPadding;
- }
-
- public void setClipPadding(float clipPadding) {
- mClipPadding = clipPadding;
- invalidate();
- }
-
- /*
- * (non-Javadoc)
- *
- * @see android.view.View#onDraw(android.graphics.Canvas)
- */
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
-
- if (mViewPager == null) {
- return;
- }
- final int count = mViewPager.getAdapter().getCount();
- if (count == 0) {
- return;
- }
-
- //Calculate views bounds
- ArrayList<RectF> bounds = calculateAllBounds(mPaintText);
-
- //Make sure we're on a page that still exists
- if (mCurrentPage >= bounds.size()) {
- setCurrentItem(bounds.size()-1);
- }
-
- final int countMinusOne = count - 1;
- final float halfWidth = getWidth() / 2f;
- final int left = getLeft();
- final float leftClip = left + mClipPadding;
- final int width = getWidth();
- final int height = getHeight();
- final int right = left + width;
- final float rightClip = right - mClipPadding;
-
- int page = mCurrentPage;
- float offsetPercent;
- if (mCurrentOffset <= halfWidth) {
- offsetPercent = 1.0f * mCurrentOffset / width;
- } else {
- page += 1;
- offsetPercent = 1.0f * (width - mCurrentOffset) / width;
- }
- final boolean currentSelected = (offsetPercent <= SELECTION_FADE_PERCENTAGE);
- final boolean currentBold = (offsetPercent <= BOLD_FADE_PERCENTAGE);
- final float selectedPercent = (SELECTION_FADE_PERCENTAGE - offsetPercent) / SELECTION_FADE_PERCENTAGE;
-
- //Verify if the current view must be clipped to the screen
- RectF curPageBound = bounds.get(mCurrentPage);
- float curPageWidth = curPageBound.right - curPageBound.left;
- if (curPageBound.left < leftClip) {
- //Try to clip to the screen (left side)
- clipViewOnTheLeft(curPageBound, curPageWidth, left);
- }
- if (curPageBound.right > rightClip) {
- //Try to clip to the screen (right side)
- clipViewOnTheRight(curPageBound, curPageWidth, right);
- }
-
- //Left views starting from the current position
- if (mCurrentPage > 0) {
- for (int i = mCurrentPage - 1; i >= 0; i--) {
- RectF bound = bounds.get(i);
- //Is left side is outside the screen
- if (bound.left < leftClip) {
- float w = bound.right - bound.left;
- //Try to clip to the screen (left side)
- clipViewOnTheLeft(bound, w, left);
- //Except if there's an intersection with the right view
- RectF rightBound = bounds.get(i + 1);
- //Intersection
- if (bound.right + mTitlePadding > rightBound.left) {
- bound.left = rightBound.left - w - mTitlePadding;
- bound.right = bound.left + w;
- }
- }
- }
- }
- //Right views starting from the current position
- if (mCurrentPage < countMinusOne) {
- for (int i = mCurrentPage + 1 ; i < count; i++) {
- RectF bound = bounds.get(i);
- //If right side is outside the screen
- if (bound.right > rightClip) {
- float w = bound.right - bound.left;
- //Try to clip to the screen (right side)
- clipViewOnTheRight(bound, w, right);
- //Except if there's an intersection with the left view
- RectF leftBound = bounds.get(i - 1);
- //Intersection
- if (bound.left - mTitlePadding < leftBound.right) {
- bound.left = leftBound.right + mTitlePadding;
- bound.right = bound.left + w;
- }
- }
- }
- }
-
- //Now draw views
- for (int i = 0; i < count; i++) {
- //Get the title
- RectF bound = bounds.get(i);
- //Only if one side is visible
- if ((bound.left > left && bound.left < right) || (bound.right > left && bound.right < right)) {
- final boolean currentPage = (i == page);
- //Only set bold if we are within bounds
- mPaintText.setFakeBoldText(currentPage && currentBold && mBoldText);
-
- //Draw text as unselected
- mPaintText.setColor(mColorText);
- canvas.drawText(mTitleProvider.getTitle(i), bound.left, bound.bottom + mTopPadding, mPaintText);
-
- //If we are within the selected bounds draw the selected text
- if (currentPage && currentSelected) {
- mPaintText.setColor(mColorSelected);
- mPaintText.setAlpha((int)((mColorSelected >>> 24) * selectedPercent));
- canvas.drawText(mTitleProvider.getTitle(i), bound.left, bound.bottom + mTopPadding, mPaintText);
- }
- }
- }
-
- //Draw the footer line
- mPath.reset();
- mPath.moveTo(0, height - mFooterLineHeight / 2f);
- mPath.lineTo(width, height - mFooterLineHeight / 2f);
- mPath.close();
- canvas.drawPath(mPath, mPaintFooterLine);
-
- switch (mFooterIndicatorStyle) {
- case Triangle:
- mPath.reset();
- mPath.moveTo(halfWidth, height - mFooterLineHeight - mFooterIndicatorHeight);
- mPath.lineTo(halfWidth + mFooterIndicatorHeight, height - mFooterLineHeight);
- mPath.lineTo(halfWidth - mFooterIndicatorHeight, height - mFooterLineHeight);
- mPath.close();
- canvas.drawPath(mPath, mPaintFooterIndicator);
- break;
-
- case Underline:
- if (!currentSelected) {
- break;
- }
-
- RectF underlineBounds = bounds.get(page);
- mPath.reset();
- mPath.moveTo(underlineBounds.left - mFooterIndicatorUnderlinePadding, height - mFooterLineHeight);
- mPath.lineTo(underlineBounds.right + mFooterIndicatorUnderlinePadding, height - mFooterLineHeight);
- mPath.lineTo(underlineBounds.right + mFooterIndicatorUnderlinePadding, height - mFooterLineHeight - mFooterIndicatorHeight);
- mPath.lineTo(underlineBounds.left - mFooterIndicatorUnderlinePadding, height - mFooterLineHeight - mFooterIndicatorHeight);
- mPath.close();
-
- mPaintFooterIndicator.setAlpha((int)(0xFF * selectedPercent));
- canvas.drawPath(mPath, mPaintFooterIndicator);
- mPaintFooterIndicator.setAlpha(0xFF);
- break;
-
- default:
- break;
- }
- }
-
- @Override
- public boolean onTouchEvent(android.view.MotionEvent ev) {
- if ((mViewPager == null) || (mViewPager.getAdapter().getCount() == 0)) {
- return false;
- }
-
- final int action = ev.getAction();
-
- switch (action & MotionEventCompat.ACTION_MASK) {
- case MotionEvent.ACTION_DOWN:
- mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
- mLastMotionX = ev.getX();
- break;
-
- case MotionEvent.ACTION_MOVE: {
- final int activePointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId);
- final float x = MotionEventCompat.getX(ev, activePointerIndex);
- final float deltaX = x - mLastMotionX;
-
- if (!mIsDragging) {
- if (Math.abs(deltaX) > mTouchSlop) {
- mIsDragging = true;
- }
- }
-
- if (mIsDragging) {
- if (!mViewPager.isFakeDragging()) {
- mViewPager.beginFakeDrag();
- }
-
- mLastMotionX = x;
-
- mViewPager.fakeDragBy(deltaX);
- }
-
- break;
- }
-
- case MotionEvent.ACTION_CANCEL:
- case MotionEvent.ACTION_UP:
- if (!mIsDragging) {
- final int count = mViewPager.getAdapter().getCount();
- final int width = getWidth();
- final float halfWidth = width / 2f;
- final float sixthWidth = width / 6f;
-
- if ((mCurrentPage > 0) && (ev.getX() < halfWidth - sixthWidth)) {
- mViewPager.setCurrentItem(mCurrentPage - 1);
- return true;
- } else if ((mCurrentPage < count - 1) && (ev.getX() > halfWidth + sixthWidth)) {
- mViewPager.setCurrentItem(mCurrentPage + 1);
- return true;
- }
- }
-
- mIsDragging = false;
- mActivePointerId = INVALID_POINTER;
- if (mViewPager.isFakeDragging()) {
- mViewPager.endFakeDrag();
- }
- break;
-
- case MotionEventCompat.ACTION_POINTER_DOWN: {
- final int index = MotionEventCompat.getActionIndex(ev);
- mLastMotionX = MotionEventCompat.getX(ev, index);
- mActivePointerId = MotionEventCompat.getPointerId(ev, index);
- break;
- }
-
- case MotionEventCompat.ACTION_POINTER_UP:
- final int pointerIndex = MotionEventCompat.getActionIndex(ev);
- final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex);
- if (pointerId == mActivePointerId) {
- final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
- mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex);
- }
- mLastMotionX = MotionEventCompat.getX(ev, MotionEventCompat.findPointerIndex(ev, mActivePointerId));
- break;
- }
-
- return true;
- }
-
- /**
- * Set bounds for the right textView including clip padding.
- *
- * @param curViewBound
- * current bounds.
- * @param curViewWidth
- * width of the view.
- */
- private void clipViewOnTheRight(RectF curViewBound, float curViewWidth, int right) {
- curViewBound.right = right - mClipPadding;
- curViewBound.left = curViewBound.right - curViewWidth;
- }
-
- /**
- * Set bounds for the left textView including clip padding.
- *
- * @param curViewBound
- * current bounds.
- * @param curViewWidth
- * width of the view.
- */
- private void clipViewOnTheLeft(RectF curViewBound, float curViewWidth, int left) {
- curViewBound.left = left + mClipPadding;
- curViewBound.right = mClipPadding + curViewWidth;
- }
-
- /**
- * Calculate views bounds and scroll them according to the current index
- *
- * @param paint
- * @param currentIndex
- * @return
- */
- private ArrayList<RectF> calculateAllBounds(Paint paint) {
- ArrayList<RectF> list = new ArrayList<RectF>();
- //For each views (If no values then add a fake one)
- final int count = mViewPager.getAdapter().getCount();
- final int width = getWidth();
- final int halfWidth = width / 2;
- for (int i = 0; i < count; i++) {
- RectF bounds = calcBounds(i, paint);
- float w = (bounds.right - bounds.left);
- float h = (bounds.bottom - bounds.top);
- bounds.left = (halfWidth) - (w / 2) - mCurrentOffset + ((i - mCurrentPage) * width);
- bounds.right = bounds.left + w;
- bounds.top = 0;
- bounds.bottom = h;
- list.add(bounds);
- }
-
- return list;
- }
-
- /**
- * Calculate the bounds for a view's title
- *
- * @param index
- * @param paint
- * @return
- */
- private RectF calcBounds(int index, Paint paint) {
- //Calculate the text bounds
- RectF bounds = new RectF();
- bounds.right = paint.measureText(mTitleProvider.getTitle(index));
- bounds.bottom = paint.descent() - paint.ascent();
- return bounds;
- }
-
- @Override
- public void setViewPager(ViewPager view) {
- final PagerAdapter adapter = view.getAdapter();
- if (adapter == null) {
- throw new IllegalStateException("ViewPager does not have adapter instance.");
- }
- if (!(adapter instanceof TitleProvider)) {
- throw new IllegalStateException("ViewPager adapter must implement TitleProvider to be used with TitlePageIndicator.");
- }
- mViewPager = view;
- mViewPager.setOnPageChangeListener(this);
- mTitleProvider = (TitleProvider)adapter;
- invalidate();
- }
-
- @Override
- public void setViewPager(ViewPager view, int initialPosition) {
- setViewPager(view);
- setCurrentItem(initialPosition);
- }
-
- @Override
- public void notifyDataSetChanged() {
- invalidate();
- }
-
- @Override
- public void setCurrentItem(int item) {
- if (mViewPager == null) {
- throw new IllegalStateException("ViewPager has not been bound.");
- }
- mViewPager.setCurrentItem(item);
- mCurrentPage = item;
- invalidate();
- }
-
- @Override
- public void onPageScrollStateChanged(int state) {
- mScrollState = state;
-
- if (mListener != null) {
- mListener.onPageScrollStateChanged(state);
- }
- }
-
- @Override
- public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
- mCurrentPage = position;
- mCurrentOffset = positionOffsetPixels;
- invalidate();
-
- if (mListener != null) {
- mListener.onPageScrolled(position, positionOffset, positionOffsetPixels);
- }
- }
-
- @Override
- public void onPageSelected(int position) {
- if (mScrollState == ViewPager.SCROLL_STATE_IDLE) {
- mCurrentPage = position;
- invalidate();
- }
-
- if (mListener != null) {
- mListener.onPageSelected(position);
- }
- }
-
- @Override
- public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener) {
- mListener = listener;
- }
-
- /*
- * (non-Javadoc)
- *
- * @see android.view.View#onMeasure(int, int)
- */
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec));
- }
-
- /**
- * Determines the width of this view
- *
- * @param measureSpec
- * A measureSpec packed into an int
- * @return The width of the view, honoring constraints from measureSpec
- */
- private int measureWidth(int measureSpec) {
- int specMode = MeasureSpec.getMode(measureSpec);
- int specSize = MeasureSpec.getSize(measureSpec);
-
- if (specMode != MeasureSpec.EXACTLY) {
- throw new IllegalStateException(getClass().getSimpleName() + " can only be used in EXACTLY mode.");
- }
- return specSize;
- }
-
- /**
- * Determines the height of this view
- *
- * @param measureSpec
- * A measureSpec packed into an int
- * @return The height of the view, honoring constraints from measureSpec
- */
- private int measureHeight(int measureSpec) {
- float result;
- int specMode = MeasureSpec.getMode(measureSpec);
- int specSize = MeasureSpec.getSize(measureSpec);
-
- if (specMode == MeasureSpec.EXACTLY) {
- //We were told how big to be
- result = specSize;
- } else {
- //Calculate the text bounds
- RectF bounds = new RectF();
- bounds.bottom = mPaintText.descent()-mPaintText.ascent();
- result = bounds.bottom - bounds.top + mFooterLineHeight + mFooterPadding + mTopPadding;
- if (mFooterIndicatorStyle != IndicatorStyle.None) {
- result += mFooterIndicatorHeight;
- }
- }
- return (int)result;
- }
-
- @Override
- public void onRestoreInstanceState(Parcelable state) {
- SavedState savedState = (SavedState)state;
- super.onRestoreInstanceState(savedState.getSuperState());
- mCurrentPage = savedState.currentPage;
- requestLayout();
- }
-
- @Override
- public Parcelable onSaveInstanceState() {
- Parcelable superState = super.onSaveInstanceState();
- SavedState savedState = new SavedState(superState);
- savedState.currentPage = mCurrentPage;
- return savedState;
- }
-
- static class SavedState extends BaseSavedState {
- int currentPage;
-
- public SavedState(Parcelable superState) {
- super(superState);
- }
-
- private SavedState(Parcel in) {
- super(in);
- currentPage = in.readInt();
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- super.writeToParcel(dest, flags);
- dest.writeInt(currentPage);
- }
-
- public static final Parcelable.Creator<SavedState> CREATOR = new Parcelable.Creator<SavedState>() {
- @Override
- public SavedState createFromParcel(Parcel in) {
- return new SavedState(in);
- }
-
- @Override
- public SavedState[] newArray(int size) {
- return new SavedState[size];
- }
- };
- }
-}
diff --git a/main/src/com/viewpagerindicator/TitleProvider.java b/main/src/com/viewpagerindicator/TitleProvider.java
deleted file mode 100644
index 2a04b65..0000000
--- a/main/src/com/viewpagerindicator/TitleProvider.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2011 Patrik Akerfeldt
- *
- * 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.viewpagerindicator;
-
-/**
- * A TitleProvider provides the title to display according to a view.
- */
-public interface TitleProvider {
- /**
- * Returns the title of the view at position
- * @param position
- * @return
- */
- public String getTitle(int position);
-}
diff --git a/main/src/gnu/android/app/appmanualclient/AppManualReaderClient.java b/main/src/gnu/android/app/appmanualclient/AppManualReaderClient.java
deleted file mode 100644
index af4c03e..0000000
--- a/main/src/gnu/android/app/appmanualclient/AppManualReaderClient.java
+++ /dev/null
@@ -1,375 +0,0 @@
-package gnu.android.app.appmanualclient;
-
-import android.content.ActivityNotFoundException;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.net.Uri;
-import android.util.Log;
-
-import java.util.List;
-
-/**
- * The "App Manual Reader" client is a class to be used in applications which
- * want to offer their users manuals through the gnu.android.appmanualreader
- * application. Such applications do not need to include the whole
- * "App Manual Reader" app but instead just have to include only this little
- * package. This package then provides the mechanism to open suitable installed
- * manuals. It does not include any manuals itself.
- * <p>
- *
- * (c) 2011 Geocrasher (geocrasher@gmx.eu)
- * <p>
- *
- * This program is free software: you can redistribute it and/or modify it under
- * the terms of the GNU Lesser General Public License as published by the Free
- * Software Foundation, either version 3 of the License, or (at your option) any
- * later version.
- * <p>
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
- * details.
- * <p>
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program. If not, see http://www.gnu.org/licenses/.
- *
- * @author Geocrasher
- */
-public class AppManualReaderClient {
-
- /**
- * The URI scheme used to identify application manual URIs when flinging
- * Intents around within an Android device, in the hope that there are
- * activities registered which will handle such application manual URIs.
- * Usually, there won't be just a single activity registered but instead
- * many, depending on how many manuals are installed on an Android device.
- */
- public static final String URI_SCHEME_APPMANUAL = "appmanual";
-
- /**
- * Standardized topic for opening a manual at its beginning.
- *
- * @see #openManual(String, String, Context)
- * @see #openManual(String, String, Context, String)
- */
- public static final String TOPIC_HOME = "andtw-home";
- /**
- * Standardized topic for opening the index of a manual.
- *
- * @see #openManual(String, String, Context)
- * @see #openManual(String, String, Context, String)
- */
- public static final String TOPIC_INDEX = "andtw-index";
- /**
- * Standardized topic for opening a manual's "about" topic.
- *
- * @see #openManual(String, String, Context)
- * @see #openManual(String, String, Context, String)
- */
- public static final String TOPIC_ABOUT_MANUAL = "andtw-about";
-
- /**
- * Convenience function to open a manual at a specific topic. See
- * {@link #openManual(String, String, Context, String)} for a detailed
- * description.
- *
- * @param manualIdentifier
- * the identifier of the manual to open. This identifier must
- * uniquely identify the manual as such, independent of the
- * particular locale the manual is intended for.
- * @param topic
- * the topic to open. Please do not use spaces for topic names.
- * With respect to the TiddlyWiki infrastructure used for manuals
- * the topic needs to the tag of a (single) tiddler. This way
- * manuals can be localized (especially their topic titles)
- * without breaking an app's knowledge about topics. Some
- * standardized topics are predefined, such as {@link #TOPIC_HOME}, {@link #TOPIC_INDEX}, and
- * {@link #TOPIC_ABOUT_MANUAL}.
- * @param context
- * the context (usually an Activity) from which the manual is to
- * be opened. In particular, this context is required to derive
- * the proper current locale configuration in order to open
- * appropriate localized manuals, if installed.
- *
- * @exception ActivityNotFoundException
- * there is no suitable manual installed and all combinations
- * of locale scope failed to activate any manual.
- *
- * @see #openManual(String, String, Context, String, boolean)
- */
- public static void openManual(String manualIdentifier, String topic,
- Context context) throws ActivityNotFoundException {
- openManual(manualIdentifier, topic, context, null, false);
- }
-
- /**
- * Convenience function to open a manual at a specific topic. See
- * {@link #openManual(String, String, Context, String)} for a detailed
- * description.
- *
- * @param manualIdentifier
- * the identifier of the manual to open. This identifier must
- * uniquely identify the manual as such, independent of the
- * particular locale the manual is intended for.
- * @param topic
- * the topic to open. Please do not use spaces for topic names.
- * With respect to the TiddlyWiki infrastructure used for manuals
- * the topic needs to the tag of a (single) tiddler. This way
- * manuals can be localized (especially their topic titles)
- * without breaking an app's knowledge about topics. Some
- * standardized topics are predefined, such as {@link #TOPIC_HOME}, {@link #TOPIC_INDEX}, and
- * {@link #TOPIC_ABOUT_MANUAL}.
- * @param context
- * the context (usually an Activity) from which the manual is to
- * be opened. In particular, this context is required to derive
- * the proper current locale configuration in order to open
- * appropriate localized manuals, if installed.
- * @param fallbackUri
- * either <code>null</code> or a fallback URI to be used in case
- * the user has not installed any suitable manual.
- *
- * @exception ActivityNotFoundException
- * there is no suitable manual installed and all combinations
- * of locale scope failed to activate any manual.
- *
- * @see #openManual(String, String, Context, String, boolean)
- */
- public static void openManual(String manualIdentifier, String topic,
- Context context, String fallbackUri)
- throws ActivityNotFoundException {
- openManual(manualIdentifier, topic, context, fallbackUri, false);
- }
-
- /**
- * Opens a manual at a specific topic. At least it tries to open a manual.
- * As manuals are (usually) installed separately and we use late binding in
- * form of implicit intents, a lot of things can go wrong.
- *
- * We use late binding and the intent architecture in particular as follows:
- * first, we use our own URI scheme called "appmanual". Second, we use the
- * host field as a unique manual identifier (such as "c-geo" for the app
- * manuals for a map which must not be named by the powers that wanna be).
- * Third, a localized manual is differentiated as a path with a single
- * element in form of (in this precedence) "/lang_country_variant",
- * "/lang__variant", "/lang_country", "/lang", or "/". Fourth, the topic to
- * open is encoded as the a fragment "#topic=mytopic".
- *
- * In order to support localization, manuals can register themselves with
- * different URIs.
- *
- * @param manualIdentifier
- * the identifier of the manual to open. This identifier must
- * uniquely identify the manual as such, independent of the
- * particular locale the manual is intended for.
- * @param topic
- * the topic to open. Please do not use spaces for topic names.
- * With respect to the TiddlyWiki infrastructure used for manuals
- * the topic needs to the tag of a (single) tiddler. This way
- * manuals can be localized (especially their topic titles)
- * without breaking an app's knowledge about topics. Some
- * standardized topics are predefined, such as
- * {@link #TOPIC_HOME}, {@link #TOPIC_INDEX}, and
- * {@link #TOPIC_ABOUT_MANUAL}.
- * @param context
- * the context (usually an Activity) from which the manual is to
- * be opened. In particular, this context is required to derive
- * the proper current locale configuration in order to open
- * appropriate localized manuals, if installed.
- * @param fallbackUri
- * either <code>null</code> or a fallback URI to be used in case
- * the user has not installed any suitable manual.
- * @param contextAffinity
- * if <code>true</code>, then we try to open the manual within
- * the context, if possible. That is, if the package of the
- * calling context also offers suitable activity registrations,
- * then we will prefer them over any other registrations. If you
- * don't know what this means, then you probably don't need this
- * very special capability and should specify <code>false</code>
- * for this parameter.
- *
- * @exception ActivityNotFoundException
- * there is no suitable manual installed and all combinations
- * of locale scope failed to activate any manual and no
- * {@literal fallbackUri} was given.
- */
- public static void openManual(String manualIdentifier, String topic,
- Context context, String fallbackUri, boolean contextAffinity)
- throws ActivityNotFoundException {
- //
- // The path of an "appmanual:" URI consists simply of the locale
- // information. This allows manual packages to register themselves
- // for both very specific locales as well as very broad ones.
- //
- String localePath = "/"
- + context.getResources().getConfiguration().locale.toString();
- //
- // We later need this intent in order to try to launch an appropriate
- // manual (respectively its manual viewer). And yes, we need to set
- // the intent's category explicitly, even as we will later use
- // startActivity(): if we don't do this, the proper activity won't be
- // started albeit the filter almost matches. That dirty behavior (it is
- // documented wrong) had cost me half a day until I noticed some
- // informational log entry generated from the ActivityManager. Grrrr!
- //
- Intent intent = new Intent(Intent.ACTION_VIEW);
- int defaultIntentFlags = intent.getFlags();
- intent.addCategory(Intent.CATEGORY_DEFAULT);
- //
- // Try to open the manual in the following order (subject to
- // availability):
- // 1. manualIdentifier_lang_country_variant (can also be
- // manualIdentifier_lang__variant in some cases)
- // 2. manualIdentifier_lang_country
- // 3. manualIdentifier_lang
- // 4. manualIdentifier
- // Of course, manuals are free to register more than one Intent,
- // in particular, the should register also the plain manualIdentifier
- // as a suitable fallback strategy. Even when installing multiple
- // manuals this doesn't matter, as the user then can choose which
- // one to use on a single or permanent basis.
- //
- while (true) {
- Uri uri = Uri.parse(URI_SCHEME_APPMANUAL + "://" + manualIdentifier
- + localePath + "#topic='" + topic + "'");
- // Note: we do not use a MIME type for this.
- intent.setData(uri);
- intent.setFlags(defaultIntentFlags);
- if ( contextAffinity ) {
- //
- // What is happening here? Well, here we try something that we
- // would like to call "package affinity activity resolving".
- // Given an implicit(!) intent we try to figure out whether the
- // package of the context which is trying to open the manual is
- // able to resolve the intent. If this is the case, then we
- // simply turn the implicit intent into an explicit(!) intent.
- // We do this by setting the concrete module, that is: package
- // name (eventually the one of the calling context) and class
- // name within the package.
- //
- List<ResolveInfo> capableActivities = context
- .getPackageManager()
- .queryIntentActivityOptions(null, null, intent,
- PackageManager.MATCH_DEFAULT_ONLY);
- int capables = capableActivities.size();
- if ( capables > 1 ) {
- for ( int idx = 0; idx < capables; ++idx ) {
- ActivityInfo activityInfo = capableActivities.get(idx).activityInfo;
- if ( activityInfo.packageName.contentEquals(context
- .getPackageName()) ) {
- intent.setClassName(activityInfo.packageName,
- activityInfo.name);
- //
- // First match is okay, so we quit searching and
- // continue with the usual attempt to start the
- // activity. This should not fail, as we already
- // found a match; yet the code is very forgiving in
- // this respect and would just try another round
- // with "downsized" locale requirements.
- //
- break;
- }
- }
- }
- // FIXME
- intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
- } else {
- //
- // No context affinity required, thus we need to set some flags:
- //
- // ...NEW_TASK: we want to start the manual reader activity as a
- // separate
- // task so that it can be kept open, yet in the background when
- // returning to the application from which the manual was
- // opened.
- //
- // ...SINGLE_TOP:
- //
- // ...RESET_TASK_IF_NEEDED: clear the manual reader activities
- // down to the root activity. We've set the required
- // ...CLEAR_WHEN_TASK_RESET above when opening the meta-manual
- // with the context affinity.
- //
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_SINGLE_TOP
- | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
- }
- try {
- String logTag = "appmanualclient";
- if ( Log.isLoggable(logTag, Log.INFO) ) {
- Log.i(logTag,
- "Trying to activate manual: uri=" + uri.toString());
- }
- context.startActivity(intent);
- //
- // We could successfully activate the manual activity, so no
- // further trials are required.
- //
- return;
- } catch ( ActivityNotFoundException noActivity ) {
- //
- // Ensure that we switch back to implicit intent resolving for
- // the next round.
- //
- intent.setComponent(null);
- //
- // As long as we still have some locale information, reduce it
- // and try again a broader locale.
- //
- if ( localePath.length() > 1 ) {
- int underscore = localePath.lastIndexOf('_');
- if ( underscore > 0 ) {
- localePath = localePath.substring(0, underscore);
- //
- // Handle the case where we have a locale variant, yet
- // no locale country, thus two underscores in immediate
- // series. Get rid of both.
- //
- if ( localePath.endsWith("_") ) {
- localePath = localePath
- .substring(0, underscore - 1);
- }
- } else {
- //
- // Ready for the last round: try without any locale
- // modifiers.
- //
- localePath = "/";
- }
- } else {
- //
- // We've tried all combinations, so we've run out of them
- // and bail out.
- //
- break;
- }
- }
- //
- // Okay, go for the next round, we've updated (or rather trimmed)
- // the localeIdent, so let us try this.
- //
- }
- //
- // If we reach this code point then no suitable activity could be found
- // and activated. In case the caller specified a fallback URI we will
- // try to open that. As this will activate a suitable browser and this
- // is an asynchronous activity we won't get back any negative results,
- // such as 404's. Here we will only see such problems that prevented the
- // start of a suitable browsing activity.
- //
- if ( fallbackUri != null ) {
- intent = new Intent(Intent.ACTION_VIEW, Uri.parse(fallbackUri));
- intent.addCategory(Intent.CATEGORY_BROWSABLE);
- context.startActivity(intent);
- }
- //
- // We could not activate any manual and there was no fallback URI to
- // open, so we finally bail out unsuccessful with an exception.
- //
- throw new ActivityNotFoundException();
- }
-}
diff --git a/main/src/org/openintents/intents/FileManagerIntents.java b/main/src/org/openintents/intents/FileManagerIntents.java
deleted file mode 100644
index 8ff10c8..0000000
--- a/main/src/org/openintents/intents/FileManagerIntents.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (C) 2008 OpenIntents.org
- *
- * 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 org.openintents.intents;
-
-/**
- * Provides OpenIntents actions, extras, and categories used by providers.
- * <p>These specifiers extend the standard Android specifiers.</p>
- */
-public final class FileManagerIntents {
-
- /**
- * Activity Action: Pick a file through the file manager, or let user
- * specify a custom file name.
- * Data is the current file name or file name suggestion.
- * Returns a new file name as file URI in data.
- *
- * <p>Constant Value: "org.openintents.action.PICK_FILE"</p>
- */
- public static final String ACTION_PICK_FILE = "org.openintents.action.PICK_FILE";
-
- /**
- * Activity Action: Pick a directory through the file manager, or let user
- * specify a custom file name.
- * Data is the current directory name or directory name suggestion.
- * Returns a new directory name as file URI in data.
- *
- * <p>Constant Value: "org.openintents.action.PICK_DIRECTORY"</p>
- */
- public static final String ACTION_PICK_DIRECTORY = "org.openintents.action.PICK_DIRECTORY";
-
- /**
- * Activity Action: Move, copy or delete after select entries.
- * Data is the current directory name or directory name suggestion.
- *
- * <p>Constant Value: "org.openintents.action.MULTI_SELECT"</p>
- */
- public static final String ACTION_MULTI_SELECT = "org.openintents.action.MULTI_SELECT";
-
- public static final String ACTION_SEARCH_STARTED = "org.openintents.action.SEARCH_STARTED";
-
- public static final String ACTION_SEARCH_FINISHED = "org.openintens.action.SEARCH_FINISHED";
-
- /**
- * The title to display.
- *
- * <p>This is shown in the title bar of the file manager.</p>
- *
- * <p>Constant Value: "org.openintents.extra.TITLE"</p>
- */
- public static final String EXTRA_TITLE = "org.openintents.extra.TITLE";
-
- /**
- * The text on the button to display.
- *
- * <p>Depending on the use, it makes sense to set this to "Open" or "Save".</p>
- *
- * <p>Constant Value: "org.openintents.extra.BUTTON_TEXT"</p>
- */
- public static final String EXTRA_BUTTON_TEXT = "org.openintents.extra.BUTTON_TEXT";
-
- /**
- * Flag indicating to show only writeable files and folders.
- *
- * <p>Constant Value: "org.openintents.extra.WRITEABLE_ONLY"</p>
- */
- public static final String EXTRA_WRITEABLE_ONLY = "org.openintents.extra.WRITEABLE_ONLY";
-
- /**
- * The path to prioritize in search. Usually denotes the path the user was on when the search was initiated.
- *
- * <p>Constant Value: "org.openintents.extra.SEARCH_INIT_PATH"</p>
- */
- public static final String EXTRA_SEARCH_INIT_PATH = "org.openintents.extra.SEARCH_INIT_PATH";
-
- /**
- * The search query as sent to SearchService.
- *
- * <p>Constant Value: "org.openintents.extra.SEARCH_QUERY"</p>
- */
- public static final String EXTRA_SEARCH_QUERY = "org.openintents.extra.SEARCH_QUERY";
-
- /**
- * <p>Constant Value: "org.openintents.extra.DIR_PATH"</p>
- */
- public static final String EXTRA_DIR_PATH = "org.openintents.extra.DIR_PATH";
-
- /**
- * Extension by which to filter.
- *
- * <p>Constant Value: "org.openintents.extra.FILTER_FILETYPE"</p>
- */
- public static final String EXTRA_FILTER_FILETYPE = "org.openintents.extra.FILTER_FILETYPE";
-
- /**
- * Mimetype by which to filter.
- *
- * <p>Constant Value: "org.openintents.extra.FILTER_MIMETYPE"</p>
- */
- public static final String EXTRA_FILTER_MIMETYPE = "org.openintents.extra.FILTER_MIMETYPE";
-
- /**
- * Only show directories.
- *
- * <p>Constant Value: "org.openintents.extra.DIRECTORIES_ONLY"</p>
- */
- public static final String EXTRA_DIRECTORIES_ONLY = "org.openintents.extra.DIRECTORIES_ONLY";
-
- public static final String EXTRA_DIALOG_FILE_HOLDER = "org.openintents.extra.DIALOG_FILE";
-
- public static final String EXTRA_IS_GET_CONTENT_INITIATED = "org.openintents.extra.ENABLE_ACTIONS";
-
- public static final String EXTRA_FILENAME = "org.openintents.extra.FILENAME";
-}