can I send “SMS received intent” in android 4.1.2? - android

This code doesn't work with android version 4.1.2,
private static void createFakeSms(Context context, String sender,String body)
{
byte[] pdu = null;
byte[] scBytes = PhoneNumberUtils.networkPortionToCalledPartyBCD("0000000000");
byte[] senderBytes = PhoneNumberUtils.networkPortionToCalledPartyBCD(sender);
int lsmcs = scBytes.length;
byte[] dateBytes = new byte[7];
Calendar calendar = new GregorianCalendar();
dateBytes[0] = reverseByte((byte) (calendar.get(Calendar.YEAR)));
dateBytes[1] = reverseByte((byte) (calendar.get(Calendar.MONTH) + 1));
dateBytes[2] = reverseByte((byte) (calendar.get(Calendar.DAY_OF_MONTH)));
dateBytes[3] = reverseByte((byte) (calendar.get(Calendar.HOUR_OF_DAY)));
dateBytes[4] = reverseByte((byte) (calendar.get(Calendar.MINUTE)));
dateBytes[5] = reverseByte((byte) (calendar.get(Calendar.SECOND)));
dateBytes[6] = reverseByte((byte) ((calendar.get(Calendar.ZONE_OFFSET) + calendar
.get(Calendar.DST_OFFSET)) / (60 * 1000 * 15)));
try
{
ByteArrayOutputStream bo = new ByteArrayOutputStream();
bo.write(lsmcs);
bo.write(scBytes);
bo.write(0x04);
bo.write((byte) sender.length());
bo.write(senderBytes);
bo.write(0x00);
bo.write(0x00); // encoding: 0 for default 7bit
bo.write(dateBytes);
try
{
String sReflectedClassName = "com.android.internal.telephony.GsmAlphabet";
Class cReflectedNFCExtras = Class.forName(sReflectedClassName);
Method stringToGsm7BitPacked = cReflectedNFCExtras.getMethod(
"stringToGsm7BitPacked", new Class[] { String.class });
stringToGsm7BitPacked.setAccessible(true);
byte[] bodybytes = (byte[]) stringToGsm7BitPacked.invoke(null,body);
bo.write(bodybytes);
}
catch (Exception e)
{
}
pdu = bo.toByteArray();
}
catch (IOException e)
{
}
Intent intent = new Intent();
intent.setClassName("com.android.mms",
"com.android.mms.transaction.SmsReceiverService");
intent.setAction("android.provider.Telephony.SMS_RECEIVED");
intent.putExtra("pdus", new Object[] { pdu });
intent.putExtra("format", "3gpp");
context.startService(intent);
}
private static byte reverseByte(byte b) {
return (byte) ((b & 0xF0) >> 4 | (b & 0x0F) << 4);
}
When I call context.startService(intent) I am getting this exception
java.lang.SecurityException: Not allowed to start service Intent { act=android.provider.Telephony.SMS_RECEIVED cmp=com.android.mms/.transaction.SmsReceiverService (has extras) } without permission not exported from uid 10046**
on virtual device 4.1.2 it works perfectly but not in my GS2 device.
Can anyone help me?

In newer versions of Android this is a protected broadcast which can only be sent by system apps for security reasons.
The only way to get your app to send it is to convince the OEM to make it a system app on their ROM

Related

Android.How to send SMS without SIM card?

I have a device with Android 4.4 in a board but it doesn't have a SIM card module.
Please, tell me , how i can emulate incoming SMS from my application?
I just wanna see standart notification aboute incoming sms.
I tried this example:
enter code here
private static void createFakeSms(Context context, String sender,
String body) {
byte[] pdu = null;
byte[] scBytes =PhoneNumberUtils.networkPortionToCalledPartyBCD("0000000000");
byte[] senderBytes = PhoneNumberUtils.networkPortionToCalledPartyBCD(sender);
int lsmcs = scBytes.length;
byte[] dateBytes = new byte[7];
Calendar calendar = new GregorianCalendar();
dateBytes[0] = reverseByte((byte) (calendar.get(Calendar.YEAR)));
dateBytes[1] = reverseByte((byte) (calendar.get(Calendar.MONTH) + 1));
dateBytes[2] = reverseByte((byte) (calendar.get(Calendar.DAY_OF_MONTH)));
dateBytes[3] = reverseByte((byte) (calendar.get(Calendar.HOUR_OF_DAY)));
dateBytes[4] = reverseByte((byte) (calendar.get(Calendar.MINUTE)));
dateBytes[5] = reverseByte((byte) (calendar.get(Calendar.SECOND)));
dateBytes[6] = reverseByte((byte) ((calendar.get(Calendar.ZONE_OFFSET) + calendar
.get(Calendar.DST_OFFSET)) / (60 * 1000 * 15)));
try {
ByteArrayOutputStream bo = new ByteArrayOutputStream();
bo.write(lsmcs);
bo.write(scBytes,0,scBytes.length);
bo.write(0x04);
bo.write((byte) sender.length());
bo.write(senderBytes,0,senderBytes.length);
bo.write(0x00);
bo.write(0x00); // encoding: 0 for default 7bit
bo.write(dateBytes,0,dateBytes.length);
try {
String sReflectedClassName = "com.android.internal.telephony.GsmAlphabet";
Class cReflectedNFCExtras = Class.forName(sReflectedClassName);
Method stringToGsm7BitPacked = cReflectedNFCExtras.getMethod(
"stringToGsm7BitPacked", new Class[] { String.class });
stringToGsm7BitPacked.setAccessible(true);
byte[] bodybytes = (byte[]) stringToGsm7BitPacked.invoke(null,
body);
bo.write(bodybytes);
} catch (Exception e) {
}
pdu = bo.toByteArray();
}finally {
}
Intent intent = new Intent();
intent.setClassName("com.android.mms",
"com.android.mms.transaction.SmsReceiverService");
intent.setAction("android.provider.Telephony.SMS_RECEIVED");
intent.putExtra("pdus", new Object[] { pdu });
intent.putExtra("format", "3gpp");
context.startService(intent);
}
private static byte reverseByte(byte b) {
return (byte) ((b & 0xF0) >> 4 | (b & 0x0F) << 4);
}
But when i call this function my application is crashed.
Please help me.

I'm getting a tag lost exception when I try writing to an NFC tag

I hope someone can tell me what I'm missing here. Maybe it's my approach to connecting. My Tag, is in fact a Mifare Ultralight so I'm not getting things wrong there. I debugged, connecting to the tag was successful - everything seemed fine. But the log keeps on saying:
android.nfc.TagLostException: Tag was lost.
public class MainActivity extends Activity {
NfcAdapter mNfcAdapter;
TextView displayInfo;
Tag mNfcTag;
NdefMessage mNdefMessage;
IntentFilter [] intentFiltersArray;
String [] [] techListsArray;
PendingIntent pendingIntent;
String TAG = "MainActivity";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
displayInfo = (TextView) findViewById(R.id.displayInfo);
NdefRecord application = NdefRecord.createApplicationRecord("com.studios.nfcdemo");
Locale locale = new Locale("en");
NdefRecord textText = createTextRecord("pleaseWork", locale, true);
mNdefMessage = new NdefMessage(textText);
pendingIntent = PendingIntent.getActivity(
this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
IntentFilter ndef = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
try {
ndef.addDataType("*/*"); /* Handles all MIME based dispatches.
You should specify only the ones that you need. */
}
catch (IntentFilter.MalformedMimeTypeException e) {
throw new RuntimeException("fail", e);
}
intentFiltersArray = new IntentFilter[] {ndef};
techListsArray = new String[][] { new String[] { MifareUltralight.class.getName() } };
}
public NdefRecord createTextRecord(String payload, Locale locale, boolean encodeInUtf8) {
byte[] langBytes = locale.getLanguage().getBytes(Charset.forName("US-ASCII"));
Charset utfEncoding = encodeInUtf8 ? Charset.forName("UTF-8") : Charset.forName("UTF-16");
byte[] textBytes = payload.getBytes(utfEncoding);
int utfBit = encodeInUtf8 ? 0 : (1 << 7);
char status = (char) (utfBit + langBytes.length);
byte[] data = new byte[1 + langBytes.length + textBytes.length];
data[0] = (byte) status;
System.arraycopy(langBytes, 0, data, 1, langBytes.length);
System.arraycopy(textBytes, 0, data, 1 + langBytes.length, textBytes.length);
NdefRecord record = new NdefRecord(NdefRecord.TNF_WELL_KNOWN,
NdefRecord.RTD_TEXT, new byte[0], data);
return record;
}
#Override
public void onNewIntent(Intent intent) {
Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
MifareUltralight ultralight = MifareUltralight.get(tagFromIntent);
write(ultralight);
}
private void write(MifareUltralight lol) {
try{
lol.connect();
lol.writePage(0, "please work".getBytes(Charset.forName("US-ASCII")));
Toast.makeText(this, "Tag written", Toast.LENGTH_LONG).show();
}
catch (Exception e){
Log.d(TAG, "no " + e.toString());
}
finally{
try{
lol.close();
}
catch (Exception e){
Log.d(TAG, e.toString());
}
}
}
public void onPause() {
super.onPause();
mNfcAdapter.disableForegroundDispatch(this);
}
public void onResume() {
super.onResume();
mNfcAdapter.enableForegroundDispatch(this, pendingIntent, intentFiltersArray, techListsArray);
}
}
I found my error. I wanted to write Ndef messages and using the tag as MifareUltralight was a little silly as it just complicates everything. Instead, I cast the tag as an Ndef. Here's me code:
private void write(Tag tag) {
Ndef ndef = Ndef.get(tag);
Locale locale = Locale.ENGLISH;
NdefRecord hi = createTextRecord("hello world", locale, true);
mNdefMessage = new NdefMessage(hi);
try{
ndef.connect();
ndef.writeNdefMessage(mNdefMessage);
Toast.makeText(this, "Message Written", Toast.LENGTH_LONG).show();
}
catch (Exception e){
Log.d(TAG, "Exception: " + e.toString());
}
finally {
try{
ndef.close();
}
catch(Exception e){
Log.d(TAG, ":( no " + e.toString());
}
}
}
In case anyone needs to figure out how to create text records (encoded in UTF 8) and read from Ndef supported tags, I have added my methods for those as well:
Creating text records:
public NdefRecord createTextRecord(String payload, Locale locale, boolean encodeInUtf8) {
byte[] langBytes = locale.getLanguage().getBytes(Charset.forName("US-ASCII"));
Charset utfEncoding = encodeInUtf8 ? Charset.forName("UTF-8") : Charset.forName("UTF-16");
byte[] textBytes = payload.getBytes(utfEncoding);
int utfBit = encodeInUtf8 ? 0 : (1 << 7);
char status = (char) (utfBit + langBytes.length);
byte[] data = new byte[1 + langBytes.length + textBytes.length];
data[0] = (byte) status;
System.arraycopy(langBytes, 0, data, 1, langBytes.length);
System.arraycopy(textBytes, 0, data, 1 + langBytes.length, textBytes.length);
NdefRecord record = new NdefRecord(NdefRecord.TNF_WELL_KNOWN,
NdefRecord.RTD_TEXT, new byte[0], data);
return record;
}
Reading NDEF tags:
private void read(Tag tagFromIntent) {
Ndef ndef = Ndef.get(tagFromIntent);
try{
ndef.connect();
mNdefMessage = ndef.getNdefMessage();
NdefRecord [] records = mNdefMessage.getRecords();
byte [] payload = records[0].getPayload();
String displayString = getTextFromNdefRecord(records[0]);
displayInfo.setText(displayString);
Toast.makeText(this, "String read", Toast.LENGTH_LONG).show();
}
catch (Exception e){
Log.d(TAG, e.toString());
}
finally {
try{
ndef.close();
}
catch (Exception e){
Log.d(TAG, e.toString());
}
}
reading text from NdefRecords:
public String getTextFromNdefRecord(NdefRecord ndefRecord)
{
String tagContent = null;
try {
byte[] payload = ndefRecord.getPayload();
String textEncoding = "UTF-8";
int languageSize = payload[0] & 0063;
tagContent = new String(payload, languageSize + 1,
payload.length - languageSize - 1, textEncoding);
} catch (UnsupportedEncodingException e) {
Log.e("getTextFromNdefRecord", e.getMessage(), e);
}
return tagContent;
}
I hope this helps anyone else working with NFC. These simple methods should give you all the functionality you need within Android.
There are two problems with your call to the writePage() method:
Page 0 of MIFARE Ultralight tags is read-only. You cannot write to that page. The same applies to page 1 and parts of page 2 (though write commands for page two should succeed and will set the lock bits).
The write command takes 4 bytes (exactly 4 bytes, not more and not less) but you try to pass 11 bytes ("please work" in US-ASCII).

How solve "android.nfc.TagLostException: Tag was lost." ?(Select PICC app)

I am facing an issue with a Mifare DESFire card.
I usetransceive() method to send apdu for selection the PICC app, The flow of the application is:
1) Tech Discovered
2) Create MifareDESFire object using
intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
3) Called connect();
4) Send the select PICC app apdu command using transceive();
5) Received a "android.nfc.TagLostException: Tag was lost." when I send
apdu. I specify the line maked above error by an '****'
Here is my onNewIntent event:
public void onNewIntent(Intent intent)
{
String action = intent.getAction();
if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(action)
|| NfcAdapter.ACTION_TECH_DISCOVERED.equals(action)
|| NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action)) {
Toast.makeText(this, "discovered", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "Falied", Toast.LENGTH_SHORT).show();
}
byte cmdSelect_PICCapp=(byte) 0x5A ; //select my app
byte[] PICCAPPID = new byte[]{(byte)0x00 ,(byte)0x00 , (byte)0x00};
byte[] tagResponse_cmdSelect_PICC_app = new byte[]{(byte)0x12 ,(byte)0x12};
Tag desfire = (Tag) intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
isodep = IsoDep.get(desfire);
try
{
isodep.connect();
} catch (IOException e)
{
e.printStackTrace();
}
**** tagResponse_cmdSelect_PICC_app = isodep.transceive(Utils.wrapMessage(cmdSelect_PICCapp, PICCAPPID));
Log.d("picc app selected", "111 "+Utils.bytesToHex(tagResponse_cmdSelect_PICC_app));
try
{
isodep.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
And
Class Utils is here:
public class Utils {
final protected static char[] hexArray = "0123456789ABCDEF".toCharArray();
public static byte[] wrapMessage (byte command, byte[] parameters) throws Exception {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
stream.write((byte) 0x90);
stream.write(command);
stream.write((byte) 0x00);
stream.write((byte) 0x00);
if (parameters != null) {
stream.write((byte) parameters.length);
stream.write(parameters);
}
stream.write((byte) 0x00);
byte[] b = stream.toByteArray();
return b;
}
//**************************************
public static String bytesToHex(byte[] bytes)
{
char[] hexChars = new char[bytes.length * 2];
for ( int j = 0; j < bytes.length; j++ )
{
int v = bytes[j] & 0xFF;
hexChars[j * 2] = hexArray[v >>> 4];
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
}
return new String(hexChars);
}
}//end class Utils
Appreciate it anyone can help me.
Thank you.

Android: onRecieve's intent getSerializableExtra(String key) returns null

So i have this code here;
myIntent.putExtra("schedule",serializableClass);
and this intent goes to my Broadcast Reciever and i did get that serializable as below,
public void onRecieve(Context context, Intent intent)
{
Schedule s = (Schedule) intent.getSerializableExtra("schedule");
}
but it always returns even though when i put the Extras its not null, even checked before passing it on myIntent.putExtra() i really don't know what happen returns, why does it always returns null?.. anyone knows this problem?
The cast is wrong, i would be more easier to pass the serialized string and do deserialization. I' m using this class.
public final class ObjectSerializer {
private ObjectSerializer() {
}
public static String serialize(Serializable obj) throws IOException {
if (obj == null)
return "";
try {
ByteArrayOutputStream serialObj = new ByteArrayOutputStream();
ObjectOutputStream objStream = new ObjectOutputStream(serialObj);
objStream.writeObject(obj);
objStream.close();
return encodeBytes(serialObj.toByteArray());
} catch (Exception e) {
throw new IOException("Serialization error: " + e.getMessage(), e);
}
}
public static Object deserialize(String str) throws IOException {
if (str == null || str.length() == 0)
return null;
try {
ByteArrayInputStream serialObj = new ByteArrayInputStream(
decodeBytes(str));
ObjectInputStream objStream = new ObjectInputStream(serialObj);
return objStream.readObject();
} catch (Exception e) {
throw new IOException("Serialization error: " + e.getMessage(), e);
}
}
public static String encodeBytes(byte[] bytes) {
StringBuffer strBuf = new StringBuffer();
for (int i = 0; i < bytes.length; i++) {
strBuf.append((char) (((bytes[i] >> 4) & 0xF) + ('a')));
strBuf.append((char) (((bytes[i]) & 0xF) + ('a')));
}
return strBuf.toString();
}
public static byte[] decodeBytes(String str) {
byte[] bytes = new byte[str.length() / 2];
for (int i = 0; i < str.length(); i += 2) {
char c = str.charAt(i);
bytes[i / 2] = (byte) ((c - 'a') << 4);
c = str.charAt(i + 1);
bytes[i / 2] += (c - 'a');
}
return bytes;
}
}
after that use like this:
String scheduleSerialization = ObjectSerializer.serialize(schedule);
myIntent.putExtra("schedule",scheduleSerialization);
the last thing to do is:
public void onRecieve(Context context, Intent intent)
{
String serial = intent.getStringExtra("schedule");
if(serial!=null)
Schedule s = (Schedule) ObjectSerializer.deserialize(serial) ;
}
Using Serializable on Android is discouraged because it is slow. If you look at the android source code you will see that
the usually break down the information into multiple keys and send them as primitive types (Integer, String, etc..)
when that can't be done, the will use a Parcelable object

What is the function of "Intent.ACTION_PRE_BOOT_COMPLETED"?

I want to know the exact functionality of Intent.ACTION_PRE_BOOT_COMPLETED. Currently, my requirement is to complete the task before the completion of booting of the device, i.e. before the call of Intent.ACTION_BOOT_COMPLETED.
Can anyone guide me on how to proceed to fulfill the requirement? Any help in this regard will be well appreciated.
ACTION_PRE_BOOT_COMPLETED is sended in ActivityManagerService.java::systemReady.
But to received it, the uid of your application must be system(1000).
for (int i=ris.size()-1; i>=0; i--) {
if ((ris.get(i).activityInfo.applicationInfo.flags
&ApplicationInfo.FLAG_SYSTEM) == 0) {
ris.remove(i);
}
}
Further more, this broadcast could only be received once in each upgrade( not very sure here, maybe should be each wipe data).
Note code below, if the target is in lastDoneReceivers, it will be removed.
ArrayList<ComponentName> lastDoneReceivers = readLastDonePreBootReceivers();
final ArrayList<ComponentName> doneReceivers = new ArrayList<ComponentName>();
for (int i=0; i<ris.size(); i++) {
ActivityInfo ai = ris.get(i).activityInfo;
ComponentName comp = new ComponentName(ai.packageName, ai.name);
if (lastDoneReceivers.contains(comp)) {
ris.remove(i);
i--;
}
}
lastDoneReceivers is read from file /data/system/called_pre_boots.dat.
private static File getCalledPreBootReceiversFile() {
File dataDir = Environment.getDataDirectory();
File systemDir = new File(dataDir, "system");
File fname = new File(systemDir, "called_pre_boots.dat");
return fname;
}
static final int LAST_DONE_VERSION = 10000;
private static ArrayList<ComponentName> readLastDonePreBootReceivers() {
ArrayList<ComponentName> lastDoneReceivers = new ArrayList<ComponentName>();
File file = getCalledPreBootReceiversFile();
FileInputStream fis = null;
try {
fis = new FileInputStream(file);
DataInputStream dis = new DataInputStream(new BufferedInputStream(fis, 2048));
int fvers = dis.readInt();
if (fvers == LAST_DONE_VERSION) {
String vers = dis.readUTF();
String codename = dis.readUTF();
String build = dis.readUTF();
if (android.os.Build.VERSION.RELEASE.equals(vers)
&& android.os.Build.VERSION.CODENAME.equals(codename)
&& android.os.Build.VERSION.INCREMENTAL.equals(build)) {
int num = dis.readInt();
while (num > 0) {
num--;
String pkg = dis.readUTF();
String cls = dis.readUTF();
lastDoneReceivers.add(new ComponentName(pkg, cls));
}
}
}
} catch (FileNotFoundException e) {
} catch (IOException e) {
Slog.w(TAG, "Failure reading last done pre-boot receivers", e);
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
}
}
}
return lastDoneReceivers;
}
There is no such action as ACTION_PRE_BOOT_COMPLETED. I think that you normally can't fill your requirement. May be there is some mechanism for system signed apps to do that.

Categories

Resources