CustomLockService.java :  » UnTagged » mylockforandroid » i4nc4mp » myLockAdvanced » Android Open Source

Android Open Source » UnTagged » mylockforandroid 
mylockforandroid » i4nc4mp » myLockAdvanced » CustomLockService.java
package i4nc4mp.myLockAdvanced;

import i4nc4mp.myLockAdvanced.ManageKeyguard.LaunchOnKeyguardExit;
import android.app.Notification;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.os.Handler;
import android.os.PowerManager;
import android.os.SystemClock;
import android.provider.Settings.SettingNotFoundException;
import android.util.Log;


//advanced mode- lockscreen wakes up with any key
//supports advanced power save for setting locked-down buttons (screen stays off)
//or for reducing the timeout while in lockscreen mode
public class CustomLockService extends MediatorService {
  
  public boolean persistent = false;
  public boolean timeoutenabled = false;
  
  public int timeoutpref = 15;
  
  public int patternsetting = 0;
  //we'll see if the user has pattern enabled when we startup
  //so we can disable it and then restore when we finish
  
/* Life-Cycle Flags */
  public boolean shouldLock = true;
  //Flagged true upon Lock Activity exit callback, remains true until StartLock intent is fired.
    
  public boolean PendingLock = false;
  //Flagged true upon sleep, remains true until StartLock sends first callback indicating Create success.
  
  
  public boolean idle = false;
  //when the idle alarm intent comes in we set this true to properly start closing down
  
  Handler serviceHandler;
  Task myTask = new Task();
  
  @Override
  public void onDestroy() {
    super.onDestroy();
    
    if (patternsetting == 1) {
      android.provider.Settings.System.putInt(getContentResolver(), 
          android.provider.Settings.System.LOCK_PATTERN_ENABLED, 1);
      //re-enable pattern lock if applicable
    }
      serviceHandler.removeCallbacks(myTask);
        serviceHandler = null;
        
        unregisterReceiver(idleExit);
        unregisterReceiver(lockStarted);
        unregisterReceiver(lockStopped);
        //unregisterReceiver(homeUnlock);
        
        
        ManageWakeLock.releasePartial();
        
}

  @Override
  public void onRestartCommand() {
    
    SharedPreferences settings = getSharedPreferences("myLock", 0);
    boolean fgpref = settings.getBoolean("FG", true);
    
    //int newtimeout = 0;
    
    //FIXME - implementing implicit intent for lifecycle callbacks.
    //we can use plain broadcast receivers like we do for the idle event.
    
/*========Settings change re-start commands that come from settings activity*/
  
    if (persistent != fgpref) {//user changed pref
      if (persistent) {
          stopForeground(true);//kills the ongoing notif
          persistent = false;
      }
      else doFGstart();//so FG mode is started again
    }  
    else {
/*========Safety start that ensures the settings activity toggle button can work, first press to start, 2nd press to stop*/
        Log.v("toggle request","user first press of toggle after a startup at boot");
      }    
  }
  
  @Override
  public void onFirstStart() {
    SharedPreferences settings = getSharedPreferences("myLock", 0);
    persistent = settings.getBoolean("FG", true);
    
    timeoutenabled = settings.getBoolean("timeout", false);
    
    
    if (persistent) doFGstart();
    //else send a toast telling user what mode is starting and whether stay awake is active
    //perhaps do that in the boot handler service
    
    //we have to toggle pattern lock off to use a custom lockscreen
    try {
      patternsetting = android.provider.Settings.System.getInt(getContentResolver(), android.provider.Settings.System.LOCK_PATTERN_ENABLED);
    } catch (SettingNotFoundException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
    
    if (patternsetting == 1) {      
      android.provider.Settings.System.putInt(getContentResolver(), 
          android.provider.Settings.System.LOCK_PATTERN_ENABLED, 0); 
    }
    
        
    serviceHandler = new Handler();
    ManageWakeLock.acquirePartial(getApplicationContext());
    //if not always holding partial we would only acquire at Lock activity exit callback
    //we found we always need it to ensure key events will not occasionally drop on the floor from idle state wakeup
    
    IntentFilter idleFinish = new IntentFilter ("i4nc4mp.myLockAdvanced.lifecycle.IDLE_TIMEOUT");
    registerReceiver(idleExit, idleFinish);
    
    IntentFilter lockStart = new IntentFilter ("i4nc4mp.myLockAdvanced.lifecycle.LOCKSCREEN_PRIMED");
    registerReceiver(lockStarted, lockStart);
    
    IntentFilter lockStop = new IntentFilter ("i4nc4mp.myLockAdvanced.lifecycle.LOCKSCREEN_EXITED");
    registerReceiver(lockStopped, lockStop);
    
    //IntentFilter home = new IntentFilter ("i4nc4mp.myLockAdvanced.lifecycle.HOMEKEY_UNLOCK");
    //registerReceiver(homeUnlock, home);
  }
  
  BroadcastReceiver lockStarted = new BroadcastReceiver() {
    @Override
      public void onReceive(Context context, Intent intent) {
    int newtimeout = 0;
      
    if (!intent.getAction().equals("i4nc4mp.myLockAdvanced.lifecycle.LOCKSCREEN_PRIMED")) return;

    if (!PendingLock) Log.v("lock start callback","did not expect this call");
    else PendingLock = false;
    
    Log.v("lock start callback","Lock Activity is primed");
    
  //=====Advanced power save timeout reduction----
    //compare our stored user-pref to the currently held system entry
    //update the stored value only if it has changed, and is at least 15
    //FIXME need to store the value in our prefs file
    
      try {
                newtimeout = android.provider.Settings.System.getInt(getContentResolver(), android.provider.Settings.System.SCREEN_OFF_TIMEOUT);
        } catch (SettingNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
        }
        
        if (newtimeout != 1) timeoutpref = newtimeout;
        else Log.v("lock start callback","the system timeout is already 1, our stored pref is " + timeoutpref);
        //for now this code protects us from improperly overwriting our stored timeout pref with the reduced pref
        
        
        //====Advanced power save timeout reduction
        //-----always set the timeout to 1 at lockscreen start success
        android.provider.Settings.System.putInt(getContentResolver(), 
                android.provider.Settings.System.SCREEN_OFF_TIMEOUT, 1);
        
               
        if (timeoutenabled) IdleTimer.start(getApplicationContext());
                
        //if we don't get user unlock callback within user-set idle timeout
        //this alarm kills off the lock activity and this service, restores KG, & starts the user present service
        
        //TODO we're going to want to start at stop it within the activity wakeup as well
        //example: stop when user deliberately wakes lockscreen to use it
        //start again if sleeping again from that screenwake
          
  }};
  
  BroadcastReceiver lockStopped = new BroadcastReceiver() {
    @Override
      public void onReceive(Context context, Intent intent) {
    if (!intent.getAction().equals("i4nc4mp.myLockAdvanced.lifecycle.LOCKSCREEN_EXITED")) return;

    if (shouldLock) Log.v("lock exit callback","did not expect this call"); 
    else shouldLock = true;
        
        
    Log.v("lock exit callback","Lock Activity is finished");
                    
      
    if (!idle) {
      if (timeoutenabled) IdleTimer.cancel(getApplicationContext());
      
      //FIXME
      //this should restore screen off to our known user-pref that is stored in prefs
      //that pref will be set at Lock start, when we detect a change that isn't to 0 or 1
      //(0 used by screebl, 1 is our advanced power save setting)
      android.provider.Settings.System.putInt(getContentResolver(), android.provider.Settings.System.SCREEN_OFF_TIMEOUT, timeoutpref);
        
      PowerManager pm = (PowerManager) getSystemService (Context.POWER_SERVICE); 
         pm.userActivity(SystemClock.uptimeMillis(), false);
         
         }
    else {        
        ManageKeyguard.reenableKeyguard();
        //funny - you will see the regular lockscreen after this call because it is restoring it from time that pattern was off
        //if you slide that, you land at the security pattern screen ;]
        //otherwise if it sleeps like that, next wakeup places us at pattern screen
          
        Intent u = new Intent();
          u.setClassName("i4nc4mp.myLockAdvanced", "i4nc4mp.myLockAdvanced.UserPresentService");
          //service that reacts to the completion of the keyguard to start this mediator again
          startService(u);
        stopSelf();
      }      
  }};
  
  /*BroadcastReceiver homeUnlock = new BroadcastReceiver() {
    @Override
      public void onReceive(Context context, Intent intent) {
    if (!intent.getAction().equals("i4nc4mp.myLockAdvanced.lifecycle.HOMEKEY_UNLOCK")) return;
    
    ManageKeyguard.disableKeyguard(context);
    StartDismiss(context);
    return;
    
    }};*/
  
  BroadcastReceiver idleExit = new BroadcastReceiver() {
    @Override
      public void onReceive(Context context, Intent intent) {
    if (!intent.getAction().equals("i4nc4mp.myLockAdvanced.lifecycle.IDLE_TIMEOUT")) return;
        
    idle = true;
    
    PowerManager myPM = (PowerManager) getApplicationContext().getSystemService(Context.POWER_SERVICE);
      myPM.userActivity(SystemClock.uptimeMillis(), true);
      
      Log.v("mediator idle reaction","preparing to restore KG. timeout pref is " + timeoutpref);
      
      android.provider.Settings.System.putInt(getContentResolver(),
        android.provider.Settings.System.SCREEN_OFF_TIMEOUT, timeoutpref);
      
      //the idle flag will cause proper handling on receipt of the exit callback from lockscreen
      //we basically unlock as if user requested, but then force KG back on in the callback reaction
  }};
  
  class Task implements Runnable {
      public void run() {
        Context mCon = getApplicationContext();
        Log.v("startLock task","executing, PendingLock is " + PendingLock);
        if (!PendingLock) return;//ensures break the attempt cycle if user has aborted the lock
        //user can abort Power key lock by another power key, or timeout sleep by any key wakeup
        
        
        //see if any keyguard exists yet
          ManageKeyguard.initialize(mCon);
          if (ManageKeyguard.inKeyguardRestrictedInputMode()) {
            
            //the keyguard exists here on first try if this isn't a timeout lock
            shouldLock = false;
            StartLock(mCon);//take over the lock
          }
          else serviceHandler.postDelayed(myTask, 500L);
          
            
        }        
      }
  
  @Override
  public void onScreenWakeup() {
    if (!PendingLock) return;
    //we only handle this when we get a screen on that's happening while we are waiting for a lockscreen start callback
      
        
    //This case comes in two scenarios
    //Known bug (seems to be fixed)--- the start of LockActivity was delayed to screen on due to CPU load
    //User aborting a timeout sleep by any key input before 5 second limit
                        
      PendingLock = false;
      if (!shouldLock) {
        //this is the case that the lockscreen still hasn't sent us a start callback at time of this screen on
        shouldLock = true;
      }
        
      
    return;
  }
  
  
  @Override
  public void onScreenSleep() {
    //when sleep after an unlock, start the lockscreen again
    
    if (receivingcall || placingcall) {
      Log.v("mediator screen off","call flag in progress, aborting handling");
      return;//don't handle during calls at all
    }
    
    if (shouldLock) {
          PendingLock = true;
          //means trying to start lock (waiting for start callback from activity)
        
          
          //FIXME stay awake mode is probably preventing the logic in the quiet wake that flags that off
          //---need to move more logic into the timeout task we have running as a screen off will never come in to flag cpuwake off
          
          Log.v("mediator screen off","sleep - starting check for keyguard");

          serviceHandler.postDelayed(myTask, 500L);
          }
        
    
    return;//prevents unresponsive broadcast error
  }
  
  private void StartLock(Context context) {
    
    Intent closeDialogs = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
            context.sendBroadcast(closeDialogs);
    
            
    if (timeoutenabled) ManageKeyguard.disableKeyguard(getApplicationContext());
    //this just calls a temporary KG pause. doing this allows us to be recognized when we later want to re-enable
    //we only need this when the timeout mode is active

            Class w = Lockscreen.class;
            
           

    /* launch UI, explicitly stating that this is not due to user action
             * so that the current app's notification management is not disturbed */
            Intent lockscreen = new Intent(context, w);
            
            
          //new task required for our service activity start to succeed. exception otherwise
            lockscreen.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                    | Intent.FLAG_ACTIVITY_NO_USER_ACTION);
           //without this flag my alarm clock only buzzes once. but with it wakeup doesn't want to happen (also impacts handcent notifs)
                   
            
                    //| Intent.FLAG_ACTIVITY_NO_HISTORY
                    //this flag will tell OS to always finish the activity when user leaves it
                    //when this was on, it was exiting every time it got created. interesting unexpected behavior
                    //even happening when i wait 4 seconds to create it.
                    //| Intent.FLAG_ACTIVITY_NO_ANIMATION)
                    //because we don't need to animate... O_o doesn't really seem to be for this
            
            context.startActivity(lockscreen);
    }
  
  public void DoExit(Context context) {//try the alpha keyguard manager secure exit
      
      //ManageKeyguard.initialize(context);
      PowerManager pm = (PowerManager) getSystemService (Context.POWER_SERVICE); 
      pm.userActivity(SystemClock.uptimeMillis(), false);
      //ensure it will be awake
      
      ManageKeyguard.disableKeyguard(getApplicationContext());
      //advantage here is we don't have to do a task delay
      //because we're already showing on top of keyguard this gets the job done
      
      
      ManageKeyguard.exitKeyguardSecurely(new LaunchOnKeyguardExit() {
            public void LaunchOnKeyguardExitSuccess() {
               Log.v("start", "This is the exit callback");
               }});      
    }
  
  public void StartDismiss(Context context) {
                
        Class w = DismissActivity.class; 
                      
        Intent dismiss = new Intent(context, w);
        dismiss.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK//For some reason it requires this even though we're already an activity
                        | Intent.FLAG_ACTIVITY_NO_USER_ACTION//Just helps avoid conflicting with other important notifications
                        | Intent.FLAG_ACTIVITY_NO_HISTORY//Ensures the activity WILL be finished after the one time use
                        | Intent.FLAG_ACTIVITY_NO_ANIMATION);
                        
        context.startActivity(dismiss);
    }
  
//============Phone call case handling
  
  //we have many cases where the phone reloads the lockscreen even while screen is awake at call end
  //my testing shows it actually comes back after any timeout sleep plus 5 sec grace period
  //then phone is doing a KM disable command at re-wake. and restoring at call end
  

  
  @Override
  public void onCallStart() {
    
    if (!shouldLock) {
      //should is only false while lock activity is alive
      //we don't have to do anything for calls initiated as no lock activity is alive
    Intent intent = new Intent("i4nc4mp.myLockAdvanced.lifecycle.CALL_START");
    getApplicationContext().sendBroadcast(intent);
    }
    else shouldLock = false;
    //FIXME we need to have the custom mode destroy itself
  }
  
  @Override
  public void onCallEnd() {
    //TODO 2.1 lets us check whether the screen is on
    
    //all timeout sleep causes KG to visibly restore after the 5 sec grace period
    //the phone appears to be doing a KM disable to pause it should user wake up again, and then re-enables at call end
    
    //if call ends while asleep and not in the KG-restored mode (watching for prox wake)
    //then KG is still restored, and we can't catch it due to timing
    
    //therefore, all calls ending while screen is off result in restart lockactivity
    //if screen is awake we check for KG, exit if needed, and reset shouldLock to true
    
    Context mCon = getApplicationContext();
    
    if (IsAwake()) {
      Log.v("call end, screen awake","checking if we need to exit KG");
      shouldLock = true;
      ManageKeyguard.initialize(mCon);
      if (ManageKeyguard.inKeyguardRestrictedInputMode()) DoExit(mCon);
      //TODO change this to the dismiss activity now that we have timing bugs fixed
    }
    else {
      Log.v("call end, screen asleep","restarting lock activity.");
      PendingLock = true;
      StartLock(mCon);
    }
  }
  
  @Override
  public void onCallRing() {  
    Intent intent = new Intent("i4nc4mp.myLockAdvanced.lifecycle.CALL_PENDING");
    getApplicationContext().sendBroadcast(intent);
    //lets the activity know it should not treat focus loss as a navigation exit
    //this will keep activity alive, only stopping it at call accept
  }
  
//============================
  
  void doFGstart() {
    //putting ongoing notif together for start foreground
    
    //String ns = Context.NOTIFICATION_SERVICE;
    //NotificationManager mNotificationManager = (NotificationManager) getSystemService(ns);
    //No need to get the mgr, since we aren't manually sending this for FG mode.
    
    int icon = R.drawable.icon;
    CharSequence tickerText = "myLock is starting up";
    
    long when = System.currentTimeMillis();

    Notification notification = new Notification(icon, tickerText, when);
    
    Context context = getApplicationContext();
    CharSequence contentTitle = "myLock - click to open settings";
    CharSequence contentText = "lockscreen is disabled";

    Intent notificationIntent = new Intent(this, SettingsActivity.class);
    PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);

    notification.setLatestEventInfo(context, contentTitle, contentText, contentIntent);
    
    final int SVC_ID = 1;
    
    //don't need to pass notif because startForeground will do it
    //mNotificationManager.notify(SVC_ID, notification);
    persistent = true;
    
    startForeground(SVC_ID, notification);
  }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.