GeneralLocation.java

/*
 * Copyright (C) 2014 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package androidx.test.espresso.action;

import android.graphics.Rect;
import android.view.View;

/** Calculates coordinate position for general locations. */
public enum GeneralLocation implements CoordinatesProvider {
  TOP_LEFT {
    @Override
    public float[] calculateCoordinates(View view) {
      return getCoordinates(view, Position.BEGIN, Position.BEGIN);
    }
  },
  TOP_CENTER {
    @Override
    public float[] calculateCoordinates(View view) {
      return getCoordinates(view, Position.BEGIN, Position.MIDDLE);
    }
  },
  TOP_RIGHT {
    @Override
    public float[] calculateCoordinates(View view) {
      return getCoordinates(view, Position.BEGIN, Position.END);
    }
  },
  CENTER_LEFT {
    @Override
    public float[] calculateCoordinates(View view) {
      return getCoordinates(view, Position.MIDDLE, Position.BEGIN);
    }
  },
  CENTER {
    @Override
    public float[] calculateCoordinates(View view) {
      return getCoordinates(view, Position.MIDDLE, Position.MIDDLE);
    }
  },
  CENTER_RIGHT {
    @Override
    public float[] calculateCoordinates(View view) {
      return getCoordinates(view, Position.MIDDLE, Position.END);
    }
  },
  BOTTOM_LEFT {
    @Override
    public float[] calculateCoordinates(View view) {
      return getCoordinates(view, Position.END, Position.BEGIN);
    }
  },
  BOTTOM_CENTER {
    @Override
    public float[] calculateCoordinates(View view) {
      return getCoordinates(view, Position.END, Position.MIDDLE);
    }
  },
  BOTTOM_RIGHT {
    @Override
    public float[] calculateCoordinates(View view) {
      return getCoordinates(view, Position.END, Position.END);
    }
  },
  VISIBLE_CENTER {
    @Override
    public float[] calculateCoordinates(View view) {
      return getCoordinatesOfVisiblePart(view, Position.MIDDLE, Position.MIDDLE);
    }
  };

  /**
   * Translates the given coordinates by the given distances. The distances are given in term of the
   * view's size -- 1.0 means to translate by an amount equivalent to the view's length.
   */
  static CoordinatesProvider translate(
      final CoordinatesProvider coords, final float dx, final float dy) {
    return new TranslatedCoordinatesProvider(coords, dx, dy);
  }

  private static float[] getCoordinates(View view, Position vertical, Position horizontal) {
    final int[] xy = new int[2];
    view.getLocationOnScreen(xy);
    final float x = horizontal.getPosition(xy[0], view.getWidth());
    final float y = vertical.getPosition(xy[1], view.getHeight());
    float[] coordinates = {x, y};
    return coordinates;
  }

  private static float[] getCoordinatesOfVisiblePart(
      View view, Position vertical, Position horizontal) {
    final int[] xy = new int[2];
    view.getLocationOnScreen(xy);
    Rect visibleParts = new Rect();
    view.getGlobalVisibleRect(visibleParts);
    final float x = horizontal.getPosition(xy[0], visibleParts.width());
    final float y = vertical.getPosition(xy[1], visibleParts.height());
    float[] coordinates = {x, y};
    return coordinates;
  }

  private enum Position {
    BEGIN {
      @Override
      public float getPosition(int viewPos, int viewLength) {
        return viewPos;
      }
    },
    MIDDLE {
      @Override
      public float getPosition(int viewPos, int viewLength) {
        // Midpoint between the leftmost and rightmost pixel (position viewLength - 1).
        return viewPos + (viewLength - 1) / 2.0f;
      }
    },
    END {
      @Override
      public float getPosition(int viewPos, int viewLength) {
        return viewPos + viewLength - 1;
      }
    };

    abstract float getPosition(int widgetPos, int widgetLength);
  }
}