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.java31
-rw-r--r--main/src/cgeo/geocaching/AbstractLoggingActivity.java22
-rw-r--r--main/src/cgeo/geocaching/AbstractPopupActivity.java54
-rw-r--r--main/src/cgeo/geocaching/AddressListActivity.java6
-rw-r--r--main/src/cgeo/geocaching/CacheDetailActivity.java261
-rw-r--r--main/src/cgeo/geocaching/CachePopup.java8
-rw-r--r--main/src/cgeo/geocaching/CompassActivity.java (renamed from main/src/cgeo/geocaching/cgeonavigate.java)141
-rw-r--r--main/src/cgeo/geocaching/EditWaypointActivity.java100
-rw-r--r--main/src/cgeo/geocaching/Geocache.java63
-rw-r--r--main/src/cgeo/geocaching/GpxFileListActivity.java7
-rw-r--r--main/src/cgeo/geocaching/ImageSelectActivity.java62
-rw-r--r--main/src/cgeo/geocaching/ImagesActivity.java18
-rw-r--r--main/src/cgeo/geocaching/Intents.java4
-rw-r--r--main/src/cgeo/geocaching/LogTrackableActivity.java10
-rw-r--r--main/src/cgeo/geocaching/MainActivity.java (renamed from main/src/cgeo/geocaching/cgeo.java)102
-rw-r--r--main/src/cgeo/geocaching/NavigateAnyPointActivity.java114
-rw-r--r--main/src/cgeo/geocaching/SearchActivity.java12
-rw-r--r--main/src/cgeo/geocaching/SelectMapfileActivity.java5
-rw-r--r--main/src/cgeo/geocaching/Settings.java30
-rw-r--r--main/src/cgeo/geocaching/SettingsActivity.java17
-rw-r--r--main/src/cgeo/geocaching/StaticMapsActivity.java11
-rw-r--r--main/src/cgeo/geocaching/StaticMapsProvider.java27
-rw-r--r--main/src/cgeo/geocaching/StoredList.java37
-rw-r--r--main/src/cgeo/geocaching/TrackableActivity.java66
-rw-r--r--main/src/cgeo/geocaching/UsefulAppsActivity.java123
-rw-r--r--main/src/cgeo/geocaching/VisitCacheActivity.java193
-rw-r--r--main/src/cgeo/geocaching/Waypoint.java2
-rw-r--r--main/src/cgeo/geocaching/WaypointPopup.java15
-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.java4
-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.java4
-rw-r--r--main/src/cgeo/geocaching/apps/cache/navi/CompassApp.java8
-rw-r--r--main/src/cgeo/geocaching/cgData.java17
-rw-r--r--main/src/cgeo/geocaching/cgeoapplication.java4
-rw-r--r--main/src/cgeo/geocaching/cgeocaches.java112
-rw-r--r--main/src/cgeo/geocaching/connector/gc/GCConstants.java2
-rw-r--r--main/src/cgeo/geocaching/connector/gc/GCParser.java45
-rw-r--r--main/src/cgeo/geocaching/connector/oc/OC11XMLParser.java26
-rw-r--r--main/src/cgeo/geocaching/connector/oc/OCXMLClient.java11
-rw-r--r--main/src/cgeo/geocaching/enumerations/CacheAttribute.java27
-rw-r--r--main/src/cgeo/geocaching/export/AbstractExport.java7
-rw-r--r--main/src/cgeo/geocaching/export/FieldnoteExport.java58
-rw-r--r--main/src/cgeo/geocaching/export/GpxExport.java195
-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.java921
-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/maps/AbstractMap.java2
-rw-r--r--main/src/cgeo/geocaching/maps/CGeoMap.java99
-rw-r--r--main/src/cgeo/geocaching/maps/MapProviderFactory.java9
-rw-r--r--main/src/cgeo/geocaching/maps/google/GoogleMapActivity.java11
-rw-r--r--main/src/cgeo/geocaching/maps/interfaces/MapActivityImpl.java2
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapActivity.java11
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapActivity024.java6
-rw-r--r--main/src/cgeo/geocaching/network/HtmlImage.java24
-rw-r--r--main/src/cgeo/geocaching/network/Network.java18
-rw-r--r--main/src/cgeo/geocaching/speech/SpeechService.java188
-rw-r--r--main/src/cgeo/geocaching/speech/TextFactory.java71
-rw-r--r--main/src/cgeo/geocaching/twitter/Twitter.java68
-rw-r--r--main/src/cgeo/geocaching/twitter/TwitterAuthorizationActivity.java12
-rw-r--r--main/src/cgeo/geocaching/ui/CacheDetailsCreator.java21
-rw-r--r--main/src/cgeo/geocaching/ui/CacheListAdapter.java24
-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/ImagesList.java42
-rw-r--r--main/src/cgeo/geocaching/ui/LoggingUI.java40
-rw-r--r--main/src/cgeo/geocaching/ui/dialog/CoordinatesInputDialog.java8
-rw-r--r--main/src/cgeo/geocaching/ui/dialog/EditorDialog.java60
-rw-r--r--main/src/cgeo/geocaching/utils/AsyncTaskWithProgress.java139
-rw-r--r--main/src/cgeo/geocaching/utils/GeoDirHandler.java22
-rw-r--r--main/src/cgeo/geocaching/utils/ImageHelper.java38
-rw-r--r--main/src/cgeo/geocaching/utils/Log.java7
-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
96 files changed, 2445 insertions, 4167 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..3164602 100644
--- a/main/src/cgeo/geocaching/AboutActivity.java
+++ b/main/src/cgeo/geocaching/AboutActivity.java
@@ -1,28 +1,29 @@
package cgeo.geocaching;
+import butterknife.InjectView;
+
import cgeo.geocaching.activity.AbstractActivity;
+import cgeo.geocaching.ui.AnchorAwareLinkMovementMethod;
import cgeo.geocaching.utils.Version;
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;
public class AboutActivity extends AbstractActivity {
+ @InjectView(R.id.about_version_string) protected TextView version;
+ @InjectView(R.id.contributors) protected TextView contributors;
+ @InjectView(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));
+ 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());
+ version.setText(Version.getVersionName(this));
+ contributors.setMovementMethod(AnchorAwareLinkMovementMethod.getInstance());
+ changeLog.setMovementMethod(AnchorAwareLinkMovementMethod.getInstance());
}
/**
@@ -70,6 +71,16 @@ public class AboutActivity extends AbstractActivity {
* 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/")));
+ startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://manual.cgeo.org/")));
+ }
+
+ /**
+ * @param view
+ * unused here but needed since this method is referenced from XML layout
+ */
+ public void market(View view) {
+ 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..73dc86d 100644
--- a/main/src/cgeo/geocaching/AbstractPopupActivity.java
+++ b/main/src/cgeo/geocaching/AbstractPopupActivity.java
@@ -2,7 +2,6 @@ package cgeo.geocaching;
import cgeo.geocaching.activity.AbstractActivity;
import cgeo.geocaching.activity.ActivityMixin;
-import cgeo.geocaching.apps.cache.navi.NavigationAppFactory;
import cgeo.geocaching.enumerations.CacheSize;
import cgeo.geocaching.enumerations.LoadFlags;
import cgeo.geocaching.gcvote.GCVote;
@@ -34,11 +33,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;
@@ -67,14 +61,24 @@ public abstract class AbstractPopupActivity extends AbstractActivity {
cacheDistance.setText(Units.getDistanceFromKilometers(geo.getCoords().distanceTo(cache.getCoords())));
cacheDistance.bringToFront();
}
+ onUpdateGeoData(geo);
} catch (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 +106,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 +132,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 +159,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 +168,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,11 +201,11 @@ 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);
+ LoggingUI.onPrepareOptionsMenu(menu, cache);
} catch (Exception e) {
// nothing
}
@@ -269,8 +261,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..150bbc5 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.addresses);
// 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 b670ec9..11c4b4f 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,13 +24,14 @@ 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.WeakReferenceHandler;
-import cgeo.geocaching.ui.dialog.EditorDialog;
import cgeo.geocaching.utils.BaseUtils;
import cgeo.geocaching.utils.CancellableHandler;
import cgeo.geocaching.utils.ClipboardUtils;
@@ -65,12 +69,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 +116,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;
@@ -139,6 +144,8 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
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) {
@@ -187,19 +194,9 @@ 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);
-
- // initialize the main view and set a default title
- setTheme();
- setContentView(R.layout.cacheview);
- setTitle(res.getString(R.string.cache));
+ super.onCreate(savedInstanceState, R.layout.cacheview);
String geocode = null;
@@ -541,7 +538,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 +554,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);
}
@@ -795,7 +793,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();
}
@@ -899,7 +897,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
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) {
@@ -1163,7 +1161,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
@@ -1202,23 +1200,7 @@ 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]));
- }
- });
+ valueView.setOnClickListener(new CoordinatesFormatSwitcher(cache.getCoords()));
registerForContextMenu(valueView);
}
@@ -1258,7 +1240,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
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);
}
@@ -1354,6 +1336,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());
@@ -1498,7 +1485,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
}
}
- /** 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;
@@ -1512,7 +1499,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;
@@ -1539,25 +1526,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()));
}
}
@@ -1750,7 +1737,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() {
@@ -1760,11 +1749,11 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
}
view = (ScrollView) getLayoutInflater().inflate(R.layout.cacheview_description, 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
@@ -1784,31 +1773,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);
@@ -1861,13 +1839,28 @@ 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);
+ setPersonalNote();
+ cgData.saveCache(cache, EnumSet.of(SaveFlag.SAVE_DB));
+ }
+ };
+ 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);
}
}
@@ -1878,12 +1871,43 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
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;
@@ -1910,28 +1934,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 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.
@@ -1943,6 +1972,10 @@ 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) {
@@ -1951,25 +1984,40 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
return null;
}
- /*
- * (non-Javadoc)
- *
- * @see android.os.AsyncTask#onProgressUpdate(Progress[])
- */
@Override
protected void onProgressUpdate(Void... values) {
- if (description != null) {
- if (StringUtils.isNotBlank(descriptionString)) {
- descriptionView.setText(description, TextView.BufferType.SPANNABLE);
- descriptionView.setMovementMethod(AnchorAwareLinkMovementMethod.getInstance());
- fixBlackTextColor(descriptionView, descriptionString);
- }
-
- descriptionView.setVisibility(View.VISIBLE);
- } else {
+ if (description == null) {
showToast(res.getString(R.string.err_load_descr_failed));
+ return;
}
+ if (StringUtils.isNotBlank(descriptionString)) {
+ descriptionView.setText(description, TextView.BufferType.SPANNABLE);
+ descriptionView.setMovementMethod(AnchorAwareLinkMovementMethod.getInstance());
+ fixBlackTextColor(descriptionView, descriptionString);
+ descriptionView.setVisibility(View.VISIBLE);
+ 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)) {
+ 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);
}
@@ -2096,7 +2144,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
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 });
+ loader.execute(logText);
}
}
else {
@@ -2130,7 +2178,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
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);
}
@@ -2188,10 +2236,24 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
statusMarker = (ImageView) base.findViewById(R.id.log_mark);
}
+ /**
+ * 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;
}
@@ -2222,6 +2284,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);
}
diff --git a/main/src/cgeo/geocaching/CachePopup.java b/main/src/cgeo/geocaching/CachePopup.java
index e6d0148..4df428e 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
@@ -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 17c2e20..d0f980e 100644
--- a/main/src/cgeo/geocaching/cgeonavigate.java
+++ b/main/src/cgeo/geocaching/CompassActivity.java
@@ -4,6 +4,7 @@ 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;
@@ -12,8 +13,9 @@ import org.apache.commons.lang3.StringUtils;
import android.content.Context;
import android.content.Intent;
+import android.hardware.Sensor;
+import android.hardware.SensorManager;
import android.os.Bundle;
-import android.os.PowerManager;
import android.view.Menu;
import android.view.MenuItem;
import android.view.SubMenu;
@@ -24,16 +26,14 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
-public class cgeonavigate extends AbstractActivity {
+public class CompassActivity extends AbstractActivity {
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 Geopoint dstCoords = null;
private float cacheHeading = 0;
private String title = null;
@@ -45,25 +45,24 @@ public class cgeonavigate extends AbstractActivity {
private TextView distanceView = null;
private TextView headingView = null;
private CompassView compassView = null;
-
- public cgeonavigate() {
- super("c:geo-compass", true);
- }
+ private boolean hasMagneticFieldSensor;
@Override
public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
+ super.onCreate(savedInstanceState, R.layout.navigate);
- setTheme();
- setContentView(R.layout.navigate);
- setTitle(res.getString(R.string.compass_title));
+ final SensorManager sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
+ hasMagneticFieldSensor = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) != null;
+ if (!hasMagneticFieldSensor) {
+ Settings.setUseCompass(false);
+ }
// get parameters
Bundle extras = getIntent().getExtras();
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)) {
@@ -96,11 +95,6 @@ public class cgeonavigate extends AbstractActivity {
// sensor & geolocation manager
geoDirHandler.startGeoAndDir();
-
- // keep backlight on
- if (pm == null) {
- pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
- }
}
@Override
@@ -112,23 +106,23 @@ 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.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);
+ }
+ else {
+ menu.findItem(R.id.menu_select_destination).setVisible(false);
}
return true;
}
@@ -136,45 +130,56 @@ 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();
-
- 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);
-
- 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;
+ 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:
+ SpeechService.startService(this, dstCoords);
+ 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;
}
@@ -272,7 +277,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));
}
}
};
@@ -286,11 +291,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) {
@@ -301,7 +310,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/EditWaypointActivity.java b/main/src/cgeo/geocaching/EditWaypointActivity.java
index 7f011fc..0a1d22d 100644
--- a/main/src/cgeo/geocaching/EditWaypointActivity.java
+++ b/main/src/cgeo/geocaching/EditWaypointActivity.java
@@ -1,7 +1,8 @@
package cgeo.geocaching;
+import butterknife.InjectView;
+
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;
@@ -37,6 +38,7 @@ 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;
@@ -44,6 +46,19 @@ import java.util.EnumSet;
import java.util.List;
public class EditWaypointActivity extends AbstractActivity {
+ @InjectView(R.id.buttonLatitude) protected Button buttonLat;
+ @InjectView(R.id.buttonLongitude) protected Button buttonLon;
+ @InjectView(R.id.add_waypoint) protected Button addWaypoint;
+ @InjectView(R.id.note) protected EditText note;
+ @InjectView(R.id.wpt_visited_checkbox) protected CheckBox visitedCheckBox;
+ @InjectView(R.id.name) protected AutoCompleteTextView waypointName;
+ @InjectView(R.id.type) protected Spinner waypointTypeSelector;
+ @InjectView(R.id.distance) protected EditText distanceView;
+ @InjectView(R.id.modify_cache_coordinates_group) protected RadioGroup coordinatesGroup;
+ @InjectView(R.id.modify_cache_coordinates_local_and_remote) protected RadioButton modifyBoth;
+ @InjectView(R.id.distanceUnit) protected Spinner distanceUnitSelector;
+ @InjectView(R.id.bearing) protected EditText bearing;
+ @InjectView(R.id.modify_cache_coordinates_local) protected RadioButton modifyLocal;
private String geocode = null;
private int id = -1;
@@ -78,15 +93,15 @@ public class EditWaypointActivity extends AbstractActivity {
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));
+ buttonLat.setText(waypoint.getCoords().format(GeopointFormatter.Format.LAT_DECMINUTE));
+ buttonLon.setText(waypoint.getCoords().format(GeopointFormatter.Format.LON_DECMINUTE));
}
- ((EditText) findViewById(R.id.name)).setText(Html.fromHtml(StringUtils.trimToEmpty(waypoint.getName())).toString());
+ waypointName.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());
+ note.setText(Html.fromHtml(StringUtils.trimToEmpty(waypoint.getNote())).toString());
}
else {
- ((EditText) findViewById(R.id.note)).setText(StringUtils.trimToEmpty(waypoint.getNote()));
+ note.setText(StringUtils.trimToEmpty(waypoint.getNote()));
}
Geocache cache = cgData.loadCache(geocode, LoadFlags.LOAD_CACHE_ONLY);
setCoordsModificationVisibility(ConnectorFactory.getConnector(geocode), cache);
@@ -95,7 +110,7 @@ public class EditWaypointActivity extends AbstractActivity {
if (own) {
initializeWaypointTypeSelector();
}
- ((CheckBox) findViewById(R.id.wpt_visited_checkbox)).setChecked(visited);
+ visitedCheckBox.setChecked(visited);
initializeDistanceUnitSelector();
} catch (Exception e) {
@@ -111,11 +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");
+ super.onCreate(savedInstanceState, R.layout.edit_waypoint_activity);
// get parameters
Bundle extras = getIntent().getExtras();
@@ -138,24 +149,19 @@ 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());
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);
waitDialog = ProgressDialog.show(this, null, res.getString(R.string.waypoint_loading), true);
@@ -171,7 +177,6 @@ public class EditWaypointActivity extends AbstractActivity {
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) {
@@ -181,16 +186,16 @@ public class EditWaypointActivity extends AbstractActivity {
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);
}
}
@@ -211,25 +216,12 @@ public class EditWaypointActivity extends AbstractActivity {
}
@Override
- public void onDestroy() {
- super.onDestroy();
- }
-
- @Override
- public void onStop() {
- super.onStop();
- }
-
- @Override
public void onPause() {
geoDirHandler.stopGeo();
super.onPause();
}
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);
@@ -247,9 +239,6 @@ public class EditWaypointActivity extends AbstractActivity {
}
private void initializeDistanceUnitSelector() {
-
- Spinner distanceUnitSelector = (Spinner) findViewById(R.id.distanceUnit);
-
if (StringUtils.isBlank(distanceUnit)) {
if (Settings.isUseMetricUnits()) {
distanceUnitSelector.setSelection(0); // m
@@ -271,10 +260,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);
}
@@ -311,8 +298,8 @@ 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));
+ buttonLat.setText(gp.format(GeopointFormatter.Format.LAT_DECMINUTE));
+ buttonLon.setText(gp.format(GeopointFormatter.Format.LON_DECMINUTE));
if (waypoint != null) {
waypoint.setCoords(gp);
} else {
@@ -378,11 +365,11 @@ public class EditWaypointActivity extends AbstractActivity {
@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() + distanceUnit;
+ 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,9 +417,9 @@ 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 ProgressDialog progress = ProgressDialog.show(EditWaypointActivity.this, getString(R.string.cache), getString(R.string.waypoint_being_saved), true);
final Handler finishHandler = new Handler() {
@@ -483,7 +470,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 +488,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,11 +526,6 @@ 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));
diff --git a/main/src/cgeo/geocaching/Geocache.java b/main/src/cgeo/geocaching/Geocache.java
index 836cccb..2c9ba32 100644
--- a/main/src/cgeo/geocaching/Geocache.java
+++ b/main/src/cgeo/geocaching/Geocache.java
@@ -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;
@@ -483,34 +483,37 @@ public class Geocache implements ICache, IWaypoint {
}
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;
}
@@ -710,10 +713,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 +765,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
@@ -1360,6 +1360,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 +1381,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,6 +1399,25 @@ 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)) {
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..4abf310 100644
--- a/main/src/cgeo/geocaching/ImageSelectActivity.java
+++ b/main/src/cgeo/geocaching/ImageSelectActivity.java
@@ -2,6 +2,7 @@ package cgeo.geocaching;
import cgeo.geocaching.activity.AbstractActivity;
import cgeo.geocaching.compatibility.Compatibility;
+import cgeo.geocaching.utils.ImageHelper;
import cgeo.geocaching.utils.Log;
import org.apache.commons.lang3.StringUtils;
@@ -10,14 +11,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;
@@ -28,34 +33,31 @@ public class ImageSelectActivity extends AbstractActivity {
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;
+ private Spinner scaleView;
// 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.visit_image);
+ scaleChoiceIndex = Settings.getLogImageScale();
imageCaption = "";
imageDescription = "";
imageUri = Uri.EMPTY;
@@ -66,6 +68,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,6 +76,7 @@ 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);
@@ -103,6 +107,20 @@ public class ImageSelectActivity extends AbstractActivity {
descriptionView.setText(imageDescription);
}
+ scaleView = (Spinner) findViewById(R.id.logImageScale);
+ 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) {
+ }
+ });
+
final Button saveButton = (Button) findViewById(R.id.save);
saveButton.setOnClickListener(new View.OnClickListener() {
@@ -131,15 +149,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 +174,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 +254,27 @@ public class ImageSelectActivity extends AbstractActivity {
loadImagePreview();
}
+ /**
+ * Scales and writes the scaled image.
+ *
+ * @param filePath
+ * @return
+ */
+ private String writeScaledImage(String filePath) {
+ Bitmap image = BitmapFactory.decodeFile(filePath);
+ scaleChoiceIndex = scaleView.getSelectedItemPosition();
+ int maxXY = getResources().getIntArray(R.array.log_image_scale_values)[scaleChoiceIndex];
+ String uploadFilename = filePath;
+ if (maxXY > 0) {
+ BitmapDrawable scaledImage = ImageHelper.scaleBitmapTo(image, maxXY, maxXY);
+ uploadFilename = getOutputImageFile().getPath();
+ ImageHelper.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() {
diff --git a/main/src/cgeo/geocaching/ImagesActivity.java b/main/src/cgeo/geocaching/ImagesActivity.java
index 24f699e..07ff734 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) {
@@ -54,7 +50,7 @@ public class ImagesActivity extends AbstractActivity {
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/LogTrackableActivity.java b/main/src/cgeo/geocaching/LogTrackableActivity.java
index b8983ba..7aee6ae 100644
--- a/main/src/cgeo/geocaching/LogTrackableActivity.java
+++ b/main/src/cgeo/geocaching/LogTrackableActivity.java
@@ -104,17 +104,9 @@ 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.touch);
// get parameters
final Bundle extras = getIntent().getExtras();
diff --git a/main/src/cgeo/geocaching/cgeo.java b/main/src/cgeo/geocaching/MainActivity.java
index 5680ff3..9a8083f 100644
--- a/main/src/cgeo/geocaching/cgeo.java
+++ b/main/src/cgeo/geocaching/MainActivity.java
@@ -1,7 +1,9 @@
package cgeo.geocaching;
+import butterknife.InjectView;
+import butterknife.Views;
+
import cgeo.geocaching.activity.AbstractActivity;
-import cgeo.geocaching.activity.ActivityMixin;
import cgeo.geocaching.connector.gc.Login;
import cgeo.geocaching.enumerations.CacheType;
import cgeo.geocaching.enumerations.StatusCode;
@@ -31,11 +33,9 @@ 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.TextView;
import java.util.ArrayList;
@@ -45,14 +45,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) protected TextView userInfoView;
+ @InjectView(R.id.nav_satellites) protected TextView navSatellites;
+ @InjectView(R.id.filter_button_title)protected TextView filterTitle;
+ @InjectView(R.id.map) protected View findOnMap;
+ @InjectView(R.id.search_offline) protected View findByOffline;
+ @InjectView(R.id.advanced_button) protected View advanced;
+ @InjectView(R.id.any_button) protected View any;
+ @InjectView(R.id.filter_button) protected View filter;
+ @InjectView(R.id.nearest) protected View 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,8 +79,6 @@ public class cgeo extends AbstractActivity {
@Override
public void handleMessage(Message msg) {
- TextView userInfoView = (TextView) findViewById(R.id.user_info);
-
StringBuilder userInfo = new StringBuilder("geocaching.com").append(Formatter.SEPARATOR);
if (Login.isActualLoginStatus()) {
userInfo.append(Login.getActualUserName());
@@ -109,7 +119,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 +146,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);
@@ -169,13 +177,12 @@ public class cgeo extends AbstractActivity {
}
};
- 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);
+ 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 +190,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 +238,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;
}
@@ -311,6 +295,7 @@ public class cgeo extends AbstractActivity {
@Override
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
if (requestCode == SCAN_REQUEST_CODE) {
+ // Only handle positive results, don't do anything if cancelled.
if (resultCode == RESULT_OK) {
String scan = intent.getStringExtra("SCAN_RESULT");
if (StringUtils.isBlank(scan)) {
@@ -318,8 +303,6 @@ public class cgeo extends AbstractActivity {
}
SearchActivity.startActivityScan(scan, this);
- } else if (resultCode == RESULT_CANCELED) {
- // do nothing
}
} else if (requestCode == SEARCH_REQUEST_CODE) {
// SearchActivity activity returned without making a search
@@ -338,9 +321,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 +338,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 +346,6 @@ public class cgeo extends AbstractActivity {
}
});
- final View findByOffline = findViewById(R.id.search_offline);
findByOffline.setClickable(true);
findByOffline.setOnClickListener(new OnClickListener() {
@Override
@@ -379,12 +357,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 +370,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 +378,6 @@ public class cgeo extends AbstractActivity {
}
});
- final View any = findViewById(R.id.any_button);
any.setClickable(true);
any.setOnClickListener(new OnClickListener() {
@Override
@@ -410,7 +386,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 +476,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 +494,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 +554,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 +567,7 @@ public class cgeo extends AbstractActivity {
return;
}
- findViewById(R.id.nearest).setPressed(true);
+ nearestView.setPressed(true);
cgeocaches.startActivityNearest(this, app.currentGeo().getCoords());
}
@@ -605,7 +576,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 +585,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 +594,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 +603,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 +617,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 {
@@ -745,7 +711,7 @@ public class cgeo extends AbstractActivity {
// invoke settings activity to insert login details
if (status == StatusCode.NO_LOGIN_INFO_STORED) {
- SettingsActivity.startActivity(cgeo.this);
+ SettingsActivity.startActivity(MainActivity.this);
}
}
}
@@ -765,7 +731,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) {
diff --git a/main/src/cgeo/geocaching/NavigateAnyPointActivity.java b/main/src/cgeo/geocaching/NavigateAnyPointActivity.java
index efea819..4e17caa 100644
--- a/main/src/cgeo/geocaching/NavigateAnyPointActivity.java
+++ b/main/src/cgeo/geocaching/NavigateAnyPointActivity.java
@@ -1,5 +1,8 @@
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;
@@ -37,10 +40,17 @@ 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;
+
+ protected static class ViewHolder {
+ @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) {
+ Views.inject(this, rowView);
+ rowView.setTag(this);
+ }
+ }
private static class DestinationHistoryAdapter extends ArrayAdapter<Destination> {
private LayoutInflater inflater = null;
@@ -52,29 +62,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() {
@@ -90,7 +100,7 @@ public class NavigateAnyPointActivity extends AbstractActivity {
private Button lonButton = null;
private boolean changed = false;
private List<Destination> historyOfSearchedLocations;
- private DestinationHistoryAdapter destionationHistoryAdapter;
+ private DestinationHistoryAdapter destinationHistoryAdapter;
private ListView historyListView;
private TextView historyFooter;
@@ -100,19 +110,11 @@ public class NavigateAnyPointActivity extends AbstractActivity {
private int contextMenuItemPosition;
- String distanceUnit = "";
-
- public NavigateAnyPointActivity() {
- super("c:geo-navigate-any");
- }
+ private String distanceUnit = "";
@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.point);
createHistoryView();
@@ -146,7 +148,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 +192,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.caches_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,16 +229,6 @@ 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();
@@ -326,14 +316,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 +327,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 +350,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 +386,7 @@ public class NavigateAnyPointActivity extends AbstractActivity {
runOnUiThread(new Runnable() {
@Override
public void run() {
- destionationHistoryAdapter.notifyDataSetChanged();
+ destinationHistoryAdapter.notifyDataSetChanged();
}
});
}
diff --git a/main/src/cgeo/geocaching/SearchActivity.java b/main/src/cgeo/geocaching/SearchActivity.java
index 6fdff5a..73459e5 100644
--- a/main/src/cgeo/geocaching/SearchActivity.java
+++ b/main/src/cgeo/geocaching/SearchActivity.java
@@ -33,14 +33,9 @@ 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");
- }
-
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -64,7 +59,6 @@ public class SearchActivity extends AbstractActivity {
setTheme();
setContentView(R.layout.search);
- setTitle(res.getString(R.string.search));
init();
}
@@ -414,13 +408,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 +426,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/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..b5c8a6e 100644
--- a/main/src/cgeo/geocaching/Settings.java
+++ b/main/src/cgeo/geocaching/Settings.java
@@ -112,6 +112,7 @@ public final class Settings {
private static final String KEY_MAP_DIRECTORY = "mapDirectory";
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 final static int unitsMetric = 1;
@@ -149,6 +150,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;
@@ -1424,4 +1426,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..002293b 100644
--- a/main/src/cgeo/geocaching/SettingsActivity.java
+++ b/main/src/cgeo/geocaching/SettingsActivity.java
@@ -123,19 +123,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.init);
init();
}
@@ -169,14 +159,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("");
diff --git a/main/src/cgeo/geocaching/StaticMapsActivity.java b/main/src/cgeo/geocaching/StaticMapsActivity.java
index 005ee9e..a6a81d5 100644
--- a/main/src/cgeo/geocaching/StaticMapsActivity.java
+++ b/main/src/cgeo/geocaching/StaticMapsActivity.java
@@ -27,7 +27,6 @@ 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;
private final List<Bitmap> maps = new ArrayList<Bitmap>();
private boolean download = false;
private Integer waypoint_id = null;
@@ -88,11 +87,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));
+ super.onCreate(savedInstanceState, R.layout.map_static);
// get parameters
final Bundle extras = getIntent().getExtras();
@@ -163,13 +158,13 @@ public class StaticMapsActivity extends AbstractActivity {
@Override
public boolean onCreateOptionsMenu(Menu menu) {
- menu.add(0, MENU_REFRESH, 0, res.getString(R.string.cache_offline_refresh));
+ getMenuInflater().inflate(R.menu.static_maps_activity_options, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
- if (item.getItemId() == MENU_REFRESH) {
+ if (item.getItemId() == R.id.menu_refresh) {
downloadStaticMaps();
restartActivity();
return true;
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..c505e3c 100644
--- a/main/src/cgeo/geocaching/StoredList.java
+++ b/main/src/cgeo/geocaching/StoredList.java
@@ -12,7 +12,10 @@ 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 {
@@ -69,7 +72,7 @@ public class StoredList {
}
public void promptForListSelection(final int titleId, final RunnableWithArgument<Integer> runAfterwards, final boolean onlyMoveTargets, final int exceptListId) {
- final List<StoredList> lists = cgData.getLists();
+ final List<StoredList> lists = getSortedLists();
if (lists == null) {
return;
@@ -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/TrackableActivity.java b/main/src/cgeo/geocaching/TrackableActivity.java
index fea4521..9b6f491 100644
--- a/main/src/cgeo/geocaching/TrackableActivity.java
+++ b/main/src/cgeo/geocaching/TrackableActivity.java
@@ -8,6 +8,7 @@ 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;
@@ -26,7 +27,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 +56,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;
@@ -108,17 +106,9 @@ public class TrackableActivity extends AbstractViewPagerActivity<TrackableActivi
}
};
- public TrackableActivity() {
- super("c:geo-trackable-details");
- }
-
@Override
public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- setTheme();
- setContentView(R.layout.trackable_activity);
- setTitle(res.getString(R.string.trackable));
+ super.onCreate(savedInstanceState, R.layout.trackable_activity);
// get parameters
Bundle extras = getIntent().getExtras();
@@ -241,18 +231,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 +252,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);
}
@@ -398,18 +387,18 @@ public class TrackableActivity extends AbstractViewPagerActivity<TrackableActivi
private final TextView type;
private final TextView author;
private final TextView location;
- private final TextView log;
+ private final TextView text;
+ private final TextView images;
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);
+ text = (TextView) rowView.findViewById(R.id.log);
+ images = (TextView) rowView.findViewById(R.id.log_images);
marker = (ImageView) rowView.findViewById(R.id.log_mark);
- logImages = (LinearLayout) rowView.findViewById(R.id.log_layout);
}
}
@@ -440,7 +429,7 @@ 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));
}
@@ -462,8 +451,8 @@ public class TrackableActivity extends AbstractViewPagerActivity<TrackableActivi
});
}
- TextView logView = holder.log;
- logView.setMovementMethod(LinkMovementMethod.getInstance());
+ TextView logView = holder.text;
+ logView.setMovementMethod(AnchorAwareLinkMovementMethod.getInstance());
String logText = log.log;
if (BaseUtils.containsHtml(logText)) {
@@ -485,25 +474,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());
@@ -614,7 +596,7 @@ public class TrackableActivity extends AbstractViewPagerActivity<TrackableActivi
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());
+ descView.setMovementMethod(AnchorAwareLinkMovementMethod.getInstance());
}
// trackable details
@@ -623,7 +605,7 @@ public class TrackableActivity extends AbstractViewPagerActivity<TrackableActivi
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());
+ descView.setMovementMethod(AnchorAwareLinkMovementMethod.getInstance());
}
// trackable image
diff --git a/main/src/cgeo/geocaching/UsefulAppsActivity.java b/main/src/cgeo/geocaching/UsefulAppsActivity.java
index af643b3..dc5ea32 100644
--- a/main/src/cgeo/geocaching/UsefulAppsActivity.java
+++ b/main/src/cgeo/geocaching/UsefulAppsActivity.java
@@ -1,79 +1,106 @@
package cgeo.geocaching;
+import butterknife.InjectView;
+import butterknife.Views;
+
import cgeo.geocaching.activity.AbstractActivity;
+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 {
+ @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) {
+ Views.inject(this, 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_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.useful_apps_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.useful_apps_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.useful_apps_item, null);
+ }
+ ViewHolder holder = (ViewHolder) rowView.getTag();
+ if (null == holder) {
+ holder = new ViewHolder(rowView);
+ rowView.setTag(holder);
+ }
+
+ 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/VisitCacheActivity.java b/main/src/cgeo/geocaching/VisitCacheActivity.java
index dce0fbf..c19cceb 100644
--- a/main/src/cgeo/geocaching/VisitCacheActivity.java
+++ b/main/src/cgeo/geocaching/VisitCacheActivity.java
@@ -12,6 +12,8 @@ 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;
@@ -20,17 +22,15 @@ 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;
@@ -67,7 +67,6 @@ 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;
@@ -112,7 +111,6 @@ public class VisitCacheActivity extends AbstractLoggingActivity implements DateD
viewstates = Login.getViewstates(page);
trackables = GCParser.parseTrackableLog(page);
possibleLogTypes = GCParser.parseTypes(page);
- possibleLogTypes.remove(LogType.UPDATE_COORDINATES);
if (possibleLogTypes.isEmpty()) {
showErrorLoadingData();
@@ -240,45 +238,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.visit);
// Get parameters from intent and basic cache information from database
final Bundle extras = getIntent().getExtras();
@@ -392,8 +354,16 @@ public class VisitCacheActivity extends AbstractLoggingActivity implements DateD
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,8 +377,8 @@ public class VisitCacheActivity extends AbstractLoggingActivity implements DateD
}
}
text = null;
- imageCaption = "";
- imageDescription = "";
+ imageCaption = StringUtils.EMPTY;
+ imageDescription = StringUtils.EMPTY;
imageUri = Uri.EMPTY;
}
@@ -549,81 +519,79 @@ 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(VisitCacheActivity.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 ImmutablePair<StatusCode, String> postResult = GCParser.postLog(geocode, cacheid, viewstates, typeSelected,
+ date.get(Calendar.YEAR), (date.get(Calendar.MONTH) + 1), date.get(Calendar.DATE),
+ log, trackables);
+
+ if (postResult.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);
+ }
+
+ cgData.saveChangedCache(cache);
+ cgData.clearLogOffline(geocode);
+
+ if (typeSelected == LogType.FOUND_IT) {
+ if (tweetCheck.isChecked() && tweetBox.getVisibility() == View.VISIBLE) {
+ Twitter.postTweetCache(geocode);
+ }
+ GCVote.setRating(cache, rating);
+ }
+
+ if (StringUtils.isNotBlank(imageUri.getPath())) {
+ ImmutablePair<StatusCode, String> imageResult = GCParser.uploadLogImage(postResult.right, imageCaption, imageDescription, imageUri);
+ final String uploadedImageUrl = imageResult.right;
+ if (StringUtils.isNotEmpty(uploadedImageUrl)) {
+ logNow.addLogImage(new Image(uploadedImageUrl, imageCaption, imageDescription));
+ cgData.saveChangedCache(cache);
+ }
+ return imageResult.left;
+ }
}
- 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 postResult.left;
+ } catch (Exception e) {
+ Log.e("cgeovisit.postLogFn", 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 +645,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();
}
});
diff --git a/main/src/cgeo/geocaching/Waypoint.java b/main/src/cgeo/geocaching/Waypoint.java
index 48c9bc5..6112986 100644
--- a/main/src/cgeo/geocaching/Waypoint.java
+++ b/main/src/cgeo/geocaching/Waypoint.java
@@ -275,7 +275,7 @@ 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..ad1d981 100644
--- a/main/src/cgeo/geocaching/WaypointPopup.java
+++ b/main/src/cgeo/geocaching/WaypointPopup.java
@@ -2,6 +2,7 @@ package cgeo.geocaching;
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;
@@ -19,9 +20,10 @@ import android.widget.TextView;
public class WaypointPopup extends AbstractPopupActivity {
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
@@ -35,6 +37,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);
@@ -53,6 +63,9 @@ public class WaypointPopup extends AbstractPopupActivity {
//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);
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..8793c1c 100644
--- a/main/src/cgeo/geocaching/activity/AbstractViewPagerActivity.java
+++ b/main/src/cgeo/geocaching/activity/AbstractViewPagerActivity.java
@@ -29,10 +29,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.
*
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..ef56f87 100644
--- a/main/src/cgeo/geocaching/apps/AbstractApp.java
+++ b/main/src/cgeo/geocaching/apps/AbstractApp.java
@@ -1,7 +1,7 @@
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;
@@ -29,7 +29,7 @@ public abstract class AbstractApp implements App {
if (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/cgData.java b/main/src/cgeo/geocaching/cgData.java
index 28485a5..d5002a0 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();
@@ -1396,7 +1407,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>();
}
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..7c758e9 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;
@@ -373,21 +374,6 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
}
}
};
- private Handler dropDetailsHandler = new Handler() {
-
- @Override
- public void handleMessage(Message msg) {
- if (msg.what != MSG_CANCEL) {
- adapter.setSelectMode(false);
-
- refreshCurrentList();
-
- replaceCacheListFromSearch();
-
- progress.dismiss();
- }
- }
- };
private Handler clearOfflineLogsHandler = new Handler() {
@Override
@@ -428,7 +414,7 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
if (extras != null) {
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 +426,17 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
}
}
+ // Add the list selection in code. This way we can leave the XML layout 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();
@@ -625,8 +622,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);
@@ -794,7 +789,6 @@ 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()) {
if (cache.isEventCache()) {
@@ -804,7 +798,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() {
@@ -858,7 +852,7 @@ 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()) {
@@ -1082,6 +1076,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,
@@ -1144,7 +1143,7 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
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();
}
@@ -1177,10 +1176,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();
}
});
@@ -1196,9 +1192,9 @@ public class cgeocaches extends AbstractListActivity implements FilteredActivity
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()]));
}
/**
@@ -1309,7 +1305,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() {
@@ -1383,24 +1379,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 {
@@ -1566,21 +1573,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);
}
@@ -1667,7 +1659,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 +1672,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 +1683,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 +1717,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];
+ AbstractSearchLoader loader = null;
switch (enumType) {
case OFFLINE:
listId = Settings.getLastList();
diff --git a/main/src/cgeo/geocaching/connector/gc/GCConstants.java b/main/src/cgeo/geocaching/connector/gc/GCConstants.java
index 357f971..c032c34 100644
--- a/main/src/cgeo/geocaching/connector/gc/GCConstants.java
+++ b/main/src/cgeo/geocaching/connector/gc/GCConstants.java
@@ -152,7 +152,7 @@ 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*'([^']+)'");
diff --git a/main/src/cgeo/geocaching/connector/gc/GCParser.java b/main/src/cgeo/geocaching/connector/gc/GCParser.java
index 62570c2..3334c42 100644
--- a/main/src/cgeo/geocaching/connector/gc/GCParser.java
+++ b/main/src/cgeo/geocaching/connector/gc/GCParser.java
@@ -239,7 +239,7 @@ public abstract class GCParser {
cache.setFavoritePoints(Integer.parseInt(result));
}
} catch (NumberFormatException e) {
- Log.w("GCParser.parseSearch: Failed to parse favourite count");
+ Log.w("GCParser.parseSearch: Failed to parse favorite count");
}
searchResult.addCache(cache);
@@ -453,11 +453,11 @@ public abstract class GCParser {
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);
+ Log.e("Error parsing favorite count", e);
}
// cache size
@@ -1090,7 +1090,7 @@ 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) {
+ 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").encodedQuery("LID=" + logId).build().toString();
String page = Network.getResponseData(Network.getRequest(uri));
@@ -1102,7 +1102,7 @@ public abstract class GCParser {
page = Network.getResponseData(Network.getRequest(uri));
} else {
Log.e("Image upload: No login (error: " + loginState + ')');
- return StatusCode.NOT_LOGGED_IN;
+ return ImmutablePair.of(StatusCode.NOT_LOGGED_IN, null);
}
}
@@ -1119,18 +1119,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);
+ 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)) {
@@ -1405,7 +1410,11 @@ public abstract class GCParser {
// trackable distance
final String distance = BaseUtils.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 (NumberFormatException e) {
+ Log.e("GCParser.parseTrackable: Failed to parse distance", e);
+ }
}
// trackable goal
@@ -1612,15 +1621,8 @@ 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) {
+ String typesText = typeBoxMatcher.group(1);
final MatcherWrapper typeMatcher = new MatcherWrapper(GCConstants.PATTERN_TYPE2, typesText);
while (typeMatcher.find()) {
if (typeMatcher.groupCount() > 1) {
@@ -1636,6 +1638,9 @@ public abstract class GCParser {
}
}
+ // we don't support this log type
+ types.remove(LogType.UPDATE_COORDINATES);
+
return types;
}
diff --git a/main/src/cgeo/geocaching/connector/oc/OC11XMLParser.java b/main/src/cgeo/geocaching/connector/oc/OC11XMLParser.java
index 621032f..d03062f 100644
--- a/main/src/cgeo/geocaching/connector/oc/OC11XMLParser.java
+++ b/main/src/cgeo/geocaching/connector/oc/OC11XMLParser.java
@@ -48,6 +48,8 @@ public class OC11XMLParser {
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 final Pattern WHITESPACE = Pattern.compile("<p>(\\s|&nbsp;)*</p>");
+
private static ImageHolder imageHolder = null;
@@ -513,7 +515,7 @@ public class OC11XMLParser {
@Override
public void end(String body) {
final String content = body.trim();
- descHolder.shortDesc = linkify(stripMarkup(content));
+ descHolder.shortDesc = linkify(stripEmptyText(content));
}
});
@@ -523,7 +525,7 @@ public class OC11XMLParser {
@Override
public void end(String body) {
final String content = body.trim();
- descHolder.desc = linkify(stripMarkup(content));
+ descHolder.desc = linkify(stripEmptyText(content));
}
});
@@ -626,7 +628,7 @@ public class OC11XMLParser {
@Override
public void end(String logText) {
- logHolder.logEntry.log = stripMarkup(logText);
+ logHolder.logEntry.log = stripEmptyText(logText);
}
});
@@ -728,14 +730,20 @@ public class OC11XMLParser {
}
/**
- * Removes unneeded markup. Log texts are typically encapsulated in paragraph tags which lead to more empty space on
- * rendering.
+ * Removes some unneeded markup and whitespace. 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;
+ protected static String stripEmptyText(String input) {
+ final Matcher matcher = WHITESPACE.matcher(input);
+ String result = matcher.replaceAll("").trim();
+ if (!StringUtils.startsWith(result, "<")) {
+ return result;
}
- String result = input.trim();
+ return stripMarkup(result);
+ }
+
+ private static String stripMarkup(final String input) {
+ String result = input;
for (String tagName : MARKUP) {
final String startTag = "<" + tagName + ">";
if (StringUtils.startsWith(result, startTag)) {
diff --git a/main/src/cgeo/geocaching/connector/oc/OCXMLClient.java b/main/src/cgeo/geocaching/connector/oc/OCXMLClient.java
index 6767b48..df75682 100644
--- a/main/src/cgeo/geocaching/connector/oc/OCXMLClient.java
+++ b/main/src/cgeo/geocaching/connector/oc/OCXMLClient.java
@@ -9,12 +9,14 @@ import cgeo.geocaching.geopoint.Geopoint;
import cgeo.geocaching.geopoint.GeopointFormatter;
import cgeo.geocaching.network.Network;
import cgeo.geocaching.network.Parameters;
+import cgeo.geocaching.utils.IOUtils;
import cgeo.geocaching.utils.Log;
import ch.boye.httpclientandroidlib.HttpResponse;
import org.apache.commons.lang3.StringUtils;
+import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;
@@ -39,10 +41,12 @@ public class OCXMLClient {
return null;
}
- Collection<Geocache> caches = OC11XMLParser.parseCaches(new GZIPInputStream(data));
+ final BufferedInputStream stream = new BufferedInputStream(new GZIPInputStream(data));
+ Collection<Geocache> caches = OC11XMLParser.parseCaches(stream);
if (caches.iterator().hasNext()) {
Geocache cache = caches.iterator().next();
cgData.saveCache(cache, LoadFlags.SAVE_ALL);
+ IOUtils.closeQuietly(stream);
return cache;
}
return null;
@@ -64,7 +68,10 @@ public class OCXMLClient {
return Collections.emptyList();
}
- return OC11XMLParser.parseCachesFiltered(new GZIPInputStream(data));
+ final BufferedInputStream stream = new BufferedInputStream(new GZIPInputStream(data));
+ final Collection<Geocache> result = OC11XMLParser.parseCachesFiltered(stream);
+ IOUtils.closeQuietly(stream);
+ return result;
} catch (IOException e) {
Log.e("Error parsing nearby search result", e);
return Collections.emptyList();
diff --git a/main/src/cgeo/geocaching/enumerations/CacheAttribute.java b/main/src/cgeo/geocaching/enumerations/CacheAttribute.java
index 530869f..339516b 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),
@@ -108,8 +109,8 @@ public enum CacheAttribute {
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
+ // 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 +147,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/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..a42a48a 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,18 +57,19 @@ 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) {
+ private Dialog getExportOptionsDialog(final Geocache[] caches, final Activity activity) {
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
// AlertDialog has always dark style, so we have to apply it as well always
@@ -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,22 +120,15 @@ 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;
@@ -165,16 +154,19 @@ class FieldnoteExport extends AbstractExport {
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());
+ buffer = new BufferedOutputStream(os);
+ fileWriter = new OutputStreamWriter(buffer, CharEncoding.UTF_16);
+ fileWriter.write(fieldNoteBuffer.toString());
} catch (IOException e) {
Log.e("FieldnoteExport.ExportTask export", e);
return false;
} finally {
- IOUtils.closeQuietly(fw);
+ IOUtils.closeQuietly(fileWriter);
+ IOUtils.closeQuietly(buffer);
}
if (upload) {
@@ -227,10 +219,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 +238,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 c2a58b7..c17448f 100644
--- a/main/src/cgeo/geocaching/export/GpxExport.java
+++ b/main/src/cgeo/geocaching/export/GpxExport.java
@@ -6,11 +6,12 @@ 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.AsyncTaskWithProgress;
import cgeo.geocaching.utils.BaseUtils;
import cgeo.geocaching.utils.Log;
import cgeo.geocaching.utils.XmlUtils;
@@ -22,25 +23,27 @@ 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.Collection;
import java.util.Date;
import java.util.List;
import java.util.Locale;
+import java.util.Set;
class GpxExport extends AbstractExport {
private static final SimpleDateFormat dateFormatZ = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
@@ -48,24 +51,30 @@ class GpxExport extends AbstractExport {
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;
+
protected GpxExport() {
super(getString(R.string.export_gpx));
}
@Override
public void export(final List<Geocache> caches, final Activity activity) {
+ 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) {
+ private Dialog getExportDialog(final String[] geocodes, final Activity activity) {
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
// AlertDialog has always dark style, so we have to apply it as well always
@@ -91,55 +100,56 @@ 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) {
+ 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();
+ private int countExported = 0;
/**
* 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;
}
+ 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);
+ writer = new BufferedWriter(new FileWriter(exportFile));
gpx.setOutput(writer);
gpx.startDocument("UTF-8", true);
@@ -153,68 +163,17 @@ class GpxExport extends AbstractExport {
PREFIX_GPX + " http://www.topografix.com/GPX/1/0/gpx.xsd " +
PREFIX_GROUNDSPEAK + " http://www.groundspeak.com/cache/1/0/1/cache.xsd");
- 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));
- }
-
- 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);
+ // 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();
- } catch (final IOException e) {
+ } catch (final Exception e) {
Log.e("GpxExport.ExportTask export", e);
if (writer != null) {
@@ -235,6 +194,67 @@ class GpxExport extends AbstractExport {
return exportFile;
}
+ private void exportBatch(final XmlSerializer gpx, Collection<String> geocodesOfBatch) throws IOException {
+ Set<Geocache> caches = cgData.loadCaches(geocodesOfBatch, LoadFlags.LOAD_ALL_DB_ONLY);
+ for (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(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);
+
+ countExported++;
+ publishProgress(countExported);
+ }
+ }
+
private void writeWaypoints(final XmlSerializer gpx, final Geocache cache) throws IOException {
List<Waypoint> waypoints = cache.getWaypoints();
List<Waypoint> ownWaypoints = new ArrayList<Waypoint>(waypoints.size());
@@ -345,9 +365,8 @@ class GpxExport extends AbstractExport {
}
@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()) {
@@ -363,11 +382,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/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..69d2dac 100644
--- a/main/src/cgeo/geocaching/files/GPXImporter.java
+++ b/main/src/cgeo/geocaching/files/GPXImporter.java
@@ -1,458 +1,463 @@
-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 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 (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()));
+ 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(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 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);
+ }
+ }
+}
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/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..89d1cdc 100644
--- a/main/src/cgeo/geocaching/maps/CGeoMap.java
+++ b/main/src/cgeo/geocaching/maps/CGeoMap.java
@@ -116,21 +116,6 @@ 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";
@@ -173,8 +158,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 */
@@ -382,9 +365,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);
@@ -541,36 +524,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 +545,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,21 +560,27 @@ 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);
+
+ Strategy strategy = Settings.getLiveMapStrategy();
+ menu.findItem(R.id.menu_strategy_fastest).setChecked(strategy == Strategy.FASTEST);
+ menu.findItem(R.id.menu_strategy_fast).setChecked(strategy == Strategy.FAST);
+ menu.findItem(R.id.menu_strategy_auto).setChecked(strategy == Strategy.AUTO);
+ menu.findItem(R.id.menu_strategy_detailed).setChecked(strategy == Strategy.DETAILED);
} catch (Exception e) {
Log.e("cgeomap.onPrepareOptionsMenu", e);
}
@@ -623,12 +592,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 +607,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 +641,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 +650,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 +720,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());
@@ -1578,12 +1545,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);
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/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/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/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/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/network/HtmlImage.java b/main/src/cgeo/geocaching/network/HtmlImage.java
index 38498d6..d5b610c 100644
--- a/main/src/cgeo/geocaching/network/HtmlImage.java
+++ b/main/src/cgeo/geocaching/network/HtmlImage.java
@@ -6,6 +6,7 @@ import cgeo.geocaching.cgeoapplication;
import cgeo.geocaching.compatibility.Compatibility;
import cgeo.geocaching.connector.ConnectorFactory;
import cgeo.geocaching.files.LocalStorage;
+import cgeo.geocaching.utils.IOUtils;
import cgeo.geocaching.utils.ImageHelper;
import cgeo.geocaching.utils.Log;
@@ -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 {
@@ -66,6 +67,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;
@@ -194,7 +196,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 +211,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..5a8cbb2 100644
--- a/main/src/cgeo/geocaching/network/Network.java
+++ b/main/src/cgeo/geocaching/network/Network.java
@@ -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;
@@ -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/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..0e13564
--- /dev/null
+++ b/main/src/cgeo/geocaching/speech/TextFactory.java
@@ -0,0 +1,71 @@
+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()) {
+ if (kilometers >= 5.0) {
+ return getString(R.string.tts_kilometers, String.valueOf(Math.round(kilometers)));
+ }
+ if (kilometers >= 1.0) {
+ String digits = String.format(Locale.getDefault(), "%.1f", kilometers);
+ return getString(R.string.tts_kilometers, digits);
+ }
+ int meters = (int) (kilometers * 1000.0);
+ if (meters > 50) {
+ return getString(R.string.tts_meters, String.valueOf(Math.round(meters / 10.0) * 10));
+ }
+ return getString(R.string.tts_meters, String.valueOf(meters));
+ }
+
+ float miles = kilometers / IConversion.MILES_TO_KILOMETER;
+ if (miles >= 3.0) {
+ return getString(R.string.tts_miles, String.valueOf(Math.round(miles)));
+ }
+ if (miles >= 0.2) { // approx 1000 ft
+ String digits = String.format(Locale.getDefault(), "%.1f", miles);
+ return getString(R.string.tts_miles, digits);
+ }
+ int feet = (int) (kilometers * 1000.0 * IConversion.METERS_TO_FEET);
+ if (feet > 300) {
+ return getString(R.string.tts_feet, String.valueOf(Math.round(feet / 10.0) * 10));
+ }
+ return getString(R.string.tts_feet, String.valueOf(feet));
+ }
+
+ private static String getString(int resourceId, Object... formatArgs) {
+ return cgeoapplication.getInstance().getString(resourceId, 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;
+ }
+ 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..e3d3f77 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) {
@@ -47,49 +50,56 @@ public final class Twitter {
}
}
- 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..3bc1dec 100644
--- a/main/src/cgeo/geocaching/twitter/TwitterAuthorizationActivity.java
+++ b/main/src/cgeo/geocaching/twitter/TwitterAuthorizationActivity.java
@@ -89,21 +89,11 @@ public class TwitterAuthorizationActivity extends AbstractActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- setTheme();
- setContentView(R.layout.twitter_authorization_activity);
- setTitle(res.getString(R.string.auth_twitter));
+ super.onCreate(savedInstanceState, R.layout.twitter_authorization_activity);
init();
}
- @Override
- public void onResume() {
- super.onResume();
-
- }
-
private void init() {
startButton = (Button) findViewById(R.id.start);
pinEntry = (EditText) findViewById(R.id.pin);
diff --git a/main/src/cgeo/geocaching/ui/CacheDetailsCreator.java b/main/src/cgeo/geocaching/ui/CacheDetailsCreator.java
index e98bd77..80f01e2 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;
@@ -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 163d396..99ae405 100644
--- a/main/src/cgeo/geocaching/ui/CacheListAdapter.java
+++ b/main/src/cgeo/geocaching/ui/CacheListAdapter.java
@@ -76,13 +76,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;
}
}
@@ -94,7 +94,7 @@ public class CacheListAdapter extends ArrayAdapter<Geocache> {
CheckBox checkbox;
ImageView logStatusMark;
TextView text;
- TextView favourite;
+ TextView favorite;
TextView info;
ImageView inventory;
DistanceView distance;
@@ -357,7 +357,7 @@ public class CacheListAdapter extends ArrayAdapter<Geocache> {
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.favorite = (TextView) v.findViewById(R.id.favorite);
holder.info = (TextView) v.findViewById(R.id.info);
v.setTag(holder);
@@ -449,14 +449,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
@@ -477,7 +477,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/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/ImagesList.java b/main/src/cgeo/geocaching/ui/ImagesList.java
index 9464114..218e16e 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;
@@ -46,16 +46,14 @@ public class ImagesList {
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 +62,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 +78,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 +141,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();
- }
- }
}
}
@@ -205,15 +185,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);
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..1ba15a2 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:
@@ -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/dialog/CoordinatesInputDialog.java b/main/src/cgeo/geocaching/ui/dialog/CoordinatesInputDialog.java
index dada8fd..3d93a56 100644
--- a/main/src/cgeo/geocaching/ui/dialog/CoordinatesInputDialog.java
+++ b/main/src/cgeo/geocaching/ui/dialog/CoordinatesInputDialog.java
@@ -74,14 +74,6 @@ public class CoordinatesInputDialog extends Dialog {
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");
- }
- });
-
final Spinner spinner = (Spinner) findViewById(R.id.spinnerCoordinateFormats);
final ArrayAdapter<CharSequence> adapter =
ArrayAdapter.createFromResource(context,
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/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/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/ImageHelper.java b/main/src/cgeo/geocaching/utils/ImageHelper.java
index 98cad64..ec77018 100644
--- a/main/src/cgeo/geocaching/utils/ImageHelper.java
+++ b/main/src/cgeo/geocaching/utils/ImageHelper.java
@@ -8,6 +8,9 @@ import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
+import java.io.BufferedOutputStream;
+import java.io.FileOutputStream;
+
public class ImageHelper {
// 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("Image", e);
+ }
+ }
}
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/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";
-}