public ParallaxImageView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);

    // Instantiate future objects
    mTranslationMatrix = new Matrix();
    mSensorInterpreter = new SensorInterpreter();

    // Sets scale type
    setScaleType(ScaleType.MATRIX);

    // Set available attributes
    if (attrs != null) {
      final TypedArray customAttrs =
          context.obtainStyledAttributes(attrs, R.styleable.ParallaxImageView);

      if (customAttrs != null) {
        if (customAttrs.hasValue(R.styleable.ParallaxImageView_intensity))
          setParallaxIntensity(
              customAttrs.getFloat(R.styleable.ParallaxImageView_intensity, mParallaxIntensity));

        if (customAttrs.hasValue(R.styleable.ParallaxImageView_scaledIntensity))
          setScaledIntensities(
              customAttrs.getBoolean(
                  R.styleable.ParallaxImageView_scaledIntensity, mScaledIntensities));

        if (customAttrs.hasValue(R.styleable.ParallaxImageView_tiltSensitivity))
          setTiltSensitivity(
              customAttrs.getFloat(
                  R.styleable.ParallaxImageView_tiltSensitivity,
                  mSensorInterpreter.getTiltSensitivity()));

        if (customAttrs.hasValue(R.styleable.ParallaxImageView_forwardTiltOffset))
          setForwardTiltOffset(
              customAttrs.getFloat(
                  R.styleable.ParallaxImageView_forwardTiltOffset,
                  mSensorInterpreter.getForwardTiltOffset()));

        customAttrs.recycle();
      }
    }

    // Configure matrix as early as possible by posting to MessageQueue
    post(
        new Runnable() {
          @Override
          public void run() {
            configureMatrix();
          }
        });
  }