2011-11-23 16 views
6

Sto sviluppando un'applicazione che deve visualizzare una schermata di passcode ogni volta che un utente lascia l'app e torna indietro (tramite un blocco schermo o tornando alla schermata principale attraverso il retro o tasto home). L'ho avuto a lavorare utilizzando il seguente:Sapere quando mostrare il blocco del codice d'accesso

L'attività di partenza avrebbe chiamato per il controllo codice di accesso all'avvio, e per ciascuna azione aggiunta la seguente funzionalità per il loro metodo onPause:

@Override 
public void onPause() { 
    super.onPause(); 

    if (!isFinishing()) { 
    new PasscodeCheckTask(this.getApplicationContext(),this).execute(); 
    } 
} 

Il PassocdeCheckTask ha il seguente. Esso controlla per vedere se lo schermo è spento o l'applicazione non è più in background

public class PasscodeCheckTask extends AsyncTask<Void, Void, Boolean> { 

    public static final int CHECK_PASSCODE = 0; 

    private Context mActivityApplicationContext; 
    private Context mActivityContext; 

    public PasscodeCheckTask(Context applicationContext, Context activityContext){ 
     mActivityApplicationContext = applicationContext; 
     mActivityContext = activityContext; 
    } 

    @Override 
    protected Boolean doInBackground(Void... params) { 
     Boolean result = false; 

     if (!((PowerManager)mActivityApplicationContext.getSystemService(android.content.Context.POWER_SERVICE)).isScreenOn() || 
      !isAppOnForeground(mActivityApplicationContext)) { 
      result = true; 
     } 
     return result; 
    } 

    @Override 
    protected void onPostExecute(Boolean result) { 
     if (result) { 
      // Start passcode activity to check for passcode 
      /* CODE HERE */ 
      ((Activity)mActivityContext).startActivityForResult(intent, CHECK_PASSCODE); 
     } 
    } 

    protected boolean isAppOnForeground(final Context context) { 
     List<RunningAppProcessInfo> appProcesses = ((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE)).getRunningAppProcesses(); 

     if (appProcesses == null) { 
      return false; 
     } 

     final String packageName = context.getPackageName(); 
     for (RunningAppProcessInfo appProcess : appProcesses) { 
      if ((appProcess.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND) && 
       appProcess.processName.equals(packageName)) { 
       return true; 
      } 
     } 
     return false; 
    } 
} 

L'attività Passcode avrebbe finito quando fatto, e l'attività di chiamata sarebbe moveTaskToBackground (vero) se il codice non ha passare. Questo sistema ha funzionato magnificamente fino a quando l'ho provato su un HTC Evo con mikg ROM. Per qualche motivo, appProcess.importance non si presentava mai come IMPORTANCE_FOREGROUND. Era sempre IMPORTANCE_BACKGROUND. Pertanto, il passcode verrebbe SEMPRE richiamato, anche se l'app non è mai passata in secondo piano.

Ho provato DropBox su quel telefono (che ha anche un blocco passcode), e ha funzionato magnificamente. Non riesco a trovare un modo diverso per sapere quando un'app è passata in secondo piano o se viene portata indietro dallo sfondo. Qualche idea su come farlo funzionare?

+1

Davvero non dovrebbe essere necessario fare qualcosa di simile. Cosa succede se l'utente blocca il telefono mentre utilizza la tua app? Poi devono fare il loro lockscreen e poi il lockscreen. Potrei essere punito per questo, ma la schermata di blocco di Android è sufficiente. Se stai facendo qualcosa di così importante che hai bisogno di avere la tua schermata di blocco, forse dovresti riconsiderare la possibilità di metterla su un telefono. –

+0

È necessario e si occupa delle informazioni private dell'utente. Comprendo la preoccupazione, ma un passcode è utile per questo. – Chewie

+0

è una specie di commento strano @KurtisNusbaum. Uso Dropbox sul mio telefono e ho memorizzato molte informazioni personali molto sensibili. Come la maggior parte degli account Dropbox, credo. Non puoi essere molto serio quando dici che non è una buona idea proteggere tali app con una password. Ci sono casi in cui una password è un'idea molto, molto saggia, se non obbligatoria, si potrebbe anche obiettare. Penso che anche l'app della Galleria debba avere una password, sono un po 'appassionato della mia privacy e le persone tendono a giocare con i telefoni di eachothers. – slinden77

risposta

4

In onStop() di ogni attività, aggiornare un membro dati statici con il tempo in cui si è lasciata l'attività. In onStart() di ciascuna attività, controllare quella volta e, se supera una soglia di timeout, visualizzare l'attività di autenticazione. Permetti all'utente di impostare il valore di timeout, in modo che se non vogliono essere disturbati ogni pochi secondi, possono controllarlo.

+0

Hmm, vedrò se funziona. Presumo che la variabile statica sia estesa a tutta l'applicazione? – Chewie

+0

@Chewie: "Presumo che la variabile statica sia a livello di applicazione?" - tecnicamente è a livello di processo, ma di solito equivale alla stessa cosa. – CommonsWare

+0

Gotcha, che ha senso – Chewie

1

Mi è piaciuto l'approccio basato sul tempo, ho faticato per un po 'a farlo funzionare in un modo piacevole. L'approccio basato sul tempo funziona bene. Ho fatto un corso per un utilizzo più semplice.

public class PinCodeCheck { 

    private static long INIT_TIME   = 0; 
    private static PinCodeCheck ref   = null; 
    private static SharedPreferences values = null; 

    private PinCodeCheck(Context context){ 
     values = context.getSharedPreferences("com.example.xxx", 0); //use your preferences file name key! 
    }//end constructor 

    public static synchronized PinCodeCheck getInstance(Context context) { 
     if (ref == null){ 
      ref = new PinCodeCheck(context); 
     } 
     return ref; 
    }//end method 

    public void init(){ 
     PinCodeCheck.INIT_TIME = System.currentTimeMillis();  
    }//end method 

    public void forceLock(){ 
     PinCodeCheck.INIT_TIME = 0;  
    }//end method 

    public boolean isLocked(){ 
     long currentTime = System.currentTimeMillis(); 
     long threshold  = values.getLong(Keys.PASSWORD_PROTECT_TIMEOUT, 30000); // check here, might change in between calls 
     if (currentTime - PinCodeCheck.INIT_TIME > threshold){ 
      return true; 
     } 
     return false;  
    }//end method 
}//end class 

USO

private static PinCodeCheck check = PinCodeCheck.getInstance(context); 

@Override 
public void onResume() { 
    super.onResume(); 

    if (check.isLocked()) { 
     showDialog();    
    } 
}//end method 

@Override 
public void onPause() {   
    super.onPause(); 

    check.init(); 
}//end method 
+0

Ciao, sto provando il tuo approccio per una delle mie app. Ma sto ricevendo errori in questa linea. values ​​= Preferences.init (context); come "Il metodo init (Context) non è definito per il tipo Preferences" – dhiku

+0

ah sì, è un rerefence alla mia classe personalizzata 'SharedPreferences'. Modificherò l'esempio ... – slinden77

Problemi correlati