2009-02-23 75 views
6

Ứng dụng Android của tôi yêu cầu nhập mật khẩu trong hoạt động đầu tiên. Tôi muốn có thể tự động gửi ứng dụng trở lại màn hình nhập mật khẩu sau khi ứng dụng không hoạt động trong một khoảng thời gian cố định.Khóa ứng dụng android sau một khoảng thời gian nhàn rỗi nhất định

Ứng dụng có nhiều hoạt động, nhưng tôi muốn thời gian chờ là toàn cầu cho tất cả các hoạt động. Vì vậy, sẽ không đủ để tạo một chuỗi hẹn giờ theo phương thức onPause() của Activity.

Tôi không chắc chắn định nghĩa tốt nhất cho ứng dụng ở chế độ không hoạt động là gì, nhưng không có hoạt động nào đang hoạt động sẽ là đủ.

Trả lời

5

Tôi biết câu trả lời khác được chấp nhận rồi, nhưng tôi đi qua làm việc này trên một vấn đề tương tự và nghĩ tôi sẽ thử một phương pháp tiếp cận đơn giản hơn nhiều mà tôi đã tìm ra tôi có thể là tài liệu tốt nếu bất kỳ ai khác muốn cố gắng đi cùng mã path.enter ở đây

Ý tưởng chung là chỉ theo dõi thời gian của đồng hồ hệ thống trong một SharedPreference bất cứ khi nào bất kỳ Activity tạm dừng - âm thanh đủ đơn giản, nhưng than ôi, có một lỗ hổng bảo mật nếu đó là tất cả những gì bạn sử dụng, vì đồng hồ đó reset khi khởi động lại. Để làm việc xung quanh điều đó:

  • Có một lớp con hoặc lớp tĩnh được chia sẻ với trạng thái mở khóa toàn cầu (ban đầu là sai). Giá trị này sẽ tồn tại miễn là quá trình đăng ký của bạn.
  • Tiết kiệm thời gian hệ thống (realtime kể từ khi khởi động) trong mỗi Activity có liên quan của một số SharedPreference nếu trạng thái ứng dụng hiện tại được mở khóa.
  • Nếu trạng thái mở khóa từ khi khởi động ứng dụng là sai (khởi động ứng dụng sạch - ứng dụng hoặc điện thoại được khởi động lại), hãy hiển thị màn hình khóa. Nếu không, hãy kiểm tra giá trị của SharedPreference tại onResume của hoạt động có thể khóa; nếu nó không tồn tại hoặc lớn hơn giá trị SharedPreference + khoảng thời gian chờ, cũng hiển thị màn hình khóa.
  • Khi ứng dụng được mở khóa, hãy đặt trạng thái mở khóa từ khi khởi động ứng dụng thành true.

Ngoài thời gian chờ, cách tiếp cận này cũng sẽ tự động khóa ứng dụng của bạn nếu ứng dụng của bạn bị giết và khởi động lại hoặc nếu điện thoại khởi động lại, nhưng tôi không nghĩ đó là vấn đề đặc biệt tồi tệ đối với hầu hết các ứng dụng. Đó là một chút quá an toàn và có thể khóa không cần thiết trên người dùng chuyển đổi công việc rất nhiều, nhưng tôi nghĩ đó là một sự cân bằng đáng giá để giảm mã và độ phức tạp bằng cách loại bỏ hoàn toàn mọi mối quan tâm nền/wakelock (không có dịch vụ, báo thức hoặc người nhận cần thiết).

Để làm việc xung quanh quá trình giết chết khóa ứng dụng bất kể thời gian, thay vì chia sẻ một singleton ứng dụng cho mở khóa kể từ khi khởi động, bạn có thể sử dụng SharedPreference và đăng ký người nghe cho mục đích phát sóng hệ thống khởi động để đặt Tùy chọn đó sai. Điều đó làm tăng thêm một số sự phức tạp của giải pháp ban đầu với lợi ích là một chút thuận tiện hơn trong trường hợp quá trình của ứng dụng bị giết trong khi được đặt trong khoảng thời gian chờ, mặc dù đối với hầu hết các ứng dụng, nó có thể quá mức cần thiết.

3

Tôi xử lý việc này bằng cách sử dụng AlarmManager để lên lịch và hủy hành động hết thời gian chờ.

Sau đó, trong sự kiện onPause() của tất cả các hoạt động của tôi, tôi lên lịch báo thức. Trong sự kiện onResume() của tất cả các hoạt động của tôi, tôi kiểm tra xem báo thức có tắt hay không. Nếu báo thức tắt, tôi tắt ứng dụng của mình. Nếu báo thức vẫn chưa tắt, tôi sẽ hủy báo thức.

Tôi đã tạo Timeout.java để quản lý báo thức của mình. Khi báo thức tắt mục đích được kích hoạt:

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)); 

    } 

} 

Sau đó, tôi đã tạo một dịch vụ để nắm bắt ý định được tạo bởi báo thức. Nó đặt ra một số trạng thái toàn cầu trong trường hợp của tôi về lớp ứng dụng để chỉ ra rằng ứng dụng nên khóa:

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; 
    } 

} 

Cuối cùng, tôi đã tạo ra một lớp con của Hoạt động rằng tất cả các hoạt động ứng dụng của tôi lớp con từ để quản lý khóa và mở khóa:

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(); 
     } 

    } 

} 

Sử dụng onPause and onResume để bắt đầu và ngừng thời gian chờ mang lại cho tôi các ngữ nghĩa sau đây. Miễn là một trong các hoạt động của ứng dụng của tôi đang hoạt động, đồng hồ hết giờ không hoạt động. Vì tôi đã sử dụng loại AlarmManager.RTC, bất cứ khi nào điện thoại chuyển sang chế độ ngủ, đồng hồ hết giờ sẽ chạy. Nếu thời gian chờ xảy ra trong khi điện thoại đang ngủ thì dịch vụ của tôi sẽ nhận hết thời gian chờ ngay khi điện thoại thức dậy. Ngoài ra, đồng hồ chạy khi bất kỳ hoạt động nào khác đang mở.

Đối với một phiên bản chi tiết hơn trong số này, bạn có thể thấy tôi thực sự thực hiện chúng trong ứng dụng của tôi https://github.com/bpellin/keepassdroid

+0

bạn có thể làm rõ những gì diễn ra trong tệp kê khai không? – yanokwa

+0

mã của bạn không bao giờ sử dụng lớp TimeoutService. Bạn có thể cho biết cách thức và nơi bạn đang sử dụng? – Peanut

+0

Tôi đã sử dụng để khởi động dịch vụ bất cứ khi nào ứng dụng bắt đầu và dừng lại bất cứ khi nào ứng dụng kết thúc. Điều này tạo ra rất nhiều email có liên quan, bởi vì mọi người nhìn thấy dịch vụ đang chạy và giả sử nó đang sử dụng các tài nguyên quá mức. Vì vậy, tôi đã thêm mã trong các phương thức bắt đầu và dừng của Timeout để bắt đầu và ngừng dịch vụ. Tôi đã chỉnh sửa câu trả lời của mình để phản ánh điều này. –

0

Đây thực sự là một bài đăng hữu ích đối với tôi. Để trở lại khái niệm được đưa ra bởi @Yoni Samlan. Tôi đã triển khai theo cách này

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(); 
     } 
     } 
    } 

Phương thức tạm dừng cuộc gọi từ phương thức onPause and resume from onResume.

Các vấn đề liên quan