Блокировка Android-приложения после определенного времени простоя - PullRequest
6 голосов
/ 23 февраля 2009

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

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

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

Ответы [ 4 ]

7 голосов
/ 28 июня 2011

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

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

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

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

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

3 голосов
/ 28 ноября 2009

Я справился с этим с помощью 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;
    }

}

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

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 для запуска и остановки тайм-аута дает мне следующую семантику. Пока одно из действий моего приложения активно, часы таймаута не работают. Поскольку я использовал тип AlarmManager.RTC, каждый раз, когда телефон переходит в спящий режим, срабатывает тайм-аут. Если время ожидания истекло, когда телефон спит, моя служба определит время ожидания, как только телефон проснется. Кроме того, часы работают, когда открыты любые другие действия.

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

2 голосов
/ 23 февраля 2009

Узнайте, как OpenIntents Safe реализует эту функцию.

0 голосов
/ 06 ноября 2014

Это был действительно полезный пост для меня. Чтобы поддержать концепцию, данную @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();
        }
        }
    } 

Вызов метода pause из onPause и возобновление метода из onResume.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...