PIP: Improve PIP control row's focus change animation in Recents

This includes following changes for performance
1. Passes the key events directly between the windows instead of using
   dummy Views and OnFocusChangeListener to prevent main thread from
   handling unnecessary focus changes.
2. Limits the window size for PIP controls to reduce unnecessary draw.

Here's the test result. Test is performed with paused PIP video
1. 5 visible recents task
  Focus down: 48.14 fps -> 85.396 fps (+77.39%)
  Focus up: 24.67 fps -> 45.33 fps (+83.77%)
2. 3 visible recents task
  Focus down: 51.98 fps -> 132.72 fps (+155.34%)
  Focus up: 30.91 fps -> 53.38 fps (+72.69%)

Bug: 28042495
Change-Id: I363232176975b160e122748c9997ef4b46b73a28
This commit is contained in:
Jaewan Kim
2016-05-16 22:06:46 +09:00
parent 0d35765ca3
commit a9e0621f33
19 changed files with 372 additions and 343 deletions

View File

@@ -21,6 +21,7 @@
android:clipChildren="false"
android:clipToPadding="false"
android:background="@drawable/recents_tv_background_gradient">
<com.android.systemui.recents.tv.views.TaskStackHorizontalGridView
android:id="@+id/task_list"
android:layout_width="wrap_content"
@@ -32,13 +33,13 @@
android:focusable="true"
android:layoutDirection="rtl" />
<!-- Placeholder view to give focus to the PIP menus. -->
<!-- Placeholder view to give focus to the PIP menus in talkback mode -->
<View
android:id="@+id/pip"
android:layout_width="1dp"
android:layout_height="1dp"
android:focusable="true"
android:visibility="visible" />
android:visibility="gone" />
<!-- Placeholder to dismiss during talkback. -->
<ImageView

View File

@@ -23,15 +23,25 @@
<ImageView android:id="@+id/button"
android:layout_width="34dp"
android:layout_height="34dp"
android:padding="5dp"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:focusable="true"
android:src="@drawable/ic_fullscreen_white_24dp"
android:background="@drawable/tv_pip_button_focused"
android:layerType="software" />
android:src="@drawable/tv_pip_button_focused"
android:importantForAccessibility="yes" />
<ImageView android:id="@+id/icon"
android:layout_width="34dp"
android:layout_height="34dp"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:padding="5dp"
android:importantForAccessibility="no" />
<TextView android:id="@+id/desc"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_below="@id/icon"
android:layout_centerHorizontal="true"
android:layout_marginTop="3dp"
android:gravity="center"
android:text="@string/pip_fullscreen"

View File

@@ -15,7 +15,7 @@
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="top|center_horizontal"
android:orientation="vertical">
@@ -33,7 +33,8 @@
android:layout_height="32dp"
android:translationY="-46dp"
android:layout_gravity="top|center_horizontal"
android:background="@drawable/tv_pip_recents_overlay_scrim" />
android:background="@drawable/tv_pip_recents_overlay_scrim"
android:alpha="0" />
<com.android.systemui.tv.pip.PipControlsView
android:id="@+id/pip_control_contents"
android:layout_width="wrap_content"
@@ -42,6 +43,8 @@
android:layout_gravity="top|center_horizontal" />
</com.android.systemui.tv.pip.PipRecentsControlsView>
<!-- Placeholder view to handle focus change between Recents row and PIP controls
in talkback mode -->
<View
android:id="@+id/recents"
android:layout_width="1dp"

View File

@@ -81,6 +81,7 @@ public class RecentsTvActivity extends Activity implements OnPreDrawListener {
private long mLastTabKeyEventTime;
private boolean mIgnoreAltTabRelease;
private boolean mLaunchedFromHome;
private boolean mTalkBackEnabled;
private RecentsTvView mRecentsView;
private View mPipView;
@@ -133,15 +134,22 @@ public class RecentsTvActivity extends Activity implements OnPreDrawListener {
@Override
public void onRecentsFocused() {
mRecentsView.requestFocus();
mRecentsView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
if (mTalkBackEnabled) {
mTaskStackHorizontalGridView.requestFocus();
mTaskStackHorizontalGridView.sendAccessibilityEvent(
AccessibilityEvent.TYPE_VIEW_FOCUSED);
}
mTaskStackHorizontalGridView.startFocusGainAnimation();
}
};
private final View.OnFocusChangeListener mPipViewFocusChangeListener =
new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
handlePipViewFocusChange(hasFocus);
if (hasFocus) {
requestPipControlsFocus();
}
}
};
@@ -194,17 +202,18 @@ public class RecentsTvActivity extends Activity implements OnPreDrawListener {
loadOpts.numVisibleTaskThumbnails = numVisibleTasks;
loader.loadTasks(this, plan, loadOpts);
mRecentsView.setTaskStack(stack);
List stackTasks = stack.getStackTasks();
Collections.reverse(stackTasks);
if (mTaskStackViewAdapter == null) {
mTaskStackViewAdapter = new TaskStackHorizontalViewAdapter(stackTasks);
mTaskStackHorizontalGridView = mRecentsView
.setTaskStackViewAdapter(mTaskStackViewAdapter);
mHomeRecentsEnterExitAnimationHolder = new HomeRecentsEnterExitAnimationHolder(
getApplicationContext(), mTaskStackHorizontalGridView);
} else {
mTaskStackViewAdapter.setNewStackTasks(stackTasks);
}
mRecentsView.init(stack);
if (launchState.launchedToTaskId != -1) {
ArrayList<Task> tasks = stack.getStackTasks();
@@ -305,6 +314,7 @@ public class RecentsTvActivity extends Activity implements OnPreDrawListener {
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
mPipView = findViewById(R.id.pip);
mPipView.setOnFocusChangeListener(mPipViewFocusChangeListener);
// Place mPipView at the PIP bounds for fine tuned focus handling.
Rect pipBounds = mPipManager.getRecentsFocusedPipBounds();
LayoutParams lp = (LayoutParams) mPipView.getLayoutParams();
@@ -342,7 +352,6 @@ public class RecentsTvActivity extends Activity implements OnPreDrawListener {
if(mLaunchedFromHome) {
mHomeRecentsEnterExitAnimationHolder.startEnterAnimation(mPipManager.isPipShown());
}
mTaskStackViewAdapter.setResetAddedCards(true);
EventBus.getDefault().send(new EnterRecentsWindowAnimationCompletedEvent());
}
@@ -353,19 +362,6 @@ public class RecentsTvActivity extends Activity implements OnPreDrawListener {
// Update the recent tasks
updateRecentsTasks();
mHomeRecentsEnterExitAnimationHolder = new HomeRecentsEnterExitAnimationHolder(
getApplicationContext(), mTaskStackHorizontalGridView);
if(mTaskStackHorizontalGridView != null &&
mTaskStackHorizontalGridView.getChildCount() > 0) {
if(mLaunchedFromHome) {
mHomeRecentsEnterExitAnimationHolder.setEnterFromHomeStartingAnimationValues();
} else {
mHomeRecentsEnterExitAnimationHolder.setEnterFromAppStartingAnimationValues();
}
} else {
mRecentsView.getViewTreeObserver().addOnPreDrawListener(this);
}
// If this is a new instance from a configuration change, then we have to manually trigger
// the enter animation state, or if recents was relaunched by AM, without going through
// the normal mechanisms
@@ -387,9 +383,11 @@ public class RecentsTvActivity extends Activity implements OnPreDrawListener {
} else {
mTaskStackHorizontalGridView.setSelectedPosition(0);
}
mRecentsView.getViewTreeObserver().addOnPreDrawListener(this);
View dismissPlaceholder = findViewById(R.id.dismiss_placeholder);
if (ssp.isTouchExplorationEnabled()) {
mTalkBackEnabled = ssp.isTouchExplorationEnabled();
if (mTalkBackEnabled) {
dismissPlaceholder.setAccessibilityTraversalBefore(R.id.task_list);
dismissPlaceholder.setAccessibilityTraversalAfter(R.id.dismiss_placeholder);
mTaskStackHorizontalGridView.setAccessibilityTraversalAfter(R.id.dismiss_placeholder);
@@ -408,14 +406,29 @@ public class RecentsTvActivity extends Activity implements OnPreDrawListener {
}
});
}
updatePipUI();
// Initialize PIP UI
if (mPipManager.isPipShown()) {
if (mTalkBackEnabled) {
// If talkback is on, use the mPipView to handle focus changes
// between recents row and PIP controls.
mPipView.setVisibility(View.VISIBLE);
} else {
mPipView.setVisibility(View.GONE);
}
// When PIP view has focus, recents overlay view will takes the focus
// as if it's the part of the Recents UI.
mPipRecentsOverlayManager.requestFocus(mTaskStackViewAdapter.getItemCount() > 0);
} else {
mPipView.setVisibility(View.GONE);
mPipRecentsOverlayManager.removePipRecentsOverlayView();
}
}
@Override
public void onPause() {
super.onPause();
mPipRecentsOverlayManager.onRecentsPaused();
mTaskStackViewAdapter.setResetAddedCards(false);
}
@Override
@@ -534,6 +547,7 @@ public class RecentsTvActivity extends Activity implements OnPreDrawListener {
public final void onBusEvent(AllTaskViewsDismissedEvent event) {
if (mPipManager.isPipShown()) {
mRecentsView.showEmptyView();
mPipRecentsOverlayManager.requestFocus(false);
} else {
dismissRecentsToHome(false);
}
@@ -547,10 +561,14 @@ public class RecentsTvActivity extends Activity implements OnPreDrawListener {
@Override
public boolean onPreDraw() {
mRecentsView.getViewTreeObserver().removeOnPreDrawListener(this);
if(mLaunchedFromHome) {
mHomeRecentsEnterExitAnimationHolder.setEnterFromHomeStartingAnimationValues();
// Sets the initial values for enter animation.
// Animation will be started in {@link #onEnterAnimationComplete()}
if (mLaunchedFromHome) {
mHomeRecentsEnterExitAnimationHolder
.setEnterFromHomeStartingAnimationValues(mPipManager.isPipShown());
} else {
mHomeRecentsEnterExitAnimationHolder.setEnterFromAppStartingAnimationValues();
mHomeRecentsEnterExitAnimationHolder
.setEnterFromAppStartingAnimationValues(mPipManager.isPipShown());
}
// We post to make sure that this information is delivered after this traversals is
// finished.
@@ -564,35 +582,25 @@ public class RecentsTvActivity extends Activity implements OnPreDrawListener {
}
private void updatePipUI() {
if (mPipManager.isPipShown()) {
mPipView.setVisibility(View.VISIBLE);
mPipView.setOnFocusChangeListener(mPipViewFocusChangeListener);
if (mPipView.hasFocus()) {
// This can happen only if the activity is resumed. Ask for reset.
handlePipViewFocusChange(true);
} else {
mPipView.requestFocus();
}
} else {
mPipView.setVisibility(View.GONE);
if (!mPipManager.isPipShown()) {
mPipRecentsOverlayManager.removePipRecentsOverlayView();
mTaskStackHorizontalGridView.startFocusLossAnimation();
} else {
Log.w(TAG, "An activity entered PIP mode while Recents is shown");
}
}
/**
* Handles the PIP view's focus change.
* Requests the focus to the PIP controls.
* This starts the relevant recents row animation
* and give focus to the recents overlay if needed.
*/
private void handlePipViewFocusChange(boolean hasFocus) {
mRecentsView.startRecentsRowFocusAnimation(!hasFocus);
if (hasFocus) {
// When PIP view has focus, recents overlay view will takes the focus
// as if it's the part of the Recents UI.
mPipRecentsOverlayManager.requestFocus(
mTaskStackViewAdapter.getItemCount() > 0);
} else {
mPipRecentsOverlayManager.clearFocus();
public void requestPipControlsFocus() {
if (!mPipManager.isPipShown()) {
return;
}
mTaskStackHorizontalGridView.startFocusLossAnimation();
mPipRecentsOverlayManager.requestFocus(mTaskStackViewAdapter.getItemCount() > 0);
}
}

View File

@@ -74,19 +74,35 @@ public class HomeRecentsEnterExitAnimationHolder {
}
}
public void setEnterFromHomeStartingAnimationValues() {
/**
* Sets the initial values Recents enter animation
* when Recents is started from the Launcher.
*/
public void setEnterFromHomeStartingAnimationValues(boolean isPipShown) {
for(int i = 0; i < mGridView.getChildCount(); i++) {
TaskCardView view = (TaskCardView) mGridView.getChildAt(i);
view.setTranslationX(0);
view.setAlpha(0.0f);
view.getInfoFieldView().setAlpha(isPipShown ? 0 : 1f);
if (isPipShown && view.hasFocus()) {
view.getViewFocusAnimator().changeSize(false);
}
}
}
public void setEnterFromAppStartingAnimationValues() {
/**
* Sets the initial values Recents enter animation
* when Recents is started from an app.
*/
public void setEnterFromAppStartingAnimationValues(boolean isPipShown) {
for(int i = 0; i < mGridView.getChildCount(); i++) {
TaskCardView view = (TaskCardView) mGridView.getChildAt(i);
view.setTranslationX(0);
view.setAlpha(1.0f);
view.setAlpha(isPipShown ? mDimAlpha : 1f);
view.getInfoFieldView().setAlpha(isPipShown ? 0 : 1f);
if (isPipShown && view.hasFocus()) {
view.getViewFocusAnimator().changeSize(false);
}
}
}
}

View File

@@ -29,11 +29,11 @@ import com.android.systemui.recents.tv.views.TaskCardView;
* Recents row's focus animation with PIP controls.
*/
public class RecentsRowFocusAnimationHolder {
private View mView;
private View mTitleView;
private final View mView;
private final View mTitleView;
private AnimatorSet mFocusGainAnimatorSet;
private AnimatorSet mFocusLoseAnimatorSet;
private AnimatorSet mFocusLossAnimatorSet;
public RecentsRowFocusAnimationHolder(View view, View titleView) {
mView = view;
@@ -50,28 +50,45 @@ public class RecentsRowFocusAnimationHolder {
mFocusGainAnimatorSet.setDuration(duration);
mFocusGainAnimatorSet.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
mFocusLoseAnimatorSet = new AnimatorSet();
mFocusLoseAnimatorSet.playTogether(
mFocusLossAnimatorSet = new AnimatorSet();
mFocusLossAnimatorSet.playTogether(
// Animation doesn't start from the current value (1f) sometimes,
// so specify the desired initial value here.
ObjectAnimator.ofFloat(mView, "alpha", 1f, dimAlpha),
ObjectAnimator.ofFloat(mTitleView, "alpha", 0f));
mFocusLoseAnimatorSet.setDuration(duration);
mFocusLoseAnimatorSet.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
mFocusLossAnimatorSet.setDuration(duration);
mFocusLossAnimatorSet.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
}
/**
* Returns the Recents row's focus change animation.
* Starts the Recents row's focus gain animation.
*/
public Animator getFocusChangeAnimator(boolean hasFocus) {
return hasFocus ? mFocusGainAnimatorSet : mFocusLoseAnimatorSet;
public void startFocusGainAnimation() {
cancelAnimator(mFocusLossAnimatorSet);
mFocusGainAnimatorSet.start();
}
/**
* Resets the views to the initial state immediately.
* Starts the Recents row's focus loss animation.
*/
public void startFocusLossAnimation() {
cancelAnimator(mFocusGainAnimatorSet);
mFocusLossAnimatorSet.start();
}
/**
* Resets the views immediately and ends the animations.
*/
public void reset() {
cancelAnimator(mFocusLossAnimatorSet);
cancelAnimator(mFocusGainAnimatorSet);
mView.setAlpha(1f);
mTitleView.setAlpha(1f);
}
private static void cancelAnimator(Animator animator) {
if (animator.isStarted()) {
animator.cancel();
}
}
}

View File

@@ -89,7 +89,7 @@ public class ViewFocusAnimator implements View.OnFocusChangeListener {
});
}
public void setFocusProgress(float level) {
private void setFocusProgress(float level) {
mFocusProgress = level;
float scale = mUnselectedScale + (level * mSelectedScaleDelta);
@@ -107,33 +107,19 @@ public class ViewFocusAnimator implements View.OnFocusChangeListener {
mTargetView.getDismissIconView().setZ(z);
}
public float getFocusProgress() {
return mFocusProgress;
}
public void animateFocus(boolean focused) {
private void animateFocus(boolean focused) {
if (mFocusAnimation.isStarted()) {
mFocusAnimation.cancel();
}
float target = focused ? 1.0f : 0.0f;
if (getFocusProgress() != target) {
mFocusAnimation.setFloatValues(getFocusProgress(), target);
if (mFocusProgress != target) {
mFocusAnimation.setFloatValues(mFocusProgress, target);
mFocusAnimation.start();
}
}
public void setFocusImmediate(boolean focused) {
if (mFocusAnimation.isStarted()) {
mFocusAnimation.cancel();
}
float target = focused ? 1.0f : 0.0f;
setFocusProgress(target);
}
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (v != mTargetView) {
@@ -142,21 +128,27 @@ public class ViewFocusAnimator implements View.OnFocusChangeListener {
changeSize(hasFocus);
}
protected void changeSize(boolean hasFocus) {
/**
* Changes the size of the {@link TaskCardView} to show its focused state.
*/
public void changeSize(boolean hasFocus) {
ViewGroup.LayoutParams lp = mTargetView.getLayoutParams();
int width = lp.width;
int height = lp.height;
if (width < 0 && height < 0) {
mTargetView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
height = mTargetView.getMeasuredHeight();
}
if (mTargetView.isAttachedToWindow() && mTargetView.hasWindowFocus() &&
mTargetView.getVisibility() == View.VISIBLE) {
animateFocus(hasFocus);
} else {
setFocusImmediate(hasFocus);
// Set focus immediately.
if (mFocusAnimation.isStarted()) {
mFocusAnimation.cancel();
}
setFocusProgress(hasFocus ? 1.0f : 0.0f);
}
}
}

View File

@@ -59,7 +59,7 @@ public class RecentsTvView extends FrameLayout {
private boolean mAwaitingFirstLayout = true;
private Rect mSystemInsets = new Rect();
private RecentsTvTransitionHelper mTransitionHelper;
private Handler mHandler;
private final Handler mHandler = new Handler();
private OnScrollListener mScrollListener;
public RecentsTvView(Context context) {
this(context, null);
@@ -81,9 +81,7 @@ public class RecentsTvView extends FrameLayout {
LayoutInflater inflater = LayoutInflater.from(context);
mEmptyView = inflater.inflate(R.layout.recents_tv_empty, this, false);
addView(mEmptyView);
mEmptyViewFocusAnimationHolder = new RecentsRowFocusAnimationHolder(mEmptyView, null);
mHandler = new Handler();
mTransitionHelper = new RecentsTvTransitionHelper(mContext, mHandler);
}
@@ -91,20 +89,18 @@ public class RecentsTvView extends FrameLayout {
protected void onFinishInflate() {
super.onFinishInflate();
mDismissPlaceholder = findViewById(R.id.dismiss_placeholder);
mTaskStackHorizontalView = (TaskStackHorizontalGridView) findViewById(R.id.task_list);
}
public void setTaskStack(TaskStack stack) {
/**
* Initialize the view.
*/
public void init(TaskStack stack) {
RecentsConfiguration config = Recents.getConfiguration();
RecentsActivityLaunchState launchState = config.getLaunchState();
mStack = stack;
if (mTaskStackHorizontalView != null) {
mTaskStackHorizontalView.reset();
mTaskStackHorizontalView.setStack(stack);
} else {
mTaskStackHorizontalView = (TaskStackHorizontalGridView) findViewById(R.id.task_list);
mTaskStackHorizontalView.setStack(stack);
}
mTaskStackHorizontalView.init(stack);
if (stack.getStackTaskCount() > 0) {
hideEmptyView();
@@ -112,6 +108,7 @@ public class RecentsTvView extends FrameLayout {
showEmptyView();
}
// Layout with the new stack
requestLayout();
}
@@ -188,17 +185,6 @@ public class RecentsTvView extends FrameLayout {
}
}
/**
* Starts the focus change animation.
*/
public void startRecentsRowFocusAnimation(boolean hasFocus) {
if (mEmptyView.getVisibility() == View.VISIBLE) {
mEmptyViewFocusAnimationHolder.getFocusChangeAnimator(hasFocus).start();
} else {
mTaskStackHorizontalView.startRecentsRowFocusAnimation(hasFocus);
}
}
/**
* Hides the task stack and shows the empty view.
*/

View File

@@ -40,16 +40,18 @@ import android.widget.TextView;
import com.android.systemui.R;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.tv.RecentsTvActivity;
import com.android.systemui.recents.tv.animations.DismissAnimationsHolder;
import com.android.systemui.recents.tv.animations.RecentsRowFocusAnimationHolder;
import com.android.systemui.recents.tv.animations.ViewFocusAnimator;
import com.android.systemui.recents.model.Task;
public class TaskCardView extends LinearLayout {
private static final String TAG = "TaskCardView";
private View mThumbnailView;
private View mDismissIconView;
private View mInfoFieldView;
private TextView mTitleTextView;
private ImageView mBadgeView;
private Task mTask;
@@ -79,14 +81,14 @@ public class TaskCardView extends LinearLayout {
protected void onFinishInflate() {
super.onFinishInflate();
mThumbnailView = findViewById(R.id.card_view_thumbnail);
mInfoFieldView = findViewById(R.id.card_info_field);
mTitleTextView = (TextView) findViewById(R.id.card_title_text);
mBadgeView = (ImageView) findViewById(R.id.card_extra_badge);
mDismissIconView = findViewById(R.id.dismiss_icon);
mDismissAnimationsHolder = new DismissAnimationsHolder(this);
View title = findViewById(R.id.card_info_field);
mCornerRadius = getResources().getDimensionPixelSize(
R.dimen.recents_task_view_rounded_corners_radius);
mRecentsRowFocusAnimationHolder = new RecentsRowFocusAnimationHolder(this, title);
mRecentsRowFocusAnimationHolder = new RecentsRowFocusAnimationHolder(this, mInfoFieldView);
SystemServicesProxy ssp = Recents.getSystemServices();
if (!ssp.isTouchExplorationEnabled()) {
mDismissIconView.setVisibility(VISIBLE);
@@ -102,6 +104,9 @@ public class TaskCardView extends LinearLayout {
mBadgeView.setImageDrawable(task.icon);
setThumbnailView();
setContentDescription(task.titleDescription);
mDismissState = false;
mDismissAnimationsHolder.reset();
mRecentsRowFocusAnimationHolder.reset();
}
public Task getTask() {
@@ -196,40 +201,37 @@ public class TaskCardView extends LinearLayout {
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
switch (keyCode) {
public boolean dispatchKeyEvent(KeyEvent event) {
// Override dispatchKeyEvent() instead of onKeyDown() to prevent warning from ViewRootImpl.
switch (event.getKeyCode()) {
case KeyEvent.KEYCODE_DPAD_DOWN : {
if (!isInDismissState()) {
if (!isInDismissState() && event.getAction() == KeyEvent.ACTION_DOWN) {
setDismissState(true);
return true;
}
break;
}
case KeyEvent.KEYCODE_DPAD_UP : {
if (isInDismissState()) {
setDismissState(false);
return true;
if (event.getAction() == KeyEvent.ACTION_DOWN) {
if (isInDismissState()) {
setDismissState(false);
} else {
((RecentsTvActivity) getContext()).requestPipControlsFocus();
}
}
break;
return true;
}
//Eat right and left key presses when we are in dismiss state
case KeyEvent.KEYCODE_DPAD_LEFT : {
if (isInDismissState()) {
return true;
}
break;
}
// Eat right and left key presses when we are in dismiss state
case KeyEvent.KEYCODE_DPAD_LEFT :
case KeyEvent.KEYCODE_DPAD_RIGHT : {
if (isInDismissState()) {
return true;
}
break;
}
default:
break;
}
return super.onKeyDown(keyCode, event);
return super.dispatchKeyEvent(event);
}
private void setDismissState(boolean dismissState) {
@@ -252,22 +254,14 @@ public class TaskCardView extends LinearLayout {
mDismissAnimationsHolder.startDismissAnimation(listener);
}
public ViewFocusAnimator getViewFocusAnimator() {
return mViewFocusAnimator;
}
public RecentsRowFocusAnimationHolder getRecentsRowFocusAnimationHolder() {
return mRecentsRowFocusAnimationHolder;
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
setDismissState(false);
}
public void reset() {
mDismissState = false;
mRecentsRowFocusAnimationHolder.reset();
mDismissAnimationsHolder.reset();
}
private void setThumbnailView() {
ImageView screenshotView = (ImageView) findViewById(R.id.card_view_banner_icon);
PackageManager pm = getContext().getPackageManager();
@@ -332,6 +326,10 @@ public class TaskCardView extends LinearLayout {
return mThumbnailView;
}
public View getInfoFieldView() {
return mInfoFieldView;
}
public View getDismissIconView() {
return mDismissIconView;
}

View File

@@ -18,8 +18,6 @@ package com.android.systemui.recents.tv.views;
import android.animation.Animator;
import android.animation.AnimatorSet;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.support.v17.leanback.widget.HorizontalGridView;
import android.util.AttributeSet;
import android.view.View;
@@ -39,14 +37,6 @@ import com.android.systemui.recents.views.AnimationProps;
public class TaskStackHorizontalGridView extends HorizontalGridView implements TaskStackCallbacks {
private static final int ANIMATION_DELAY_MS = 50;
private static final int MSG_START_RECENT_ROW_FOCUS_ANIMATION = 100;
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == MSG_START_RECENT_ROW_FOCUS_ANIMATION) {
startRecentsRowFocusAnimation(msg.arg1 == 1);
}
}
};
private TaskStack mStack;
private Task mFocusedTask;
private AnimatorSet mRecentsRowFocusAnimation;
@@ -74,38 +64,15 @@ public class TaskStackHorizontalGridView extends HorizontalGridView implements T
}
/**
* Resets this view for reuse.
*/
public void reset() {
for (int i = 0; i < getChildCount(); i++) {
((TaskCardView) getChildAt(i)).getRecentsRowFocusAnimationHolder().reset();
}
if (mRecentsRowFocusAnimation != null && mRecentsRowFocusAnimation.isStarted()) {
mRecentsRowFocusAnimation.cancel();
}
mHandler.removeCallbacksAndMessages(null);
requestLayout();
}
/**
* @param task - Task to reset
*/
private void resetFocusedTask(Task task) {
mFocusedTask = null;
}
/**
* Sets the task stack.
* Initializes the grid view.
* @param stack
*/
public void setStack(TaskStack stack) {
//Set new stack
public void init(TaskStack stack) {
// Set new stack
mStack = stack;
if (mStack != null) {
mStack.setCallbacks(this);
}
//Layout with new stack
requestLayout();
}
/**
@@ -125,13 +92,6 @@ public class TaskStackHorizontalGridView extends HorizontalGridView implements T
return mFocusedTask;
}
/**
* @return - The focused task card view.
*/
public TaskCardView getFocusedTaskCardView() {
return ((TaskCardView)findFocus());
}
/**
* @param task
* @return Child view for given task
@@ -146,32 +106,31 @@ public class TaskStackHorizontalGridView extends HorizontalGridView implements T
return null;
}
/**
* Starts the focus change animation.
* Starts the Recents row's focus gain animation.
*/
public void startRecentsRowFocusAnimation(final boolean hasFocus) {
if (getChildCount() == 0) {
// Animation request may happen before view is attached.
// Post again with small dealy so animation can be run again later.
if (getAdapter().getItemCount() > 0) {
mHandler.sendMessageDelayed(mHandler.obtainMessage(
MSG_START_RECENT_ROW_FOCUS_ANIMATION, hasFocus ? 1 : 0),
ANIMATION_DELAY_MS);
public void startFocusGainAnimation() {
for (int i = 0; i < getChildCount(); i++) {
TaskCardView v = (TaskCardView) getChildAt(i);
if (v.hasFocus()) {
v.getViewFocusAnimator().changeSize(true);
}
return;
v.getRecentsRowFocusAnimationHolder().startFocusGainAnimation();
}
if (mRecentsRowFocusAnimation != null && mRecentsRowFocusAnimation.isStarted()) {
mRecentsRowFocusAnimation.cancel();
}
/**
* Starts the Recents row's focus loss animation.
*/
public void startFocusLossAnimation() {
for (int i = 0; i < getChildCount(); i++) {
TaskCardView v = (TaskCardView) getChildAt(i);
if (v.hasFocus()) {
v.getViewFocusAnimator().changeSize(false);
}
v.getRecentsRowFocusAnimationHolder().startFocusLossAnimation();
}
Animator animator = ((TaskCardView) getChildAt(0)).getRecentsRowFocusAnimationHolder()
.getFocusChangeAnimator(hasFocus);
mRecentsRowFocusAnimation = new AnimatorSet();
AnimatorSet.Builder builder = mRecentsRowFocusAnimation.play(animator);
for (int i = 1; i < getChildCount(); i++) {
builder.with(((TaskCardView) getChildAt(i)).getRecentsRowFocusAnimationHolder()
.getFocusChangeAnimator(hasFocus));
}
mRecentsRowFocusAnimation.start();
}
@Override
@@ -185,7 +144,7 @@ public class TaskStackHorizontalGridView extends HorizontalGridView implements T
AnimationProps animation, boolean fromDockGesture) {
((TaskStackHorizontalViewAdapter) getAdapter()).removeTask(removedTask);
if (mFocusedTask == removedTask) {
resetFocusedTask(removedTask);
mFocusedTask = null;
}
// If there are no remaining tasks, then just close recents
if (mStack.getStackTaskCount() == 0) {

View File

@@ -43,17 +43,13 @@ public class TaskStackHorizontalViewAdapter extends
private static final String TAG = "TaskStackViewAdapter";
private List<Task> mTaskList;
private TaskStackHorizontalGridView mGridView;
private boolean mResetAddedCards;
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
private TaskCardView mTaskCardView;
private Task mTask;
private boolean mShouldReset;
public ViewHolder(View v) {
super(v);
if(v instanceof TaskCardView) {
mTaskCardView = (TaskCardView) v;
}
mTaskCardView = (TaskCardView) v;
}
public void init(Task task) {
@@ -90,7 +86,6 @@ public class TaskStackHorizontalViewAdapter extends
public void onAnimationEnd(Animator animation) {
removeTask(task);
EventBus.getDefault().send(new DeleteTaskDataEvent(task));
mShouldReset = true;
}
@Override
@@ -130,23 +125,6 @@ public class TaskStackHorizontalViewAdapter extends
holder.init(task);
}
@Override
public void onViewAttachedToWindow(ViewHolder holder) {
if (mResetAddedCards) {
holder.mTaskCardView.reset();
}
}
@Override
public void onViewDetachedFromWindow(ViewHolder holder) {
// We only want to reset on view detach if this is the last task being dismissed.
// This is so that we do not reset when shifting to apps etc, as it is not needed.
if (holder.mShouldReset) {
holder.mTaskCardView.reset();
holder.mShouldReset = false;
}
}
@Override
public int getItemCount() {
return mTaskList.size();
@@ -178,8 +156,4 @@ public class TaskStackHorizontalViewAdapter extends
mTaskList.add(position, task);
notifyItemInserted(position);
}
public void setResetAddedCards(boolean reset) {
mResetAddedCards = reset;
}
}

View File

@@ -21,12 +21,11 @@ import android.animation.AnimatorInflater;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View.OnFocusChangeListener;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.android.systemui.R;
@@ -34,31 +33,28 @@ import com.android.systemui.R;
/**
* A view containing PIP controls including fullscreen, close, and media controls.
*/
public class PipControlButtonView extends LinearLayout {
public class PipControlButtonView extends RelativeLayout {
private OnFocusChangeListener mFocusChangeListener;
private ImageView mButtonImageView;
private ImageView mIconImageView;
ImageView mButtonImageView;
private TextView mDescriptionTextView;
private Animator mFocusGainAnimator;
private Animator mFocusLoseAnimator;
private Animator mTextFocusGainAnimator;
private Animator mButtonFocusGainAnimator;
private Animator mTextFocusLossAnimator;
private Animator mButtonFocusLossAnimator;
private final OnFocusChangeListener mInternalFocusChangeListener =
new OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
if (mFocusLoseAnimator.isStarted()) {
mFocusLoseAnimator.cancel();
}
mFocusGainAnimator.start();
startFocusGainAnimation();
} else {
if (mFocusGainAnimator.isStarted()) {
mFocusGainAnimator.cancel();
}
mFocusLoseAnimator.start();
startFocusLossAnimation();
}
if (mFocusChangeListener != null) {
mFocusChangeListener.onFocusChange(v, hasFocus);
mFocusChangeListener.onFocusChange(PipControlButtonView.this, hasFocus);
}
}
};
@@ -82,9 +78,7 @@ public class PipControlButtonView extends LinearLayout {
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.tv_pip_control_button, this);
setOrientation(LinearLayout.VERTICAL);
setGravity(Gravity.CENTER);
mIconImageView = (ImageView) findViewById(R.id.icon);
mButtonImageView = (ImageView) findViewById(R.id.button);
mDescriptionTextView = (TextView) findViewById(R.id.desc);
@@ -103,12 +97,19 @@ public class PipControlButtonView extends LinearLayout {
super.onFinishInflate();
mButtonImageView.setOnFocusChangeListener(mInternalFocusChangeListener);
mFocusGainAnimator = AnimatorInflater.loadAnimator(getContext(),
R.anim.tv_pip_controls_text_focus_gain_animation);
mFocusGainAnimator.setTarget(mDescriptionTextView);
mFocusLoseAnimator = AnimatorInflater.loadAnimator(getContext(),
R.anim.tv_pip_controls_text_focus_lose_animation);
mFocusLoseAnimator.setTarget(mDescriptionTextView);
mTextFocusGainAnimator = AnimatorInflater.loadAnimator(getContext(),
R.anim.tv_pip_controls_focus_gain_animation);
mTextFocusGainAnimator.setTarget(mDescriptionTextView);
mButtonFocusGainAnimator = AnimatorInflater.loadAnimator(getContext(),
R.anim.tv_pip_controls_focus_gain_animation);
mButtonFocusGainAnimator.setTarget(mButtonImageView);
mTextFocusLossAnimator = AnimatorInflater.loadAnimator(getContext(),
R.anim.tv_pip_controls_focus_loss_animation);
mTextFocusLossAnimator.setTarget(mDescriptionTextView);
mButtonFocusLossAnimator = AnimatorInflater.loadAnimator(getContext(),
R.anim.tv_pip_controls_focus_loss_animation);
mButtonFocusLossAnimator.setTarget(mButtonImageView);
}
@Override
@@ -125,7 +126,7 @@ public class PipControlButtonView extends LinearLayout {
* Sets the drawable for the button with the given resource id.
*/
public void setImageResource(int resId) {
mButtonImageView.setImageResource(resId);
mIconImageView.setImageResource(resId);
}
/**
@@ -136,8 +137,51 @@ public class PipControlButtonView extends LinearLayout {
mDescriptionTextView.setText(resId);
}
@Override
public boolean isFocused() {
return mButtonImageView.isFocused();
private static void cancelAnimator(Animator animator) {
if (animator.isStarted()) {
animator.cancel();
}
}
/**
* Starts the focus gain animation.
*/
public void startFocusGainAnimation() {
cancelAnimator(mButtonFocusLossAnimator);
cancelAnimator(mTextFocusLossAnimator);
mTextFocusGainAnimator.start();
if (mButtonImageView.getAlpha() < 1f) {
// If we had faded out the ripple drawable, run our manual focus change animation.
// See the comment at {@link #startFocusLossAnimation()} for the reason of manual
// animator.
mButtonFocusGainAnimator.start();
}
}
/**
* Starts the focus loss animation.
*/
public void startFocusLossAnimation() {
cancelAnimator(mButtonFocusGainAnimator);
cancelAnimator(mTextFocusGainAnimator);
mTextFocusLossAnimator.start();
if (mButtonImageView.hasFocus()) {
// Button uses ripple that has the default animation for the focus changes.
// Howevever, it doesn't expose the API to fade out while it is focused,
// so we should manually run the fade out animation when PIP controls row loses focus.
mButtonFocusLossAnimator.start();
}
}
/**
* Resets to initial state.
*/
public void reset() {
cancelAnimator(mButtonFocusGainAnimator);
cancelAnimator(mTextFocusGainAnimator);
cancelAnimator(mButtonFocusLossAnimator);
cancelAnimator(mTextFocusLossAnimator);
mButtonImageView.setAlpha(1f);
mDescriptionTextView.setAlpha(mButtonImageView.hasFocus() ? 1f : 0f);
}
}

View File

@@ -61,8 +61,7 @@ public class PipControlsView extends LinearLayout {
private PipControlButtonView mCloseButtonView;
private PipControlButtonView mPlayPauseButtonView;
private boolean mHasFocus;
private OnFocusChangeListener mOnChildFocusChangeListener;
private PipControlButtonView mFocusedChild;
private MediaController.Callback mMediaControllerCallback = new MediaController.Callback() {
@Override
@@ -80,8 +79,12 @@ public class PipControlsView extends LinearLayout {
private final OnFocusChangeListener mFocusChangeListener = new OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
onChildViewFocusChanged();
public void onFocusChange(View view, boolean hasFocus) {
if (hasFocus) {
mFocusedChild = (PipControlButtonView) view;
} else if (mFocusedChild == view) {
mFocusedChild = null;
}
}
};
@@ -200,23 +203,13 @@ public class PipControlsView extends LinearLayout {
}
/**
* Sets a listener to be invoked when {@link android.view.View.hasFocus()} is changed.
* Resets to initial state.
*/
public void setOnChildFocusChangeListener(OnFocusChangeListener listener) {
mOnChildFocusChangeListener = listener;
}
private void onChildViewFocusChanged() {
// At this moment, hasFocus() returns true although there's no focused child.
boolean hasFocus = (mFullButtonView != null && mFullButtonView.isFocused())
|| (mPlayPauseButtonView != null && mPlayPauseButtonView.isFocused())
|| (mCloseButtonView != null && mCloseButtonView.isFocused());
if (mHasFocus != hasFocus) {
mHasFocus = hasFocus;
if (mOnChildFocusChangeListener != null) {
mOnChildFocusChangeListener.onFocusChange(getFocusedChild(), mHasFocus);
}
}
public void reset() {
mFullButtonView.reset();
mCloseButtonView.reset();
mPlayPauseButtonView.reset();
mFullButtonView.requestFocus();
}
/**
@@ -225,4 +218,11 @@ public class PipControlsView extends LinearLayout {
public void setListener(Listener listener) {
mListener = listener;
}
/**
* Returns the focused control button view to animate focused button.
*/
PipControlButtonView getFocusedButton() {
return mFocusedChild;
}
}

View File

@@ -126,7 +126,6 @@ public class PipManager {
private int mSuspendPipResizingReason;
private Context mContext;
private SystemServicesProxy mSystemServiceProxy;
private PipRecentsOverlayManager mPipRecentsOverlayManager;
private IActivityManager mActivityManager;
private MediaSessionManager mMediaSessionManager;
@@ -213,8 +212,7 @@ public class PipManager {
mPipBounds = mDefaultPipBounds;
mActivityManager = ActivityManagerNative.getDefault();
mSystemServiceProxy = SystemServicesProxy.getInstance(context);
mSystemServiceProxy.registerTaskStackListener(mTaskStackListener);
SystemServicesProxy.getInstance(context).registerTaskStackListener(mTaskStackListener);
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_MEDIA_RESOURCE_GRANTED);
mContext.registerReceiver(mBroadcastReceiver, intentFilter);

View File

@@ -48,12 +48,12 @@ public class PipRecentsControlsView extends FrameLayout {
abstract void onBackPressed();
}
final PipManager mPipManager = PipManager.getInstance();
private final PipManager mPipManager = PipManager.getInstance();
private Listener mListener;
private PipControlsView mPipControlsView;
private View mScrim;
private Animator mFocusGainAnimator;
private AnimatorSet mFocusLoseAnimatorSet;
private AnimatorSet mFocusLossAnimatorSet;
public PipRecentsControlsView(Context context) {
this(context, null, 0, 0);
@@ -80,12 +80,12 @@ public class PipRecentsControlsView extends FrameLayout {
mScrim = findViewById(R.id.scrim);
mFocusGainAnimator = loadAnimator(mPipControlsView,
R.anim.tv_pip_controls_in_recents_focus_gain_animation);
R.anim.tv_pip_controls_in_recents_focus_gain_animation);
mFocusLoseAnimatorSet = new AnimatorSet();
mFocusLoseAnimatorSet.playSequentially(
mFocusLossAnimatorSet = new AnimatorSet();
mFocusLossAnimatorSet.playSequentially(
loadAnimator(mPipControlsView,
R.anim.tv_pip_controls_in_recents_focus_lose_animation),
R.anim.tv_pip_controls_in_recents_focus_loss_animation),
loadAnimator(mScrim, R.anim.tv_pip_controls_in_recents_scrim_fade_in_animation));
Rect pipBounds = mPipManager.getRecentsFocusedPipBounds();
@@ -99,21 +99,29 @@ public class PipRecentsControlsView extends FrameLayout {
}
/**
* Starts focus gaining animation.
* Starts focus gain animation.
*/
public void startFocusGainAnimation() {
// Hides the scrim view as soon as possible, before the PIP resize animation starts.
// If we don't, PIP will be moved down a bit and a gap between the scrim and PIP will be
// shown at the bottom of the PIP.
mScrim.setAlpha(0);
startAnimator(mFocusGainAnimator, mFocusLoseAnimatorSet);
PipControlButtonView focus = mPipControlsView.getFocusedButton();
if (focus != null) {
focus.startFocusGainAnimation();
}
startAnimator(mFocusGainAnimator, mFocusLossAnimatorSet);
}
/**
* Starts focus losing animation.
* Starts focus loss animation.
*/
public void startFocusLoseAnimation() {
startAnimator(mFocusLoseAnimatorSet, mFocusGainAnimator);
public void startFocusLossAnimation() {
PipControlButtonView focus = mPipControlsView.getFocusedButton();
if (focus != null) {
focus.startFocusLossAnimation();
}
startAnimator(mFocusLossAnimatorSet, mFocusGainAnimator);
}
/**
@@ -121,14 +129,14 @@ public class PipRecentsControlsView extends FrameLayout {
*/
public void reset() {
cancelAnimator(mFocusGainAnimator);
cancelAnimator(mFocusLoseAnimatorSet);
cancelAnimator(mFocusLossAnimatorSet);
// Reset to initial state (i.e. end of focused)
requestFocus();
mScrim.setAlpha(0);
mPipControlsView.setTranslationY(0);
mPipControlsView.setScaleX(1);
mPipControlsView.setScaleY(1);
mScrim.setAlpha(0);
mPipControlsView.reset();
}
private static void startAnimator(Animator animator, Animator previousAnimator) {
@@ -153,13 +161,20 @@ public class PipRecentsControlsView extends FrameLayout {
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (!event.isCanceled()
&& event.getKeyCode() == KeyEvent.KEYCODE_BACK
&& event.getAction() == KeyEvent.ACTION_UP) {
if (mPipControlsView.mListener != null) {
((PipRecentsControlsView.Listener) mPipControlsView.mListener).onBackPressed();
if (!event.isCanceled()) {
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK
&& event.getAction() == KeyEvent.ACTION_UP) {
if (mPipControlsView.mListener != null) {
((PipRecentsControlsView.Listener) mPipControlsView.mListener).onBackPressed();
}
return true;
} else if (event.getKeyCode() == KeyEvent.KEYCODE_DPAD_DOWN) {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
mPipManager.getPipRecentsOverlayManager().clearFocus();
}
// Consume the down event always to prevent warning logs from ViewRootImpl.
return true;
}
return true;
}
return super.dispatchKeyEvent(event);
}

View File

@@ -18,15 +18,20 @@ package com.android.systemui.tv.pip;
import android.content.Context;
import android.graphics.PixelFormat;
import android.graphics.Rect;
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 android.view.WindowManager.LayoutParams;
import android.view.accessibility.AccessibilityEvent;
import com.android.systemui.R;
import com.android.systemui.recents.misc.SystemServicesProxy;
import static android.view.Gravity.CENTER_HORIZONTAL;
import static android.view.Gravity.TOP;
import static android.view.View.MeasureSpec.UNSPECIFIED;
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;
@@ -42,13 +47,16 @@ public class PipRecentsOverlayManager {
private final PipManager mPipManager = PipManager.getInstance();
private final WindowManager mWindowManager;
private final SystemServicesProxy mSystemServicesProxy;
private View mOverlayView;
private PipRecentsControlsView mPipControlsView;
private View mRecentsView;
private boolean mTalkBackEnabled;
private final LayoutParams mPipRecentsControlsViewLayoutParams;
private final LayoutParams mPipRecentsControlsViewFocusedLayoutParams;
private LayoutParams mPipRecentsControlsViewLayoutParams;
private LayoutParams mPipRecentsControlsViewFocusedLayoutParams;
private boolean mHasFocusableInRecents;
private boolean mIsPipRecentsOverlayShown;
private boolean mIsRecentsShown;
private boolean mIsPipFocusedInRecent;
@@ -72,18 +80,7 @@ public class PipRecentsOverlayManager {
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);
mSystemServicesProxy = SystemServicesProxy.getInstance(context);
initViews(context);
}
@@ -101,6 +98,20 @@ public class PipRecentsOverlayManager {
}
}
});
mOverlayView.measure(UNSPECIFIED, UNSPECIFIED);
mPipRecentsControlsViewLayoutParams = new WindowManager.LayoutParams(
mOverlayView.getMeasuredWidth(), mOverlayView.getMeasuredHeight(),
LayoutParams.TYPE_SYSTEM_DIALOG,
LayoutParams.FLAG_NOT_FOCUSABLE | LayoutParams.FLAG_NOT_TOUCHABLE,
PixelFormat.TRANSLUCENT);
mPipRecentsControlsViewLayoutParams.gravity = TOP | CENTER_HORIZONTAL;
mPipRecentsControlsViewFocusedLayoutParams = new WindowManager.LayoutParams(
mOverlayView.getMeasuredWidth(), mOverlayView.getMeasuredHeight(),
LayoutParams.TYPE_SYSTEM_DIALOG,
0,
PixelFormat.TRANSLUCENT);
mPipRecentsControlsViewFocusedLayoutParams.gravity = TOP | CENTER_HORIZONTAL;
}
/**
@@ -111,9 +122,10 @@ public class PipRecentsOverlayManager {
if (mIsPipRecentsOverlayShown) {
return;
}
mTalkBackEnabled = mSystemServicesProxy.isTouchExplorationEnabled();
mRecentsView.setVisibility(mTalkBackEnabled ? View.VISIBLE : View.GONE);
mIsPipRecentsOverlayShown = true;
mIsPipFocusedInRecent = true;
mPipControlsView.reset();
mWindowManager.addView(mOverlayView, mPipRecentsControlsViewFocusedLayoutParams);
}
@@ -126,50 +138,46 @@ public class PipRecentsOverlayManager {
return;
}
mWindowManager.removeView(mOverlayView);
// Resets the controls view when its removed.
// If not, changing focus in reset will be show animation when Recents is resumed.
mPipControlsView.reset();
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)
* @param hasFocusableInRecents {@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);
public void requestFocus(boolean hasFocusableInRecents) {
mHasFocusableInRecents = hasFocusableInRecents;
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();
mWindowManager.updateViewLayout(mOverlayView, mPipRecentsControlsViewFocusedLayoutParams);
mPipManager.resizePinnedStack(STATE_PIP_RECENTS_FOCUSED);
if (mTalkBackEnabled) {
mPipControlsView.requestFocus();
mPipControlsView.sendAccessibilityEvent(
AccessibilityEvent.TYPE_VIEW_FOCUSED);
}
}
/**
* 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()) {
|| !mPipManager.isPipShown() || !mHasFocusableInRecents) {
return;
}
if (!mRecentsView.hasFocus()) {
// Let mRecentsView's focus listener handle clearFocus().
mRecentsView.requestFocus();
}
mIsPipFocusedInRecent = false;
mPipManager.resizePinnedStack(STATE_PIP_RECENTS);
mPipControlsView.startFocusLossAnimation();
mWindowManager.updateViewLayout(mOverlayView, mPipRecentsControlsViewLayoutParams);
mPipControlsView.startFocusLoseAnimation();
mPipManager.resizePinnedStack(STATE_PIP_RECENTS);
if (mCallback != null) {
mCallback.onRecentsFocused();
}