code: package freed.cam.histogram;
  
  import android.graphics.Bitmap;
  import android.view.View;
  import android.widget.ImageView;
  
  import java.util.concurrent.ArrayBlockingQueue;
  
  import freed.gl.MeteringProcessor;
  import freed.settings.SettingsManager;
  import freed.utils.Log;
  
  public class HistogramController implements HistogramChangedEvent {
  
      public interface DataListner
      {
          void setData(HistogramData data);
          void setWaveFormData(int[] data, int width, int height);
      }
  
      private static final String TAG = HistogramController.class.getSimpleName();
      private MyHistogram myHistogram;
      private MyHistogram cameraHistogram;
      private HistogramFeed feedToRegister;
      private final HistogramProcessor histogramProcessor;
      private boolean enabled;
      private boolean cameraHistogramEnabled;
      private final HistogramData histogramData;
      private DataListner dataListner;
      private ImageView waveFormView;
      private final MeteringProcessor meteringProcessor;
  
      public HistogramController(SettingsManager settingsManager)
      {
          histogramProcessor = new HistogramProcessor(this);
          histogramData = new HistogramData();
          meteringProcessor = new MeteringProcessor(settingsManager);
      }
  
      public MeteringProcessor getMeteringProcessor() {
          return meteringProcessor;
      }
  
      public void setMyHistogram(MyHistogram myHistogram)
      {
          this.myHistogram = myHistogram;
          if (enabled && myHistogram != null)
              myHistogram.setVisibility(View.VISIBLE);
      }
  
      public void setCameraHistogram(MyHistogram histogram)
      {
          this.cameraHistogram = histogram;
          if (cameraHistogramEnabled && cameraHistogram != null)
              cameraHistogram.setVisibility(View.VISIBLE);
      }
  
      public void setWaveFormView(ImageView imageView)
      {
          this.waveFormView = imageView;
          if (enabled && waveFormView != null)
              waveFormView.setVisibility(View.VISIBLE);
      }
  
      public void setDataListner(DataListner dataListner) {
          this.dataListner = dataListner;
      }
  
      public void setFeedToRegister(HistogramFeed histogramFeed) {
          this.feedToRegister = histogramFeed;
      }
  
      public void enable(boolean en)
      {
          if(myHistogram != null) {
              enabled = en;
              myHistogram.post(new Runnable() {
                  @Override
                  public void run() {
                      if (en) {
                          if (myHistogram != null) {
                              myHistogram.setVisibility(View.VISIBLE);
                              myHistogram.bringToFront();
                          }
                          if (waveFormView != null) {
                              waveFormView.setVisibility(View.VISIBLE);
                              waveFormView.bringToFront();
                          }
  
                      } else {
                          if (myHistogram != null)
                              myHistogram.setVisibility(View.GONE);
                          if (waveFormView != null)
                              waveFormView.setVisibility(View.GONE);
                          if (dataListner != null) {
                              dataListner.setData(null);
                              dataListner.setWaveFormData(null, 0, 0);
                          }
  
                      }
                  }
              });
  
          }
      }
  
      public void enableCameraHistogram(boolean en)
      {
          if (cameraHistogram != null)
          {
              cameraHistogramEnabled = en;
              cameraHistogram.post(new Runnable() {
                  @Override
                  public void run() {
                      if (cameraHistogramEnabled)
                      {
                          if (cameraHistogram != null) {
                              cameraHistogram.setVisibility(View.VISIBLE);
                              cameraHistogram.bringToFront();
                          }
                          if (feedToRegister != null)
                              feedToRegister.setHistogramFeed(HistogramController.this);
                          else
                              Log.d(TAG, "histogram on feed to Register is null!");
                      }
                      else {
                          if (cameraHistogram != null)
                              cameraHistogram.setVisibility(View.GONE);
                          if (feedToRegister != null)
                              feedToRegister.setHistogramFeed(null);
                          else
                              Log.d(TAG, "histogram off feed to Register is null!");
                      }
                  }
              });
          }
      }
  
      @Override
      public int[] getRedHistogram(){return histogramData.getRedHistogram();}
      @Override
      public int[] getGreenHistogram(){return histogramData.getGreenHistogram();}
      @Override
      public int[] getBlueHistogram() {return histogramData.getBlueHistogram();}
  
      @Override
      public void setBlueHistogram(int[] blue) {
          histogramData.setBlueHistogram(blue);
      }
  
      @Override
      public void setRedHistogram(int[] red) {
          histogramData.setRedHistogram(red);
      }
  
      @Override
      public void setGreenHistogram(int[] green) {
          histogramData.setGreenHistogram(green);
      }
  
      @Override
      public void updateHistogram() {
          myHistogram.post(new Runnable() {
              @Override
  
              public void run() {
                  //src pos 0,256,512
                  myHistogram.setHistogramData(histogramData);
              }
          });
      }
  
      @Override
      public void onHistogramChanged(final int[] histogram_data) {
          histogramData.setHistogramData(histogram_data, HistogramData.HistoDataAlignment.RGBA);
          cameraHistogram.post(() -> {
              //src pos 0,256,512
              cameraHistogram.setHistogramData(histogramData);
          });
          if (dataListner != null)
              dataListner.setData(histogramData);
      }
  
      @Override
      protected void finalize() throws Throwable {
          super.finalize();
      }
  
      public void setImageData(final byte[] imagedata,int width, int height)
      {
          histogramProcessor.add(imagedata,width,height);
      }
  
      public boolean isEnabled() {
          return enabled;
      }
  
      public boolean isCameraHistogramEnabled()
      {
          return cameraHistogramEnabled;
      }
  
      public void setWaveFormData(int[] waveFormData,int width, int height)
      {
          if(waveFormView != null) {
              waveFormUpdater.setData(waveFormData, width, height);
              waveFormView.post(waveFormUpdater);
          }
  
          if (dataListner != null)
              dataListner.setWaveFormData(waveFormData,width,height);
      }
  
  
      WaveFormUpdater waveFormUpdater = new WaveFormUpdater() {
  
          final ArrayBlockingQueue<int[]> waveformQueue = new ArrayBlockingQueue(3);
          int width; int height;
          private Bitmap bitmap;
  
          public void setData(int[] waveFormData,int width, int height)
          {
              synchronized (waveformQueue)
              {
                  if (waveformQueue.size() == 3)
                      waveformQueue.poll();
                  waveformQueue.offer(waveFormData);
              }
              this.width = width;
              this.height = height;
  
          }
  
          @Override
          public void run() {
  
              int[] waveFormData = waveformQueue.poll();
              if (waveFormData == null || width == 0 || height == 0)
              {
                  Log.e(TAG, "Error updating waveform");
                  return;
              }
              if (bitmap == null)
                  bitmap = Bitmap.createBitmap(width,height,Bitmap.Config.ARGB_8888);
  
              try {
                  bitmap.setPixels(waveFormData, 0, width, 0, 0, width, height);
                  waveFormView.setImageBitmap(bitmap);
              }
              catch (IllegalArgumentException ex)
              {
                  Log.e(TAG, ex.getMessage());
              }
          }
      };
  
      interface  WaveFormUpdater extends Runnable
      {
          void setData(int[] waveFormData, int width, int height);
      }
  
      interface  HistogramUpdater extends Runnable
      {
          void setData(HistogramData histogramData);
      }
  
      HistogramUpdater histogramUpdater = new HistogramUpdater() {
          final ArrayBlockingQueue<HistogramData> histogramDatas = new ArrayBlockingQueue(3);
          @Override
          public void setData(HistogramData histogramData) {
              synchronized (histogramDatas)
              {
                  if (histogramDatas.size() == 3)
                      histogramDatas.poll();
                  histogramDatas.offer(histogramData);
              }
          }
  
          @Override
          public void run() {
              HistogramData data = histogramDatas.poll();
              if (data != null)
                  myHistogram.setHistogramData(data);
          }
      };
  
      public void updateData(HistogramData data)
      {
          histogramUpdater.setData(data);
          myHistogram.post(histogramUpdater);
      }
  }
  