Merge "PIP: Improve PIP control row\'s focus change animation in Recents" into nyc-dev

am: f8c504db7f

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

Change-Id: Ic1633d3a1f03fbb000a70743b13a8b4483c3279a
This commit is contained in:
Jaewan Kim
2016-05-27 17:33:48 +00:00
committed by android-build-merger
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();
}