blob: 6e4a5938d7b5c8c57343a2142aeef240b2a1a49a [file] [log] [blame]
/*
* Copyright (C) 2016 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.systemui.tv.pip;
import android.content.Context;
import android.graphics.PixelFormat;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
import android.view.WindowManager.LayoutParams;
import android.view.WindowManager;
import com.android.systemui.R;
import static com.android.systemui.tv.pip.PipManager.STATE_PIP_OVERLAY;
import static com.android.systemui.tv.pip.PipManager.STATE_PIP_RECENTS;
import static com.android.systemui.tv.pip.PipManager.STATE_PIP_RECENTS_FOCUSED;
public class PipRecentsOverlayManager {
private static final String TAG = "PipRecentsOverlayManager";
public interface Callback {
void onClosed();
void onBackPressed();
void onRecentsFocused();
}
private final PipManager mPipManager = PipManager.getInstance();
private final WindowManager mWindowManager;
private View mOverlayView;
private PipRecentsControlsView mPipControlsView;
private View mRecentsView;
private final LayoutParams mPipRecentsControlsViewLayoutParams;
private final LayoutParams mPipRecentsControlsViewFocusedLayoutParams;
private boolean mIsPipRecentsOverlayShown;
private boolean mIsRecentsShown;
private boolean mIsPipFocusedInRecent;
private Callback mCallback;
private PipRecentsControlsView.Listener mPipControlsViewListener =
new PipRecentsControlsView.Listener() {
@Override
public void onClosed() {
if (mCallback != null) {
mCallback.onClosed();
}
}
@Override
public void onBackPressed() {
if (mCallback != null) {
mCallback.onBackPressed();
}
}
};
PipRecentsOverlayManager(Context context) {
mWindowManager = (WindowManager) context.getSystemService(WindowManager.class);
mPipRecentsControlsViewLayoutParams = new WindowManager.LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
LayoutParams.TYPE_SYSTEM_DIALOG,
LayoutParams.FLAG_NOT_FOCUSABLE | LayoutParams.FLAG_NOT_TOUCHABLE,
PixelFormat.TRANSLUCENT);
mPipRecentsControlsViewFocusedLayoutParams = new WindowManager.LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
LayoutParams.TYPE_SYSTEM_DIALOG,
0,
PixelFormat.TRANSLUCENT);
initViews(context);
}
private void initViews(Context context) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mOverlayView = inflater.inflate(R.layout.tv_pip_recents_overlay, null);
mPipControlsView = (PipRecentsControlsView) mOverlayView.findViewById(R.id.pip_controls);
mRecentsView = mOverlayView.findViewById(R.id.recents);
mRecentsView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
clearFocus();
}
}
});
}
/**
* Add Recents overlay view.
* This is expected to be called after the PIP animation is over.
*/
void addPipRecentsOverlayView() {
if (mIsPipRecentsOverlayShown) {
return;
}
mIsPipRecentsOverlayShown = true;
mIsPipFocusedInRecent = true;
mPipControlsView.reset();
mWindowManager.addView(mOverlayView, mPipRecentsControlsViewFocusedLayoutParams);
}
/**
* Remove Recents overlay view.
* This should be called when Recents or PIP is closed.
*/
public void removePipRecentsOverlayView() {
if (!mIsPipRecentsOverlayShown) {
return;
}
mWindowManager.removeView(mOverlayView);
mIsPipRecentsOverlayShown = false;
}
/**
* Request focus to the PIP Recents overlay.
* Called when the PIP view in {@link com.android.systemui.recents.tv.RecentsTvActivity}
* is focused.
* This should be called only by {@link com.android.systemui.recents.tv.RecentsTvActivity}.
* @param allowRecentsFocusable {@code true} if Recents can have focus. (i.e. Has a recent task)
*/
public void requestFocus(boolean allowRecentsFocusable) {
mRecentsView.setVisibility(allowRecentsFocusable ? View.VISIBLE : View.GONE);
if (!mIsPipRecentsOverlayShown || !mIsRecentsShown || mIsPipFocusedInRecent
|| !mPipManager.isPipShown()) {
return;
}
mIsPipFocusedInRecent = true;
mPipManager.resizePinnedStack(STATE_PIP_RECENTS_FOCUSED);
mWindowManager.updateViewLayout(mOverlayView, mPipRecentsControlsViewFocusedLayoutParams);
mPipControlsView.requestFocus();
mPipControlsView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
mPipControlsView.startFocusGainAnimation();
}
/**
* Request focus to the PIP Recents overlay.
* Called when the PIP view in {@link com.android.systemui.recents.tv.RecentsTvActivity}
* is focused.
* This should be called only by {@link com.android.systemui.recents.tv.RecentsTvActivity}.
*/
public void clearFocus() {
if (!mIsPipRecentsOverlayShown || !mIsRecentsShown || !mIsPipFocusedInRecent
|| !mPipManager.isPipShown()) {
return;
}
if (!mRecentsView.hasFocus()) {
// Let mRecentsView's focus listener handle clearFocus().
mRecentsView.requestFocus();
}
mIsPipFocusedInRecent = false;
mPipManager.resizePinnedStack(STATE_PIP_RECENTS);
mWindowManager.updateViewLayout(mOverlayView, mPipRecentsControlsViewLayoutParams);
mPipControlsView.startFocusLoseAnimation();
if (mCallback != null) {
mCallback.onRecentsFocused();
}
}
public void setCallback(Callback listener) {
mCallback = listener;
mPipControlsView.setListener(mCallback != null ? mPipControlsViewListener : null);
}
/**
* Called when Recents is resumed.
* PIPed activity will be resized accordingly and overlay will show available buttons.
*/
public void onRecentsResumed() {
if (!mPipManager.isPipShown()) {
return;
}
mIsRecentsShown = true;
mIsPipFocusedInRecent = true;
mPipManager.resizePinnedStack(STATE_PIP_RECENTS_FOCUSED);
// Overlay view will be added after the resize animation ends, if any.
}
/**
* Called when Recents is paused.
* PIPed activity will be resized accordingly and overlay will hide available buttons.
*/
public void onRecentsPaused() {
mIsRecentsShown = false;
mIsPipFocusedInRecent = false;
removePipRecentsOverlayView();
if (mPipManager.isPipShown()) {
mPipManager.resizePinnedStack(STATE_PIP_OVERLAY);
}
}
/**
* Returns {@code true} if recents is shown.
*/
boolean isRecentsShown() {
return mIsRecentsShown;
}
/**
* Updates the PIP per configuration changed.
*/
void onConfigurationChanged(Context context) {
if (mIsRecentsShown) {
Log.w(TAG, "Configuration is changed while Recents is shown");
}
initViews(context);
}
}