public TableData(ChartData chartData) {
   this.setFields(chartData.getFields());
   this.setFiles(chartData.getFiles());
   this.setFilters(chartData.getFilters());
   this.setHpccConnection(chartData.getHpccConnection());
   this.setInputParams(chartData.getInputParams());
   this.setIsFiltered(chartData.getIsFiltered());
   this.setIsQuery(chartData.getIsQuery());
   this.setJoins(chartData.getJoins());
 }
  void finishPaths(
      int w,
      int h,
      int levelh,
      int startX,
      int y,
      Path curLevelPath,
      int lastX,
      boolean lastCharging,
      boolean lastScreenOn,
      boolean lastGpsOn,
      boolean lastWifiRunning,
      boolean lastWakeLock,
      Path lastPath) {
    if (curLevelPath != null) {
      if (lastX >= 0 && lastX < w) {
        if (lastPath != null) {
          lastPath.lineTo(w, y);
        }
        curLevelPath.lineTo(w, y);
      }
      curLevelPath.lineTo(w, mLevelTop + levelh);
      curLevelPath.lineTo(startX, mLevelTop + levelh);
      curLevelPath.close();
    }

    if (lastCharging) {
      mChargingPath.lineTo(w, h - mChargingOffset);
    }
    if (lastScreenOn) {
      mScreenOnPath.lineTo(w, h - mScreenOnOffset);
    }
    if (lastGpsOn) {
      mGpsOnPath.lineTo(w, h - mGpsOnOffset);
    }
    if (lastWifiRunning) {
      mWifiRunningPath.lineTo(w, h - mWifiRunningOffset);
    }
    if (lastWakeLock) {
      mWakeLockPath.lineTo(w, h - mWakeLockOffset);
    }
    mPhoneSignalChart.finish(w);
  }
  @Override
  protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);

    int textHeight = mTextDescent - mTextAscent;
    mThinLineWidth =
        (int)
            TypedValue.applyDimension(
                TypedValue.COMPLEX_UNIT_DIP, 2, getResources().getDisplayMetrics());
    if (h > (textHeight * 6)) {
      mLargeMode = true;
      mLineWidth = textHeight / 2;
      mLevelTop = textHeight + mLineWidth;
      mScreenOnPaint.setARGB(255, 32, 64, 255);
      mGpsOnPaint.setARGB(255, 32, 64, 255);
      mWifiRunningPaint.setARGB(255, 32, 64, 255);
      mWakeLockPaint.setARGB(255, 32, 64, 255);
    } else {
      mLargeMode = false;
      mLineWidth = mThinLineWidth;
      mLevelTop = 0;
      mScreenOnPaint.setARGB(255, 0, 0, 255);
      mGpsOnPaint.setARGB(255, 0, 0, 255);
      mWifiRunningPaint.setARGB(255, 0, 0, 255);
      mWakeLockPaint.setARGB(255, 0, 0, 255);
    }
    if (mLineWidth <= 0) mLineWidth = 1;
    mTextPaint.setStrokeWidth(mThinLineWidth);
    mBatteryGoodPaint.setStrokeWidth(mThinLineWidth);
    mBatteryWarnPaint.setStrokeWidth(mThinLineWidth);
    mBatteryCriticalPaint.setStrokeWidth(mThinLineWidth);
    mChargingPaint.setStrokeWidth(mLineWidth);
    mScreenOnPaint.setStrokeWidth(mLineWidth);
    mGpsOnPaint.setStrokeWidth(mLineWidth);
    mWifiRunningPaint.setStrokeWidth(mLineWidth);
    mWakeLockPaint.setStrokeWidth(mLineWidth);

    if (mLargeMode) {
      int barOffset = textHeight + mLineWidth;
      mChargingOffset = mLineWidth;
      mScreenOnOffset = mChargingOffset + barOffset;
      mWakeLockOffset = mScreenOnOffset + barOffset;
      mWifiRunningOffset = mWakeLockOffset + barOffset;
      mGpsOnOffset = mWifiRunningOffset + (mHaveWifi ? barOffset : 0);
      mPhoneSignalOffset = mGpsOnOffset + (mHaveGps ? barOffset : 0);
      mLevelOffset = mPhoneSignalOffset + barOffset + mLineWidth;
      mPhoneSignalChart.init(w);
    } else {
      mScreenOnOffset = mGpsOnOffset = mWifiRunningOffset = mWakeLockOffset = mLineWidth;
      mChargingOffset = mLineWidth * 2;
      mPhoneSignalOffset = 0;
      mLevelOffset = mLineWidth * 3;
      mPhoneSignalChart.init(0);
    }

    mBatLevelPath.reset();
    mBatGoodPath.reset();
    mBatWarnPath.reset();
    mBatCriticalPath.reset();
    mScreenOnPath.reset();
    mGpsOnPath.reset();
    mWifiRunningPath.reset();
    mWakeLockPath.reset();
    mChargingPath.reset();

    final long timeStart = mHistStart;
    final long timeChange = mHistEnd - mHistStart;

    final int batLow = mBatLow;
    final int batChange = mBatHigh - mBatLow;

    final int levelh = h - mLevelOffset - mLevelTop;
    mLevelBottom = mLevelTop + levelh;

    int x = 0, y = 0, startX = 0, lastX = -1, lastY = -1;
    int i = 0;
    Path curLevelPath = null;
    Path lastLinePath = null;
    boolean lastCharging = false, lastScreenOn = false, lastGpsOn = false;
    boolean lastWifiRunning = false, lastWakeLock = false;
    final int N = mNumHist;
    if (mStats.startIteratingHistoryLocked()) {
      final HistoryItem rec = new HistoryItem();
      while (mStats.getNextHistoryLocked(rec) && i < N) {
        if (rec.cmd == BatteryStats.HistoryItem.CMD_UPDATE) {
          x = (int) (((rec.time - timeStart) * w) / timeChange);
          y = mLevelTop + levelh - ((rec.batteryLevel - batLow) * (levelh - 1)) / batChange;

          if (lastX != x) {
            // We have moved by at least a pixel.
            if (lastY != y) {
              // Don't plot changes within a pixel.
              Path path;
              byte value = rec.batteryLevel;
              if (value <= BATTERY_CRITICAL) path = mBatCriticalPath;
              else if (value <= BATTERY_WARN) path = mBatWarnPath;
              else path = mBatGoodPath;

              if (path != lastLinePath) {
                if (lastLinePath != null) {
                  lastLinePath.lineTo(x, y);
                }
                path.moveTo(x, y);
                lastLinePath = path;
              } else {
                path.lineTo(x, y);
              }

              if (curLevelPath == null) {
                curLevelPath = mBatLevelPath;
                curLevelPath.moveTo(x, y);
                startX = x;
              } else {
                curLevelPath.lineTo(x, y);
              }
              lastX = x;
              lastY = y;
            }

            final boolean charging = (rec.states & HistoryItem.STATE_BATTERY_PLUGGED_FLAG) != 0;
            if (charging != lastCharging) {
              if (charging) {
                mChargingPath.moveTo(x, h - mChargingOffset);
              } else {
                mChargingPath.lineTo(x, h - mChargingOffset);
              }
              lastCharging = charging;
            }

            final boolean screenOn = (rec.states & HistoryItem.STATE_SCREEN_ON_FLAG) != 0;
            if (screenOn != lastScreenOn) {
              if (screenOn) {
                mScreenOnPath.moveTo(x, h - mScreenOnOffset);
              } else {
                mScreenOnPath.lineTo(x, h - mScreenOnOffset);
              }
              lastScreenOn = screenOn;
            }

            final boolean gpsOn = (rec.states & HistoryItem.STATE_GPS_ON_FLAG) != 0;
            if (gpsOn != lastGpsOn) {
              if (gpsOn) {
                mGpsOnPath.moveTo(x, h - mGpsOnOffset);
              } else {
                mGpsOnPath.lineTo(x, h - mGpsOnOffset);
              }
              lastGpsOn = gpsOn;
            }

            final boolean wifiRunning = (rec.states & HistoryItem.STATE_WIFI_RUNNING_FLAG) != 0;
            if (wifiRunning != lastWifiRunning) {
              if (wifiRunning) {
                mWifiRunningPath.moveTo(x, h - mWifiRunningOffset);
              } else {
                mWifiRunningPath.lineTo(x, h - mWifiRunningOffset);
              }
              lastWifiRunning = wifiRunning;
            }

            final boolean wakeLock = (rec.states & HistoryItem.STATE_WAKE_LOCK_FLAG) != 0;
            if (wakeLock != lastWakeLock) {
              if (wakeLock) {
                mWakeLockPath.moveTo(x, h - mWakeLockOffset);
              } else {
                mWakeLockPath.lineTo(x, h - mWakeLockOffset);
              }
              lastWakeLock = wakeLock;
            }

            if (mLargeMode) {
              int bin;
              if (((rec.states & HistoryItem.STATE_PHONE_STATE_MASK)
                      >> HistoryItem.STATE_PHONE_STATE_SHIFT)
                  == ServiceState.STATE_POWER_OFF) {
                bin = 0;
              } else if ((rec.states & HistoryItem.STATE_PHONE_SCANNING_FLAG) != 0) {
                bin = 1;
              } else {
                bin =
                    (rec.states & HistoryItem.STATE_SIGNAL_STRENGTH_MASK)
                        >> HistoryItem.STATE_SIGNAL_STRENGTH_SHIFT;
                bin += 2;
              }
              mPhoneSignalChart.addTick(x, bin);
            }
          }

        } else if (rec.cmd != BatteryStats.HistoryItem.CMD_OVERFLOW) {
          if (curLevelPath != null) {
            finishPaths(
                x + 1,
                h,
                levelh,
                startX,
                lastY,
                curLevelPath,
                lastX,
                lastCharging,
                lastScreenOn,
                lastGpsOn,
                lastWifiRunning,
                lastWakeLock,
                lastLinePath);
            lastX = lastY = -1;
            curLevelPath = null;
            lastLinePath = null;
            lastCharging = lastScreenOn = lastGpsOn = lastWakeLock = false;
          }
        }

        i++;
      }
    }

    finishPaths(
        w,
        h,
        levelh,
        startX,
        lastY,
        curLevelPath,
        lastX,
        lastCharging,
        lastScreenOn,
        lastGpsOn,
        lastWifiRunning,
        lastWakeLock,
        lastLinePath);
  }
  public BatteryHistoryChart(Context context, AttributeSet attrs) {
    super(context, attrs);

    mBatteryBackgroundPaint.setARGB(255, 128, 128, 128);
    mBatteryBackgroundPaint.setStyle(Paint.Style.FILL);
    mBatteryGoodPaint.setARGB(128, 0, 255, 0);
    mBatteryGoodPaint.setStyle(Paint.Style.STROKE);
    mBatteryWarnPaint.setARGB(128, 255, 255, 0);
    mBatteryWarnPaint.setStyle(Paint.Style.STROKE);
    mBatteryCriticalPaint.setARGB(192, 255, 0, 0);
    mBatteryCriticalPaint.setStyle(Paint.Style.STROKE);
    mChargingPaint.setARGB(255, 0, 128, 0);
    mChargingPaint.setStyle(Paint.Style.STROKE);
    mScreenOnPaint.setStyle(Paint.Style.STROKE);
    mGpsOnPaint.setStyle(Paint.Style.STROKE);
    mWifiRunningPaint.setStyle(Paint.Style.STROKE);
    mWakeLockPaint.setStyle(Paint.Style.STROKE);
    mPhoneSignalChart.setColors(
        new int[] {
          0x00000000, 0xffa00000, 0xffa0a000, 0xff808020, 0xff808040, 0xff808060, 0xff008000
        });

    mTextPaint.density = getResources().getDisplayMetrics().density;
    mTextPaint.setCompatibilityScaling(getResources().getCompatibilityInfo().applicationScale);

    TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.BatteryHistoryChart, 0, 0);

    ColorStateList textColor = null;
    int textSize = 15;
    int typefaceIndex = -1;
    int styleIndex = -1;

    TypedArray appearance = null;
    int ap = a.getResourceId(R.styleable.BatteryHistoryChart_android_textAppearance, -1);
    if (ap != -1) {
      appearance =
          context.obtainStyledAttributes(ap, com.android.internal.R.styleable.TextAppearance);
    }
    if (appearance != null) {
      int n = appearance.getIndexCount();
      for (int i = 0; i < n; i++) {
        int attr = appearance.getIndex(i);

        switch (attr) {
          case com.android.internal.R.styleable.TextAppearance_textColor:
            textColor = appearance.getColorStateList(attr);
            break;

          case com.android.internal.R.styleable.TextAppearance_textSize:
            textSize = appearance.getDimensionPixelSize(attr, textSize);
            break;

          case com.android.internal.R.styleable.TextAppearance_typeface:
            typefaceIndex = appearance.getInt(attr, -1);
            break;

          case com.android.internal.R.styleable.TextAppearance_textStyle:
            styleIndex = appearance.getInt(attr, -1);
            break;
        }
      }

      appearance.recycle();
    }

    int shadowcolor = 0;
    float dx = 0, dy = 0, r = 0;

    int n = a.getIndexCount();
    for (int i = 0; i < n; i++) {
      int attr = a.getIndex(i);

      switch (attr) {
        case R.styleable.BatteryHistoryChart_android_shadowColor:
          shadowcolor = a.getInt(attr, 0);
          break;

        case R.styleable.BatteryHistoryChart_android_shadowDx:
          dx = a.getFloat(attr, 0);
          break;

        case R.styleable.BatteryHistoryChart_android_shadowDy:
          dy = a.getFloat(attr, 0);
          break;

        case R.styleable.BatteryHistoryChart_android_shadowRadius:
          r = a.getFloat(attr, 0);
          break;

        case R.styleable.BatteryHistoryChart_android_textColor:
          textColor = a.getColorStateList(attr);
          break;

        case R.styleable.BatteryHistoryChart_android_textSize:
          textSize = a.getDimensionPixelSize(attr, textSize);
          break;

        case R.styleable.BatteryHistoryChart_android_typeface:
          typefaceIndex = a.getInt(attr, typefaceIndex);
          break;

        case R.styleable.BatteryHistoryChart_android_textStyle:
          styleIndex = a.getInt(attr, styleIndex);
          break;
      }
    }

    a.recycle();

    mTextPaint.setColor(textColor.getDefaultColor());
    mTextPaint.setTextSize(textSize);

    Typeface tf = null;
    switch (typefaceIndex) {
      case SANS:
        tf = Typeface.SANS_SERIF;
        break;

      case SERIF:
        tf = Typeface.SERIF;
        break;

      case MONOSPACE:
        tf = Typeface.MONOSPACE;
        break;
    }

    setTypeface(tf, styleIndex);

    if (shadowcolor != 0) {
      mTextPaint.setShadowLayer(r, dx, dy, shadowcolor);
    }
  }