@Override
 public String toString() {
   // Static class, so the time in this toString will not reflect the
   // home tz settings. This should only affect debugging.
   Time time = new Time();
   StringBuilder sb = new StringBuilder();
   time.setJulianDay(start);
   time.normalize(false);
   sb.append("Start:").append(time.toString());
   time.setJulianDay(end);
   time.normalize(false);
   sb.append(" End:").append(time.toString());
   sb.append(" Offset:").append(offset);
   sb.append(" Size:").append(size);
   return sb.toString();
 }
 // To make it easy to query for the exact date, we normalize all dates that go into
 // the database to the start of the the Julian day at UTC.
 public static long normalizeDate(long startDate) {
   // normalize the start date to the beginning of the (UTC) day
   Time time = new Time();
   time.set(startDate);
   int julianDay = Time.getJulianDay(startDate, time.gmtoff);
   return time.setJulianDay(julianDay);
 }
  public static long normalizeDate(long startDate) {

    Time time = new Time();
    time.set(startDate);
    int julianDay = Time.getJulianDay(startDate, time.gmtoff);
    return time.setJulianDay(julianDay);
  }
  // Do a "snap to start of month" fling
  private void doFling(float velocityY) {

    // Stop the list-view movement and take over
    MotionEvent cancelEvent =
        MotionEvent.obtain(
            mDownActionTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_CANCEL, 0, 0, 0);
    onTouchEvent(cancelEvent);

    // Below the threshold, fling one month. Above the threshold , fling
    // according to the speed of the fling.
    int monthsToJump;
    if (Math.abs(velocityY) < MULTIPLE_MONTH_VELOCITY_THRESHOLD) {
      if (velocityY < 0) {
        monthsToJump = 1;
      } else {
        // value here is zero and not -1 since by the time the fling is
        // detected the list moved back one month.
        monthsToJump = 0;
      }
    } else {
      if (velocityY < 0) {
        monthsToJump =
            1 - (int) ((velocityY + MULTIPLE_MONTH_VELOCITY_THRESHOLD) / FLING_VELOCITY_DIVIDER);
      } else {
        monthsToJump =
            -(int) ((velocityY - MULTIPLE_MONTH_VELOCITY_THRESHOLD) / FLING_VELOCITY_DIVIDER);
      }
    }

    // Get the day at the top right corner
    int day = getUpperRightJulianDay();
    // Get the day of the first day of the next/previous month
    // (according to scroll direction)
    mTempTime.setJulianDay(day);
    mTempTime.monthDay = 1;
    mTempTime.month += monthsToJump;
    long timeInMillis = mTempTime.normalize(false);
    // Since each view is 7 days, round the target day up to make sure the
    // scroll will be  at least one view.
    int scrollToDay =
        Time.getJulianDay(timeInMillis, mTempTime.gmtoff) + ((monthsToJump > 0) ? 6 : 0);

    // Since all views have the same height, scroll by pixels instead of
    // "to position".
    // Compensate for the top view offset from the top.
    View firstView = getChildAt(0);
    int firstViewHeight = firstView.getHeight();
    // Get visible part length
    firstView.getLocalVisibleRect(mFirstViewRect);
    int topViewVisiblePart = mFirstViewRect.bottom - mFirstViewRect.top;
    int viewsToFling = (scrollToDay - day) / 7 - ((monthsToJump <= 0) ? 1 : 0);
    int offset =
        (viewsToFling > 0)
            ? -(firstViewHeight - topViewVisiblePart + SimpleDayPickerFragment.LIST_TOP_OFFSET)
            : (topViewVisiblePart - SimpleDayPickerFragment.LIST_TOP_OFFSET);
    // Fling
    smoothScrollBy(viewsToFling * firstViewHeight + offset, FLING_TIME);
  }
  private String[] getWeatherDataFromJson(String forecastJsonStr, int numDays)
      throws JSONException {
    final String OWM_LIST = "list";
    final String OWM_WEATHER = "weather";
    final String OWM_TEMPERATURE = "temp";
    final String OWM_MAX = "max";
    final String OWM_MIN = "min";
    final String OWM_DESCRIPTION = "main";

    if (forecastJsonStr == null) {
      return null;
    }

    JSONObject forecastJson = new JSONObject(forecastJsonStr);
    if (forecastJson == null) {
      return null;
    }
    JSONArray weatherArray = forecastJson.getJSONArray(OWM_LIST);
    if (weatherArray == null || weatherArray.length() == 0) {
      return null;
    }

    Time dayTime = new Time();
    dayTime.setToNow();
    int julianStartDay = Time.getJulianDay(System.currentTimeMillis(), dayTime.gmtoff);

    dayTime = new Time();
    String[] resultStr = new String[numDays];
    for (int i = 0; i < weatherArray.length(); i++) {
      String day;
      String desciption;
      String highAndLow;
      JSONObject dayForecast = weatherArray.getJSONObject(i);
      long dateTime;
      dateTime = dayTime.setJulianDay(julianStartDay + i);
      day = getReadableDateString(dateTime);
      JSONObject weatherObject = (JSONObject) dayForecast.getJSONArray(OWM_WEATHER).get(0);
      desciption = weatherObject.getString(OWM_DESCRIPTION);

      JSONObject temperature = dayForecast.getJSONObject(OWM_TEMPERATURE);
      double high = temperature.getLong(OWM_MAX);
      double low = temperature.getLong(OWM_MIN);
      highAndLow = formatHighLow(high, low);
      resultStr[i] = day + " - " + desciption + " - " + highAndLow;
    }

    for (String s : resultStr) {
      Log.v(TAG, "Forecast entry: " + s);
    }
    return resultStr;
  }
 private String formatDateString(int julianDay) {
   Time time = new Time(mTimeZone);
   time.setJulianDay(julianDay);
   long millis = time.toMillis(false);
   mStringBuilder.setLength(0);
   return DateUtils.formatDateRange(
           mContext,
           mFormatter,
           millis,
           millis,
           DateUtils.FORMAT_SHOW_YEAR | DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_ABBREV_MONTH,
           mTimeZone)
       .toString();
 }
  private AgendaItem buildAgendaItemFromCursor(
      final Cursor cursor, int cursorPosition, boolean isDayHeader) {
    if (cursorPosition == -1) {
      cursor.moveToFirst();
    } else {
      cursor.moveToPosition(cursorPosition);
    }
    AgendaItem agendaItem = new AgendaItem();
    agendaItem.begin = cursor.getLong(AgendaWindowAdapter.INDEX_BEGIN);
    agendaItem.end = cursor.getLong(AgendaWindowAdapter.INDEX_END);
    agendaItem.startDay = cursor.getInt(AgendaWindowAdapter.INDEX_START_DAY);
    agendaItem.allDay = cursor.getInt(AgendaWindowAdapter.INDEX_ALL_DAY) != 0;
    if (agendaItem.allDay) { // UTC to Local time conversion
      Time time = new Time(mTimeZone);
      time.setJulianDay(Time.getJulianDay(agendaItem.begin, 0));
      agendaItem.begin = time.toMillis(false /* use isDst */);
    } else if (isDayHeader) { // Trim to midnight.
      Time time = new Time(mTimeZone);
      time.set(agendaItem.begin);
      time.hour = 0;
      time.minute = 0;
      time.second = 0;
      agendaItem.begin = time.toMillis(false /* use isDst */);
    }

    // If this is not a day header, then it's an event.
    if (!isDayHeader) {
      agendaItem.id = cursor.getLong(AgendaWindowAdapter.INDEX_EVENT_ID);
      if (agendaItem.allDay) {
        Time time = new Time(mTimeZone);
        time.setJulianDay(Time.getJulianDay(agendaItem.end, 0));
        agendaItem.end = time.toMillis(false /* use isDst */);
      }
    }
    return agendaItem;
  }
  @Override
  public Time getDayFromLocation(float x) {
    int dayPosition = getDayIndexFromLocation(x);
    if (dayPosition == -1) {
      return null;
    }
    int day = mFirstJulianDay + dayPosition;

    Time time = new Time(mTimeZone);
    if (mWeek == 0) {
      // This week is weird...
      if (day < Time.EPOCH_JULIAN_DAY) {
        day++;
      } else if (day == Time.EPOCH_JULIAN_DAY) {
        time.set(1, 0, 1970);
        time.normalize(true);
        return time;
      }
    }

    time.setJulianDay(day);
    return time;
  }
    /**
     * Take the String representing the complete forecast in JSON Format and pull out the data we
     * need to construct the Strings needed for the wireframes.
     *
     * <p>Fortunately parsing is easy: constructor takes the JSON string and converts it into an
     * Object hierarchy for us.
     */
    private ForeCastObj[] getWeatherDataFromJson(String forecastJsonStr, int numDays)
        throws JSONException {

      // These are the names of the JSON objects that need to be extracted.
      final String OWM_LIST = "list";
      final String OWM_WEATHER = "weather";
      final String OWM_TEMPERATURE = "temp";
      final String OWM_MAX = "max";
      final String OWM_MIN = "min";
      final String OWM_DESCRIPTION = "main";

      JSONObject forecastJson = new JSONObject(forecastJsonStr);
      JSONArray weatherArray = forecastJson.getJSONArray(OWM_LIST);

      // OWM returns daily forecasts based upon the local time of the city that is being
      // asked for, which means that we need to know the GMT offset to translate this data
      // properly.

      // Since this data is also sent in-order and the first day is always the
      // current day, we're going to take advantage of that to get a nice
      // normalized UTC date for all of our weather.

      Time dayTime = new Time();
      dayTime.setToNow();

      // we start at the day returned by local time. Otherwise this is a mess.
      int julianStartDay = Time.getJulianDay(System.currentTimeMillis(), dayTime.gmtoff);

      // now we work exclusively in UTC
      dayTime = new Time();

      ForeCastObj[] resultStrs = new ForeCastObj[numDays];
      for (int i = 0; i < weatherArray.length(); i++) {
        // For now, using the format "Day, description, hi/low"
        String day;
        String description;
        String highAndLow;

        // Get the JSON object representing the day
        JSONObject dayForecast = weatherArray.getJSONObject(i);

        // The date/time is returned as a long.  We need to convert that
        // into something human-readable, since most people won't read "1400356800" as
        // "this saturday".
        long dateTime;
        // Cheating to convert this to UTC time, which is what we want anyhow
        dateTime = dayTime.setJulianDay(julianStartDay + i);
        // day = getReadableDateString(dateTime);
        day = Utility.getDayName(getApplicationContext(), dateTime);

        // description is in a child array called "weather", which is 1 element long.
        JSONObject weatherObject = dayForecast.getJSONArray(OWM_WEATHER).getJSONObject(0);
        description = weatherObject.getString(OWM_DESCRIPTION);

        // Temperatures are in a child object called "temp".  Try not to name variables
        // "temp" when working with temperature.  It confuses everybody.
        JSONObject temperatureObject = dayForecast.getJSONObject(OWM_TEMPERATURE);
        double high = temperatureObject.getDouble(OWM_MAX);
        double low = temperatureObject.getDouble(OWM_MIN);

        ForeCastObj tmpObj = new ForeCastObj();
        tmpObj.day = day;
        tmpObj.description = description;
        Log.d(LOG_TAG, Unit);
        tmpObj.hight =
            Utility.formatTemperature(
                getApplicationContext(), high, (Unit == "metric" ? false : true));
        tmpObj.low =
            Utility.formatTemperature(
                getApplicationContext(), low, (Unit == "metric" ? false : true));

        resultStrs[i] = tmpObj;
      }

      return resultStrs;
    }
  public void calculateDays(DayAdapterInfo dayAdapterInfo) {
    Cursor cursor = dayAdapterInfo.cursor;
    ArrayList<RowInfo> rowInfo = new ArrayList<RowInfo>();
    int prevStartDay = -1;

    Time tempTime = new Time(mTimeZone);
    long now = System.currentTimeMillis();
    tempTime.set(now);
    mTodayJulianDay = Time.getJulianDay(now, tempTime.gmtoff);

    LinkedList<MultipleDayInfo> multipleDayList = new LinkedList<MultipleDayInfo>();
    for (int position = 0; cursor.moveToNext(); position++) {
      int startDay = cursor.getInt(AgendaWindowAdapter.INDEX_START_DAY);
      long id = cursor.getLong(AgendaWindowAdapter.INDEX_EVENT_ID);
      long startTime = cursor.getLong(AgendaWindowAdapter.INDEX_BEGIN);
      long endTime = cursor.getLong(AgendaWindowAdapter.INDEX_END);
      long instanceId = cursor.getLong(AgendaWindowAdapter.INDEX_INSTANCE_ID);
      boolean allDay = cursor.getInt(AgendaWindowAdapter.INDEX_ALL_DAY) != 0;
      if (allDay) {
        startTime = Utils.convertAlldayUtcToLocal(tempTime, startTime, mTimeZone);
        endTime = Utils.convertAlldayUtcToLocal(tempTime, endTime, mTimeZone);
      }
      // Skip over the days outside of the adapter's range
      startDay = Math.max(startDay, dayAdapterInfo.start);
      // Make sure event's start time is not before the start of the day
      // (setJulianDay sets the time to 12:00am)
      long adapterStartTime = tempTime.setJulianDay(startDay);
      startTime = Math.max(startTime, adapterStartTime);

      if (startDay != prevStartDay) {
        // Check if we skipped over any empty days
        if (prevStartDay == -1) {
          rowInfo.add(new RowInfo(TYPE_DAY, startDay));
        } else {
          // If there are any multiple-day events that span the empty
          // range of days, then create day headers and events for
          // those multiple-day events.
          boolean dayHeaderAdded = false;
          for (int currentDay = prevStartDay + 1; currentDay <= startDay; currentDay++) {
            dayHeaderAdded = false;
            Iterator<MultipleDayInfo> iter = multipleDayList.iterator();
            while (iter.hasNext()) {
              MultipleDayInfo info = iter.next();
              // If this event has ended then remove it from the
              // list.
              if (info.mEndDay < currentDay) {
                iter.remove();
                continue;
              }

              // If this is the first event for the day, then
              // insert a day header.
              if (!dayHeaderAdded) {
                rowInfo.add(new RowInfo(TYPE_DAY, currentDay));
                dayHeaderAdded = true;
              }
              long nextMidnight =
                  Utils.getNextMidnight(tempTime, info.mEventStartTimeMilli, mTimeZone);

              long infoEndTime =
                  (info.mEndDay == currentDay) ? info.mEventEndTimeMilli : nextMidnight;
              rowInfo.add(
                  new RowInfo(
                      TYPE_MEETING,
                      currentDay,
                      info.mPosition,
                      info.mEventId,
                      info.mEventStartTimeMilli,
                      infoEndTime,
                      info.mInstanceId,
                      info.mAllDay));

              info.mEventStartTimeMilli = nextMidnight;
            }
          }

          // If the day header was not added for the start day, then
          // add it now.
          if (!dayHeaderAdded) {
            rowInfo.add(new RowInfo(TYPE_DAY, startDay));
          }
        }
        prevStartDay = startDay;
      }

      // If this event spans multiple days, then add it to the multipleDay
      // list.
      int endDay = cursor.getInt(AgendaWindowAdapter.INDEX_END_DAY);

      // Skip over the days outside of the adapter's range
      endDay = Math.min(endDay, dayAdapterInfo.end);
      if (endDay > startDay) {
        long nextMidnight = Utils.getNextMidnight(tempTime, startTime, mTimeZone);
        multipleDayList.add(
            new MultipleDayInfo(position, endDay, id, nextMidnight, endTime, instanceId, allDay));
        // Add in the event for this cursor position - since it is the start of a multi-day
        // event, the end time is midnight
        rowInfo.add(
            new RowInfo(
                TYPE_MEETING, startDay, position, id, startTime, nextMidnight, instanceId, allDay));
      } else {
        // Add in the event for this cursor position
        rowInfo.add(
            new RowInfo(
                TYPE_MEETING, startDay, position, id, startTime, endTime, instanceId, allDay));
      }
    }

    // There are no more cursor events but we might still have multiple-day
    // events left.  So create day headers and events for those.
    if (prevStartDay > 0) {
      for (int currentDay = prevStartDay + 1; currentDay <= dayAdapterInfo.end; currentDay++) {
        boolean dayHeaderAdded = false;
        Iterator<MultipleDayInfo> iter = multipleDayList.iterator();
        while (iter.hasNext()) {
          MultipleDayInfo info = iter.next();
          // If this event has ended then remove it from the
          // list.
          if (info.mEndDay < currentDay) {
            iter.remove();
            continue;
          }

          // If this is the first event for the day, then
          // insert a day header.
          if (!dayHeaderAdded) {
            rowInfo.add(new RowInfo(TYPE_DAY, currentDay));
            dayHeaderAdded = true;
          }
          long nextMidnight = Utils.getNextMidnight(tempTime, info.mEventStartTimeMilli, mTimeZone);
          long infoEndTime = (info.mEndDay == currentDay) ? info.mEventEndTimeMilli : nextMidnight;
          rowInfo.add(
              new RowInfo(
                  TYPE_MEETING,
                  currentDay,
                  info.mPosition,
                  info.mEventId,
                  info.mEventStartTimeMilli,
                  infoEndTime,
                  info.mInstanceId,
                  info.mAllDay));

          info.mEventStartTimeMilli = nextMidnight;
        }
      }
    }
    mRowInfo = rowInfo;
  }
  @Override
  public View getView(int position, View convertView, ViewGroup parent) {
    if ((mRowInfo == null) || (position > mRowInfo.size())) {
      // If we have no row info, mAgendaAdapter returns the view.
      return mAgendaAdapter.getView(position, convertView, parent);
    }

    RowInfo row = mRowInfo.get(position);
    if (row.mType == TYPE_DAY) {
      ViewHolder holder = null;
      View agendaDayView = null;
      if ((convertView != null) && (convertView.getTag() != null)) {
        // Listview may get confused and pass in a different type of
        // view since we keep shifting data around. Not a big problem.
        Object tag = convertView.getTag();
        if (tag instanceof ViewHolder) {
          agendaDayView = convertView;
          holder = (ViewHolder) tag;
          holder.julianDay = row.mDay;
        }
      }

      if (holder == null) {
        // Create a new AgendaView with a ViewHolder for fast access to
        // views w/o calling findViewById()
        holder = new ViewHolder();
        agendaDayView = mInflater.inflate(R.layout.agenda_day, parent, false);
        holder.dayView = (TextView) agendaDayView.findViewById(R.id.day);
        holder.dateView = (TextView) agendaDayView.findViewById(R.id.date);
        holder.julianDay = row.mDay;
        holder.grayed = false;
        agendaDayView.setTag(holder);
      }

      // Re-use the member variable "mTime" which is set to the local
      // time zone.
      // It's difficult to find and update all these adapters when the
      // home tz changes so check it here and update if needed.
      String tz = Utils.getTimeZone(mContext, mTZUpdater);
      if (!TextUtils.equals(tz, mTmpTime.timezone)) {
        mTimeZone = tz;
        mTmpTime = new Time(tz);
      }

      // Build the text for the day of the week.
      // Should be yesterday/today/tomorrow (if applicable) + day of the week

      Time date = mTmpTime;
      long millis = date.setJulianDay(row.mDay);
      int flags = DateUtils.FORMAT_SHOW_WEEKDAY;
      mStringBuilder.setLength(0);

      String dayViewText = Utils.getDayOfWeekString(row.mDay, mTodayJulianDay, millis, mContext);

      // Build text for the date
      // Format should be month day

      mStringBuilder.setLength(0);
      flags = DateUtils.FORMAT_SHOW_DATE;
      String dateViewText =
          DateUtils.formatDateRange(mContext, mFormatter, millis, millis, flags, mTimeZone)
              .toString();

      if (AgendaWindowAdapter.BASICLOG) {
        dayViewText += " P:" + position;
        dateViewText += " P:" + position;
      }
      holder.dayView.setText(dayViewText);
      holder.dateView.setText(dateViewText);

      // Set the background of the view, it is grayed for day that are in the past and today
      if (row.mDay > mTodayJulianDay) {
        agendaDayView.setBackgroundResource(R.drawable.agenda_item_bg_primary);
        holder.grayed = false;
      } else {
        agendaDayView.setBackgroundResource(R.drawable.agenda_item_bg_secondary);
        holder.grayed = true;
      }
      return agendaDayView;
    } else if (row.mType == TYPE_MEETING) {
      View itemView = mAgendaAdapter.getView(row.mPosition, convertView, parent);
      AgendaAdapter.ViewHolder holder = ((AgendaAdapter.ViewHolder) itemView.getTag());
      TextView title = holder.title;
      // The holder in the view stores information from the cursor, but the cursor has no
      // notion of multi-day event and the start time of each instance of a multi-day event
      // is the same.  RowInfo has the correct info , so take it from there.
      holder.startTimeMilli = row.mEventStartTimeMilli;
      boolean allDay = holder.allDay;
      if (AgendaWindowAdapter.BASICLOG) {
        title.setText(title.getText() + " P:" + position);
      } else {
        title.setText(title.getText());
      }

      // if event in the past or started already, un-bold the title and set the background
      if ((!allDay && row.mEventStartTimeMilli <= System.currentTimeMillis())
          || (allDay && row.mDay <= mTodayJulianDay)) {
        itemView.setBackgroundResource(R.drawable.agenda_item_bg_secondary);
        title.setTypeface(Typeface.DEFAULT);
        holder.grayed = true;
      } else {
        itemView.setBackgroundResource(R.drawable.agenda_item_bg_primary);
        title.setTypeface(Typeface.DEFAULT_BOLD);
        holder.grayed = false;
      }
      holder.julianDay = row.mDay;
      return itemView;
    } else {
      // Error
      throw new IllegalStateException("Unknown event type:" + row.mType);
    }
  }
  /**
   * Take the String representing the complete forecast in JSON Format and pull out the data we need
   * to construct the Strings needed for the wireframes.
   *
   * <p>Fortunately parsing is easy: constructor takes the JSON string and converts it into an
   * Object hierarchy for us.
   */
  private void getWeatherDataFromJson(String forecastJsonStr, String locationSetting)
      throws JSONException {

    // Location information
    final String OWM_CITY = "city";
    final String OWM_CITY_NAME = "name";
    final String OWM_COORD = "coord";

    // Location coordinate
    final String OWM_LATITUDE = "lat";
    final String OWM_LONGITUDE = "lon";

    // These are the names of the JSON objects that need to be extracted.
    final String OWM_PRESSURE = "pressure";
    final String OWM_HUMIDITY = "humidity";
    final String OWM_WINDSPEED = "speed";
    final String OWM_WIND_DIRECTION = "deg";

    // All temperatures are children of the "temp" object.
    final String OWM_LIST = "list";

    final String OWM_TEMPERATURE = "temp";
    final String OWM_MAX = "max";
    final String OWM_MIN = "min";

    final String OWM_WEATHER = "weather";
    final String OWM_DESCRIPTION = "main";
    final String OWM_WEATHER_ID = "id";

    JSONObject forecastJson = new JSONObject(forecastJsonStr);
    JSONArray weatherArray = forecastJson.getJSONArray(OWM_LIST);

    // OWM returns daily forecasts based upon the local time of the city that is being
    // asked for, which means that we need to know the GMT offset to translate this data
    // properly.

    JSONObject cityJson = forecastJson.getJSONObject(OWM_CITY);
    String cityName = cityJson.getString(OWM_CITY_NAME);

    JSONObject cityCoordJson = cityJson.getJSONObject(OWM_COORD);
    double cityLongitude = cityCoordJson.getDouble(OWM_LONGITUDE);
    double cityLatitude = cityCoordJson.getDouble(OWM_LATITUDE);

    long locationId = addLocation(locationSetting, cityName, cityLongitude, cityLatitude);

    // Insert the new weather information into the database
    Vector<ContentValues> cVVector = new Vector<ContentValues>(weatherArray.length());

    // Since this data is also sent in-order and the first day is always the
    // current day, we're going to take advantage of that to get a nice
    // normalized UTC date for all of our weather.

    Time dayTime = new Time();
    dayTime.setToNow();

    // we start at the day returned by local time. Otherwise this is a mess.
    int julianStartDay = Time.getJulianDay(System.currentTimeMillis(), dayTime.gmtoff);

    // now we work exclusively in UTC
    dayTime = new Time();

    for (int i = 0; i < weatherArray.length(); i++) {
      // These are the values that will be collected.
      long dateTime;
      double pressure;
      int humidity;
      double windSpeed;
      double windDirection;

      double high;
      double low;

      String description;
      int weatherId;

      // Get the JSON object representing the day
      JSONObject dayForecast = weatherArray.getJSONObject(i);

      pressure = dayForecast.getDouble(OWM_PRESSURE);
      humidity = dayForecast.getInt(OWM_HUMIDITY);
      windSpeed = dayForecast.getDouble(OWM_WINDSPEED);
      windDirection = dayForecast.getDouble(OWM_WIND_DIRECTION);

      // Description is in a child array called "weather", which is 1 element long.
      // That element also contains a weather code.
      JSONObject weatherObject = dayForecast.getJSONArray(OWM_WEATHER).getJSONObject(0);
      description = weatherObject.getString(OWM_DESCRIPTION);
      weatherId = weatherObject.getInt(OWM_WEATHER_ID);

      // Cheating to convert this to UTC time, which is what we want anyhow
      dateTime = dayTime.setJulianDay(julianStartDay + i);

      // Temperatures are in a child object called "temp".  Try not to name variables
      // "temp" when working with temperature.  It confuses everybody.
      JSONObject temperatureObject = dayForecast.getJSONObject(OWM_TEMPERATURE);
      high = temperatureObject.getDouble(OWM_MAX);
      low = temperatureObject.getDouble(OWM_MIN);

      ContentValues weatherValues = new ContentValues();

      weatherValues.put(WeatherEntry.COLUMN_LOC_KEY, locationId);
      weatherValues.put(WeatherEntry.COLUMN_DATE, dateTime);
      weatherValues.put(WeatherEntry.COLUMN_HUMIDITY, humidity);
      weatherValues.put(WeatherEntry.COLUMN_PRESSURE, pressure);
      weatherValues.put(WeatherEntry.COLUMN_WIND_SPEED, windSpeed);
      weatherValues.put(WeatherEntry.COLUMN_DEGREES, windDirection);
      weatherValues.put(WeatherEntry.COLUMN_MAX_TEMP, high);
      weatherValues.put(WeatherEntry.COLUMN_MIN_TEMP, low);
      weatherValues.put(WeatherEntry.COLUMN_SHORT_DESC, description);
      weatherValues.put(WeatherEntry.COLUMN_WEATHER_ID, weatherId);

      cVVector.add(weatherValues);
    }

    // add to database
    if (cVVector.size() > 0) {
      // Student: call bulkInsert to add the weatherEntries to the database here

      ContentValues[] contents = new ContentValues[cVVector.size()];

      ContentResolver weatherProvider = mContext.getContentResolver();
      weatherProvider.bulkInsert(WeatherEntry.CONTENT_URI, cVVector.toArray(contents));
    }

    String sortOrder = WeatherEntry.COLUMN_DATE + " ASC";
    Uri weatherForLocationUri =
        WeatherEntry.buildWeatherLocationWithStartDate(locationSetting, System.currentTimeMillis());

    // Students: Uncomment the next lines to display what what you stored in the bulkInsert

    Cursor cur =
        mContext.getContentResolver().query(weatherForLocationUri, null, null, null, sortOrder);

    cVVector = new Vector<ContentValues>(cur.getCount());
    if (cur.moveToFirst()) {
      do {
        ContentValues cv = new ContentValues();
        DatabaseUtils.cursorRowToContentValues(cur, cv);
        cVVector.add(cv);
      } while (cur.moveToNext());
    }

    Log.d(LOG_TAG, "FetchWeatherTask Complete. " + cVVector.size() + " Inserted");
  }
  private void doQuery(QuerySpec queryData) {
    if (!mAdapterInfos.isEmpty()) {
      int start = mAdapterInfos.getFirst().start;
      int end = mAdapterInfos.getLast().end;
      int queryDuration = calculateQueryDuration(start, end);
      switch (queryData.queryType) {
        case QUERY_TYPE_OLDER:
          queryData.end = start - 1;
          queryData.start = queryData.end - queryDuration;
          break;
        case QUERY_TYPE_NEWER:
          queryData.start = end + 1;
          queryData.end = queryData.start + queryDuration;
          break;
      }

      // By "compacting" cursors, this fixes the disco/ping-pong problem
      // b/5311977
      if (mRowCount < 20 && queryData.queryType != QUERY_TYPE_CLEAN) {
        if (DEBUGLOG) {
          Log.e(
              TAG,
              "Compacting cursor: mRowCount="
                  + mRowCount
                  + " totalStart:"
                  + start
                  + " totalEnd:"
                  + end
                  + " query.start:"
                  + queryData.start
                  + " query.end:"
                  + queryData.end);
        }

        queryData.queryType = QUERY_TYPE_CLEAN;

        if (queryData.start > start) {
          queryData.start = start;
        }
        if (queryData.end < end) {
          queryData.end = end;
        }
      }
    }

    if (BASICLOG) {
      Time time = new Time(mTimeZone);
      time.setJulianDay(queryData.start);
      Time time2 = new Time(mTimeZone);
      time2.setJulianDay(queryData.end);
      Log.v(
          TAG,
          "startQuery: "
              + time.toString()
              + " to "
              + time2.toString()
              + " then go to "
              + queryData.goToTime);
    }

    mQueryHandler.cancelOperation(0);
    if (BASICLOG) queryData.queryStartMillis = System.nanoTime();

    Uri queryUri = buildQueryUri(queryData.start, queryData.end, queryData.searchQuery);
    mQueryHandler.startQuery(
        0, queryData, queryUri, PROJECTION, buildQuerySelection(), null, AGENDA_SORT_ORDER);
  }
Exemple #14
0
    /**
     * Take the String representing the complete forecast in JSON Format and pull out the data we
     * need to construct the Strings needed for the wireframes.
     *
     * <p>Fortunately parsing is easy: constructor takes the JSON string and converts it into an
     * Object hierarchy for us.
     */
    private String[] getWeatherDataFromJson(String forecastJsonStr, int numDays)
        throws JSONException {

      // These are the names of the JSON objects that need to be extracted.
      final String OWM_LIST = "list";
      final String OWM_MAIN = "main";
      final String OWM_WEATHER = "weather";
      final String OWM_MAX = "temp_max";
      final String OWM_MIN = "temp_min";
      final String OWM_DESCRIPTION = "main";

      JSONObject forecastJson = new JSONObject(forecastJsonStr);
      JSONArray weatherArray = forecastJson.getJSONArray(OWM_LIST);

      // OWM returns daily forecasts based upon the local time of the city that is being
      // asked for, which means that we need to know the GMT offset to translate this data
      // properly.

      // Since this data is also sent in-order and the first day is always the
      // current day, we're going to take advantage of that to get a nice
      // normalized UTC date for all of our weather.

      Time dayTime = new Time();
      dayTime.setToNow();

      // we start at the day returned by local time. Otherwise this is a mess.
      int julianStartDay = Time.getJulianDay(System.currentTimeMillis(), dayTime.gmtoff);

      // now we work exclusively in UTC
      dayTime = new Time();

      String[] resultStrs = new String[numDays];

      // Temperature Unit Preference
      SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getActivity());

      // Default is Metric
      String unitType =
          sharedPref.getString(
              getString(R.string.pref_units_key), getString(R.string.pref_units_metric));

      for (int i = 0; i < weatherArray.length(); i++) {
        // For now, using the format "Day, description, hi/low"
        String day;
        String description;
        String highAndLow;

        // Get the JSON object representing the day
        JSONObject dayForecast = weatherArray.getJSONObject(i);

        // The date/time is returned as a long.  We need to convert that
        // into something human-readable, since most people won't read "1400356800" as
        // "this saturday".
        long dateTime;
        // Cheating to convert this to UTC time, which is what we want anyhow
        dateTime = dayTime.setJulianDay(julianStartDay + i);
        day = getReadableDateString(dateTime);

        // description is in a child array called "weather", which is 1 element long.
        JSONObject weatherObject = dayForecast.getJSONArray(OWM_WEATHER).getJSONObject(0);
        description = weatherObject.getString(OWM_DESCRIPTION);

        // 3 Temperatures values are in a child object called "main". Try not to name variables
        // "temp" when working with temperature.  It confuses everybody.
        JSONObject descriptionObject = dayForecast.getJSONObject(OWM_MAIN);
        double high = descriptionObject.getDouble(OWM_MAX);
        double low = descriptionObject.getDouble(OWM_MIN);

        highAndLow = formatHighLows(high, low, unitType);
        resultStrs[i] = day + " - " + description + " - " + highAndLow;
      }

      return resultStrs;
    }
  /**
   * Take the String representing the complete forecast in JSON Format and pull out the data we need
   * to construct the Strings needed for the wireframes.
   *
   * <p>Fortunately parsing is easy: constructor takes the JSON string and converts it into an
   * Object hierarchy for us.
   */
  private void getWeatherDataFromJson(String forecastJsonStr, String locationSetting)
      throws JSONException {

    // Now we have a String representing the complete forecast in JSON Format.
    // Fortunately parsing is easy:  constructor takes the JSON string and converts it
    // into an Object hierarchy for us.

    // These are the names of the JSON objects that need to be extracted.

    // Location information
    final String OWM_CITY = "city";
    final String OWM_CITY_NAME = "name";
    final String OWM_COORD = "coord";

    // Location coordinate
    final String OWM_LATITUDE = "lat";
    final String OWM_LONGITUDE = "lon";

    // Weather information.  Each day's forecast info is an element of the "list" array.
    final String OWM_LIST = "list";

    final String OWM_PRESSURE = "pressure";
    final String OWM_HUMIDITY = "humidity";
    final String OWM_WINDSPEED = "speed";
    final String OWM_WIND_DIRECTION = "deg";

    // All temperatures are children of the "temp" object.
    final String OWM_TEMPERATURE = "temp";
    final String OWM_MAX = "max";
    final String OWM_MIN = "min";

    final String OWM_WEATHER = "weather";
    final String OWM_DESCRIPTION = "main";
    final String OWM_WEATHER_ID = "id";

    try {
      JSONObject forecastJson = new JSONObject(forecastJsonStr);
      JSONArray weatherArray = forecastJson.getJSONArray(OWM_LIST);

      JSONObject cityJson = forecastJson.getJSONObject(OWM_CITY);
      String cityName = cityJson.getString(OWM_CITY_NAME);

      JSONObject cityCoord = cityJson.getJSONObject(OWM_COORD);
      double cityLatitude = cityCoord.getDouble(OWM_LATITUDE);
      double cityLongitude = cityCoord.getDouble(OWM_LONGITUDE);

      long locationId = addLocation(locationSetting, cityName, cityLatitude, cityLongitude);

      // Insert the new weather information into the database
      Vector<ContentValues> cVVector = new Vector<ContentValues>(weatherArray.length());

      // OWM returns daily forecasts based upon the local time of the city that is being
      // asked for, which means that we need to know the GMT offset to translate this data
      // properly.

      // Since this data is also sent in-order and the first day is always the
      // current day, we're going to take advantage of that to get a nice
      // normalized UTC date for all of our weather.

      Time dayTime = new Time();
      dayTime.setToNow();

      // we start at the day returned by local time. Otherwise this is a mess.
      int julianStartDay = Time.getJulianDay(System.currentTimeMillis(), dayTime.gmtoff);

      // now we work exclusively in UTC
      dayTime = new Time();

      for (int i = 0; i < weatherArray.length(); i++) {
        // These are the values that will be collected.
        long dateTime;
        double pressure;
        int humidity;
        double windSpeed;
        double windDirection;

        double high;
        double low;

        String description;
        int weatherId;

        // Get the JSON object representing the day
        JSONObject dayForecast = weatherArray.getJSONObject(i);

        // Cheating to convert this to UTC time, which is what we want anyhow
        dateTime = dayTime.setJulianDay(julianStartDay + i);

        pressure = dayForecast.getDouble(OWM_PRESSURE);
        humidity = dayForecast.getInt(OWM_HUMIDITY);
        windSpeed = dayForecast.getDouble(OWM_WINDSPEED);
        windDirection = dayForecast.getDouble(OWM_WIND_DIRECTION);

        // Description is in a child array called "weather", which is 1 element long.
        // That element also contains a weather code.
        JSONObject weatherObject = dayForecast.getJSONArray(OWM_WEATHER).getJSONObject(0);
        description = weatherObject.getString(OWM_DESCRIPTION);
        weatherId = weatherObject.getInt(OWM_WEATHER_ID);

        // Temperatures are in a child object called "temp".  Try not to name variables
        // "temp" when working with temperature.  It confuses everybody.
        JSONObject temperatureObject = dayForecast.getJSONObject(OWM_TEMPERATURE);
        high = temperatureObject.getDouble(OWM_MAX);
        low = temperatureObject.getDouble(OWM_MIN);

        ContentValues weatherValues = new ContentValues();

        weatherValues.put(WeatherEntry.COLUMN_LOC_KEY, locationId);
        weatherValues.put(WeatherEntry.COLUMN_DATE, dateTime);
        weatherValues.put(WeatherEntry.COLUMN_HUMIDITY, humidity);
        weatherValues.put(WeatherEntry.COLUMN_PRESSURE, pressure);
        weatherValues.put(WeatherEntry.COLUMN_WIND_SPEED, windSpeed);
        weatherValues.put(WeatherEntry.COLUMN_DEGREES, windDirection);
        weatherValues.put(WeatherEntry.COLUMN_MAX_TEMP, high);
        weatherValues.put(WeatherEntry.COLUMN_MIN_TEMP, low);
        weatherValues.put(WeatherEntry.COLUMN_SHORT_DESC, description);
        weatherValues.put(WeatherEntry.COLUMN_WEATHER_ID, weatherId);

        cVVector.add(weatherValues);
      }

      int inserted = 0;
      // add to database
      if (cVVector.size() > 0) {
        ContentValues[] cvArray = new ContentValues[cVVector.size()];
        cVVector.toArray(cvArray);
        inserted = mContext.getContentResolver().bulkInsert(WeatherEntry.CONTENT_URI, cvArray);
      }

      Log.d(LOG_TAG, "FetchWeatherTask Complete. " + inserted + " Inserted");

    } catch (JSONException e) {
      Log.e(LOG_TAG, e.getMessage(), e);
      e.printStackTrace();
    }
  }