Please help me fix my code so that, when I press the call button the code calls the cell number that I've given.
//monitor phone call activities
private class PhoneCallListener extends PhoneStateListener {
private boolean isPhoneCalling = false;
String LOG_TAG = "LOGGING 123";
#Override
public void onCallStateChanged(int state, String incomingNumber) {
if (TelephonyManager.CALL_STATE_RINGING == state) {
// phone ringing
Log.i(LOG_TAG, "RINGING, number: " + incomingNumber);
isPhoneCalling = true;
}
if (TelephonyManager.CALL_STATE_OFFHOOK == state) {
// active
Log.i(LOG_TAG, "OFFHOOK");
isPhoneCalling = true;
}
if (TelephonyManager.CALL_STATE_IDLE == state) {
// run when class initial and phone call ended,
// need detect flag from CALL_STATE_OFFHOOK
Log.i(LOG_TAG, "IDLE");
if (isPhoneCalling) {
Log.i(LOG_TAG, "restart app");
// restart app
Intent i = getBaseContext().getPackageManager()
.getLaunchIntentForPackage(
getBaseContext().getPackageName());
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(i);
isPhoneCalling = true;
}
}
}
}
For making the code you should write the easy and small code instead of that the accurate code for making a call of the given number is given below:
// add button listener
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
Intent callIntent = new Intent(Intent.ACTION_CALL);
callIntent.setData(Uri.parse("tel:"+999999999));//change the number
startActivity(callIntent);
}
});
I have created the following chart using google organisation chart but I have some problems. When I open the page or when I refresh the page it shows up the full chart like in picture below. But I want only the items that are in red square to be shown how can I do this.
I do not want to get a few items from the list but when I open the page it shows the whole chart with its all list item and instead when it opens I want to display only 5 items and let user to expand others do you understand me?
This is the picture of chart how it looks like and how I want it to be!
And here is my full c# code:
namespace OrganizationChartUsingGoogleAPI.OrganizationChart
{
public static class ConvertTo
{
/// <summary>
/// Convert the object type in the given type and handle the DBNULL.
/// </summary>
/// <typeparam name="T">Type to convert</typeparam>
/// <param name="value">value</param>
/// <returns>converted value and if DBNULL then return the type's default value i.e. string = string.Empty, Int16=0 </returns>
public static T CastIn<T>(this object value) where T : IConvertible
{
if (value == DBNull.Value)
if (typeof(T) == typeof(string))
{
return (T)Convert.ChangeType(string.Empty, typeof(T));
}
else
{
return default(T);
}
if (typeof(T) == typeof(bool))
return (T)Convert.ChangeType(Convert.ToInt32(value), typeof(T));
return (T)Convert.ChangeType(value, typeof(T));
}
}
public partial class OrganizationChartUserControl : UserControl
{
//Get the List name to fetch the data from
string listName = "OrgChart_Demo";
int iRowCounter = 0;
string sAllNewRows = string.Empty;
protected void Page_Load(object sender, EventArgs e)
{
//Fetch the data (recursively) from the list
GetNode(string.Empty);
//Generate the Client Script and Register
GenerateClientScript(sAllNewRows);
}
private void GenerateClientScript(string sAllNewRows)
{
string csName1 = "OrgChartScript";
Type csType = this.GetType();
ClientScriptManager cs = Page.ClientScript;
// Check to see if the startup script is already registered.
if (!cs.IsStartupScriptRegistered(csType, csName1))
{
StringBuilder cstext = new StringBuilder();
cstext.Append("<script type='text/javascript' src='https://www.google.com/jsapi'></script>");
cstext.Append("<script type='text/javascript'>");
cstext.Append("google.load('visualization', '1', { packages: ['orgchart'] });");
cstext.Append("google.setOnLoadCallback(drawChart);");
cstext.Append("function drawChart() {");
cstext.Append("var data = new google.visualization.DataTable();");
cstext.Append("data.addColumn('string', 'Name');");
cstext.Append("data.addColumn('string', 'Manager');");
cstext.Append("data.addColumn('string', 'ToolTip');");
cstext.Append("var rowArr = new Array();");
cstext.Append(sAllNewRows);
cstext.Append("data.addRows(rowArr);");
cstext.Append("var chart = new google.visualization.OrgChart(document.getElementById('chart_div'));");
cstext.Append("chart.draw(data, { allowHtml: true, allowCollapse: true });");
cstext.Append("}");
cstext.Append("</script>");
cs.RegisterClientScriptBlock(csType, csName1, cstext.ToString(), false);
}
}
private void GetNode(string reportsTo)
{
SPListItemCollection itemCol = GetListItems(listName, reportsTo);
foreach (SPListItem item in itemCol)
{
//create a new row
sAllNewRows += createNewRow(item);
//Recursion
GetNode(item["Name"].ToString());
}
}
private string createNewRow(SPListItem listItem)
{
//Converting list items to strings.
string sName = ConvertTo.CastIn<string>(listItem["Name"]);
string sTitle = ConvertTo.CastIn<string>(listItem["Title"]);
string sMoreInfo = ConvertTo.CastIn<string>(listItem["MoreInfo"]);
string sReportsTo = ConvertTo.CastIn<string>(listItem["ReportsTo"]);
//Checking if image field ref is empty or null (if it does't provide any img source link!)
ImageFieldValue pageImage = listItem["Pageimage"] as ImageFieldValue;
string sPicture = string.IsNullOrEmpty(pageImage.ImageUrl) ? "#" : pageImage.ImageUrl;
StringBuilder sText = new StringBuilder();
sText.Append("var NewRow = new Array();");
//this row shows the image and everything else what chart needs
sText.Append(String.Format("NewRow.push({{ v: '{0}', f: '<img src =\"{1}\" style=\"width:57px; height:57px; float:left;\" />{2}<div style=\"color:white; font-style:Arial\">{3}</div>' }});", sName, sPicture, sName, sTitle));
sText.Append(String.Format("NewRow.push('{0}');", sReportsTo));
sText.Append(String.Format("NewRow.push('{0}');", sMoreInfo));
//sText.Append(String.Format("NewRow.push('{0}');", sPicture));
sText.Append(String.Format("rowArr[{0}] = NewRow;", iRowCounter));
//Pageimage
iRowCounter++;
return sText.ToString();
}
private SPListItemCollection GetListItems(string destList, string reportsTo)
{
SPListItemCollection ResultListItems = null;
using (SPSite oSite = new SPSite(SPContext.Current.Web.Url))
{
using (SPWeb oWeb = oSite.OpenWeb())
{
SPList list = oWeb.Lists.TryGetList(destList);
if (null == list)
return ResultListItems;
string selected = DropDownList2.SelectedValue;
// Label1.Text = selected;
//Check if the item already exist.
StringBuilder sCAMLQuery = new StringBuilder(string.Empty);
sCAMLQuery.Append("<Where>");
sCAMLQuery.Append("<And>");
if (reportsTo != string.Empty)
{
sCAMLQuery.Append("<Eq>");
sCAMLQuery.Append("<FieldRef Name='ReportsTo' />");
//sCAMLQuery.Append("<Value Type='Lookup'>" + reportsTo + "</Value>");
sCAMLQuery.Append("<Value Type='Text'>" + reportsTo + "</Value>");
sCAMLQuery.Append("</Eq>");
}
else
{
sCAMLQuery.Append("<IsNull>");
sCAMLQuery.Append("<FieldRef Name='ReportsTo' />");
sCAMLQuery.Append("</IsNull>");
}
sCAMLQuery.Append("<Eq>");
sCAMLQuery.Append("<FieldRef Name='Kompania' />");
//sCAMLQuery.Append("<Value Type='Lookup'>" + reportsTo + "</Value>");
sCAMLQuery.Append("<Value Type='Text'>" + selected + "</Value>");
sCAMLQuery.Append("</Eq>");
sCAMLQuery.Append("</And>");
sCAMLQuery.Append("</Where>");
SPQuery QueryResult = new SPQuery();
QueryResult.Query = sCAMLQuery.ToString();
ResultListItems = list.GetItems(QueryResult);
}
}
return ResultListItems;
}
}
}
Thanks all of you
I see you have a GetNode(string reportsTo).
could you pass the level you're in and return if the level gets higher than you want?
private void GetNode(string reportsTo, int level)
{
// maybe have some config or value you can set for the max level you want.
if (level >= 2) return;
SPListItemCollection itemCol = GetListItems(listName, reportsTo);
foreach (SPListItem item in itemCol)
{
//create a new row
sAllNewRows += createNewRow(item);
//Recursion
GetNode(item["Name"].ToString(). ++level);
}
}
I need to read the Data off NfcV (ISO 15693) Tags, I already tried the Phonegap-Nfc Plugin from Chariotsolution, but it seems this plugin can only read the TagId and Type off NfcV tags, so i decided i could create my own custom plugin, I first foud the echo Hello World Plugin tutorial which worked fine and without problems, so I looked for Java NfcV reader and found this Java NfcV Reader.
From what I understood so far is, that I need to call the cordova.exec function and extend my Java class from CordovaPlugin, which is working.
I don't know Java since I am a Webdeveloper, which makes it a little hard for me.
This actually looks pretty good but i tried to implement it in the way of the Hello World echo example which didnt work out as planned.
I have now a plugin folder with
Hello.java
package org.apache.cordova.plugin;
import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaPlugin;
import org.json.JSONArray;
import org.json.JSONException;
/**
* This class echoes a string called from JavaScript.
*/
public class Hello extends CordovaPlugin
{
#Override
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
if (action.equals("hello")) {
String message = args.getString(0);
this.hello(message, callbackContext);
return true;
}
return false;
}
private void hello(String message, CallbackContext callbackContext) {
if (message != null && message.length() > 0) {
callbackContext.success(message);
} else {
callbackContext.error("Expected one non-empty string argument.");
}
}
}
ReadNfcV.java from the link above
package org.apache.cordova.plugin;
import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaPlugin;
import org.json.JSONArray;
import org.json.JSONException;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.HashMap;
import org.apache.http.util.ByteArrayBuffer;
import android.nfc.Tag;
import android.nfc.TagLostException;
import android.nfc.tech.NfcV;
import android.nfc.tech.TagTechnology;
//import android.os.Parcelable;
import android.util.Log;
/**
* #author uhahn
*
*/
public class ReadNfcV extends CordovaPlugin implements TagTechnology {
protected NfcV mynfcv;
// protected Tag mytag; // can be retrieved through mynfcv
private final String TAG=this.getClass().getName();
protected final int maxtries=3;
protected boolean isTainted=true; // Tag info already read?
protected byte[] mysysinfo=null; // NfcV SystemInformation - or generated
protected byte[] myuserdata=null; // buffer user content
protected boolean[] blocktainted; // true when block is to be uploaded to tag
protected byte[] blocklocked; // 0 means writable
protected byte afi=0;
public byte nBlocks=0;
public byte blocksize=0;
public byte[] Id;
public byte[] UID; // becomes valid when a real tag is contacted
public byte DSFID = -1;
public int maxtrans=0; // tag dependent max transceive length
public byte lastErrorFlags=-1; // re-set by each transceive
public byte lastErrorCode=-1; // re-set by each transceive
public byte manuByte=0;
public static final byte BYTE_IDSTART=(byte)0xe0;
public static final byte MANU_TAGSYS=0x04;
public static final HashMap<Byte,String> manuMap = new HashMap<Byte, String>();
static{
manuMap.put(MANU_TAGSYS, "TagSys");
}
/**
* read new NfcV Tag from NFC device
*/
public ReadNfcV(Tag t) {
UID = t.getId(); // sysinfo holds the UID in lsb order - Id will be filled lateron from sysinfo!
// Log.d(TAG,"getId: "+toHex(t.getId()));
mynfcv=NfcV.get(t);
try {
mynfcv.connect();
mysysinfo=getSystemInformation();
// explore Nfcv properties..
//initfields(); // done by getSys..
maxtrans=mynfcv.getMaxTransceiveLength();
DSFID=mynfcv.getDsfId();
Log.d(TAG,nBlocks + " x " + blocksize + " bytes");
blocklocked=new byte[nBlocks]; // init the lock shadow
getMultiSecStatus(0, nBlocks); // and fill from tag
blocktainted=new boolean[nBlocks];
taintblock(0,nBlocks);
// Log.d(TAG,"maxtrans "+maxtrans);
// init space for userdata ?
myuserdata= new byte[nBlocks*blocksize];
} catch (IOException e) {
// TODO Auto-generated catch block
lastErrorFlags=-1;
Log.d(TAG, "MyNfcV failed: "+e.getMessage());
e.printStackTrace();
}
}
/**
* recreate NfcV Tag from log
* #param sysinfo: the logged system info only
*/
public ReadNfcV(String sysinfo){
int startat=0;
sysinfo.toLowerCase(); // ignore case
if(sysinfo.startsWith("0x")){ // lets believe in HEX
startat=2;
}
mysysinfo=hexStringToByteArray(sysinfo.substring(startat));
initfields();
// init space for userdata TODO limit size?
//myuserdata= new byte[nBlocks*blocksize];
isTainted=false;
// TODO fake Tag? mytag = Tag.CREATOR.createFromParcel(???);
}
/**
* recreate NfcV Tag from log
* #param sysinfo: the logged system info
* #param userdata: the logged userdata
*/
public ReadNfcV(String sysinfo, String userdata){
this(sysinfo);
// TODO fake userdata
int startat=0;
userdata.toLowerCase(); // ignore case
if(userdata.startsWith("0x")){ // lets believe in HEX
startat=2;
}
myuserdata=hexStringToByteArray(userdata.substring(startat));
}
/**
* parse system information byte array into attributes
* with respect to the flags found
* DSFID
* AFI
* memsize values (block count and length)
*/
private void initfields(){
byte[] read=mysysinfo;
if((null!=read)&&(12<read.length)&&(0==read[0])){// no error
char flags=(char)read[1]; //s.charAt(1);
// String s=new String(read);
//s.substring(2, 9).compareTo(Id.toString()) // the same?
//set the Id from mysysinfo
int pos=2;
boolean forwardId=false; // the Id field is in lsb order
if(BYTE_IDSTART==read[pos]){
forwardId=true;
manuByte=read[pos+1];
}else if(BYTE_IDSTART==read[pos+7]){
manuByte=read[pos+6];
forwardId=false;
}else
Log.e(TAG,"Id start byte not found where expected");
if(null==Id){ // dont overwrite, if given
Id=new byte[8];
for(int i=0;i<8;i++)
// TODO decide if Id to be reversed (Zebra needs msb order, that is Id[7] changes between tags)
Id[i]=(forwardId? read[pos+i] : read[pos + 7 - i]); //reverse?!
Log.d(TAG,"Id from sysinfo (reversed): "+toHex(Id));
}
pos=10; // start after flags, Infoflags and Id TODO: change if transceive should eat up the error byte
if(0<(flags&0x1)){ // DSFID valid
pos++; // already implemented
}
if(0<(flags&0x2)){ // AFI valid
afi=(byte)read[pos++];//s.charAt(pos++);
}
if(0<(flags&0x4)){ // memsize valid
nBlocks=(byte)(read[pos++]+1);//(s.charAt(pos++)+1);
blocksize=(byte)(read[pos++]+1); //((s.charAt(pos++)&0x1f)+1);
}
}
}
/**
* #return the stored afi byte
*/
public byte getAFI(){
if(isTainted){ // system info not read yet
getSystemInformation(); // fill in the fields
}
return afi;
}
public byte getDsfId(){
// return mynfcv.getDsfId(); // avoid re-reading
return DSFID;
}
public int getblocksize(){
return (int)blocksize;
}
public int getnBlocks(){
return (int)nBlocks;
}
public byte[] getSystemInformation(){
if(isTainted){ // dont reread
mysysinfo=transceive((byte)0x2b);
isTainted=false; // remember: we have read it and found it valid
if(0==lastErrorFlags){// no error
isTainted=false; // remember: we have read it and found it valid
initfields(); // analyze
}}
return mysysinfo;
}
/**
* overload method transceive
* #return resulting array (or error?)
*/
protected byte[] transceive(byte cmd){
return transceive(cmd, -1, -1, null);
}
protected byte[] transceive(byte cmd, int m){
return transceive(cmd, m, -1, null);
}
protected byte[] transceive(byte cmd, int m ,int n){
return transceive(cmd, m, n, null);
}
/**
* prepare and run the command according to NfcV specification
* #param cmd command byte
* #param m command length
* #param n
* #param in input data
* #return
*/
protected byte[] transceive(byte cmd,int m, int n, byte[] in){
byte[] command;
byte[] res="transceive failed message".getBytes();
ByteArrayBuffer bab = new ByteArrayBuffer(128);
// flags: bit x=adressed,
bab.append(0x00);
bab.append(cmd); // cmd byte
// 8 byte UID - or unaddressed
// bab.append(mytag.getId(), 0, 8);
// block Nr
if(-1!=m)bab.append(m);
if(-1!=n)bab.append(n);
if(null!=in)bab.append(in, 0, in.length);
command=bab.toByteArray();
Log.d(TAG,"transceive cmd: "+toHex(command));
// Log.d(TAG,"transceive cmd length: "+command.length);
// TODO background!
try {
if(!mynfcv.isConnected()) return res;
for(int t=maxtries;t>0;t++){ // retry reading
res=mynfcv.transceive(command);
if(0==res[0]) break;
}
}
catch (TagLostException e){ //TODO roll back user action
Log.e(TAG, "Tag lost "+e.getMessage());
try {
mynfcv.close();
} catch (IOException e1) {
e1.printStackTrace();
}
return e.getMessage().getBytes();
}
catch (IOException e) {
Log.d(TAG, "transceive IOEx: "+e.getMessage()+toHex(res));
// e.printStackTrace();
return e.getMessage().getBytes();
}
finally{
Log.d(TAG,"getResponseFlags: "+mynfcv.getResponseFlags());
lastErrorFlags=res[0];
Log.d(TAG,"Flagbyte: "+String.format("%2x", lastErrorFlags));
if(0!=lastErrorFlags){
lastErrorCode=res[1];
Log.d(TAG,"ErrorCodebyte: "+String.format("%2x", lastErrorCode));
}
}
if(0==mynfcv.getResponseFlags())
return (res);
else
// return new String("response Flags not 0").getBytes();
return res;
}
public void taintblock(int i, int n){
for(int j=0;j<n;j++)
setblocktaint(j,true);
}
public void taintblock(int i){
setblocktaint(i,true);
}
protected void setblocktaint(int i, boolean b){
blocktainted[i]=b;
}
/* (non-Javadoc)
* #see android.nfc.tech.TagTechnology#getTag()
*
*/
#Override
public Tag getTag() {
// TODO Auto-generated method stub
//return mytag;
return mynfcv.getTag();
}
/* (non-Javadoc)
* #see android.nfc.tech.TagTechnology#close()
*/
#Override
public void close() throws IOException {
try {
mynfcv.close();
} catch (IOException e) {
// TODO Auto-generated catch block
Log.d(TAG, "close failed: "+e.getMessage());
e.printStackTrace();
}
}
/* (non-Javadoc)
* #see android.nfc.tech.TagTechnology#connect()
*/
#Override
public void connect() throws IOException {
try {
mynfcv.connect();
} catch (IOException e) {
lastErrorFlags=-1; // TODO discriminate error states
Log.d(TAG,"connect failed: "+e.getMessage());
e.printStackTrace();
}
}
/* (non-Javadoc)
* #see android.nfc.tech.TagTechnology#isConnected()
*/
#Override
public boolean isConnected() {
// TODO Auto-generated method stub
// mynfcv.getDsfId();
return mynfcv.isConnected(); // better?
}
public byte[] readSingleBlock(int i){
byte[] read=transceive((byte)0x20,i);
setblocktaint(i,false); // remember we read this block
if(0!=lastErrorFlags)return read; // TODO not so ignorant..
byte[] res=new byte[read.length-1]; // drop the (0) flag byte TODO: in transceive?
for (int l = 0; l < read.length-1; l++) {
res[l]=read[l+1];
myuserdata[i*blocksize+l]=res[l]; // sort block into our buffer
}
return res;
}
/**
*
* #param i starting block number
* #param j block count
* #return block content concatenated
*/
public byte[] readMultipleBlocks(int i,int j){
if(0==blocksize){
Log.e(TAG,"readMult w/o initfields?");
getSystemInformation(); // system info was not read yet
}
byte[] read = transceive((byte)0x23,i,j);
if(0!=read[0])return read; // error flag set: TODO left as exercise..
byte[] res=new byte[read.length-1]; // drop the (0) flag byte
for (int l = 0; l < read.length-1; l++) {
res[l]=read[l+1];
myuserdata[i*blocksize+l]=res[l]; // sort block into our buffer
}
if(res.length<j*blocksize) return read; // da fehlt was
for (int k = i; k < j; k++) { // all blocks we read
setblocktaint(k, false); // untaint blocks we read
// #TODO reverting block order should be done on demand - or under user control (done again in DDMData)
// reverse(res,k*blocksize,blocksize); // swap string positions
}
return res;
}
public byte[] getMultiSecStatus(int i,int n){
byte[] read = transceive((byte)0x2c,i,n-1);
Log.d(TAG,"secstatus "+toHex(read));
if(0!=read[0])return read;
int startat=1; // TODO transceive will skip the error field soon
for(int j=0;j<nBlocks;j++)
blocklocked[j]=read[startat+i+j];
return read;
}
/**
* move anywhere to utils
* #param s
* #return
*/
public static String toHex(byte[] in){
String text=String.format("0x");
for (byte element : in) {
text=text.concat(String.format("%02x", element));
}
return text;
}
public static byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}
return data;
}
}
my hello.js file
var hello = {
world: function(str, callback) {
cordova.exec(callback, function(err) {
callback('Nothing to hello.');
}, "Hello", "hello", [str]);
}
}
var ReadNfcV = {
read: function (str, callback) {
cordova.exec(callback, function (err) {
callback('Nothing to hello.');
}, "Hello", "hello", [str]);
}
}
module.exports = hello;
module.exports = ReadNfcV;
and my plugin.xml
<?xml version="1.0" encoding="UTF-8"?>
<plugin xmlns="http://cordova.apache.org/ns/plugins/1.0"
id="org.apache.cordova.plugin"
version="0.1.0">
<js-module src="hello.js" name="hello">
<clobbers target="hello" />
</js-module>
<!-- Android -->
<platform name="android">
<source-file src="Hello.java" target-dir="src/org/apache/cordova/plugin" />
<source-file src="ReadNfcV.java" target-dir="src/org/apache/cordova/plugin" />
<config-file target="res/xml/config.xml" parent="/*">
<feature name="Hello" >
<param name="android-package" value="org.apache.cordova.plugin.Hello"/>
</feature>
</config-file>
</platform>
</plugin>
I was able to deploy the app so I can test a bit, My problem is that I dont really understand how i can call the ReadNfc class from the ReadNfcV.java file from within my app via javascript. I just did the same as in the Tutorial but now the hello.World function is not a function anymore so i guess i did smth wrong in my hello.js file. I would really appreciate it if someone could help and explain me how i can call my java class via javascript and then return the result from the java class back to my javascript. I looked 2 Days for an already existing plugin but didnt find anything on that subject but the phonegap-nfc plugin.
Kind regards Christopher
Update Day1
I added tech.NfcV to the Import List
import android.nfc.tech.NfcV;
Changed the execute function as suggested
#Override
public boolean execute(String action, JSONArray data, CallbackContext callbackContext) throws JSONException {
Log.d(TAG, "execute " + action);
if (!getNfcStatus().equals(STATUS_NFC_OK)) {
callbackContext.error(getNfcStatus());
return true; // short circuit
}
createPendingIntent();
if (action.equals(REGISTER_DEFAULT_TAG)) {
addTechList(new String[]{NfcV.class.getName()}); //changed this form Mifare to NfcV
registerDefaultTag(callbackContext);
} else if (action.equalsIgnoreCase(INIT)) {
init(callbackContext);
} else {
// invalid action
return false;
}
return true;
}
Problem seems to be that I get Invalid action returned at the moment so something is wrong here
I changed the registerDefault function to
private void registerDefaultTag(CallbackContext callbackContext) {
addTechFilter();
callbackContext.success();
}
And i changed the Parse Message function to
void parseMessage() {
cordova.getThreadPool().execute(new Runnable() {
#Override
public void run() {
Log.d(TAG, "parseMessage " + getIntent());
Intent intent = getIntent();
String action = intent.getAction();
Log.d(TAG, "action " + action);
if (action == null) {
return;
}
if (action.equals(NfcAdapter.ACTION_TECH_DISCOVERED) || action.equals(NfcAdapter.ACTION_TAG_DISCOVERED)){
Tag tagFromIntent = (Tag)intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
NfcV mfc = NfcV.get(tagFromIntent);
fireTagEvent(tag);
}
/*if (action.equals(NfcAdapter.ACTION_NDEF_DISCOVERED)) {
Ndef ndef = Ndef.get(tag);
fireNdefEvent(NDEF_MIME, ndef, messages);
} else if (action.equals(NfcAdapter.ACTION_TECH_DISCOVERED)) {
for (String tagTech : tag.getTechList()) {
Log.d(TAG, tagTech);
if (tagTech.equals(NdefFormatable.class.getName())) {
fireNdefFormatableEvent(tag);
} else if (tagTech.equals(Ndef.class.getName())) { //
Ndef ndef = Ndef.get(tag);
fireNdefEvent(NDEF, ndef, messages);
}
}
}
if (action.equals(NfcAdapter.ACTION_TAG_DISCOVERED)) {
fireTagEvent(tag);
}*/
setIntent(new Intent());
}
});
}
So currently i get the error invalid action as soon as i click on start Listening and calling the Taglisteners in Javascript atm I use all 4 different Listeners to see if any work. It seems that I need to write a new fireEvent function specific for NfcV since the existing ones arent working
Update 2
I have managed to compile the plugin and deploy the app but nothing is happening i am not getting a Tag object back
The parse Message Function
void parseMessage() {
cordova.getThreadPool().execute(new Runnable() {
#Override
public void run() {
Log.d(TAG, "parseMessage " + getIntent());
Intent intent = getIntent();
String action = intent.getAction();
Log.d(TAG, "action " + action);
if (action == null) {
return;
}
if (action.equals(NfcAdapter.ACTION_TECH_DISCOVERED) || action.equals(NfcAdapter.ACTION_TAG_DISCOVERED)){
Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
if(tag != null){
byte[] id = tag.getId();
// set up read command buffer
byte blockNo = 0; // block address
byte[] readCmd = new byte[3 + id.length];
readCmd[0] = 0x20; // set "address" flag (only send command to this tag)
readCmd[1] = 0x20; // ISO 15693 Single Block Read command byte
System.arraycopy(id, 0, readCmd, 2, id.length); // copy ID
readCmd[2 + id.length] = blockNo; // 1 byte payload: block address
NfcV tech = NfcV.get(tag);
if (tech != null) {
// send read command
try {
tech.connect();
byte[] data = tech.transceive(readCmd);
fireTagEvent(data);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
tech.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
setIntent(new Intent());
}
}
});
}
My fireTagEvent
private void fireTagEvent(byte[] data) {
String s2 = new String(data);
String command = MessageFormat.format(javaScriptEventTemplate, TAG_DEFAULT, s2);
Log.v(TAG, s2);
this.webView.sendJavascript(s2);
}
The execute function
#Override
public boolean execute(String action, JSONArray data, CallbackContext callbackContext) throws JSONException {
Log.d(TAG, "execute " + action);
if (!getNfcStatus().equals(STATUS_NFC_OK)) {
callbackContext.error(getNfcStatus());
return true; // short circuit
}
createPendingIntent();
if (action.equals(REGISTER_DEFAULT_TAG)) {
addTechList(new String[]{NfcV.class.getName()});
registerDefaultTag(callbackContext);
} else if (action.equalsIgnoreCase(INIT)) {
init(callbackContext);
} else {
// invalid action
return false;
}
return true;
}
Thats pretty much it the app starts the "addTagDiscoveredListener" is registered but im not getting any Object back so either the nfcv tag is not read or i just dont get anything back not really sure...
I used the Chariotsolution plugin as a start to build my own nfc reading plugin. I think it would save you much time if you don't start from scratch.
There are many things you can remove because the original plugin only deals with NDEF tags, but removing lines is faster than re-inventing the wheel.
It's a bit old in my head, so I'm not sure I can explain everything right...
My nead was to read info in Mifare classic tags, but maybe you can adapt for your needs...
So, if you look at NfcPlugin.java, in the execute function, all I kept was the code for the actions REGISTER_DEFAULT_TAG and INIT.
Updated the code in REGISTER_DEFAULT_TAG to register the listening for mifare classic tag. And modified registerDefaultTag function to call addTechFilter instead of addTagFilter.
So this leaves us with
public boolean execute(String action, JSONArray data, CallbackContext callbackContext) throws JSONException {
Log.d(TAG, "execute " + action);
if (!getNfcStatus().equals(STATUS_NFC_OK)) {
callbackContext.error(getNfcStatus());
return true; // short circuit
}
createPendingIntent();
if (action.equals(REGISTER_DEFAULT_TAG)) {
addTechList(new String[]{MifareClassic.class.getName()});
registerDefaultTag(callbackContext);
} else if (action.equalsIgnoreCase(INIT)) {
init(callbackContext);
} else {
// invalid action
return false;
}
return true;
}
private void registerDefaultTag(CallbackContext callbackContext) {
addTechFilter();
callbackContext.success();
}
Now what you need to understand is that once you called from the js the init function, the parseMessage function of the plugin will be called each time the device sees a nfc tag.
So in the parseMessage function I have a test
if (action.equals(NfcAdapter.ACTION_TECH_DISCOVERED) || action.equals(NfcAdapter.ACTION_TAG_DISCOVERED))
in wich I have all the code to deal with my tag.
In that code can get info from the tag in the intent using something like this :
Tag tagFromIntent = (Tag)intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
MifareClassic mfc = MifareClassic.get(tagFromIntent);
and then depending on your treatment you can call either fireErrorEvent or a fire...Event of your own that would return the data to the javascript using the webView.sendJavascript function.
I'm running out of time to detail the js part.
Not sure sure if it will help you or if it's the way you want to go (don't know how the tag you're using is working). Let me know if it helps you and if you need more details.
Okay so I finally managed to get it working
In the Phonegap-nfc.js I added an eventlistener for the NFCV tag
addNfcVListener: function (callback, win, fail) {
document.addEventListener("nfcv", callback, false);
cordova.exec(win, fail, "NfcPlugin", "registerNfcV", []);
},
The matching Execute function looks like this
#Override
public boolean execute(String action, JSONArray data, CallbackContext callbackContext) throws JSONException {
Log.d(TAG, "execute " + action);
if (!getNfcStatus().equals(STATUS_NFC_OK)) {
callbackContext.error(getNfcStatus());
return true; // short circuit
}
createPendingIntent();
if (action.equalsIgnoreCase(REGISTER_NFCV)) {
registerNfcV(callbackContext);
}else {
// invalid action
return false;
}
return true;
}
Here is where the Tag gets added to the techlist
private void registerNfcV(CallbackContext callbackContext) {
addTechList(new String[]{NfcV.class.getName()});
callbackContext.success();
}
Here the Tag gets parsed and fires an event
void parseMessage() {
cordova.getThreadPool().execute(new Runnable() {
#Override
public void run() {
Log.d(TAG, "parseMessage " + getIntent());
Intent intent = getIntent();
String action = intent.getAction();
Log.d(TAG, "action " + action);
if (action == null) {
return;
}
if (action.equals(NfcAdapter.ACTION_TECH_DISCOVERED) || action.equals(NfcAdapter.ACTION_TAG_DISCOVERED)){
NfcvData ma;
Tag tagFromIntent = (Tag)intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
Parcelable[] messages = intent.getParcelableArrayExtra((NfcAdapter.EXTRA_NDEF_MESSAGES));
NfcV mfc = NfcV.get(tagFromIntent);
Tag tag = mfc.getTag();
fireNfcVReadEvent(NFCV, mfc, messages);
}
setIntent(new Intent());
}
});
}
Then this event is called
private void fireNfcVReadEvent(String type, NfcV nfcv, Parcelable[] messages) {
JSONObject jsonObject = buildNfcVReadJSON(nfcv, messages);
String tag = jsonObject.toString();
String command = MessageFormat.format(javaScriptEventTemplate, type, tag);
Log.v(TAG, command);
this.webView.sendJavascript(command);
}
Which sends the Taginformation back to my Javascript
It appears that you are not sending any data back in you callback, just the cordova SUCCESS. callbackContext.success(returndatahere); See the cordova plugin spec for supported data types.
i have another problem using a cordova plugin (3.2) in android. I create a custom plugin for cordova because the default one does not match with my expectation. I expect to create a custom alert dialog with item and checkboxes in it. Here is the source code:
Javascript:
cordova.exec(
function(listitem) {
console.log("select: " +interestResultName[listitem]);
selectedResult.push(interestResultName[listitem]);
},
function(error) {
alert("Error Occured");
}, "AlertList", "showlistitem", interestResultName );
Java:
public class AlertList extends CordovaPlugin {
public AlertList() {
}
#Override
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
if(action.equals("showlistitem")) {
this.loadList(args, callbackContext);
}
return true;
}
public void loadList(final JSONArray thelist, final CallbackContext callbackContext) {
final CordovaInterface cordova = this.cordova;
Runnable runnable = new Runnable() {
public void run() {
List<String> list = new ArrayList<String>();
for( int x = 0; x < thelist.length(); x++) {
try {
list.add( thelist.getString(x) );
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
CharSequence[] items = list.toArray(new CharSequence[list.size()]);
boolean[] checkbox = new boolean[list.size()];
AlertDialog.Builder builder = new AlertDialog.Builder(cordova.getActivity());
builder.setTitle(" ");
builder.setMultiChoiceItems(items, checkbox, new DialogInterface.OnMultiChoiceClickListener() {
#Override
public void onClick(DialogInterface dialog, int item, boolean isChecked) {
// TODO Auto-generated method stub
PluginResult result = new PluginResult(PluginResult.Status.OK, item);
result.setKeepCallback(true);
callbackContext.sendPluginResult(result);
}
});
AlertDialog alert = builder.create();
alert.getWindow().getAttributes().windowAnimations = android.R.style.Animation_Dialog;
alert.show();
}
};
this.cordova.getActivity().runOnUiThread(runnable);
}
}
The problem comes in the onClick method. Since its a checkbox i'm still keep callback open until user pressed back button. However i cannot implement the backbutton function as usual because my java class extends CordovaPlugin instead of Activity. Does anyone can help me with this ?
My expectation is: after user select item he wants and click back button. Then the callback context will send the selected item to my javascript function (the code: selectedResult.push(interestResultName[listitem]); ) .
Thank you,
Hary
I'm trying to use some javascript on a page layout, and I'm encountering a strange issue where the ClientID of a Sharepoint.WebControls.TextField seems to change between OnLoad and the page being displayed.
In the OnLoad event, TextField3.ClientID resolves to "ctl00_PlaceHolderMain_TextField3", but if look to see why my js doesn't work, the page source reveals that the control id to be "ctl00_PlaceHolderMain_TextField3_ctl00_TextField".
Any ideas what's going on?
Here's the code I'm using:
public class PostingTemplate : Microsoft.SharePoint.Publishing.PublishingLayoutPage
{
protected DropDownList author;
protected TextField TextField3;
private List<string> _authorNames;
public List<string> AuthorName
{
get { return _authorNames; }
set { _authorNames = value; }
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
author.AutoPostBack = false;
this.Page.ClientScript.RegisterClientScriptBlock(this.GetType(),
"fillInAuthorText", getQuery(), true);
author.Attributes.Add("onChange", "fillInAuthorText()");
if (!Page.IsPostBack)
{
_authorNames = new List<string>();
_authorNames = Utilities.GetAuthorList(SPContext.Current.Site);
author.DataSource = _authorNames;
author.DataBind();
}
}
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
if (author.Items.Count > 0)
{
author.SelectedIndex = 0;
TextField3.Text = ((ListItem)author.Items[author.SelectedIndex]).Text;
}
}
private string getQuery()
{
string query = #" function fillInAuthorText() {
var IndexValue = document.getElementById('";
query += author.ClientID;
query += #"').selectedIndex;
var SelectedVal = document.getElementById('";
query += author.ClientID;
query += #"').options[IndexValue].value;
document.getElementById('";
query += TextField3.ClientID;
query += #"').value = SelectedVal;
}";
return query;
}
}
You need to include the client ID of the parent control as well.
// Replace:
query += author.ClientID;
// With:
query += base.ClientID + "_" + author.ClientID;
(Note that I've only ever done this with a web part so there may be some tweaking you need to do for it to work in a page layout.)
Another option is to resolve this client side. See Eric Shupp's blog for most info.
With help form Alex Angas, Here is what I discovered:
The TexField renders out some literals that end up surrounding a textbox, and it's really the textbox that you're interested in. Here's the modified section of code:
private string getQuery()
{
string query = #" function fillInAuthorText() {
var IndexValue = document.getElementById('";
query += author.ClientID;
query += #"').selectedIndex;
var SelectedVal = document.getElementById('";
query += author.ClientID;
query += #"').options[IndexValue].value;
document.getElementById('";
query += getTextFieldID(TextField3);
query += #"').value = SelectedVal;
}";
return query;
}
private string getTextFieldID(Control txt)
{
foreach (Control c in txt.Controls)
{
if (c.HasControls())
{
foreach (Control con in c.Controls)
if (con is TextBox)
return con.ClientID;
}
}
return "";
}
Keep in mind, this is specific to my application, your mileage my vary.