/*
* Copyright 2020 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.camera.view.preview.transform;
import android.util.Pair;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.camera.view.preview.transform.transformation.TranslationTransformation;
/**
* Computes the horizontal and vertical translations by which the preview needs to be translated
* to position it at the start, center or end of its parent.
* <p>
* The start represents the top left corner in a left-to-right (LTR) layout, or the top right
* corner in a right-to-left (RTL) layout.
* <p>
* The end represents the bottom right corner in a left-to-right (LTR) layout, or the bottom left
* corner in a right-to-left (RTL) layout.
*/
final class TranslationTransform {
private TranslationTransform() {
}
/**
* Computes the horizontal and vertical translations to set on {@code view} to align it to the
* start of its parent {@code container}.
* <p>
* The start represents the top left corner in a left-to-right (LTR) layout, or the top right
* corner in a right-to-left (RTL) layout.
*/
static TranslationTransformation start(@NonNull final View view,
@NonNull final Pair<Float, Float> scaleXY, final int deviceRotation) {
if (view.getWidth() == 0 || view.getHeight() == 0) {
return new TranslationTransformation(0, 0);
}
// Scaled width and height of the view
final int scaledWidth = (int) (view.getWidth() * scaleXY.first);
final int scaledHeight = (int) (view.getHeight() * scaleXY.second);
final int viewRotationDegrees = (int) RotationTransform.getRotationDegrees(view,
deviceRotation);
final boolean isPortrait = viewRotationDegrees == 0 || viewRotationDegrees == 180;
// Coordinates of the view's center after the `start` translation
final int targetCenterX;
final int targetCenterY;
if (isPortrait) {
targetCenterX = scaledWidth / 2;
targetCenterY = scaledHeight / 2;
} else {
targetCenterX = scaledHeight / 2;
targetCenterY = scaledWidth / 2;
}
// Current coordinates of the view's center
final int currentCenterX = view.getWidth() / 2;
final int currentCenterY = view.getHeight() / 2;
final int transX = reverseIfRTLLayout(view, targetCenterX - currentCenterX);
final int transY = targetCenterY - currentCenterY;
return new TranslationTransformation(transX, transY);
}
/**
* Computes the horizontal and vertical translations to set on {@code view} to center it in its
* parent {@code container}.
*/
static TranslationTransformation center(@NonNull final View container,
@NonNull final View view) {
if (view.getWidth() == 0 || view.getHeight() == 0) {
return new TranslationTransformation(0, 0);
}
// Coordinates of the view's center after the `center` translation
final int targetCenterX = container.getWidth() / 2;
final int targetCenterY = container.getHeight() / 2;
// Current coordinates of the view's center
final int currentCenterX = view.getWidth() / 2;
final int currentCenterY = view.getHeight() / 2;
final int transX = reverseIfRTLLayout(view, targetCenterX - currentCenterX);
final int transY = targetCenterY - currentCenterY;
return new TranslationTransformation(transX, transY);
}
/**
* Computes the horizontal and vertical translations to set on {@code view} to align it to the
* end of its parent {@code container}.
* <p>
* The end represents the bottom right corner in a left-to-right (LTR) layout, or the bottom
* left corner in a right-to-left (RTL) layout.
*/
static TranslationTransformation end(@NonNull final View container, @NonNull final View view,
@NonNull final Pair<Float, Float> scaleXY, final int deviceRotation) {
if (view.getWidth() == 0 || view.getHeight() == 0) {
return new TranslationTransformation(0, 0);
}
// Coordinates of the bottom right corner of the container
final int endX = container.getWidth();
final int endY = container.getHeight();
// Scaled width and height of the view
final int scaledWidth = (int) (view.getWidth() * scaleXY.first);
final int scaledHeight = (int) (view.getHeight() * scaleXY.second);
final int viewRotationDegrees = (int) RotationTransform.getRotationDegrees(view,
deviceRotation);
final boolean isPortrait = viewRotationDegrees == 0 || viewRotationDegrees == 180;
// Coordinates of the view's center after the `end` translation
final int targetCenterX;
final int targetCenterY;
if (isPortrait) {
targetCenterX = endX - (scaledWidth / 2);
targetCenterY = endY - (scaledHeight / 2);
} else {
targetCenterX = endX - (scaledHeight / 2);
targetCenterY = endY - (scaledWidth / 2);
}
// Current coordinates of the view's center
final int currentCenterX = view.getWidth() / 2;
final int currentCenterY = view.getHeight() / 2;
final int transX = reverseIfRTLLayout(view, targetCenterX - currentCenterX);
final int transY = targetCenterY - currentCenterY;
return new TranslationTransformation(transX, transY);
}
/**
* Reverses a horizontal translation if the {@code view} is in a right-to-left (RTL) layout.
*
* @return The passed in horizontal translation if the layout is left-to-right (LTR), or its
* reverse if the layout is right-to-left (RTL).
*/
private static int reverseIfRTLLayout(@NonNull final View view, int transX) {
final boolean isRTLDirection = view.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
return isRTLDirection ? -transX : transX;
}
}