Android Open Source - appsensor App Usage Logger






From Project

Back to project page appsensor.

License

The source code is released under:

GNU General Public License

If you think the Android project appsensor listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package de.dfki.appsensor.logging;
/*  ww w .  j av a 2 s .co  m*/
import java.util.ArrayList;
import java.util.List;


import de.dfki.appsensor.data.db.AppUsageEventDAO;
import de.dfki.appsensor.data.entities.AppUsageEvent;
import de.dfki.appsensor.utils.App;
import de.dfki.appsensor.utils.Utils;

import android.app.ActivityManager;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.KeyguardManager;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.preference.PreferenceManager;

/**
 * This runnable observes a users device interaction and makes it persistent to
 * the local database. It tracks the application usage and saves events in
 * memory (in a list). At the end of a session (i.e. when the device goes into
 * standby) the data is saved to a local database on the mobile device.
 * database.
 * 
 * This component is a thread that can be controlled through the start and pause
 * methods.
 * 
 * @author Matthias Boehmer, matthias.boehmer@dfki.de
 */
public class AppUsageLogger extends Thread {

  /** number of recent tasks that will be tracked form the API */
  private static final int MAX_TASKS = 1;

  /** period of running app usage checks (in milliseconds) */
  public static long TIME_APPCHECKINTERVAL = 500;
  private static final long TIME_IMMEDIATELY = 5;

  /** states of the thread */
  private static final int DO_OBSERVE = 0;
  private static final int DO_PAUSE = 1;
  private static final int DO_START = 2;

  /** task id for the app that was open before going into standby */
  private static final int LAST_BEFORE_STANDBY = -1;

  /** package name of the phone app */
  private static final Object PHONEPACKAGENAME = "com.android.phone";

  // CHANGEONRELEASE
  /** number of items in table that we cache on the mobile before sending data to the server */
  public static final int MIN_INTERACTIONS_TO_SEND = 1;

  /** history of apps that have been used in current session */
  public static ArrayList<AppUsageEvent> appHistory;

  public static boolean ACTIVE = true;

  
  
  /** general history of other app events */
  private ArrayList<AppUsageEvent> generalInteractionHistory;
  
  /** reference to the activity manager for retrieving info on current apps */
  private ActivityManager activityManager;

  /** the previous app */
  private AppUsageEvent lastApp;

  /** list of recently running apps */
  private List<RunningTaskInfo> apps = null;
  
  /** handler for thread messages */
  private Handler mHandler;

  /** number of apps that are already in our list */
  private int lengthHistory;

  /** context of the app */
  private Context context;

  /** to check if keyboard is locked */
  private KeyguardManager keyManager;

  
  
  private static final Object semaphore = new Object();

  private static AppUsageLogger instance = null;
  
  public static AppUsageLogger getAppUsageLogger(Context c) {
    synchronized (semaphore) {
      if (instance == null)
        instance = new AppUsageLogger(c);  
    }
    
    return instance;
  }
  
  
  /**
   * creates a new app logger that needs to be started afterwards
   * @param context
   */
  private AppUsageLogger(Context context) {
    super();
    Utils.d(this, "constructed");
    this.context = context;
    keyManager = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
    appHistory = new ArrayList<AppUsageEvent>();
    generalInteractionHistory = new ArrayList<AppUsageEvent>();
    activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
  }

  /**
   * Analyzes the runtime of the currently used application and adds the
   * information to the history (list of recent apps) in memory.
   * 
   * @param forceClosingHistory
   */
  private void observeCurrentApp(boolean forceClosingHistory) {
    synchronized (appHistory) {

      apps = activityManager.getRunningTasks(MAX_TASKS);

      if (apps == null) {
        Utils.e(this, "ups, we cannot look which apps are running; API ERROR");
        return;
      }
      
      /** fill list with running apps */
      for (RunningTaskInfo app : apps) {
        // Utils.d2(this, "we are in the RunningTaskInfo loop");

        lengthHistory = appHistory.size();

        if (lengthHistory > 0) {

          lastApp = appHistory.get(appHistory.size() - 1);

          if (app.id == lastApp.taskID) {

            /** here the previous app is still running */
            lastApp.runtime = Utils.getCurrentTime() - lastApp.starttime;
            lastApp.longitude = LocationObserver.longitude;
            lastApp.latitude = LocationObserver.latitude;
            lastApp.accuracy = LocationObserver.accuracy;
            lastApp.speed = LocationObserver.speed;
            lastApp.altitude = LocationObserver.altitude;
            lastApp.powerstate = HardwareObserver.powerstate;
            
            /** update "running" attributes FIXME build sliding average*/
            lastApp.wifistate = HardwareObserver.wifistate;
            lastApp.bluetoothstate = HardwareObserver.bluetoothstate;
            lastApp.headphones = HardwareObserver.headphones;
            
            // HardwareObserver.orientation is either +1 or -1
            HardwareObserver.updateOrientation(context);
            lastApp.orientation += HardwareObserver.orientation;
            
            if (forceClosingHistory) {
              lastApp.taskID = LAST_BEFORE_STANDBY;
            }
          } else {
            /** here the user has opened a different app */
            if (lastApp.taskID != LAST_BEFORE_STANDBY) {
              // add runtime to the old app
              lastApp.runtime = (Utils.getCurrentTime() - lastApp.starttime);
            }

            Utils.d2(this, lastApp.packageName + "(taskID:" + lastApp.taskID + ") " + " was running " + lastApp.runtime);
            //Utils.dToast(context, lastApp.packageName + " ran " + Math.round(lastApp.runtime/1000) + " s");
            
            if (!forceClosingHistory) {
              
              // create a usage event and fill in all the context information
              AppUsageEvent aue = new AppUsageEvent();
              aue.taskID = app.id;
              aue.packageName = app.baseActivity.getPackageName();
              aue.eventtype = AppUsageEvent.EVENT_INUSE;
              aue.starttime = Utils.getCurrentTime();
              aue.runtime = 0; // since we just started
              aue.longitude = LocationObserver.longitude;
              aue.latitude = LocationObserver.latitude;
              aue.accuracy = LocationObserver.accuracy;
              aue.speed = LocationObserver.speed;
              aue.altitude = LocationObserver.altitude;
              aue.powerstate = HardwareObserver.powerstate;
              aue.wifistate = HardwareObserver.wifistate;
              aue.bluetoothstate = HardwareObserver.bluetoothstate;
              aue.headphones = HardwareObserver.headphones;
              aue.orientation = HardwareObserver.orientation;
              aue.timestampOfLastScreenOn = HardwareObserver.timestampOfLastScreenOn;
              aue.syncStatus = AppUsageEvent.STATUS_LOCAL_ONLY;
              
              appHistory.add(aue);
              Utils.d(this,"added the following app to history: " + aue.packageName);
            }
          }

        } else {

          /** here the user starts his first app */
          AppUsageEvent aue = new AppUsageEvent();
          aue.taskID = app.id;
          aue.runtime = 0; // since we just started
          aue.packageName = app.baseActivity.getPackageName();
          aue.eventtype = AppUsageEvent.EVENT_INUSE;
          aue.starttime = Utils.getCurrentTime();
          aue.longitude = LocationObserver.longitude;
          aue.latitude = LocationObserver.latitude;
          aue.accuracy = LocationObserver.accuracy;
          aue.powerlevel = HardwareObserver.powerlevel;
          aue.speed = LocationObserver.speed;
          aue.altitude = LocationObserver.altitude;
          aue.powerstate = HardwareObserver.powerstate;
          aue.wifistate = HardwareObserver.wifistate;
          aue.bluetoothstate = HardwareObserver.bluetoothstate;
          aue.headphones = HardwareObserver.headphones;
          aue.orientation = HardwareObserver.orientation;
          aue.timestampOfLastScreenOn = HardwareObserver.timestampOfLastScreenOn;
          aue.syncStatus = AppUsageEvent.STATUS_LOCAL_ONLY;
          
          appHistory.add(aue);
          Utils.d(this,"added the first app to history: " + aue.packageName);
        }
        
        
        // BOF
        if (Utils.D) {
          AppUsageEvent lastAUE = getLastInteraction();
          Utils.d(this, lastAUE.toStringLong());
        }
      }

    }
  }

  private AppUsageEvent getLastInteraction() {
    int s = appHistory.size();
    if (s > 0) {
      return appHistory.get(s-1); 
    } else {
      return null;
    }
  }

  /**
   * Makes the history of app interaction, which is normally written to the
   * list in memory, persistent to the local database. Usually, this is done
   * when the device goes into standby mode.
   */
  private void makeAppHistoryPersistent() {
    Utils.d(this, "making app history persistent from memory");
    AppUsageEventDAO d = new AppUsageEventDAO(context);
    d.openWrite();
    synchronized (appHistory) {
      d.insert(appHistory);
      appHistory.clear();
    }
    synchronized (generalInteractionHistory) {
      d.insert(generalInteractionHistory);
      generalInteractionHistory.clear();
    }
    d.close();
  }
  
  public void logAppInstalled(String packageName) {
    synchronized (generalInteractionHistory) {
      generalInteractionHistory.add(new AppUsageEvent(packageName, Utils.getCurrentTime(), 0, AppUsageEvent.EVENT_INSTALLED, AppUsageEvent.STATUS_LOCAL_ONLY));
    }
  }

  public void logAppRemoved(String packageName) {
    synchronized (generalInteractionHistory) {
      generalInteractionHistory.add(new AppUsageEvent(packageName, Utils.getCurrentTime(), 0, AppUsageEvent.EVENT_UNINSTALLED, AppUsageEvent.STATUS_LOCAL_ONLY));
    }
  }

  public void logAppUpdated(String packageName) {
    synchronized (generalInteractionHistory) {
      generalInteractionHistory.add(new AppUsageEvent(packageName, Utils.getCurrentTime(), 0, AppUsageEvent.EVENT_UPDATE, AppUsageEvent.STATUS_LOCAL_ONLY));
    }
  }

  
  
  
  @Override
  public void run() {
    Utils.d(this, "running the thread");
    Looper.prepare();

    mHandler = new Handler() {
      
      
      
      @Override
      public void handleMessage(Message msg) {

        switch (msg.what) {
        
        case DO_OBSERVE:
          if (keyManager.inKeyguardRestrictedInputMode() || (HardwareObserver.screenState == HardwareObserver.SCREEN_OFF) && !getLastInteraction().packageName.equals(PHONEPACKAGENAME)) {
            // screen still to be locked
            mHandler.sendEmptyMessageDelayed(DO_START, TIME_APPCHECKINTERVAL);
          } else {
            observeCurrentApp(false);
            mHandler.sendEmptyMessageDelayed(DO_OBSERVE, TIME_APPCHECKINTERVAL);
          }
          break;
          
        case DO_START:
          if (keyManager.inKeyguardRestrictedInputMode()) {
            // screen still seems to be locked
            //Utils.d2(this, "device is in restricted mode");
            mHandler.sendEmptyMessageDelayed(DO_START, TIME_APPCHECKINTERVAL);
          } else {
            // screen was unlocked by user
            //Utils.d2(this, "device is not in restricted mode anymore");
            mHandler.sendEmptyMessageDelayed(DO_OBSERVE, TIME_IMMEDIATELY);
          }
          break;
          
        case DO_PAUSE:
          observeCurrentApp(true);
          mHandler.removeMessages(DO_START);
          mHandler.removeMessages(DO_OBSERVE);
          // tidy up everything and make history persistent
          makeAppHistoryPersistent();
          break;
        }
      }
    };
    
    SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(App.getAppContext());
    boolean activate = prefs.getBoolean(Utils.SETTINGS_settings_sensorsactive, true);
    if (activate) {
      Utils.dToast("AppSensor activated");
      // send the first message so that the handler starts running
      mHandler.sendEmptyMessageDelayed(DO_OBSERVE, TIME_IMMEDIATELY);
    } else {
      Utils.dToast("AppSensor deactivated");
      AppUsageLogger.getAppUsageLogger(App.getAppContext()).pauseLogging();
    }
    

    Looper.loop();
  }

  public void pauseLogging() {
    // send message to the worker thread if initialized
    if (mHandler != null) {
      mHandler.sendEmptyMessageDelayed(DO_PAUSE, TIME_IMMEDIATELY);
    }
  }

  public void startLogging() {
    // send message to the worker thread if initialized
    if (mHandler != null) {
      mHandler.sendEmptyMessageDelayed(DO_START, TIME_IMMEDIATELY);
    }
  }

  /**
   * Call this method if device screen turns off to check wheter user is
   * currently on the phone or not (some phones turn the screen off when the
   * user is coming close to the display to prevent unintended button
   * pressing). If phone app is running, we will continue to log, otherwise we
   * will pause the logging.
   */
  public void checkStandByOnSceenOff() {
    boolean userIsOnThePhone = false;
    
    List<RunningTaskInfo> current = activityManager.getRunningTasks(1);
    if (current.size() > 0) {
      RunningTaskInfo rti = current.get(0);
      userIsOnThePhone = rti.baseActivity.getPackageName().equals(PHONEPACKAGENAME);
    }
    
    // only pause if user is not on the phone, otherwise track phone usage
    if (!userIsOnThePhone) {
      pauseLogging();
    }
  }
  
  @Override
  public void destroy() {
    super.destroy();
    Utils.d2(this, "destroy()");
  };

  @Override
  protected void finalize() throws Throwable {
    super.finalize();
    Utils.d2(this, "finalize()");
  }

}




Java Source Code List

de.dfki.appsensor.backup.InstallationBackupAgent.java
de.dfki.appsensor.backup.WrapperBackupAgent.java
de.dfki.appsensor.data.AppUsageProvider.java
de.dfki.appsensor.data.db.AppUsageEventDAO.java
de.dfki.appsensor.data.db.GeneralDAO.java
de.dfki.appsensor.data.entities.AppUsageEvent.java
de.dfki.appsensor.logging.AppUsageLogger.java
de.dfki.appsensor.logging.BackgroundService.java
de.dfki.appsensor.logging.DeviceObserver.java
de.dfki.appsensor.logging.HardwareObserver.java
de.dfki.appsensor.logging.LocationObserver.java
de.dfki.appsensor.logging.ServiceStarter.java
de.dfki.appsensor.sync.AppUsageSyncAdapter.java
de.dfki.appsensor.sync.AppUsageSyncService.java
de.dfki.appsensor.sync.AuthenticationService.java
de.dfki.appsensor.sync.Authenticator.java
de.dfki.appsensor.sync.SyncThread.java
de.dfki.appsensor.ui.HomeActivity.java
de.dfki.appsensor.ui.SettingsActivity.java
de.dfki.appsensor.utils.App.java
de.dfki.appsensor.utils.CSVCompressor.java
de.dfki.appsensor.utils.MyDBHelper.java
de.dfki.appsensor.utils.NetUtils.java
de.dfki.appsensor.utils.UIUtils.java
de.dfki.appsensor.utils.Utils.java