blob: e1737eccc6e1db25027db7ff6cefd167dd7350f5 [file] [log] [blame]
/*
* Copyright (C) 2022 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 com.android.wm.shell.pip.tv;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.PictureInPictureParams;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.graphics.Insets;
import android.util.Size;
import android.view.Gravity;
import android.view.View;
import com.android.wm.shell.pip.PipBoundsAlgorithm;
import com.android.wm.shell.pip.PipBoundsState;
import com.android.wm.shell.pip.PipDisplayLayoutState;
import com.android.wm.shell.pip.phone.PipSizeSpecHandler;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* TV specific values of the current state of the PiP bounds.
*/
public class TvPipBoundsState extends PipBoundsState {
public static final int ORIENTATION_UNDETERMINED = 0;
public static final int ORIENTATION_VERTICAL = 1;
public static final int ORIENTATION_HORIZONTAL = 2;
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = {"ORIENTATION_"}, value = {
ORIENTATION_UNDETERMINED,
ORIENTATION_VERTICAL,
ORIENTATION_HORIZONTAL
})
public @interface Orientation {
}
private final Context mContext;
private int mDefaultGravity;
private int mTvPipGravity;
private int mPreviousCollapsedGravity;
private boolean mIsRtl;
private final boolean mIsTvExpandedPipSupported;
private boolean mIsTvPipExpanded;
private boolean mTvPipManuallyCollapsed;
private float mDesiredTvExpandedAspectRatio;
@Orientation
private int mTvFixedPipOrientation;
@Nullable
private Size mTvExpandedSize;
@NonNull
private Insets mPipMenuPermanentDecorInsets = Insets.NONE;
@NonNull
private Insets mPipMenuTemporaryDecorInsets = Insets.NONE;
public TvPipBoundsState(@NonNull Context context,
@NonNull PipSizeSpecHandler pipSizeSpecHandler,
@NonNull PipDisplayLayoutState pipDisplayLayoutState) {
super(context, pipSizeSpecHandler, pipDisplayLayoutState);
mContext = context;
updateDefaultGravity();
mPreviousCollapsedGravity = mDefaultGravity;
mIsTvExpandedPipSupported = context.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_EXPANDED_PICTURE_IN_PICTURE);
}
public int getDefaultGravity() {
return mDefaultGravity;
}
private void updateDefaultGravity() {
boolean isRtl = mContext.getResources().getConfiguration().getLayoutDirection()
== View.LAYOUT_DIRECTION_RTL;
mDefaultGravity = Gravity.BOTTOM | (isRtl ? Gravity.LEFT : Gravity.RIGHT);
if (mIsRtl != isRtl) {
int prevGravityX = mPreviousCollapsedGravity & Gravity.HORIZONTAL_GRAVITY_MASK;
int prevGravityY = mPreviousCollapsedGravity & Gravity.VERTICAL_GRAVITY_MASK;
if ((prevGravityX & Gravity.RIGHT) == Gravity.RIGHT) {
mPreviousCollapsedGravity = Gravity.LEFT | prevGravityY;
} else if ((prevGravityX & Gravity.LEFT) == Gravity.LEFT) {
mPreviousCollapsedGravity = Gravity.RIGHT | prevGravityY;
}
}
mIsRtl = isRtl;
}
@Override
public void onConfigurationChanged() {
updateDefaultGravity();
}
/**
* Initialize states when first entering PiP.
*/
@Override
public void setBoundsStateForEntry(ComponentName componentName, ActivityInfo activityInfo,
PictureInPictureParams params, PipBoundsAlgorithm pipBoundsAlgorithm) {
super.setBoundsStateForEntry(componentName, activityInfo, params, pipBoundsAlgorithm);
if (params == null) {
return;
}
setDesiredTvExpandedAspectRatio(params.getExpandedAspectRatioFloat(), true);
}
/** Resets the TV PiP state for a new activity. */
public void resetTvPipState() {
mTvFixedPipOrientation = ORIENTATION_UNDETERMINED;
mTvPipGravity = mDefaultGravity;
mPreviousCollapsedGravity = mDefaultGravity;
mTvPipManuallyCollapsed = false;
}
/** Set the tv expanded bounds of PiP */
public void setTvExpandedSize(@Nullable Size size) {
mTvExpandedSize = size;
}
/** Get the expanded size of the PiP. */
@Nullable
public Size getTvExpandedSize() {
return mTvExpandedSize;
}
/** Set the PiP aspect ratio for the expanded PiP (TV) that is desired by the app. */
public void setDesiredTvExpandedAspectRatio(float expandedAspectRatio, boolean override) {
if (override || mTvFixedPipOrientation == ORIENTATION_UNDETERMINED) {
resetTvPipState();
mDesiredTvExpandedAspectRatio = expandedAspectRatio;
if (expandedAspectRatio != 0) {
if (expandedAspectRatio > 1) {
mTvFixedPipOrientation = ORIENTATION_HORIZONTAL;
} else {
mTvFixedPipOrientation = ORIENTATION_VERTICAL;
}
}
return;
}
if ((expandedAspectRatio > 1 && mTvFixedPipOrientation == ORIENTATION_HORIZONTAL)
|| (expandedAspectRatio <= 1 && mTvFixedPipOrientation == ORIENTATION_VERTICAL)
|| expandedAspectRatio == 0) {
mDesiredTvExpandedAspectRatio = expandedAspectRatio;
}
}
/**
* Get the aspect ratio for the expanded PiP (TV) that is desired, or {@code 0} if it is not
* enabled by the app.
*/
public float getDesiredTvExpandedAspectRatio() {
return mDesiredTvExpandedAspectRatio;
}
/** Returns the fixed orientation of the expanded PiP on TV. */
@Orientation
public int getTvFixedPipOrientation() {
return mTvFixedPipOrientation;
}
/** Sets the current gravity of the TV PiP. */
public void setTvPipGravity(int gravity) {
mTvPipGravity = gravity;
}
/** Returns the current gravity of the TV PiP. */
public int getTvPipGravity() {
return mTvPipGravity;
}
public void setTvPipPreviousCollapsedGravity(int gravity) {
mPreviousCollapsedGravity = gravity;
}
public int getTvPipPreviousCollapsedGravity() {
return mPreviousCollapsedGravity;
}
/** Sets whether the TV PiP is currently expanded. */
public void setTvPipExpanded(boolean expanded) {
mIsTvPipExpanded = expanded;
}
/** Returns whether the TV PiP is currently expanded. */
public boolean isTvPipExpanded() {
return mIsTvPipExpanded;
}
/** Sets whether the user has manually collapsed the TV PiP. */
public void setTvPipManuallyCollapsed(boolean collapsed) {
mTvPipManuallyCollapsed = collapsed;
}
/** Returns whether the user has manually collapsed the TV PiP. */
public boolean isTvPipManuallyCollapsed() {
return mTvPipManuallyCollapsed;
}
/** Returns whether expanded PiP is supported by the device. */
public boolean isTvExpandedPipSupported() {
return mIsTvExpandedPipSupported;
}
public void setPipMenuPermanentDecorInsets(@NonNull Insets permanentInsets) {
mPipMenuPermanentDecorInsets = permanentInsets;
}
@NonNull
public Insets getPipMenuPermanentDecorInsets() {
return mPipMenuPermanentDecorInsets;
}
public void setPipMenuTemporaryDecorInsets(@NonNull Insets temporaryDecorInsets) {
mPipMenuTemporaryDecorInsets = temporaryDecorInsets;
}
@NonNull
public Insets getPipMenuTemporaryDecorInsets() {
return mPipMenuTemporaryDecorInsets;
}
}