Related
Hey guys im testing NFC and i have an issue with i think it is formating..
I added a string value in the tag with an app to write.
when i scan it with that same store app it shows ok...
when i scan with my app it shows the correct name in the app but adds a "en" before the message..
and a white space.. so if i add a name in the tag then scan and get a API it shows 404 cause there is an en and white space..
http://myapisite.com/API/getdevice.php?id= enTagString
before the = space and then en before the id or even name i put..
i tried a few ways..
public class MainActivity extends Activity {
// list of NFC technologies detected:
private final String[][] techList = new String[][]{
new String[]{
NfcA.class.getName (),
NfcB.class.getName (),
NfcF.class.getName (),
NfcV.class.getName (),
IsoDep.class.getName (),
MifareClassic.class.getName (),
MifareUltralight.class.getName (), Ndef.class.getName ()
}
};
private TextView mTextView;
private ImageView mImageView;
private String ID, machineName, MachineImg, MachinePart, level;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate (savedInstanceState);
setContentView (R.layout.activity_main);
mImageView = findViewById (R.id.imageView);
mTextView = findViewById (R.id.textView_explanation);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater ().inflate (R.menu.menu, menu);
return true;
}
#Override
protected void onResume() {
super.onResume ();
PendingIntent pendingIntent = PendingIntent.getActivity (this, 0, new Intent (this, getClass ()).addFlags (Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
// creating intent receiver for NFC events:
IntentFilter filter = new IntentFilter ();
filter.addAction (NfcAdapter.ACTION_TAG_DISCOVERED);
filter.addAction (NfcAdapter.ACTION_NDEF_DISCOVERED);
filter.addAction (NfcAdapter.ACTION_TECH_DISCOVERED);
// enabling foreground dispatch for getting intent from NFC event:
NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter (this);
nfcAdapter.enableForegroundDispatch (this, pendingIntent, new IntentFilter[]{filter}, this.techList);
}
#Override
protected void onPause() {
super.onPause ();
NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter (this);
nfcAdapter.disableForegroundDispatch (this);
}
void parseNdefMessage(Intent intent) {
Parcelable[] ndefMessageArray = intent.getParcelableArrayExtra (
NfcAdapter.EXTRA_NDEF_MESSAGES);
NdefMessage ndefMessage = (NdefMessage) ndefMessageArray[0];
String text = new String (ndefMessage.getRecords ()[0].getPayload ());
Log.d (TAG, "PAYLOAD MESS" + text);
ID = text;
getApiInfos ();
}
#Override
protected void onNewIntent(Intent intent) {
parseNdefMessage (intent);
if (intent.getAction ().equals (NfcAdapter.ACTION_TAG_DISCOVERED)) {
mTextView.setText ("NFC Tag\n" + ByteArrayToHexString (intent.getByteArrayExtra (NfcAdapter.EXTRA_ID)));
Parcelable tagN = intent.getParcelableExtra (NfcAdapter.EXTRA_TAG);
if (tagN != null) {
NdefMessage[] msgs;
byte[] empty = new byte[0];
byte[] id = intent.getByteArrayExtra (NfcAdapter.EXTRA_ID);
byte[] payload = dumpTagData (tagN).getBytes ();
NdefRecord record = new NdefRecord (NdefRecord.TNF_UNKNOWN, empty, id, payload);
NdefMessage msg = new NdefMessage (new NdefRecord[]{record});
msgs = new NdefMessage[]{msg};
Log.d (TAG, msgs[0].toString ());
} else {
Log.d (TAG, "Parcelable NULL");
}
Parcelable[] messages1 = intent.getParcelableArrayExtra (NfcAdapter.EXTRA_NDEF_MESSAGES);
if (messages1 != null) {
Log.d (TAG, "Found " + messages1.length + " NDEF messages");
for (int i = 0; i < messages1.length; ++i) {
Log.d (TAG, "Found M " + messages1[i].toString ());
}
} else {
Log.d (TAG, "Not EXTRA_NDEF_MESSAGES");
}
Tag tag = intent.getParcelableExtra (NfcAdapter.EXTRA_TAG);
Ndef ndef = Ndef.get (tag);
if (ndef != null) {
Parcelable[] messages = intent.getParcelableArrayExtra (NfcAdapter.EXTRA_NDEF_MESSAGES);
if (messages != null) {
Log.d (TAG, "Found " + messages.length + " NDEF messages");
}
} else {
Log.d (TAG, "Write to an unformatted tag not implemented");
}
}
}
private String dumpTagData(Parcelable p) {
StringBuilder sb = new StringBuilder ();
Tag tag = (Tag) p;
byte[] id = tag.getId ();
sb.append ("Tag ID (hex): ").append (getHex (id)).append ("\n");
sb.append ("Tag ID (dec): ").append (getDec (id)).append ("\n");
sb.append ("ID (reversed): ").append (getReversed (id)).append ("\n");
String prefix = "android.nfc.tech.";
sb.append ("Technologies: ");
for (String tech : tag.getTechList ()) {
sb.append (tech.substring (prefix.length ()));
sb.append (", ");
}
sb.delete (sb.length () - 2, sb.length ());
for (String tech : tag.getTechList ()) {
if (tech.equals (MifareClassic.class.getName ())) {
sb.append ('\n');
MifareClassic mifareTag = MifareClassic.get (tag);
String type = "Unknown";
switch (mifareTag.getType ()) {
case MifareClassic.TYPE_CLASSIC:
type = "Classic";
break;
case MifareClassic.TYPE_PLUS:
type = "Plus";
break;
case MifareClassic.TYPE_PRO:
type = "Pro";
break;
}
sb.append ("Mifare Classic type: ");
sb.append (type);
sb.append ('\n');
sb.append ("Mifare size: ");
sb.append (mifareTag.getSize () + " bytes");
sb.append ('\n');
sb.append ("Mifare sectors: ");
sb.append (mifareTag.getSectorCount ());
sb.append ('\n');
sb.append ("Mifare blocks: ");
sb.append (mifareTag.getBlockCount ());
}
if (tech.equals (MifareUltralight.class.getName ())) {
sb.append ('\n');
MifareUltralight mifareUlTag = MifareUltralight.get (tag);
String type = "Unknown";
switch (mifareUlTag.getType ()) {
case MifareUltralight.TYPE_ULTRALIGHT:
type = "Ultralight";
break;
case MifareUltralight.TYPE_ULTRALIGHT_C:
type = "Ultralight C";
break;
}
sb.append ("Mifare Ultralight type: ");
sb.append (type);
}
}
DateFormat TIME_FORMAT = SimpleDateFormat.getDateTimeInstance ();
Date now = new Date ();
mTextView.setText (TIME_FORMAT.format (now) + '\n' + sb.toString ());
return sb.toString ();
}
private String getHex(byte[] bytes) {
StringBuilder sb = new StringBuilder ();
for (int i = bytes.length - 1; i >= 0; --i) {
int b = bytes[i] & 0xff;
if (b < 0x10)
sb.append ('0');
sb.append (Integer.toHexString (b));
if (i > 0) {
sb.append (" ");
}
}
return sb.toString ();
}
private long getDec(byte[] bytes) {
long result = 0;
long factor = 1;
for (int i = 0; i < bytes.length; ++i) {
long value = bytes[i] & 0xffl;
result += value * factor;
factor *= 256l;
}
return result;
}
private long getReversed(byte[] bytes) {
long result = 0;
long factor = 1;
for (int i = bytes.length - 1; i >= 0; --i) {
long value = bytes[i] & 0xffl;
result += value * factor;
factor *= 256l;
}
return result;
}
private String ByteArrayToHexString(byte[] inarray) {
int i, j, in;
String[] hex = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"};
String out = "";
for (j = 0; j < inarray.length; ++j) {
in = (int) inarray[j] & 0xff;
i = (in >> 4) & 0x0f;
out += hex[i];
i = in & 0x0f;
out += hex[i];
}
Log.d ("ByteArrayToHexString", String.format ("%0" + (inarray.length * 2) + "X", new BigInteger (1, inarray)));
return out;
}
enter code here
Most likely this is because the App writing is storing it as a "WELL_KNOWN" type of text/plain
The specs for NFC Text format can be found at NFCForum-TS-RTD_Text_1.0.pdf.
The extra characters in the payload are as below:
language length (1 byte) + language (n bytes) + Text
So the space is the actually a non printable size of the language.
The "en" is defining that the text is English.
https://developer.android.com/reference/android/nfc/NdefRecord#getPayload()
returns a byte array.
So below should work to trim it (tested) as there don't seem to be nice helper methods to decode it, only create this format.
// Create Test Record
NdefRecord record = NdefRecord.createTextRecord("en", "Hello");
//Get Bytes of payload
// byte[] payload = ndefMessage.getRecords ()[0].getPayload ();
// Get Bytes of test NDEF Record
byte[] payload = record.getPayload ();
// Read First Byte and then trim off the right length
byte[] textArray = Arrays.copyOfRange(payload, (int) payload[0] + 1 , payload.length);
// Convert to Text
String text = new String(textArray);
UPDATE:
As the code given in the question is a bit of a mess and you do things you don't need to do and don't do things you do need to do (e.g. you have asked to be sent data from cards that won't have NDef data in them and then you parse for Ndef data without checking there is some data to parse)
I've simplified the code just to read a text NDEF record (Note not tested, but based on how I used to read NDEF data, I now use a better method to read cards that is more reliable especially if you want to write to cards as well)
public class MainActivity extends Activity {
private TextView mTextView;
private ImageView mImageView;
private String ID, machineName, MachineImg, MachinePart, level;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mImageView = findViewById(R.id.imageView);
mTextView = findViewById(R.id.textView_explanation);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu, menu);
return true;
}
#Override
protected void onResume() {
super.onResume();
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
// creating intent receiver for NFC events:
IntentFilter filter = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
// enabling foreground dispatch for getting intent from NFC event:
NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
nfcAdapter.enableForegroundDispatch(this, pendingIntent, new IntentFilter[]{filter}, null);
}
#Override
protected void onPause() {
super.onPause();
NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
nfcAdapter.disableForegroundDispatch(this);
}
void parseNdefMessage(Intent intent) {
Parcelable[] ndefMessageArray = intent.getParcelableArrayExtra(
NfcAdapter.EXTRA_NDEF_MESSAGES);
// Test if there is actually a NDef message passed via the Intent
if (ndefMessageArray != null) {
NdefMessage ndefMessage = (NdefMessage) ndefMessageArray[0];
//Get Bytes of payload
byte[] payload = ndefMessage.getRecords()[0].getPayload();
// Read First Byte and then trim off the right length
byte[] textArray = Arrays.copyOfRange(payload, (int) payload[0] + 1, payload.length);
// Convert to Text
String text = new String(textArray);
ID = text;
getApiInfos();
}
}
#Override
protected void onNewIntent(Intent intent) {
if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())) {
parseNdefMessage(intent);
}
}
}
Ok thx to #Andrew i used part of your code and adapted it to my tests.. it works great now i can clean it up and removed what is not used or needed.Thx happy holidays!:)
void parseNdefMessage(Intent intent) {
Parcelable[] ndefMessageArray = intent.getParcelableArrayExtra(
NfcAdapter.EXTRA_NDEF_MESSAGES);
// Test if there is actually a NDef message passed via the Intent
if (ndefMessageArray != null) {
NdefMessage ndefMessage = (NdefMessage) ndefMessageArray[0];
//Get Bytes of payload
byte[] payload = ndefMessage.getRecords()[0].getPayload();
// Read First Byte and then trim off the right length
byte[] textArray = Arrays.copyOfRange(payload, (int) payload[0] + 1, payload.length);
// Convert to Text
String text = new String(textArray);
ID = text;
getApiInfos();
}
}
If anyone is facing the same issue in React Native, here's my solution. Here, the react-native-nfc-manager package is used
// register for the NFC tag with NDEF in it
await NfcManager.requestTechnology(NfcTech.Ndef);
// the resolved tag object will contain `ndefMessage` property
const tag = await NfcManager.getTag();
// access the payload
const payload = tag?.ndefMessage[0].payload;
//remove the language code from payload
const subPayload = payload?.slice(3, payload.length);
const decoded = Ndef.util.bytesToString(subPayload);
i'm using the following function to get Allcellinfo of an device network and im getting the values as an string now i need to parse it in order to get the CellSignalStrengthLte data how can i achieve it
//code
TelephonyManager tm = (TelephonyManager) Context.getSystemService(mContext.TELEPHONY_SERVICE);
List<CellInfo> cellInfos = tm.getAllCellInfo();
String data = cellInfos.get(0).toString();
Log.d("Info ", " "+data);
Result is
CellInfoLte:{mRegistered=YES mTimeStampType=oem_ril mTimeStamp=207387894126206ns CellIdentityLte:{ mMcc=405 mMnc=869 mCi=2971664 mPci=123 mTac=56} CellSignalStrengthLte: ss=25 rsrp=-91 rsrq=-7 rssnr=2147483647 cqi=2147483647 ta=2147483647}
How can parse this string to get details regaridng CellinfoLte,CellIdentityLte
I also noticed that CellinfoLTE and CellIdentityLTE is not so great at the moment, so I just wrote my own parsing class. Only tested this a few times, and didn't have problems, but more testing should display if additional future tweaking will be necessary.
Here's the class:
public class LTEStruct
{
public static final int UNKNOWN = Integer.MAX_VALUE; //Default value for unknown fields
public boolean isRegistered;
public long timeStamp;
public int MCC;
public int MNC;
public int CID;
public int PCI;
public int TAC;
public int SS;
public int RSRP;
public int RSRQ;
public int RSSNR;
public int CQI;
public int tAdvance;
Context mContext;
//Public constructor
public LTEStruct(Context context)
{
mContext = context; //not used at the moment but possibly for future function
}
public void parse(String inTest)
{
//get isRegistered
int index = inTest.indexOf("mRegistered=") + ("mRegistered=").length();
if(inTest.substring(index,index + 3).contains("YES"))
isRegistered = true;
else
isRegistered = false;
//getTimestamp
timeStamp = getValue(inTest,"mTimeStamp=", "ns");
//get Cell Identity paramters
MCC = (int) getValue(inTest,"mMcc=", " "); //get Mcc
MNC = (int) getValue(inTest,"mMnc=", " "); //get MNC
CID = (int) getValue(inTest,"mCi=", " "); //get CID
PCI = (int) getValue(inTest,"mPci="," "); //get PCI
TAC = (int) getValue(inTest,"mTac=","}"); //get TAC
//get RF related parameters
SS = (int) getValue(inTest," ss="," "); //get SS
RSRP = (int)getValue(inTest,"rsrp=", " "); //get RSRP
RSRQ = (int)getValue(inTest,"rsrq=", " "); //get RSRQ
RSSNR = (int)getValue(inTest,"rssnr=", " "); //get RSSNR
CQI = (int)getValue(inTest," cqi=", " "); //get CQI
tAdvance = (int)getValue(inTest," ta=", "}"); //get timing advance
}
//internal function to help with parsing of raw LTE strings
private long getValue(String fullS, String startS, String stopS)
{
int index = fullS.indexOf(startS) + (startS).length();
int endIndex = fullS.indexOf(stopS,index);
return Long.parseLong(fullS.substring(index,endIndex).trim());
}
}
So if I implement this very basically with the input LTE string:
//permission check
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED)
ActivityCompat.requestPermissions((Activity)this,new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},1);
//get cell info
TelephonyManager tel = (TelephonyManager) this.getSystemService(Context.TELEPHONY_SERVICE);
List<CellInfo> infos = tel.getAllCellInfo();
for (int i = 0; i<infos.size(); ++i)
{
try
{
CellInfo info = infos.get(i);
if (info instanceof CellInfoLte) {
LTEStruct lte = new LTEStruct(this);
lte.parse(info.toString());
//write out parsed results for what it's worth
Log.i("LTE parseOutput", "tAdvance: " + lte.tAdvance + "\r\nCQI: " + lte.CQI + "\r\nRSSNR: " + lte.RSSNR + "\r\nRSRP: " + lte.RSRP + "\r\nSS: " + lte.SS +
"\r\nCID: " + lte.CID + "\r\nTimestamp: " + lte.timeStamp + "\r\nTAC: " + lte.TAC + "\r\nPCI: " + lte.PCI + "\r\nMNC: " + lte.MNC + "\r\nMCC: " + lte.MCC + "\r\nRegistered: " + lte.isRegistered);
} else
Log.i("LTE testing", "not LTE cell info measured");
} catch (Exception ex) {
Log.i("neighboring error: ", ex.getMessage());
}
}
Hope it helps ;)
This is my approach to use gcm for more than 1000 devices. Is it right that way? As I cannot try it unless I have more than 1000 users so any feedback would be appreciated and most importantly am I checking errors correctly? and updating database in a right way?
public class MessagingEndpoint {
private static final Logger log = Logger.getLogger(MessagingEndpoint.class.getName());
/**
* Api Keys can be obtained from the google cloud console
*/
private static final String API_KEY = System.getProperty("gcm.api.key");
private List<RegistrationRecord> records;
private List<String> getRegistrationId() {
records = ofy().load().type(RegistrationRecord.class).list();
List<String> records_ID = new ArrayList<String>();
for (int i = 0; i < records.size(); i++) {
records_ID.add(records.get(i).getRegId());
}
return records_ID;
}
private List<List<String>> regIdInThousands(List<String> list, final int L) {
List<List<String>> parts = new ArrayList<List<String>>();
final int N = list.size();
for (int i = 0; i < N; i += L) {
parts.add(new ArrayList<String>(list.subList(i, Math.min(N, i + L))));
}
return parts;
}
*
* #param message The message to send
*/
public void sendMessage(#Named("message") String message) throws IOException {
if (message == null || message.trim().length() == 0) {
log.warning("Not sending message because it is empty");
return;
}
// crop longer messages
if (message.length() > 1000) {
message = message.substring(0, 1000) + "[...]";
}
Sender sender = new Sender(API_KEY);
Message msg = new Message.Builder().addData("message", message).build();
List<List<String>> regIdsParts = regIdInThousands(getRegistrationId(), 1000);
for (int i = 0; i < regIdsParts.size(); i++) {
MulticastResult multicastResult = sender.send(msg, regIdsParts.get(i), 5);
if (multicastResult.getCanonicalIds() != 0) {
List<Result> results = multicastResult.getResults();
for (int j = 0; j < results.size(); j++) {
if (results.get(j).getMessageId() != null) {
log.info("Message sent to " + regIdsParts.get(i).get(j));
String canonicalRegId = results.get(j).getCanonicalRegistrationId();
if (canonicalRegId != null) {
// if the regId changed, we have to update the datastore
log.info("Registration Id changed for " + regIdsParts.get(i).get(j) + " updating to " + canonicalRegId);
regIdsParts.get(i).set(j, canonicalRegId);
ofy().save().entity(records.get((i*1000)+j)).now();
} else {
String error = results.get(j).getErrorCodeName();
if (error.equals(Constants.ERROR_NOT_REGISTERED)) {
log.warning("Registration Id " + regIdsParts.get(i).get(j) + " no longer registered with GCM, removing from datastore");
// if the device is no longer registered with Gcm, remove it from the datastore
ofy().delete().entity(records.get((i*1000)+j)).now();
} else {
log.warning("Error when sending message : " + error);
}
}
}
}
}
}
}
}
Your code looks good, Only thing I can notice is its quite verbose and complicated. You can take a look at this one just as a option if you are considerate about error handling:
public void sendMessageToMultipleDevices(String key, String value, ArrayList devices) {
Sender sender = new Sender(myApiKey);
Message message = new Message.Builder().addData(key, value).build();
try {
MulticastResult result = sender.send(message, devices, 5);
MTLog.info(TAG, "result " + result.toString());
for (int i = 0; i < result.getTotal(); i++) {
Result r = result.getResults().get(i);
if (r.getMessageId() != null) {
String canonicalRegId = r.getCanonicalRegistrationId();
if (canonicalRegId != null) {
// devices.get(i) has more than on registration ID: update database
}
} else {
String error = r.getErrorCodeName();
if (error.equals(Constants.ERROR_NOT_REGISTERED)) {
// application has been removed from devices.get(i) - unregister database
}
}
}
} catch (IOException ex) {
MTLog.err(TAG, "sending message failed", ex);
}
}
I try to write a program to read all the sector of NCF tag.So when I run the test :
the tag is detected
I get the tag Id
I get the number of sector
But i can only read the first sector !
Here my code :
public class MainActivity extends Activity {
public String TAG_LOCAL = "Home - ";
public boolean MODE_DEBUG_LOCAL = true;
NfcAdapter nfcAdapter;
PendingIntent pendingIntent;
IntentFilter[] intentFilter;
String[][] generalTechLists;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.w("ISI", "Main Start");
//detect if NFC device
if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_NFC)) {
Log.w("ISI", "NFC detected");
}else{
Log.w("ISI", "NFC NOT detected");
}
IntentFilter ndef = new IntentFilter(NfcAdapter.ACTION_TECH_DISCOVERED);
try {
ndef.addDataType("*/*");
} catch (MalformedMimeTypeException e) {
Log.w("ISI", " error ndef = " + e.getMessage());
}
intentFilter = new IntentFilter[] {ndef};
generalTechLists = new String[][] { new String[] { MifareClassic.class.getName() } };
nfcAdapter = NfcAdapter.getDefaultAdapter(this);
pendingIntent = PendingIntent.getActivity(this, 0,new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
}
#Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
resolveIntent(intent);
}
void resolveIntent(Intent intent) {
String action = intent.getAction();
if (NfcAdapter.ACTION_TECH_DISCOVERED.equals(action)) {
//Identifiant du tag NFC
byte[] byte_id = intent.getByteArrayExtra(NfcAdapter.EXTRA_ID);
Log.w("ISI", "Tag id = " + ByteArrayToHexString(byte_id));
//techno disponible
Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
String[] techList = tagFromIntent.getTechList();
for (int Cpt = 0; Cpt <techList.length; Cpt++){
Log.w("ISI", "Techno = " + techList[Cpt]);
}
//QUESTION A POSER DANS XDA!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
MifareClassic mfc = MifareClassic.get(tagFromIntent);
try{
mfc.connect();
int size = mfc.getSize();
Log.w("ISI", "size (byte) = " + size);
int nbrSector = mfc.getSectorCount();
Log.w("ISI", "NbrSector = " + nbrSector);
for (int Cpt = 0; Cpt < nbrSector; Cpt++){
boolean auth = mfc.authenticateSectorWithKeyA(Cpt, MifareClassic.KEY_DEFAULT);
if (auth){
int nbrBlock = mfc.getBlockCountInSector(Cpt);
Log.w("ISI", "NbrBlock = " + nbrBlock + " for sector " + Cpt);
for (int k = 0; k < nbrBlock; k++){
byte[] data = mfc.readBlock(k);
Log.w("ISI", "Block num " + k + " - data " + ByteArrayToHexString(data));
}
}else{
Log.w("ISI", " Impossible to connect at sector " + Cpt);
}
}
}catch(IOException e){
Log.w("ISI", " error = " + e.getMessage());
}
}// End of method
}
#Override
protected void onResume() {
super.onResume();
nfcAdapter.enableForegroundDispatch(this, pendingIntent, intentFilter, generalTechLists);
}
private String getHexString(String hex){
StringBuilder output = new StringBuilder();
for (int i = 0; i < hex.length(); i+=2) {
String str = hex.substring(i, i+2);
output.append((char)Integer.parseInt(str, 16));
}
return output.toString();
}
String ByteArrayToHexString(byte[] inarray) {
//Thanks Adam Laurie sur XDA
int i, j, in;
String [] hex = {"0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"};
String out= "";
for(j = 0 ; j < inarray.length ; ++j) {
in = (int) inarray[j] & 0xff;
i = (in >> 4) & 0x0f;
out += hex[i];
i = in & 0x0f;
out += hex[i];
}
return out;
}
}
And here the log :
Tag id = C44F0EDD
Techno = android.nfc.tech.MifareClassic
Techno = android.nfc.tech.NfcA
Techno = android.nfc.tech.NdefFormatable
size (byte) = 1024
NbrSector = 16
NbrBlock = 4 for sector 0
Block num 0 - data C44F0EDD58880400C185149849803612
Block num 1 - data 00000000000000000000000000000000
Block num 2 - data 00000000000000000000000000000000
Block num 3 - data 000000000000FF078069FFFFFFFFFFFF
NbrBlock = 4 for sector 1
error = Tag was lost.
So I don't understand what happens.
Thank for help
Try to change:
for (int k = 0; k < nbrBlock; k++){
byte[] data = mfc.readBlock(k);
Log.w("ISI", "Block num " + k + " - data " + ByteArrayToHexString(data));
}
with this
byte[] data = mfc.readBlock(bIndex);
for (int k = 0; k < nbrBlock; k++){
bIndex = mfc.sectorToBlock(Cpt);
bIndex++;
Log.w("ISI", "Block num " + k + " - data " + ByteArrayToHexString(data));
}
from: http://mifareclassicdetectiononandroid.blogspot.it/
Set your code like this:
int bIndex = 0;
try{
mfc.connect();
int size = mfc.getSize();
Log.i("ISI", "size (byte) = " + size);
int sectorCount = mfc.getSectorCount();
Log.i("ISI", "NbrSector = " + sectorCount);
for (int Cpt = 0; Cpt < sectorCount; Cpt++){
boolean auth = mfc.authenticateSectorWithKeyA(Cpt, MifareClassic.KEY_DEFAULT);
if (auth){
int nbrBlock = mfc.getBlockCountInSector(Cpt);
Log.i("ISI", "NbrBlock = " + nbrBlock + " for sector " + Cpt);
for (int k = 0; k < nbrBlock; k++){
byte[] data = mfc.readBlock(bIndex);
Log.i("ISI", "Block num " + k + " - data " + ByteArrayToHexString(data));
bIndex++;
}
}else{
Log.i("ISI", " Impossible to connect at sector " + Cpt);
}
}
}catch(IOException e){
Log.i("ISI", " error = " + e.getMessage());
}
We want to intercept the outgoing call hangup state in a broadcast receiver. We are listening to android.intent.action.PHONE_STATE and do get notified on IDLE state, that is when the call finishes.
Unfortunately, we do not get the called number from the call log content provider. It always returns the last call. Interestingly the incoming call do send a number in the intent but nothing for outgoing call.
If we use android.intent.action.NEW_OUTGOING_CALL, the phone number is coming through the intent when the call starts, but this stage is too early for us to do any processing as we want to wait for the call to complete.
public class InterceptOutgoingCall extends BroadcastReceiver {
Boolean isOutGoingCall = true;
private static final String LOG_TAG = "InterceptOutgoingCall";
#Override
public void onReceive(Context context, Intent intent) {
//1. Logging the intent params
String state = null;
StringBuffer buf = new StringBuffer();
if (intent.getAction() != null)
buf.append("Intent action: " + intent.getAction());
if (intent.getCategories() != null) {
Set<String> categories = intent.getCategories();
if (categories != null) {
Iterator<String> it = categories.iterator();
buf.append("; categories: ");
int ctr = 0;
for (; it.hasNext();) {
String category = (String) it.next();
if (ctr != 0)
buf.append("/");
buf.append(category);
++ctr;
}
}
}
if (intent.getData() != null) {
buf.append("; intent data: " + intent.getData().toString());
}
Bundle extras = intent.getExtras();
if (extras != null) {
buf.append("; extras: ");
int ctr = 0;
Set keys = extras.keySet();
for (Iterator it = keys.iterator(); it.hasNext();) {
String key = (String) it.next();
Object value = extras.get(key);
if (ctr != 0)
buf.append("/");
String strvalue = value == null ? "null" : value.toString();
if (key.equals("state"))
state = strvalue;
buf.append(key + "=" + strvalue);
++ctr;
}
Log.i(LOG_TAG, buf.toString());
if ("IDLE".equals(state)) {
Log.i(LOG_TAG, "Number of the other party: "
+ getLastCallLogEntry(context));
}
}
String outgoingCall = CallLog.Calls.getLastOutgoingCall(context);
Log.i(LOG_TAG, "Last call:" + outgoingCall);
}
private String getLastCallLogEntry(Context context) {
String[] projection = new String[] { BaseColumns._ID,
CallLog.Calls.NUMBER, CallLog.Calls.TYPE };
ContentResolver resolver = context.getContentResolver();
Cursor cur = resolver.query(CallLog.Calls.CONTENT_URI, projection,
null, null, CallLog.Calls.DEFAULT_SORT_ORDER);
int numberColumn = cur.getColumnIndex(CallLog.Calls.NUMBER);
int typeColumn = cur.getColumnIndex(CallLog.Calls.TYPE);
if (!cur.moveToNext()) {
cur.close();
return "";
}
String number = cur.getString(numberColumn);
String type = cur.getString(typeColumn);
String dir = null;
try {
int dircode = Integer.parseInt(type);
switch (dircode) {
case CallLog.Calls.OUTGOING_TYPE:
dir = "OUTGOING";
break;
case CallLog.Calls.INCOMING_TYPE:
dir = "INCOMING";
break;
case CallLog.Calls.MISSED_TYPE:
dir = "MISSED";
break;
}
} catch (NumberFormatException ex) {
}
if (dir == null)
dir = "Unknown, code: " + type;
cur.close();
return dir + "," + number;
}
Log cat
*When call starts, NEW_OUTGOING_CALL is broadcast*
04-27 13:07:16.756: INFO/InterceptOutgoingCall(775): Intent action: android.intent.action.NEW_OUTGOING_CALL; extras: android.phone.extra.ALREADY_CALLED=false/android.intent.extra.PHONE_NUMBER=999222/android.phone.extra.ORIGINAL_URI=tel:999-222
Result data
04-27 13:07:16.876: INFO/InterceptOutgoingCall(775): Result Data:999222
Call Logs last call
04-27 13:07:17.156: INFO/InterceptOutgoingCall(775): Last call:809090
*Next, PHONE_STATE is broadcast, No number in extras*
04-27 13:07:19.495: INFO/InterceptOutgoingCall(775): Intent action: android.intent.action.PHONE_STATE; extras: state=OFFHOOK
No Result Data
04-27 13:07:19.636: INFO/InterceptOutgoingCall(775): No result data
When call is complete, No number in extras
04-27 13:08:09.306: INFO/InterceptOutgoingCall(775): Intent action: android.intent.action.PHONE_STATE; extras: state=IDLE
Call log last entry is the previously called number
04-27 13:08:09.627: INFO/InterceptOutgoingCall(775): Number of the other party: OUTGOING,809090
04-27 13:08:09.675: INFO/InterceptOutgoingCall(775): No result data
04-27 13:08:10.336: INFO/InterceptOutgoingCall(775): Last call:809090
Use a broadcast listener with an intent android.intent.action.NEW_OUTGOING_CALL string parametrer for the IntentFilter and don't forget to give permission in AndroidMenifest to PROCESS_OUTGOING_CALLS. This will work.
public static final String outgoing = "android.intent.action.NEW_OUTGOING_CALL" ;
IntentFilter intentFilter = new IntentFilter(outgoing);
BroadcastReceiver OutGoingCallReceiver = new BroadcastReceiver()
{
#Override
public void onReceive(Context context, Intent intent)
{
// TODO Auto-generated method stub
String outgoingno = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
Toast.makeText(context, "outgoingnum =" + outgoingno,Toast.LENGTH_LONG).show();
}
};
registerReceiver(brForOutgoingCall, intentFilter);
You can the outgoing call number like below:
String number = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
I think you can store the number using public static variable and then refer it.