aboutsummaryrefslogtreecommitdiffstats
path: root/main/thirdparty
diff options
context:
space:
mode:
authorBananeweizen <bananeweizen@gmx.de>2013-04-22 08:35:53 +0200
committerBananeweizen <bananeweizen@gmx.de>2013-04-22 08:35:53 +0200
commit9dac2f6bb2bf6849ec74a3438b17e1c85e1b01a8 (patch)
tree8fe7e6695ea738e24bf611fc2c045f4cdea8e57e /main/thirdparty
parentfceb3c05fd6ca7108b536ec2b9b0ab9e50cfba1e (diff)
downloadcgeo-9dac2f6bb2bf6849ec74a3438b17e1c85e1b01a8.zip
cgeo-9dac2f6bb2bf6849ec74a3438b17e1c85e1b01a8.tar.gz
cgeo-9dac2f6bb2bf6849ec74a3438b17e1c85e1b01a8.tar.bz2
refactoring: move third party code into new source path
* makes it more easy to ignore warnings in third party code
Diffstat (limited to 'main/thirdparty')
-rw-r--r--main/thirdparty/android/support/v4/app/FragmentListActivity.java316
-rw-r--r--main/thirdparty/cgeo/org/kxml2/io/KXmlSerializer.java605
-rw-r--r--main/thirdparty/com/viewpagerindicator/PageIndicator.java63
-rw-r--r--main/thirdparty/com/viewpagerindicator/TitlePageIndicator.java771
-rw-r--r--main/thirdparty/com/viewpagerindicator/TitleProvider.java28
-rw-r--r--main/thirdparty/gnu/android/app/appmanualclient/AppManualReaderClient.java375
-rw-r--r--main/thirdparty/org/openintents/intents/FileManagerIntents.java127
7 files changed, 2285 insertions, 0 deletions
diff --git a/main/thirdparty/android/support/v4/app/FragmentListActivity.java b/main/thirdparty/android/support/v4/app/FragmentListActivity.java
new file mode 100644
index 0000000..e3ed42c
--- /dev/null
+++ b/main/thirdparty/android/support/v4/app/FragmentListActivity.java
@@ -0,0 +1,316 @@
+/*
+ * 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/thirdparty/cgeo/org/kxml2/io/KXmlSerializer.java b/main/thirdparty/cgeo/org/kxml2/io/KXmlSerializer.java
new file mode 100644
index 0000000..027ff53
--- /dev/null
+++ b/main/thirdparty/cgeo/org/kxml2/io/KXmlSerializer.java
@@ -0,0 +1,605 @@
+/*
+ * 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/thirdparty/com/viewpagerindicator/PageIndicator.java b/main/thirdparty/com/viewpagerindicator/PageIndicator.java
new file mode 100644
index 0000000..26414d8
--- /dev/null
+++ b/main/thirdparty/com/viewpagerindicator/PageIndicator.java
@@ -0,0 +1,63 @@
+/*
+ * 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/thirdparty/com/viewpagerindicator/TitlePageIndicator.java b/main/thirdparty/com/viewpagerindicator/TitlePageIndicator.java
new file mode 100644
index 0000000..94ac962
--- /dev/null
+++ b/main/thirdparty/com/viewpagerindicator/TitlePageIndicator.java
@@ -0,0 +1,771 @@
+/*
+ * 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/thirdparty/com/viewpagerindicator/TitleProvider.java b/main/thirdparty/com/viewpagerindicator/TitleProvider.java
new file mode 100644
index 0000000..2a04b65
--- /dev/null
+++ b/main/thirdparty/com/viewpagerindicator/TitleProvider.java
@@ -0,0 +1,28 @@
+/*
+ * 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/thirdparty/gnu/android/app/appmanualclient/AppManualReaderClient.java b/main/thirdparty/gnu/android/app/appmanualclient/AppManualReaderClient.java
new file mode 100644
index 0000000..af4c03e
--- /dev/null
+++ b/main/thirdparty/gnu/android/app/appmanualclient/AppManualReaderClient.java
@@ -0,0 +1,375 @@
+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/thirdparty/org/openintents/intents/FileManagerIntents.java b/main/thirdparty/org/openintents/intents/FileManagerIntents.java
new file mode 100644
index 0000000..8ff10c8
--- /dev/null
+++ b/main/thirdparty/org/openintents/intents/FileManagerIntents.java
@@ -0,0 +1,127 @@
+/*
+ * 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";
+}