2009-02-23 4 views
6

Приложение для Android требует ввода пароля для первого действия. Я хочу, чтобы иметь возможность автоматически отправлять приложение обратно на экран ввода пароля после того, как приложение простаивает в течение фиксированного периода времени.Заблокируйте приложение для Android после определенного количества времени простоя

Приложение имеет несколько видов деятельности, но я хотел бы, чтобы таймаут был глобальным для всех видов деятельности. Таким образом, было бы недостаточно создать поток таймера в методе onPause() для Activity.

Я не уверен, какое лучшее определение для простаивания приложения, но активных действий недостаточно.

ответ

5

Я знаю еще один ответ принят уже, но я наткнулся на это работы на аналогичной проблеме и думаю я Я собираюсь попробовать альтернативный гораздо более простой подход, который, как я полагал, может быть документирован, если кто-то еще захочет попытаться спуститься по тому же пути. Код здесь

Общая идея состоит в том, чтобы отслеживать время системных часов в SharedPreference всякий раз, когда какое-либо действие приостанавливается - звучит достаточно просто, но, увы, есть дыра в безопасности, если это все, что вы используете, поскольку эти часы сбрасываются при перезагрузке. Чтобы обойти, что:

  • Иметь Application подкласс или общий статический класса одноплодного с глобальным разблокированы-так-ботинка состоянием (изначально лжи). Это значение должно соответствовать процессу приложения.
  • Сохраните системное время (realtime с момента загрузки) в каждом соответствующем Activity в SharedPreference, если текущее состояние приложения разблокировано.
  • Если состояние с открытым доступом после загрузки по умолчанию равно false (чистый запуск приложения - либо приложение, либо телефон перезапустился), отобразите экран блокировки. В противном случае проверьте значение SharedPreference в позиции on locks блокируемой активности; если он отсутствует или больше значения SharedPreference + интервал времени ожидания, также отображается экран блокировки.
  • Когда приложение разблокировано, установите для приложения по умолчанию состояние с разблокировкой-с-загрузкой значение true.

Помимо таймаута, этот подход также автоматически блокирует ваше приложение, если ваше приложение будет убито и перезагрузится, или если ваш телефон перезагрузится, но я не думаю, что это особенно плохо для большинства приложений. Это немного чрезмерно безопасно и может заблокировать пользователей, у которых много задач, но я думаю, что это выгодный компромисс для уменьшения кода и сложности путем полного удаления любых проблем с фоновым процессом/wakelock (никаких служб, аварийных сигналов или приемников не требуется).

Чтобы обойти процесс-убийство, заблокировав приложение независимо от времени, вместо совместного использования однопользовательского однопользовательского режима для разблокировки с момента загрузки, вы можете использовать SharedPreference и зарегистрировать прослушиватель для намерения загрузки системы, чтобы установить, что предпочтение ложный. Это снова добавляет некоторую сложность первоначального решения, при этом преимущество будет немного более удобным в том случае, если процесс приложения будет убит во время фонового интервала времени ожидания, хотя для большинства приложений это, вероятно, слишком велико.

3

Я справился с этим, используя AlarmManager, чтобы запланировать и отменить действие тайм-аута.

Затем в событии onPause() всех моих действий я планирую будильник. В событии onResume() всех моих действий я проверяю, отключен ли будильник. Если будильник погас, я отключил свое приложение. Если будильник еще не погас, я отменяю его.

Я создал Timeout.java для управления своими тревогами. Когда сигнал тревоги отключается, увольнение увольняется:

public class Timeout { 
    private static final int REQUEST_ID = 0; 
    private static final long DEFAULT_TIMEOUT = 5 * 60 * 1000; // 5 minutes 

    private static PendingIntent buildIntent(Context ctx) { 
     Intent intent = new Intent(Intents.TIMEOUT); 
     PendingIntent sender = PendingIntent.getBroadcast(ctx, REQUEST_ID, intent, PendingIntent.FLAG_CANCEL_CURRENT); 

     return sender; 
    } 

    public static void start(Context ctx) { 
     ctx.startService(new Intent(ctx, TimeoutService.class)); 

     long triggerTime = System.currentTimeMillis() + DEFAULT_TIMEOUT; 

     AlarmManager am = (AlarmManager) ctx.getSystemService(Context.ALARM_SERVICE); 

     am.set(AlarmManager.RTC, triggerTime, buildIntent(ctx)); 
    } 

    public static void cancel(Context ctx) { 
     AlarmManager am = (AlarmManager) ctx.getSystemService(Context.ALARM_SERVICE); 

     am.cancel(buildIntent(ctx)); 

     ctx.startService(new Intent(ctx, TimeoutService.class)); 

    } 

} 

Затем я создал службу для захвата намерения, созданного будильником. Она устанавливает некоторое глобальное состояние в моем экземпляре класса приложения, чтобы указать, что приложение должно блокировать:

public class TimeoutService extends Service { 
    private BroadcastReceiver mIntentReceiver; 

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

     mIntentReceiver = new BroadcastReceiver() { 
      @Override 
      public void onReceive(Context context, Intent intent) { 
       String action = intent.getAction(); 

       if (action.equals(Intents.TIMEOUT)) { 
        timeout(context); 
       } 
      } 
     }; 

     IntentFilter filter = new IntentFilter(); 
     filter.addAction(Intents.TIMEOUT); 
     registerReceiver(mIntentReceiver, filter); 

    } 

    private void timeout(Context context) { 
     App.setShutdown(); 

     NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); 
     nm.cancelAll(); 
    } 

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

     unregisterReceiver(mIntentReceiver); 
    } 

    public class TimeoutBinder extends Binder { 
     public TimeoutService getService() { 
      return TimeoutService.this; 
     } 
    } 

    private final IBinder mBinder = new TimeoutBinder(); 

    @Override 
    public IBinder onBind(Intent intent) { 
     return mBinder; 
    } 

} 

Наконец, я создал подкласс деятельности, что все виды деятельности подкласса моего приложения от управления запиранием и отпирания:

public class LockingActivity extends Activity { 

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

     Timeout.start(this); 
    } 

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

     Timeout.cancel(this); 
     checkShutdown(); 
    } 

    private void checkShutdown() { 
     if (App.isShutdown()) { 
      finish(); 
     } 

    } 

} 

Использование onPause и onResume для запуска и остановки таймаута дает мне следующую семантику. Пока активна одна из моих приложений, часы тайм-аута не работают. Поскольку я использовал Alarm Type AlarmManager.RTC, всякий раз, когда телефон переходит в спящий режим, тайм-аут запускается. Если тайм-аут происходит, когда телефон спит, мой сервис будет получать таймаут, как только телефон просыпается. Кроме того, часы запускаются, когда открыто какое-либо другое действие.

Для более подробной версии этого, вы можете увидеть, как я на самом деле реализовать их в моем приложении https://github.com/bpellin/keepassdroid

+0

Можете ли вы прояснить, что входит в манифест? – yanokwa

+0

Ваш код никогда не использует класс TimeoutService. Не могли бы вы показать, как и где вы это используете? – Peanut

+0

Раньше я запускал службу при запуске приложения и останавливал его всякий раз, когда приложение заканчивалось. Это вызвало много обеспокоенных писем, потому что люди увидели, что работает служба, и предположили, что она использует неоправданные ресурсы. Итак, я добавил код в методах запуска и остановки Timeout для запуска и остановки службы. Я отредактировал свой ответ, чтобы отразить это. –

0

Это был действительно полезный пост для меня. Чтобы поддержать концепцию, данную @Yoni Samlan. Я внедрил его таким образом

public void pause() { 
     // Record timeout time in case timeout service is killed  
     long time = System.currentTimeMillis();  
     SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); 
     SharedPreferences.Editor edit = preferences.edit(); 
     edit.putLong("Timeout_key", time);// start recording the current time as soon as app is asleep 
     edit.apply(); 
    } 

    public void resume() {  
     // Check whether the timeout has expired 
     long cur_time = System.currentTimeMillis(); 
     SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); 
     long timeout_start = preferences.getLong("Timeout_key", -1); 
     // The timeout never started 
     if (timeout_start == -1) { 
      return; 
     } 
     long timeout; 
     try { 
      //timeout = Long.parseLong(sTimeout); 
      timeout=idle_delay; 
     } catch (NumberFormatException e) { 
      timeout = 60000; 
     } 
     // We are set to never timeout 
     if (timeout == -1) { 
      return; 
     } 
     if (idle){ 
     long diff = cur_time - timeout_start; 
     if (diff >= timeout) { 
      //Toast.makeText(act, "We have timed out", Toast.LENGTH_LONG).show(); 
      showLockDialog(); 
     } 
     } 
    } 

Метод приостановки вызова из onPause и метод возобновления from onResume.

Смежные вопросы