Added query and open functionality to PluginSDK

First working version of QR Plugin
This commit is contained in:
Philipp Crocoll 2014-05-21 06:44:42 +02:00
parent f0a2f9a038
commit b2baa66b71
9 changed files with 286 additions and 56 deletions

View File

@ -0,0 +1,75 @@
package keepass2android.pluginsdk;
import java.util.ArrayList;
import java.util.HashMap;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.content.Intent;
import android.text.TextUtils;
public class Kp2aControl {
/**
* Creates and returns an intent to launch Keepass2Android for adding an entry with the given fields.
* @param fields Key/Value pairs of the field values. See KeepassDefs for standard keys.
* @param protectedFields List of keys of the protected fields.
* @return Intent to start Keepass2Android.
* @throws JSONException
*/
public static Intent getAddEntryIntent(HashMap<String, String> fields, ArrayList<String> protectedFields)
{
return getAddEntryIntent(new JSONObject(fields).toString(), protectedFields);
}
public static Intent getAddEntryIntent(String outputData, ArrayList<String> protectedFields)
{
Intent startKp2aIntent = new Intent(Strings.ACTION_START_WITH_TASK);
startKp2aIntent.addCategory(Intent.CATEGORY_DEFAULT);
startKp2aIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startKp2aIntent.putExtra("KP2A_APPTASK", "CreateEntryThenCloseTask");
startKp2aIntent.putExtra("ShowUserNotifications", "false"); //KP2A expects a StringExtra
startKp2aIntent.putExtra(Strings.EXTRA_ENTRY_OUTPUT_DATA, outputData);
if (protectedFields != null)
startKp2aIntent.putStringArrayListExtra(Strings.EXTRA_PROTECTED_FIELDS_LIST, protectedFields);
return startKp2aIntent;
}
/**
* Creates an intent to open a Password Entry matching searchText
* @param searchText queryString
* @param showUserNotifications if true, the notifications (copy to clipboard, keyboard) are displayed
* @param closeAfterOpen if true, the entry is opened and KP2A is immediately closed
* @return Intent to start KP2A with
*/
public static Intent getOpenEntryIntent(String searchText, boolean showUserNotifications, boolean closeAfterOpen)
{
Intent startKp2aIntent = new Intent(Strings.ACTION_START_WITH_TASK);
startKp2aIntent.addCategory(Intent.CATEGORY_DEFAULT);
startKp2aIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startKp2aIntent.putExtra("KP2A_APPTASK", "SearchUrlTask");
startKp2aIntent.putExtra("ShowUserNotifications", String.valueOf(showUserNotifications));
startKp2aIntent.putExtra("CloseAfterCreate", String.valueOf(closeAfterOpen));
startKp2aIntent.putExtra("UrlToSearch", searchText);
return startKp2aIntent;
}
/**
* Creates an intent to query a password entry from KP2A. The credentials are returned as Activity result.
* @param searchText Text to search for. Should be a URL or "androidapp://com.my.package."
* @return an Intent to start KP2A with
*/
public static Intent getQueryEntryIntent(String searchText)
{
Intent i = new Intent(Strings.ACTION_QUERY_CREDENTIALS);
if (!TextUtils.isEmpty(searchText))
i.putExtra(Strings.EXTRA_QUERY_STRING, searchText);
return i;
}
}

View File

@ -10,6 +10,16 @@ public class Strings {
*/ */
public static final String SCOPE_CURRENT_ENTRY = "keepass2android.SCOPE_CURRENT_ENTRY"; public static final String SCOPE_CURRENT_ENTRY = "keepass2android.SCOPE_CURRENT_ENTRY";
/**
* Plugin may query credentials for its own package
*/
public static final String SCOPE_QUERY_CREDENTIALS_FOR_OWN_PACKAGE = "keepass2android.SCOPE_QUERY_CREDENTIALS_FOR_OWN_PACKAGE";
/**
* Plugin may query credentials for a deliberate package
*/
public static final String SCOPE_QUERY_CREDENTIALS = "keepass2android.SCOPE_QUERY_CREDENTIALS";
/** /**
* Extra key to transfer a (json serialized) list of scopes * Extra key to transfer a (json serialized) list of scopes
*/ */
@ -30,6 +40,11 @@ public class Strings {
*/ */
public static final String EXTRA_REQUEST_TOKEN = "keepass2android.EXTRA_REQUEST_TOKEN"; public static final String EXTRA_REQUEST_TOKEN = "keepass2android.EXTRA_REQUEST_TOKEN";
/**
* Action to start KP2A with an AppTask
*/
public static final String ACTION_START_WITH_TASK = "keepass2android.ACTION_START_WITH_TASK";
/** /**
* Action sent from KP2A to the plugin to indicate that the plugin should request * Action sent from KP2A to the plugin to indicate that the plugin should request
* access (sending it's scopes) * access (sending it's scopes)
@ -125,6 +140,24 @@ public class Strings {
*/ */
public static final String ACTION_ENTRY_ACTION_SELECTED = "keepass2android.ACTION_ENTRY_ACTION_SELECTED"; public static final String ACTION_ENTRY_ACTION_SELECTED = "keepass2android.ACTION_ENTRY_ACTION_SELECTED";
/**
* Extra key for the string which is used to query the credentials. This should be either a URL for
* a web login (google.com or a full URI) or something in the form "androidapp://com.my.package"
*/
public static final String EXTRA_QUERY_STRING = "keepass2android.EXTRA_QUERY_STRING";
/**
* Action when plugin wants to query credentials for its own package
*/
public static final String ACTION_QUERY_CREDENTIALS_FOR_OWN_PACKAGE = "keepass2android.ACTION_QUERY_CREDENTIALS_FOR_OWN_PACKAGE";
/**
* Action when plugin wants to query credentials for a deliberate package
* The query string is passed as intent data
*/
public static final String ACTION_QUERY_CREDENTIALS = "keepass2android.ACTION_QUERY_CREDENTIALS";
/** /**
* Action for an intent from the plugin to KP2A to set (i.e. add or update) a field in the entry. * Action for an intent from the plugin to KP2A to set (i.e. add or update) a field in the entry.
* May be used to update existing or add new fields at any time while the entry is opened. * May be used to update existing or add new fields at any time while the entry is opened.

View File

@ -53,7 +53,7 @@
<activity <activity
android:name="keepass2android.plugin.qr.MainActivity" android:name="keepass2android.plugin.qr.MainActivity"
android:label="@string/title_activity_main" android:label="@string/app_name"
> >
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />

View File

@ -60,7 +60,6 @@ public final class R {
public static final int share_via_barcode=0x7f020003; public static final int share_via_barcode=0x7f020003;
} }
public static final class id { public static final class id {
public static final int action_settings=0x7f0b0036;
public static final int app_picker_list_item_icon=0x7f0b0008; public static final int app_picker_list_item_icon=0x7f0b0008;
public static final int app_picker_list_item_label=0x7f0b0009; public static final int app_picker_list_item_label=0x7f0b0009;
public static final int barcode_image_view=0x7f0b000f; public static final int barcode_image_view=0x7f0b000f;
@ -143,9 +142,8 @@ public final class R {
public static final int beep=0x7f050000; public static final int beep=0x7f050000;
} }
public static final class string { public static final class string {
public static final int action_settings=0x7f070077; public static final int action_show_qr=0x7f070077;
public static final int action_show_qr=0x7f070078; public static final int all_fields=0x7f070079;
public static final int all_fields=0x7f07007a;
public static final int app_name=0x7f070000; public static final int app_name=0x7f070000;
public static final int app_picker_name=0x7f070001; public static final int app_picker_name=0x7f070001;
public static final int bookmark_picker_name=0x7f070002; public static final int bookmark_picker_name=0x7f070002;
@ -178,9 +176,9 @@ public final class R {
public static final int contents_phone=0x7f07001d; public static final int contents_phone=0x7f07001d;
public static final int contents_sms=0x7f07001e; public static final int contents_sms=0x7f07001e;
public static final int contents_text=0x7f07001f; public static final int contents_text=0x7f07001f;
public static final int enable_as_plugin=0x7f070085; public static final int create_entry=0x7f070084;
public static final int enabled_as_plugin=0x7f070084; public static final int enable_as_plugin=0x7f070082;
public static final int hello_world=0x7f07007f; public static final int enabled_as_plugin=0x7f070081;
public static final int history_clear_one_history_text=0x7f070021; public static final int history_clear_one_history_text=0x7f070021;
public static final int history_clear_text=0x7f070020; public static final int history_clear_text=0x7f070020;
public static final int history_email_title=0x7f070022; public static final int history_email_title=0x7f070022;
@ -188,10 +186,10 @@ public final class R {
public static final int history_empty_detail=0x7f070024; public static final int history_empty_detail=0x7f070024;
public static final int history_send=0x7f070025; public static final int history_send=0x7f070025;
public static final int history_title=0x7f070026; public static final int history_title=0x7f070026;
public static final int include_label=0x7f070079; public static final int include_label=0x7f070078;
public static final int kp2aplugin_author=0x7f07007d; public static final int kp2aplugin_author=0x7f07007c;
public static final int kp2aplugin_shortdesc=0x7f07007c; public static final int kp2aplugin_shortdesc=0x7f07007b;
public static final int kp2aplugin_title=0x7f07007b; public static final int kp2aplugin_title=0x7f07007a;
public static final int menu_encode_mecard=0x7f070027; public static final int menu_encode_mecard=0x7f070027;
public static final int menu_encode_vcard=0x7f070028; public static final int menu_encode_vcard=0x7f070028;
public static final int menu_help=0x7f070029; public static final int menu_help=0x7f070029;
@ -222,8 +220,8 @@ public final class R {
public static final int msg_share_text=0x7f070042; public static final int msg_share_text=0x7f070042;
public static final int msg_sure=0x7f070043; public static final int msg_sure=0x7f070043;
public static final int msg_unmount_usb=0x7f070044; public static final int msg_unmount_usb=0x7f070044;
public static final int no_host_app=0x7f070082; public static final int no_host_app=0x7f07007f;
public static final int not_enabled_as_plugin=0x7f070083; public static final int not_enabled_as_plugin=0x7f070080;
public static final int preferences_actions_title=0x7f070045; public static final int preferences_actions_title=0x7f070045;
public static final int preferences_auto_focus_title=0x7f070046; public static final int preferences_auto_focus_title=0x7f070046;
public static final int preferences_bulk_mode_summary=0x7f070047; public static final int preferences_bulk_mode_summary=0x7f070047;
@ -258,6 +256,7 @@ public final class R {
public static final int preferences_try_bsplus=0x7f070074; public static final int preferences_try_bsplus=0x7f070074;
public static final int preferences_try_bsplus_summary=0x7f070075; public static final int preferences_try_bsplus_summary=0x7f070075;
public static final int preferences_vibrate_title=0x7f070064; public static final int preferences_vibrate_title=0x7f070064;
public static final int qr_question=0x7f070083;
public static final int result_address_book=0x7f070065; public static final int result_address_book=0x7f070065;
public static final int result_calendar=0x7f070066; public static final int result_calendar=0x7f070066;
public static final int result_email_address=0x7f070067; public static final int result_email_address=0x7f070067;
@ -270,9 +269,9 @@ public final class R {
public static final int result_uri=0x7f07006e; public static final int result_uri=0x7f07006e;
public static final int result_wifi=0x7f07006f; public static final int result_wifi=0x7f07006f;
public static final int sbc_name=0x7f070070; public static final int sbc_name=0x7f070070;
public static final int scan_qr=0x7f070080; public static final int scan_qr=0x7f07007d;
public static final int show_qr=0x7f070081; public static final int search_entry=0x7f070085;
public static final int title_activity_main=0x7f07007e; public static final int show_qr=0x7f07007e;
public static final int title_activity_qr=0x7f070076; public static final int title_activity_qr=0x7f070076;
public static final int wifi_changing_network=0x7f070071; public static final int wifi_changing_network=0x7f070071;
public static final int wifi_ssid_label=0x7f070072; public static final int wifi_ssid_label=0x7f070072;

View File

@ -2,10 +2,4 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
tools:context="keepass2android.plugin.qr.MainActivity" > tools:context="keepass2android.plugin.qr.MainActivity" >
<item
android:id="@+id/action_settings"
android:orderInCategory="100"
android:showAsAction="never"
android:title="@string/action_settings"/>
</menu> </menu>

View File

@ -1,21 +1,21 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="app_name">QR Plugin for KP2A</string> <string name="app_name">QR Plugin for KP2A</string>
<string name="title_activity_qr">QRActivity</string> <string name="title_activity_qr">QR Display</string>
<string name="action_settings">Settings</string>
<string name="action_show_qr">Show QR Code</string> <string name="action_show_qr">Show QR Code</string>
<string name="include_label">Include field label</string> <string name="include_label">Include field label</string>
<string name="all_fields">All fields</string> <string name="all_fields">All fields</string>
<string name="kp2aplugin_title">QR Plugin</string> <string name="kp2aplugin_title">QR Plugin</string>
<string name="kp2aplugin_shortdesc">Displays password entries as QR code</string> <string name="kp2aplugin_shortdesc">Displays password entries as QR code</string>
<string name="kp2aplugin_author">Philipp Crocoll</string> <string name="kp2aplugin_author">Philipp Crocoll</string>
<string name="title_activity_main">MainActivity</string>
<string name="hello_world">Hello world!</string>
<string name="scan_qr">Scan QR code from other device</string> <string name="scan_qr">Scan QR code from other device</string>
<string name="show_qr">Select entry to show as QR code</string> <string name="show_qr">Select entry to show as QR code</string>
<string name="no_host_app">No host app detected! Please install Keepass2Android from Google Play!</string> <string name="no_host_app">No host app detected! Please install Keepass2Android from Google Play!</string>
<string name="not_enabled_as_plugin">Not enabled as plugin in host app!</string> <string name="not_enabled_as_plugin">Not enabled as plugin in host app!</string>
<string name="enabled_as_plugin">Enabled as plugin!</string> <string name="enabled_as_plugin">Enabled as plugin!</string>
<string name="enable_as_plugin">Enable as plugin</string> <string name="enable_as_plugin">Enable as plugin</string>
<string name="qr_question">Text found on QR code. How do you want to handle this text?</string>
</resources> <string name="create_entry">Create new entry</string>
<string name="search_entry">Search and open existing entry</string>
</resources>

View File

@ -11,6 +11,7 @@ public class AccessReceiver extends PluginAccessBroadcastReceiver {
public ArrayList<String> getScopes() { public ArrayList<String> getScopes() {
ArrayList<String> scopes = new ArrayList<String>(); ArrayList<String> scopes = new ArrayList<String>();
scopes.add(Strings.SCOPE_CURRENT_ENTRY); scopes.add(Strings.SCOPE_CURRENT_ENTRY);
scopes.add(Strings.SCOPE_QUERY_CREDENTIALS);
return scopes; return scopes;
} }

View File

@ -1,15 +1,30 @@
package keepass2android.plugin.qr; package keepass2android.plugin.qr;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import keepass2android.pluginsdk.AccessManager; import keepass2android.pluginsdk.AccessManager;
import keepass2android.pluginsdk.KeepassDefs;
import keepass2android.pluginsdk.Kp2aControl;
import keepass2android.pluginsdk.Strings; import keepass2android.pluginsdk.Strings;
import com.google.zxing.client.android.CaptureActivity; import com.google.zxing.client.android.CaptureActivity;
import android.app.Activity; import android.app.Activity;
import android.app.ActionBar; import android.app.ActionBar;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.app.Fragment; import android.app.Fragment;
import android.content.ActivityNotFoundException;
import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
@ -18,6 +33,7 @@ import android.view.View;
import android.view.View.OnClickListener; import android.view.View.OnClickListener;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast;
import android.os.Build; import android.os.Build;
public class MainActivity extends Activity { public class MainActivity extends Activity {
@ -41,39 +57,134 @@ public class MainActivity extends Activity {
return true; return true;
} }
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
@Override @Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) { protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
if (requestCode == 0) { if (requestCode == 0) {
if (resultCode == RESULT_OK) { if (resultCode == RESULT_OK) {
String contents = intent.getStringExtra("SCAN_RESULT"); final String contents = intent.getStringExtra("SCAN_RESULT");
Log.d("QR", contents); if (contents.startsWith("kp2a:"))
{
// Toast.makeText(this, contents, Toast.LENGTH_SHORT).show(); //received a full entry
} else if (resultCode == RESULT_CANCELED) { String entryText = contents.substring("kp2a:".length());
try
{
JSONObject json = new JSONObject(entryText);
String outputData = json.get("fields").toString();
String protectedFields = null;
if (json.has("p"))
protectedFields = json.get("p").toString();
ArrayList<String> protectedFieldsList = null;
if (!TextUtils.isEmpty(protectedFields))
{
JSONArray protectedFieldsJson = new JSONArray(protectedFields);
protectedFieldsList = new ArrayList<String>();
for (int i=0; i<protectedFieldsJson.length(); i++) {
protectedFieldsList.add( protectedFieldsJson.getString(i) );
}
}
Intent startKp2aIntent = Kp2aControl.getAddEntryIntent(outputData, protectedFieldsList);
startActivity(startKp2aIntent);
}
catch (JSONException e)
{
e.printStackTrace();
Toast.makeText(this, "Error reading entry", Toast.LENGTH_SHORT).show();
}
catch (ActivityNotFoundException e)
{
Toast.makeText(this, getString(R.string.no_host_app), Toast.LENGTH_SHORT).show();
}
}
else
{
//received some text
AlertDialog.Builder b = new Builder(this);
b.setMessage(R.string.qr_question)
.setPositiveButton(R.string.create_entry, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
try
{
HashMap<String, String> fields = new HashMap<String, String>();
if ((contents.startsWith("http://")) || (contents.startsWith("https://"))
|| (contents.startsWith("ftp://")))
{
fields.put(KeepassDefs.UrlField, contents);
}
else
{
fields.put(KeepassDefs.PasswordField, contents);
}
Intent startKp2aIntent = Kp2aControl.getAddEntryIntent(fields, null);
startActivity(startKp2aIntent);
}
catch (ActivityNotFoundException e)
{
Toast.makeText(MainActivity.this, R.string.no_host_app, Toast.LENGTH_SHORT).show();
}
}
})
.setNegativeButton(R.string.search_entry, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
try
{
Intent startKp2aIntent = Kp2aControl.getOpenEntryIntent(contents, true, false);
startActivity(startKp2aIntent);
}
catch (ActivityNotFoundException e)
{
Toast.makeText(MainActivity.this, R.string.no_host_app, Toast.LENGTH_SHORT).show();
}
}
}).create().show();
}
} else if (resultCode == RESULT_CANCELED) {
// Handle cancel // Handle cancel
} }
return; return;
}
if (requestCode == 124) {
if (resultCode == RESULT_OK)
{
if (intent != null)
{
Intent i = new Intent(this, QRActivity.class);
i.putExtra(Strings.EXTRA_ENTRY_OUTPUT_DATA, intent.getStringExtra(Strings.EXTRA_ENTRY_OUTPUT_DATA));
i.putExtra(Strings.EXTRA_PROTECTED_FIELDS_LIST, intent.getStringExtra(Strings.EXTRA_PROTECTED_FIELDS_LIST));
i.putExtra(Strings.EXTRA_SENDER, intent.getStringExtra(Strings.EXTRA_SENDER));
i.putExtra(Strings.EXTRA_ENTRY_ID, intent.getStringExtra(Strings.EXTRA_ENTRY_ID));
startActivity(i);
}
}
else
{
Log.d("QR", "No data received :-(");
}
} }
super.onActivityResult(requestCode, resultCode, intent); super.onActivityResult(requestCode, resultCode, intent);
} }
/** /**
* A placeholder fragment containing a simple view. * A placeholder fragment containing a simple view.
*/ */
@ -125,7 +236,7 @@ public class MainActivity extends Activity {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
//todo getActivity().startActivityForResult(Kp2aControl.getQueryEntryIntent(null),124);
Log.d("QR", "ShowqR"); Log.d("QR", "ShowqR");
} }
}); });

View File

@ -6,6 +6,7 @@ import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
@ -64,7 +65,6 @@ public class QRActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
if ((getIntent() != null) && (getIntent().getStringExtra(Strings.EXTRA_ENTRY_OUTPUT_DATA)!= null)) if ((getIntent() != null) && (getIntent().getStringExtra(Strings.EXTRA_ENTRY_OUTPUT_DATA)!= null))
Log.d("QR", getIntent().getStringExtra(Strings.EXTRA_ENTRY_OUTPUT_DATA));
setContentView(R.layout.activity_qr); setContentView(R.layout.activity_qr);
@ -100,6 +100,12 @@ public class QRActivity extends Activity {
ImageView mImageView; ImageView mImageView;
TextView mErrorView; TextView mErrorView;
HashMap<String, String> mEntryOutput; HashMap<String, String> mEntryOutput;
//JSON-Array with field keys of the protected strings.
//We don't need that list (so don't deserialize) other than for
//forwarding to KP2A
String mProtectedFieldsList;
ArrayList<String> mFieldList = new ArrayList<String>(); ArrayList<String> mFieldList = new ArrayList<String>();
Spinner mSpinner; Spinner mSpinner;
String mHostname; String mHostname;
@ -140,6 +146,7 @@ public class QRActivity extends Activity {
mSpinner = (Spinner) rootView.findViewById(R.id.spinner); mSpinner = (Spinner) rootView.findViewById(R.id.spinner);
mEntryOutput = getEntryFieldsFromIntent(getActivity().getIntent()); mEntryOutput = getEntryFieldsFromIntent(getActivity().getIntent());
mProtectedFieldsList = getProtectedFieldsList(getActivity().getIntent());
ArrayList<String> spinnerItems = new ArrayList<String>(); ArrayList<String> spinnerItems = new ArrayList<String>();
spinnerItems.add(getActivity().getString(R.string.all_fields)); spinnerItems.add(getActivity().getString(R.string.all_fields));
@ -240,6 +247,12 @@ public class QRActivity extends Activity {
return rootView; return rootView;
} }
private String getProtectedFieldsList(Intent intent) {
if (intent == null)
return null;
return intent.getStringExtra(Strings.EXTRA_PROTECTED_FIELDS_LIST);
}
private void addIfExists(String fieldKey, String resKey, private void addIfExists(String fieldKey, String resKey,
ArrayList<String> spinnerItems) { ArrayList<String> spinnerItems) {
if (!TextUtils.isEmpty(mEntryOutput.get(fieldKey))) if (!TextUtils.isEmpty(mEntryOutput.get(fieldKey)))
@ -265,21 +278,25 @@ public class QRActivity extends Activity {
if (fieldId == null) if (fieldId == null)
{ {
res = "kp2a:\n";
for (String k:mFieldList) try {
{ JSONObject json = new JSONObject();
if (k == null) json.put("fields", new JSONObject(mEntryOutput));
continue; if (!TextUtils.isEmpty(mProtectedFieldsList))
res += QRCodeEncoder.escapeMECARD(k)+":"; {
res += QRCodeEncoder.escapeMECARD(mEntryOutput.get(k))+";\n"; json.put("p", new JSONArray(mProtectedFieldsList));
}
res = "kp2a:"+json.toString();
} catch (JSONException e) {
res = "error: " + e.toString();
} }
} }
else else
{ {
if ((mCbIncludeLabel.isChecked())) if ((mCbIncludeLabel.isChecked()))
{ {
res = fieldId+": "; res = fieldId+": ";
} }
res += mEntryOutput.get(fieldId); res += mEntryOutput.get(fieldId);
} }