public void onCreate() {
   super.onCreate();
   Thread.setDefaultUncaughtExceptionHandler(PersistentUncaughtExceptionHandler.getInstance());
   props = new PropertyUtil(getResources());
   downloadExecutor =
       new ThreadPoolExecutor(
           1, 3, 5000, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
 }
 /**
  * invokes a service call to get the header information for a single survey
  *
  * @param serverBase
  * @param surveyId
  * @return
  */
 private ArrayList<Survey> getSurveyHeader(String serverBase, String surveyId, String deviceId) {
   String response = null;
   ArrayList<Survey> surveys = new ArrayList<Survey>();
   try {
     response =
         HttpUtil.httpGet(
             serverBase
                 + SURVEY_HEADER_SERVICE_PATH
                 + surveyId
                 + "&devicePhoneNumber="
                 + StatusUtil.getPhoneNumber(this)
                 + (deviceId != null
                     ? (DEV_ID_PARAM + URLEncoder.encode(deviceId, "UTF-8"))
                     : ""));
     if (response != null) {
       StringTokenizer strTok = new StringTokenizer(response, "\n");
       while (strTok.hasMoreTokens()) {
         String currentLine = strTok.nextToken();
         String[] touple = currentLine.split(",");
         if (touple.length < 4) {
           Log.e(TAG, "Survey list response is in an unrecognized format");
         } else {
           Survey temp = new Survey();
           temp.setId(touple[0]);
           temp.setName(touple[1]);
           temp.setLanguage(touple[2]);
           temp.setVersion(Double.parseDouble(touple[3]));
           temp.setType(ConstantUtil.FILE_SURVEY_LOCATION_TYPE);
           surveys.add(temp);
         }
       }
     }
   } catch (HttpException e) {
     Log.e(TAG, "Server returned an unexpected response", e);
     PersistentUncaughtExceptionHandler.recordException(e);
   } catch (Exception e) {
     Log.e(TAG, "Could not get survey headers", e);
     PersistentUncaughtExceptionHandler.recordException(e);
   }
   return surveys;
 }
  /**
   * Downloads the survey based on the ID and then updates the survey object with the filename and
   * location
   */
  private boolean downloadSurvey(String serverBase, Survey survey) {
    boolean success = false;
    try {
      HttpUtil.httpDownload(
          props.getProperty(ConstantUtil.SURVEY_S3_URL)
              + survey.getId()
              + ConstantUtil.ARCHIVE_SUFFIX,
          FileUtil.getFileOutputStream(
              survey.getId() + ConstantUtil.ARCHIVE_SUFFIX,
              ConstantUtil.DATA_DIR,
              props.getProperty(ConstantUtil.USE_INTERNAL_STORAGE),
              this));
      extractAndSave(
          FileUtil.getFileInputStream(
              survey.getId() + ConstantUtil.ARCHIVE_SUFFIX,
              ConstantUtil.DATA_DIR,
              props.getProperty(ConstantUtil.USE_INTERNAL_STORAGE),
              this));

      survey.setFileName(survey.getId() + ConstantUtil.XML_SUFFIX);
      survey.setType(DEFAULT_TYPE);
      survey.setLocation(SD_LOC);
      success = true;
    } catch (IOException e) {
      Log.e(TAG, "Could write survey file " + survey.getFileName(), e);
      String text = getResources().getString(R.string.cannotupdate);
      ViewUtil.fireNotification(text, text, this, FAIL_ID, null);
      PersistentUncaughtExceptionHandler.recordException(
          new TransferException(survey.getId(), null, e));

    } catch (Exception e) {
      Log.e(TAG, "Could not download survey " + survey.getId(), e);

      String text = getResources().getString(R.string.cannotupdate);
      ViewUtil.fireNotification(text, text, this, FAIL_ID, null);

      PersistentUncaughtExceptionHandler.recordException(
          new TransferException(survey.getId(), null, e));
    }
    return success;
  }
 /**
  * uses the thread pool executor to download the remote file passed in via a background thread
  *
  * @param remoteFile
  * @param surveyId
  */
 private void downloadBinary(final String remoteFile, final String surveyId) {
   try {
     final FileOutputStream out =
         FileUtil.getFileOutputStream(
             remoteFile.substring(remoteFile.lastIndexOf("/") + 1),
             ConstantUtil.DATA_DIR + surveyId + "/",
             props.getProperty(ConstantUtil.USE_INTERNAL_STORAGE),
             this);
     downloadExecutor.execute(
         new Runnable() {
           @Override
           public void run() {
             try {
               HttpUtil.httpDownload(remoteFile, out);
             } catch (Exception e) {
               Log.e(TAG, "Could not download help media file", e);
             }
           }
         });
   } catch (FileNotFoundException e1) {
     Log.e(TAG, "Could not download binary file", e1);
     PersistentUncaughtExceptionHandler.recordException(e1);
   }
 }
 /**
  * checks to see if we should pre-cache help media files (based on the property in the settings
  * db) and, if we should, downloads the files
  *
  * @param survey
  */
 private void downloadHelp(Survey survey, int precacheOption) {
   // first, see if we should even bother trying to download
   if (canDownload(precacheOption)) {
     try {
       InputStream in = null;
       if (ConstantUtil.RESOURCE_LOCATION.equalsIgnoreCase(survey.getLocation())) {
         // load from resource
         Resources res = getResources();
         in =
             res.openRawResource(
                 res.getIdentifier(
                     survey.getFileName(),
                     ConstantUtil.RAW_RESOURCE,
                     ConstantUtil.RESOURCE_PACKAGE));
       } else {
         // load from file
         in =
             FileUtil.getFileInputStream(
                 survey.getFileName(),
                 ConstantUtil.DATA_DIR,
                 props.getProperty(ConstantUtil.USE_INTERNAL_STORAGE),
                 this);
       }
       Survey hydratedSurvey = SurveyDao.loadSurvey(survey, in);
       if (hydratedSurvey != null) {
         // collect files in a set just in case the same binary is
         // used in multiple questions
         // we only need to download once
         HashSet<String> fileSet = new HashSet<String>();
         if (hydratedSurvey.getQuestionGroups() != null) {
           for (int i = 0; i < hydratedSurvey.getQuestionGroups().size(); i++) {
             ArrayList<Question> questions =
                 hydratedSurvey.getQuestionGroups().get(i).getQuestions();
             if (questions != null) {
               for (int j = 0; j < questions.size(); j++) {
                 if (questions.get(j).getHelpByType(ConstantUtil.VIDEO_HELP_TYPE).size() > 0) {
                   fileSet.add(
                       questions
                           .get(j)
                           .getHelpByType(ConstantUtil.VIDEO_HELP_TYPE)
                           .get(0)
                           .getValue());
                 }
                 ArrayList<QuestionHelp> helpList =
                     questions.get(j).getHelpByType(ConstantUtil.IMAGE_HELP_TYPE);
                 ArrayList<String> images = new ArrayList<String>();
                 for (int x = 0; x < helpList.size(); x++) {
                   images.add(helpList.get(x).getValue());
                 }
                 if (images != null) {
                   for (int k = 0; k < images.size(); k++) {
                     fileSet.add(images.get(k));
                   }
                 }
               }
             }
           }
         }
         for (String file : fileSet) {
           downloadBinary(file, survey.getId());
         }
         databaseAdaptor.markSurveyHelpDownloaded(survey.getId(), true);
       }
     } catch (FileNotFoundException e) {
       Log.e(TAG, "Could not parse survey survey file", e);
       PersistentUncaughtExceptionHandler.recordException(e);
     }
   }
 }
  /**
   * if no surveyId is passed in, this will check for new surveys and, if there are some new ones,
   * downloads them to the DATA_DIR. If a surveyId is passed in, then that specific survey will be
   * downloaded. If it's already on the device, the survey will be replaced with the new one.
   */
  private void checkAndDownload(String surveyId) {
    if (isAbleToRun()) {
      try {
        lock.acquire();
        databaseAdaptor = new SurveyDbAdapter(this);
        databaseAdaptor.open();
        int precacheOption =
            Integer.parseInt(databaseAdaptor.findPreference(ConstantUtil.PRECACHE_SETTING_KEY));
        String serverBase = databaseAdaptor.findPreference(ConstantUtil.SERVER_SETTING_KEY);
        if (serverBase != null && serverBase.trim().length() > 0) {
          serverBase = getResources().getStringArray(R.array.servers)[Integer.parseInt(serverBase)];
        } else {
          serverBase = props.getProperty(ConstantUtil.SERVER_BASE);
        }

        int surveyCheckOption =
            Integer.parseInt(databaseAdaptor.findPreference(ConstantUtil.CHECK_FOR_SURVEYS));
        String deviceId = databaseAdaptor.findPreference(ConstantUtil.DEVICE_IDENT_KEY);
        ArrayList<Survey> surveys = null;

        if (surveyId != null && surveyId.trim().length() > 0) {
          surveys = getSurveyHeader(serverBase, surveyId, deviceId);
          if (surveys != null && surveys.size() > 0) {
            // if we already have the survey, delete it first
            databaseAdaptor.deleteSurvey(surveyId.trim(), true);
          }
        } else {
          if (canDownload(surveyCheckOption)) {
            surveys = checkForSurveys(serverBase, deviceId);
          }
        }
        if (surveys != null && surveys.size() > 0) {
          // if there are surveys for this device, see if we need
          // them
          surveys = databaseAdaptor.checkSurveyVersions(surveys);
          int updateCount = 0;
          if (surveys != null && surveys.size() > 0) {
            for (int i = 0; i < surveys.size(); i++) {
              Survey survey = surveys.get(i);
              try {
                if (downloadSurvey(serverBase, survey)) {
                  databaseAdaptor.saveSurvey(survey);
                  downloadHelp(survey, precacheOption);
                  updateCount++;
                }
              } catch (Exception e) {
                Log.e(TAG, "Could not download survey", e);
                PersistentUncaughtExceptionHandler.recordException(e);
              }
            }
            if (updateCount > 0) {
              fireNotification(updateCount);
            }
          }
        }

        // now check if any previously downloaded surveys still need
        // don't have their help media pre-cached
        if (canDownload(precacheOption)) {
          surveys = databaseAdaptor.listSurveys(null);
          if (surveys != null) {
            for (int i = 0; i < surveys.size(); i++) {
              if (!surveys.get(i).isHelpDownloaded()) {
                downloadHelp(surveys.get(i), precacheOption);
              }
            }
          }
        }

      } catch (Exception e) {
        Log.e(TAG, "Could not update surveys", e);
        PersistentUncaughtExceptionHandler.recordException(e);
      } finally {
        databaseAdaptor.close();
        lock.release();
      }
    }
    try {
      downloadExecutor.shutdown();
      // wait up to 30 minutes to download the media
      downloadExecutor.awaitTermination(1800, TimeUnit.SECONDS);
    } catch (InterruptedException e) {
      Log.e(TAG, "Error while waiting for download executor to terminate", e);
    }
    stopSelf();
  }