2012-02-02 8 views
6

So che questa domanda è stata posta più volte, ma nessuno è riuscito a trovare una risposta funzionante da quello che ho visto.Sms ContentObserver onChange() si attiva più volte

Sto lavorando su un'app per intercettare messaggi di testo e in base al numero di invio, pop-up con un avviso personalizzato. Ho funzionato perfettamente con un ricevitore broadcast, tuttavia se l'utente ha installato goSms, il metodo onReceive() non viene mai chiamato come goSms lo interrompe prima che raggiunga la mia app.

Per aggirare questo problema, sto cercando un osservatore di contenuto su content://sms/ Sta funzionando bene, tuttavia lo onChange() viene chiamato due volte, con esattamente gli stessi parametri. Ive ha provato a controllare i timestamp, ma sono uguali, così come il tipo e ogni altro parametro che ho impostato.

Da quello che ho visto, questo è un problema comune, ma non uno che ho visto risposta da nessuna parte.

@Override 
public void onChange(boolean selfChange) { 
    super.onChange(selfChange); 
    querySMS(); 
} 

protected void querySMS() { 
    Cursor cur = getContentResolver().query(u, null, null, null, null); 
    cur.moveToNext(); // this will make it point to the first record, which is the last SMS sent 
    String type = cur.getString(cur.getColumnIndex("type")); 
    String body = cur.getString(cur.getColumnIndex("body")); //content of sms 
    String add = cur.getString(cur.getColumnIndex("address")); //phone num 
    if (type.equals("1")) { 
     if (add.equals(Test.SENDER)) {    
      String[] bodys = body.split(" ", 7); 
      if (bodys[0].equals("test")) { 
       test = true; 
      } 
      cat = bodys[1]; 
      level = bodys[2]; 
      urgency = bodys[3]; 
      certainty = bodys[4]; 
      carrier = bodys[5]; 
      message = bodys[6]; 
      final Intent intent = new Intent(context, AlertActivity.class); 
      Bundle b = new Bundle(); 
      b.putString("title", cat); 
      b.putString("certainty", certainty); 
      b.putString("urgency", urgency); 
      b.putString("level", level); 
      b.putString("message", message); 
      b.putBoolean("test", test); 
      intent.putExtras(b); 
      intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 
      intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 
      TelephonyManager manager = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE); 
      carrierName = manager.getNetworkOperatorName(); 
      if (carrierName.replaceAll(" ", "").equals(carrier)) { 

       context.startActivity(intent); 
      } else { 
       //testing 
       Toast.makeText(context, carrierName.replaceAll(" ", ""), Toast.LENGTH_LONG).show(); 
      } 
     } 
    } 
} 

A causa della onChange() essere licenziato due volte, Im ottenendo due avvisi pure. Non posso per la vita di me capire un modo per aggirare questo.

+1

i collegamenti alle altre risposte (incomplete) potrebbero essere utili – KevinDTimm

risposta

4

Se i due sono identici:
archivio ogni messaggio recv'd
confrontarlo con precedenti messaggi recv'd
se non trovato, processo
se trovato, ignorare il messaggio

La vita di i messaggi archiviati dovrebbero essere infinitesimali, un piccolo buffer circolare di 5 messaggi dovrebbe andare bene.

+0

ma il messaggio viene ricevuto solo una volta. non viene due volte. tbh, non so nemmeno da cosa viene attivato il secondo 'onChange'. – r2DoesInc

+2

Ah. ho accoppiato l'idea con http://stackoverflow.com/questions/7012703/android-detect-sms-outgoing-incorrect-count e l'ho ottenuto funzionante. Penso di aver frainteso quello che volevi dire la prima volta che l'ho letto. Ho creato un 'arrayList' statico e l'ho usato per controllare. \t \t \t 'if (! Ids.contains (id)) {ids.add (id); context.startActivity (intent);}' – r2DoesInc

3

È possibile salvare l'ID dell'ultimo messaggio e confrontarlo con l'ID del messaggio restituito da cur in onChange. puoi quindi semplicemente ignorare il messaggio se gli ID sono uguali.

// might contain mistakes, but you'll get the idea: 
protected void querySMS() { 
    Cursor cur = getContentResolver().query(u, null, null, null, null); 
    cur.moveToNext(); 
    if (lastId == cur.getLong(cur.getColumnIndex("_id"))) 
     return; 
    lastId = cur.getLong(cur.getColumnIndex("_id")); 
    ... //continue as it was 
} 

Tuttavia - GO SMS impedisce solo altre app di da recieving Broadcast se l'utente ha selezionato questa opzione (Impostazioni Ricevere - Disabilitare altro messaggio di notifica) - quindi se l'utente non vuole altre applicazioni disturbarlo - I pensa che sia una buona idea non farlo.

+0

L'app su cui sto lavorando non è quella che dovrebbe essere ignorata, mai. È preinstallato sui dispositivi e ha la precedenza assoluta su qualsiasi altra funzione attualmente in esecuzione sul telefono. Ho fatto qualcosa di simile a questo, se guardi nei commenti della risposta qui sotto puoi vedere. – r2DoesInc

+1

capisci che lo snippet che hai pubblicato dovrebbe andare molto, molto tempo prima che possa essere utilizzato nell'app che deve venire preintallata, vero? – Vladimir

+0

oh sì certo. Ive ha appena iniziato il progetto. ha una lunga strada da percorrere – r2DoesInc

4

Ecco il mio codice, funziona bene per me

public class SmsObserver extends ContentObserver { 
    private Context context; 
    private static int initialPos; 
    private static final String TAG = "SMSContentObserver"; 
    private static final Uri uriSMS = Uri.parse("content://sms/sent"); 

    public SmsObserver(Handler handler, Context ctx) { 
     super(handler); 
     context = ctx; 
     initialPos = getLastMsgId(); 

    } 

    @Override 
    public void onChange(boolean selfChange) { 
     super.onChange(selfChange); 
     queryLastSentSMS(); 
    } 

    public int getLastMsgId() { 

     Cursor cur = context.getContentResolver().query(uriSMS, null, null, null, null); 
     cur.moveToFirst(); 
     int lastMsgId = cur.getInt(cur.getColumnIndex("_id")); 
     Log.i(TAG, "Last sent message id: " + String.valueOf(lastMsgId)); 
     return lastMsgId; 
    } 

    protected void queryLastSentSMS() { 

     new Thread(new Runnable() { 

      @Override 
      public void run() { 
       Cursor cur = 
        context.getContentResolver().query(uriSMS, null, null, null, null); 

       if (cur.moveToNext()) { 


        try { 
         if (initialPos != getLastMsgId()) { 
          // Here you get the last sms. Do what you want. 
          String receiver = cur.getString(cur.getColumnIndex("address")); 
          System.out.println(" Receiver Ph no :"+receiver); 


          // Then, set initialPos to the current position. 
          initialPos = getLastMsgId(); 
         } 
        } catch (Exception e) { 
         // Treat exception here 
        } 
       } 
       cur.close(); 
      } 
     }).start(); 

    } 

}//End of class SmsObserver 
0

mi basta usare SharedPreference notare all'ultimo informazioni SMS (come: id\type ...). se è lo stesso, lo farò return.

Problemi correlati