diff --git a/code/portal_detail_display.js b/code/portal_detail_display.js
index cb2e79a7..37eb45a9 100644
--- a/code/portal_detail_display.js
+++ b/code/portal_detail_display.js
@@ -52,7 +52,6 @@ window.renderPortalDetails = function(guid) {
var poslinks = 'window.showPortalPosLinks('+lat+','+lng+',\''+escapeJavascriptString(d.portalV2.descriptiveText.TITLE)+'\')';
var portalDetailObj = window.getPortalDescriptionFromDetailsExtended(d);
-
var portalDetailedDescription = '';
if(portalDetailObj) {
@@ -101,8 +100,12 @@ window.renderPortalDetails = function(guid) {
+ randDetails
+ resoDetails
+ '
'
- + '
'
- + '
'
+ + (
+ typeof android !== 'undefined' && android && android.intentPosLink // Android handles both links via a dialog
+ ? '
'
+ : '
'
+ + '
'
+ )
+ '
'
+ '
'
);
diff --git a/code/utils_misc.js b/code/utils_misc.js
index 781fd378..541342bd 100644
--- a/code/utils_misc.js
+++ b/code/utils_misc.js
@@ -176,7 +176,7 @@ window.showPortalPosLinks = function(lat, lng, name) {
}
if (typeof android !== 'undefined' && android && android.intentPosLink) {
- android.intentPosLink(lat, lng, encoded_name);
+ android.intentPosLink(lat, lng, map.getZoom(), name);
} else {
var qrcode = '';
var script = '';
@@ -200,6 +200,15 @@ window.androidCopy = function(text) {
return false;
}
+window.androidPermalink = function() {
+ if(typeof android === 'undefined' || !android || !android.copy)
+ return true; // i.e. execute other actions
+
+ var center = map.getCenter();
+ android.intentPosLink(center.lat, center.lng, map.getZoom(), null);
+ return false;
+}
+
window.reportPortalIssue = function(info) {
var t = 'Redirecting you to a Google Help Page.\n\nThe text box contains all necessary information. Press CTRL+C to copy it.';
var d = window.portals[window.selectedPortal].options.details;
diff --git a/main.js b/main.js
index 38136170..1256988f 100644
--- a/main.js
+++ b/main.js
@@ -96,7 +96,7 @@ document.getElementsByTagName('body')[0].innerHTML = ''
// redeeming removed from stock site, so commented out for now. it may return...
// + ' '
+ ' '
+ ' '
diff --git a/mobile/res/drawable-hdpi/ic_dialog_browser.png b/mobile/res/drawable-hdpi/ic_dialog_browser.png
new file mode 100644
index 00000000..e154afdb
Binary files /dev/null and b/mobile/res/drawable-hdpi/ic_dialog_browser.png differ
diff --git a/mobile/res/drawable-hdpi/ic_dialog_copy.png b/mobile/res/drawable-hdpi/ic_dialog_copy.png
new file mode 100644
index 00000000..72c6bc6e
Binary files /dev/null and b/mobile/res/drawable-hdpi/ic_dialog_copy.png differ
diff --git a/mobile/res/drawable-hdpi/ic_dialog_share.png b/mobile/res/drawable-hdpi/ic_dialog_share.png
new file mode 100644
index 00000000..c329f58d
Binary files /dev/null and b/mobile/res/drawable-hdpi/ic_dialog_share.png differ
diff --git a/mobile/res/drawable-mdpi/ic_dialog_browser.png b/mobile/res/drawable-mdpi/ic_dialog_browser.png
new file mode 100644
index 00000000..41b56ec9
Binary files /dev/null and b/mobile/res/drawable-mdpi/ic_dialog_browser.png differ
diff --git a/mobile/res/drawable-mdpi/ic_dialog_copy.png b/mobile/res/drawable-mdpi/ic_dialog_copy.png
new file mode 100644
index 00000000..d93968e5
Binary files /dev/null and b/mobile/res/drawable-mdpi/ic_dialog_copy.png differ
diff --git a/mobile/res/drawable-mdpi/ic_dialog_share.png b/mobile/res/drawable-mdpi/ic_dialog_share.png
new file mode 100644
index 00000000..056deb57
Binary files /dev/null and b/mobile/res/drawable-mdpi/ic_dialog_share.png differ
diff --git a/mobile/res/drawable-xhdpi/ic_dialog_browser.png b/mobile/res/drawable-xhdpi/ic_dialog_browser.png
new file mode 100644
index 00000000..9b77be96
Binary files /dev/null and b/mobile/res/drawable-xhdpi/ic_dialog_browser.png differ
diff --git a/mobile/res/drawable-xhdpi/ic_dialog_copy.png b/mobile/res/drawable-xhdpi/ic_dialog_copy.png
new file mode 100644
index 00000000..04e290d8
Binary files /dev/null and b/mobile/res/drawable-xhdpi/ic_dialog_copy.png differ
diff --git a/mobile/res/drawable-xhdpi/ic_dialog_share.png b/mobile/res/drawable-xhdpi/ic_dialog_share.png
new file mode 100644
index 00000000..15549b04
Binary files /dev/null and b/mobile/res/drawable-xhdpi/ic_dialog_share.png differ
diff --git a/mobile/src/com/cradle/iitc_mobile/IITC_JSInterface.java b/mobile/src/com/cradle/iitc_mobile/IITC_JSInterface.java
index 4f6dceb7..7a4d7419 100644
--- a/mobile/src/com/cradle/iitc_mobile/IITC_JSInterface.java
+++ b/mobile/src/com/cradle/iitc_mobile/IITC_JSInterface.java
@@ -1,5 +1,11 @@
package com.cradle.iitc_mobile;
+import java.util.HashMap;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+
+import android.app.Activity;
import android.app.AlertDialog;
import android.content.ClipData;
import android.content.ClipboardManager;
@@ -7,17 +13,11 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.DialogInterface.OnMultiChoiceClickListener;
-import android.content.Intent;
-import android.net.Uri;
+import android.os.Bundle;
import android.util.Log;
import android.webkit.JavascriptInterface;
import android.widget.Toast;
-import org.json.JSONArray;
-import org.json.JSONException;
-
-import java.util.HashMap;
-
// provide communication between IITC script and android app
public class IITC_JSInterface {
@@ -35,13 +35,18 @@ public class IITC_JSInterface {
context = c;
}
- // send geo intent for navigation apps like gmaps or waze etc...
+ // open dialog to send geo intent for navigation apps like gmaps or waze etc...
@JavascriptInterface
- public void intentPosLink(String lat, String lng, String portal_name) {
- String uri = "geo:" + lat + "," + lng + "?q=" + lat + "," + lng;
- Intent intent = new Intent(android.content.Intent.ACTION_VIEW,
- Uri.parse(uri));
- context.startActivity(intent);
+ public void intentPosLink(double lat, double lng, int zoom, String portalName) {
+ Bundle args = new Bundle();
+ args.putDouble("lat", lat);
+ args.putDouble("lng", lng);
+ args.putInt("zoom", zoom);
+ args.putString("title", portalName);
+
+ IITC_ShareDialog dialog = new IITC_ShareDialog();
+ dialog.setArguments(args);
+ dialog.show(((Activity) context).getFragmentManager(), "ShareDialog");
}
// disable javascript injection while spinner is enabled
diff --git a/mobile/src/com/cradle/iitc_mobile/IITC_ShareDialog.java b/mobile/src/com/cradle/iitc_mobile/IITC_ShareDialog.java
new file mode 100644
index 00000000..cf0c9a2d
--- /dev/null
+++ b/mobile/src/com/cradle/iitc_mobile/IITC_ShareDialog.java
@@ -0,0 +1,194 @@
+package com.cradle.iitc_mobile;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.content.ClipData;
+import android.content.ClipboardManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.pm.ComponentInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.TextView;
+import android.widget.Toast;
+
+public class IITC_ShareDialog extends DialogFragment {
+ private abstract class Action {
+ private int mIcon;
+ private String mLabel;
+
+ private Action(String label, int icon) {
+ mLabel = label;
+ mIcon = icon;
+ }
+
+ abstract void invoke();
+ }
+
+ public class OnClickListener implements DialogInterface.OnClickListener {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ mAdapter.getItem(which).invoke();
+ }
+ }
+
+ class ActionAdapter extends ArrayAdapter {
+ private LayoutInflater mInflater;
+
+ public ActionAdapter(Context context) {
+ super(context, android.R.layout.simple_list_item_1, ACTIONS);
+ mInflater = LayoutInflater.from(context);
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ Action action = getItem(position);
+
+ if (convertView == null)
+ convertView = mInflater.inflate(android.R.layout.simple_list_item_1, null);
+
+ TextView tv = (TextView) convertView;
+ tv.setText(action.mLabel);
+ tv.setCompoundDrawablePadding(8);
+ tv.setCompoundDrawablesWithIntrinsicBounds(action.mIcon, 0, 0, 0);
+ return convertView;
+ }
+ }
+
+ private final Action[] ACTIONS = {
+ new Action("Share…", R.drawable.ic_dialog_share) {
+ void invoke() {
+ Intent intent = new Intent(Intent.ACTION_SEND);
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
+ intent.setType("text/plain");
+ intent.putExtra(Intent.EXTRA_TEXT, getUrl());
+ intent.putExtra(Intent.EXTRA_SUBJECT, mTitle);
+
+ startIntent(intent);
+ }
+ },
+ new Action("View map with app…", R.drawable.location_map) {
+ void invoke() {
+ String geoUri = "geo:" + mLl;
+ Intent intent = new Intent(android.content.Intent.ACTION_VIEW, Uri.parse(geoUri));
+
+ startIntent(intent);
+ }
+ },
+ new Action("Open with browser…", R.drawable.ic_dialog_browser) {
+ void invoke() {
+ Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(getUrl()));
+
+ startIntent(intent);
+ }
+ },
+ new Action("Copy to clipboard", R.drawable.ic_dialog_copy) {
+ void invoke() {
+ ClipData clip = ClipData.newPlainText("Copied text", getUrl());
+
+ ClipboardManager clipboard = (ClipboardManager) getActivity().getSystemService(
+ Activity.CLIPBOARD_SERVICE);
+ clipboard.setPrimaryClip(clip);
+
+ Toast.makeText(getActivity(), "copied to clipboard", Toast.LENGTH_SHORT).show();
+ }
+ }
+ };
+
+ private ActionAdapter mAdapter;
+ private boolean mIsPortal = true;
+ private String mLl;
+ private String mTitle;
+ private int mZoom;
+
+ private String getUrl() {
+ String url = "http://www.ingress.com/intel?ll=" + mLl + "&z=" + mZoom;
+ if (mIsPortal)
+ url += "&pll=" + mLl;
+ return url;
+ }
+
+ private void startIntent(Intent intent) {
+ // for geo: and Intel Map intents, the user may choose a default application to handle the intent. Since we have
+ // suitable intent filters declared, it might be that we *are* the default application. In theses cases, a list
+ // of designated applications is presented to the user
+
+ String packageName = getActivity().getPackageName();
+
+ PackageManager pm = getActivity().getPackageManager();
+ ResolveInfo mInfo = pm.resolveActivity(intent, 0);
+
+ if (mInfo.activityInfo.packageName.equals(packageName)) {
+ // note: Intent.createChooser would be shorter, but it also includes IITCm.
+ // Therefore, we'll filter the available activities
+ String label = null;
+ if (intent.getAction().equals(Intent.ACTION_SEND))
+ label = "Share via";
+ else if (intent.getAction().equals(Intent.ACTION_VIEW))
+ label = "Open with";
+
+ List intents = new ArrayList();
+ List activities = getActivity().getPackageManager().queryIntentActivities(intent, 0);
+
+ if (!activities.isEmpty()) {
+ for (ResolveInfo resolveInfo : activities) {
+ ComponentInfo info;
+ if (resolveInfo.activityInfo != null)
+ info = resolveInfo.activityInfo;
+ else
+ // Exactly one if these two must be non-null (according to docs)
+ info = resolveInfo.serviceInfo;
+
+ if (info.packageName.equals(packageName)) // don't show IITCm
+ continue;
+
+ // setComponent is used to route the intent towards the component
+ // setPackage is used to prevent Android from showing IITCm
+ // (without a package set, Android would still show all available components, including IITCm)
+ intents.add(new Intent(intent)
+ .setComponent(new ComponentName(info.packageName, info.name))
+ .setPackage(info.packageName));
+ }
+
+ intent = Intent.createChooser(intents.remove(intents.size() - 1), label);
+ intent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intents.toArray(new Parcelable[] {}));
+ }
+ }
+
+ startActivity(intent);
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ Bundle args = getArguments();
+ mTitle = args.getString("title");
+ mLl = args.getDouble("lat") + "," + args.getDouble("lng");
+ mZoom = args.getInt("zoom");
+
+ if (mTitle == null) {
+ mTitle = "Intel Map";
+ mIsPortal = false;
+ }
+
+ mAdapter = new ActionAdapter(getActivity());
+
+ return new AlertDialog.Builder(getActivity())
+ .setTitle(mTitle)
+ .setAdapter(mAdapter, new OnClickListener())
+ .create();
+ }
+}