Merge "PIP: Improve PIP control row's focus change animation in Recents" into nyc-dev
This commit is contained in:
@@ -21,6 +21,7 @@
|
|||||||
android:clipChildren="false"
|
android:clipChildren="false"
|
||||||
android:clipToPadding="false"
|
android:clipToPadding="false"
|
||||||
android:background="@drawable/recents_tv_background_gradient">
|
android:background="@drawable/recents_tv_background_gradient">
|
||||||
|
|
||||||
<com.android.systemui.recents.tv.views.TaskStackHorizontalGridView
|
<com.android.systemui.recents.tv.views.TaskStackHorizontalGridView
|
||||||
android:id="@+id/task_list"
|
android:id="@+id/task_list"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
@@ -32,13 +33,13 @@
|
|||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
android:layoutDirection="rtl" />
|
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
|
<View
|
||||||
android:id="@+id/pip"
|
android:id="@+id/pip"
|
||||||
android:layout_width="1dp"
|
android:layout_width="1dp"
|
||||||
android:layout_height="1dp"
|
android:layout_height="1dp"
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
android:visibility="visible" />
|
android:visibility="gone" />
|
||||||
|
|
||||||
<!-- Placeholder to dismiss during talkback. -->
|
<!-- Placeholder to dismiss during talkback. -->
|
||||||
<ImageView
|
<ImageView
|
||||||
|
|||||||
@@ -23,15 +23,25 @@
|
|||||||
<ImageView android:id="@+id/button"
|
<ImageView android:id="@+id/button"
|
||||||
android:layout_width="34dp"
|
android:layout_width="34dp"
|
||||||
android:layout_height="34dp"
|
android:layout_height="34dp"
|
||||||
android:padding="5dp"
|
android:layout_alignParentTop="true"
|
||||||
|
android:layout_centerHorizontal="true"
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
android:src="@drawable/ic_fullscreen_white_24dp"
|
android:src="@drawable/tv_pip_button_focused"
|
||||||
android:background="@drawable/tv_pip_button_focused"
|
android:importantForAccessibility="yes" />
|
||||||
android:layerType="software" />
|
|
||||||
|
<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"
|
<TextView android:id="@+id/desc"
|
||||||
android:layout_width="100dp"
|
android:layout_width="100dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_below="@id/icon"
|
||||||
|
android:layout_centerHorizontal="true"
|
||||||
android:layout_marginTop="3dp"
|
android:layout_marginTop="3dp"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:text="@string/pip_fullscreen"
|
android:text="@string/pip_fullscreen"
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
-->
|
-->
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
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:layout_height="wrap_content"
|
||||||
android:gravity="top|center_horizontal"
|
android:gravity="top|center_horizontal"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
@@ -33,7 +33,8 @@
|
|||||||
android:layout_height="32dp"
|
android:layout_height="32dp"
|
||||||
android:translationY="-46dp"
|
android:translationY="-46dp"
|
||||||
android:layout_gravity="top|center_horizontal"
|
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
|
<com.android.systemui.tv.pip.PipControlsView
|
||||||
android:id="@+id/pip_control_contents"
|
android:id="@+id/pip_control_contents"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
@@ -42,6 +43,8 @@
|
|||||||
android:layout_gravity="top|center_horizontal" />
|
android:layout_gravity="top|center_horizontal" />
|
||||||
</com.android.systemui.tv.pip.PipRecentsControlsView>
|
</com.android.systemui.tv.pip.PipRecentsControlsView>
|
||||||
|
|
||||||
|
<!-- Placeholder view to handle focus change between Recents row and PIP controls
|
||||||
|
in talkback mode -->
|
||||||
<View
|
<View
|
||||||
android:id="@+id/recents"
|
android:id="@+id/recents"
|
||||||
android:layout_width="1dp"
|
android:layout_width="1dp"
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ public class RecentsTvActivity extends Activity implements OnPreDrawListener {
|
|||||||
private long mLastTabKeyEventTime;
|
private long mLastTabKeyEventTime;
|
||||||
private boolean mIgnoreAltTabRelease;
|
private boolean mIgnoreAltTabRelease;
|
||||||
private boolean mLaunchedFromHome;
|
private boolean mLaunchedFromHome;
|
||||||
|
private boolean mTalkBackEnabled;
|
||||||
|
|
||||||
private RecentsTvView mRecentsView;
|
private RecentsTvView mRecentsView;
|
||||||
private View mPipView;
|
private View mPipView;
|
||||||
@@ -133,15 +134,22 @@ public class RecentsTvActivity extends Activity implements OnPreDrawListener {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRecentsFocused() {
|
public void onRecentsFocused() {
|
||||||
mRecentsView.requestFocus();
|
if (mTalkBackEnabled) {
|
||||||
mRecentsView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
|
mTaskStackHorizontalGridView.requestFocus();
|
||||||
|
mTaskStackHorizontalGridView.sendAccessibilityEvent(
|
||||||
|
AccessibilityEvent.TYPE_VIEW_FOCUSED);
|
||||||
|
}
|
||||||
|
mTaskStackHorizontalGridView.startFocusGainAnimation();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private final View.OnFocusChangeListener mPipViewFocusChangeListener =
|
private final View.OnFocusChangeListener mPipViewFocusChangeListener =
|
||||||
new View.OnFocusChangeListener() {
|
new View.OnFocusChangeListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onFocusChange(View v, boolean hasFocus) {
|
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;
|
loadOpts.numVisibleTaskThumbnails = numVisibleTasks;
|
||||||
loader.loadTasks(this, plan, loadOpts);
|
loader.loadTasks(this, plan, loadOpts);
|
||||||
|
|
||||||
|
|
||||||
mRecentsView.setTaskStack(stack);
|
|
||||||
List stackTasks = stack.getStackTasks();
|
List stackTasks = stack.getStackTasks();
|
||||||
Collections.reverse(stackTasks);
|
Collections.reverse(stackTasks);
|
||||||
if (mTaskStackViewAdapter == null) {
|
if (mTaskStackViewAdapter == null) {
|
||||||
mTaskStackViewAdapter = new TaskStackHorizontalViewAdapter(stackTasks);
|
mTaskStackViewAdapter = new TaskStackHorizontalViewAdapter(stackTasks);
|
||||||
mTaskStackHorizontalGridView = mRecentsView
|
mTaskStackHorizontalGridView = mRecentsView
|
||||||
.setTaskStackViewAdapter(mTaskStackViewAdapter);
|
.setTaskStackViewAdapter(mTaskStackViewAdapter);
|
||||||
|
mHomeRecentsEnterExitAnimationHolder = new HomeRecentsEnterExitAnimationHolder(
|
||||||
|
getApplicationContext(), mTaskStackHorizontalGridView);
|
||||||
} else {
|
} else {
|
||||||
mTaskStackViewAdapter.setNewStackTasks(stackTasks);
|
mTaskStackViewAdapter.setNewStackTasks(stackTasks);
|
||||||
}
|
}
|
||||||
|
mRecentsView.init(stack);
|
||||||
|
|
||||||
if (launchState.launchedToTaskId != -1) {
|
if (launchState.launchedToTaskId != -1) {
|
||||||
ArrayList<Task> tasks = stack.getStackTasks();
|
ArrayList<Task> tasks = stack.getStackTasks();
|
||||||
@@ -305,6 +314,7 @@ public class RecentsTvActivity extends Activity implements OnPreDrawListener {
|
|||||||
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
|
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
|
||||||
|
|
||||||
mPipView = findViewById(R.id.pip);
|
mPipView = findViewById(R.id.pip);
|
||||||
|
mPipView.setOnFocusChangeListener(mPipViewFocusChangeListener);
|
||||||
// Place mPipView at the PIP bounds for fine tuned focus handling.
|
// Place mPipView at the PIP bounds for fine tuned focus handling.
|
||||||
Rect pipBounds = mPipManager.getRecentsFocusedPipBounds();
|
Rect pipBounds = mPipManager.getRecentsFocusedPipBounds();
|
||||||
LayoutParams lp = (LayoutParams) mPipView.getLayoutParams();
|
LayoutParams lp = (LayoutParams) mPipView.getLayoutParams();
|
||||||
@@ -342,7 +352,6 @@ public class RecentsTvActivity extends Activity implements OnPreDrawListener {
|
|||||||
if(mLaunchedFromHome) {
|
if(mLaunchedFromHome) {
|
||||||
mHomeRecentsEnterExitAnimationHolder.startEnterAnimation(mPipManager.isPipShown());
|
mHomeRecentsEnterExitAnimationHolder.startEnterAnimation(mPipManager.isPipShown());
|
||||||
}
|
}
|
||||||
mTaskStackViewAdapter.setResetAddedCards(true);
|
|
||||||
EventBus.getDefault().send(new EnterRecentsWindowAnimationCompletedEvent());
|
EventBus.getDefault().send(new EnterRecentsWindowAnimationCompletedEvent());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -353,19 +362,6 @@ public class RecentsTvActivity extends Activity implements OnPreDrawListener {
|
|||||||
// Update the recent tasks
|
// Update the recent tasks
|
||||||
updateRecentsTasks();
|
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
|
// 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 enter animation state, or if recents was relaunched by AM, without going through
|
||||||
// the normal mechanisms
|
// the normal mechanisms
|
||||||
@@ -387,9 +383,11 @@ public class RecentsTvActivity extends Activity implements OnPreDrawListener {
|
|||||||
} else {
|
} else {
|
||||||
mTaskStackHorizontalGridView.setSelectedPosition(0);
|
mTaskStackHorizontalGridView.setSelectedPosition(0);
|
||||||
}
|
}
|
||||||
|
mRecentsView.getViewTreeObserver().addOnPreDrawListener(this);
|
||||||
|
|
||||||
View dismissPlaceholder = findViewById(R.id.dismiss_placeholder);
|
View dismissPlaceholder = findViewById(R.id.dismiss_placeholder);
|
||||||
if (ssp.isTouchExplorationEnabled()) {
|
mTalkBackEnabled = ssp.isTouchExplorationEnabled();
|
||||||
|
if (mTalkBackEnabled) {
|
||||||
dismissPlaceholder.setAccessibilityTraversalBefore(R.id.task_list);
|
dismissPlaceholder.setAccessibilityTraversalBefore(R.id.task_list);
|
||||||
dismissPlaceholder.setAccessibilityTraversalAfter(R.id.dismiss_placeholder);
|
dismissPlaceholder.setAccessibilityTraversalAfter(R.id.dismiss_placeholder);
|
||||||
mTaskStackHorizontalGridView.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
|
@Override
|
||||||
public void onPause() {
|
public void onPause() {
|
||||||
super.onPause();
|
super.onPause();
|
||||||
mPipRecentsOverlayManager.onRecentsPaused();
|
mPipRecentsOverlayManager.onRecentsPaused();
|
||||||
mTaskStackViewAdapter.setResetAddedCards(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -534,6 +547,7 @@ public class RecentsTvActivity extends Activity implements OnPreDrawListener {
|
|||||||
public final void onBusEvent(AllTaskViewsDismissedEvent event) {
|
public final void onBusEvent(AllTaskViewsDismissedEvent event) {
|
||||||
if (mPipManager.isPipShown()) {
|
if (mPipManager.isPipShown()) {
|
||||||
mRecentsView.showEmptyView();
|
mRecentsView.showEmptyView();
|
||||||
|
mPipRecentsOverlayManager.requestFocus(false);
|
||||||
} else {
|
} else {
|
||||||
dismissRecentsToHome(false);
|
dismissRecentsToHome(false);
|
||||||
}
|
}
|
||||||
@@ -547,10 +561,14 @@ public class RecentsTvActivity extends Activity implements OnPreDrawListener {
|
|||||||
@Override
|
@Override
|
||||||
public boolean onPreDraw() {
|
public boolean onPreDraw() {
|
||||||
mRecentsView.getViewTreeObserver().removeOnPreDrawListener(this);
|
mRecentsView.getViewTreeObserver().removeOnPreDrawListener(this);
|
||||||
|
// Sets the initial values for enter animation.
|
||||||
|
// Animation will be started in {@link #onEnterAnimationComplete()}
|
||||||
if (mLaunchedFromHome) {
|
if (mLaunchedFromHome) {
|
||||||
mHomeRecentsEnterExitAnimationHolder.setEnterFromHomeStartingAnimationValues();
|
mHomeRecentsEnterExitAnimationHolder
|
||||||
|
.setEnterFromHomeStartingAnimationValues(mPipManager.isPipShown());
|
||||||
} else {
|
} else {
|
||||||
mHomeRecentsEnterExitAnimationHolder.setEnterFromAppStartingAnimationValues();
|
mHomeRecentsEnterExitAnimationHolder
|
||||||
|
.setEnterFromAppStartingAnimationValues(mPipManager.isPipShown());
|
||||||
}
|
}
|
||||||
// We post to make sure that this information is delivered after this traversals is
|
// We post to make sure that this information is delivered after this traversals is
|
||||||
// finished.
|
// finished.
|
||||||
@@ -564,35 +582,25 @@ public class RecentsTvActivity extends Activity implements OnPreDrawListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updatePipUI() {
|
private void updatePipUI() {
|
||||||
if (mPipManager.isPipShown()) {
|
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);
|
|
||||||
mPipRecentsOverlayManager.removePipRecentsOverlayView();
|
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
|
* This starts the relevant recents row animation
|
||||||
* and give focus to the recents overlay if needed.
|
* and give focus to the recents overlay if needed.
|
||||||
*/
|
*/
|
||||||
private void handlePipViewFocusChange(boolean hasFocus) {
|
public void requestPipControlsFocus() {
|
||||||
mRecentsView.startRecentsRowFocusAnimation(!hasFocus);
|
if (!mPipManager.isPipShown()) {
|
||||||
if (hasFocus) {
|
return;
|
||||||
// When PIP view has focus, recents overlay view will takes the focus
|
}
|
||||||
// as if it's the part of the Recents UI.
|
|
||||||
mPipRecentsOverlayManager.requestFocus(
|
mTaskStackHorizontalGridView.startFocusLossAnimation();
|
||||||
mTaskStackViewAdapter.getItemCount() > 0);
|
mPipRecentsOverlayManager.requestFocus(mTaskStackViewAdapter.getItemCount() > 0);
|
||||||
} else {
|
|
||||||
mPipRecentsOverlayManager.clearFocus();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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++) {
|
for(int i = 0; i < mGridView.getChildCount(); i++) {
|
||||||
TaskCardView view = (TaskCardView) mGridView.getChildAt(i);
|
TaskCardView view = (TaskCardView) mGridView.getChildAt(i);
|
||||||
view.setTranslationX(0);
|
view.setTranslationX(0);
|
||||||
view.setAlpha(0.0f);
|
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++) {
|
for(int i = 0; i < mGridView.getChildCount(); i++) {
|
||||||
TaskCardView view = (TaskCardView) mGridView.getChildAt(i);
|
TaskCardView view = (TaskCardView) mGridView.getChildAt(i);
|
||||||
view.setTranslationX(0);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,11 +29,11 @@ import com.android.systemui.recents.tv.views.TaskCardView;
|
|||||||
* Recents row's focus animation with PIP controls.
|
* Recents row's focus animation with PIP controls.
|
||||||
*/
|
*/
|
||||||
public class RecentsRowFocusAnimationHolder {
|
public class RecentsRowFocusAnimationHolder {
|
||||||
private View mView;
|
private final View mView;
|
||||||
private View mTitleView;
|
private final View mTitleView;
|
||||||
|
|
||||||
private AnimatorSet mFocusGainAnimatorSet;
|
private AnimatorSet mFocusGainAnimatorSet;
|
||||||
private AnimatorSet mFocusLoseAnimatorSet;
|
private AnimatorSet mFocusLossAnimatorSet;
|
||||||
|
|
||||||
public RecentsRowFocusAnimationHolder(View view, View titleView) {
|
public RecentsRowFocusAnimationHolder(View view, View titleView) {
|
||||||
mView = view;
|
mView = view;
|
||||||
@@ -50,28 +50,45 @@ public class RecentsRowFocusAnimationHolder {
|
|||||||
mFocusGainAnimatorSet.setDuration(duration);
|
mFocusGainAnimatorSet.setDuration(duration);
|
||||||
mFocusGainAnimatorSet.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
|
mFocusGainAnimatorSet.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
|
||||||
|
|
||||||
mFocusLoseAnimatorSet = new AnimatorSet();
|
mFocusLossAnimatorSet = new AnimatorSet();
|
||||||
mFocusLoseAnimatorSet.playTogether(
|
mFocusLossAnimatorSet.playTogether(
|
||||||
// Animation doesn't start from the current value (1f) sometimes,
|
// Animation doesn't start from the current value (1f) sometimes,
|
||||||
// so specify the desired initial value here.
|
// so specify the desired initial value here.
|
||||||
ObjectAnimator.ofFloat(mView, "alpha", 1f, dimAlpha),
|
ObjectAnimator.ofFloat(mView, "alpha", 1f, dimAlpha),
|
||||||
ObjectAnimator.ofFloat(mTitleView, "alpha", 0f));
|
ObjectAnimator.ofFloat(mTitleView, "alpha", 0f));
|
||||||
mFocusLoseAnimatorSet.setDuration(duration);
|
mFocusLossAnimatorSet.setDuration(duration);
|
||||||
mFocusLoseAnimatorSet.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
|
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) {
|
public void startFocusGainAnimation() {
|
||||||
return hasFocus ? mFocusGainAnimatorSet : mFocusLoseAnimatorSet;
|
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() {
|
public void reset() {
|
||||||
|
cancelAnimator(mFocusLossAnimatorSet);
|
||||||
|
cancelAnimator(mFocusGainAnimatorSet);
|
||||||
mView.setAlpha(1f);
|
mView.setAlpha(1f);
|
||||||
mTitleView.setAlpha(1f);
|
mTitleView.setAlpha(1f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void cancelAnimator(Animator animator) {
|
||||||
|
if (animator.isStarted()) {
|
||||||
|
animator.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ public class ViewFocusAnimator implements View.OnFocusChangeListener {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setFocusProgress(float level) {
|
private void setFocusProgress(float level) {
|
||||||
mFocusProgress = level;
|
mFocusProgress = level;
|
||||||
|
|
||||||
float scale = mUnselectedScale + (level * mSelectedScaleDelta);
|
float scale = mUnselectedScale + (level * mSelectedScaleDelta);
|
||||||
@@ -107,33 +107,19 @@ public class ViewFocusAnimator implements View.OnFocusChangeListener {
|
|||||||
mTargetView.getDismissIconView().setZ(z);
|
mTargetView.getDismissIconView().setZ(z);
|
||||||
}
|
}
|
||||||
|
|
||||||
public float getFocusProgress() {
|
private void animateFocus(boolean focused) {
|
||||||
return mFocusProgress;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void animateFocus(boolean focused) {
|
|
||||||
if (mFocusAnimation.isStarted()) {
|
if (mFocusAnimation.isStarted()) {
|
||||||
mFocusAnimation.cancel();
|
mFocusAnimation.cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
float target = focused ? 1.0f : 0.0f;
|
float target = focused ? 1.0f : 0.0f;
|
||||||
|
|
||||||
if (getFocusProgress() != target) {
|
if (mFocusProgress != target) {
|
||||||
mFocusAnimation.setFloatValues(getFocusProgress(), target);
|
mFocusAnimation.setFloatValues(mFocusProgress, target);
|
||||||
mFocusAnimation.start();
|
mFocusAnimation.start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setFocusImmediate(boolean focused) {
|
|
||||||
if (mFocusAnimation.isStarted()) {
|
|
||||||
mFocusAnimation.cancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
float target = focused ? 1.0f : 0.0f;
|
|
||||||
|
|
||||||
setFocusProgress(target);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFocusChange(View v, boolean hasFocus) {
|
public void onFocusChange(View v, boolean hasFocus) {
|
||||||
if (v != mTargetView) {
|
if (v != mTargetView) {
|
||||||
@@ -142,21 +128,27 @@ public class ViewFocusAnimator implements View.OnFocusChangeListener {
|
|||||||
changeSize(hasFocus);
|
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();
|
ViewGroup.LayoutParams lp = mTargetView.getLayoutParams();
|
||||||
int width = lp.width;
|
int width = lp.width;
|
||||||
int height = lp.height;
|
int height = lp.height;
|
||||||
|
|
||||||
if (width < 0 && height < 0) {
|
if (width < 0 && height < 0) {
|
||||||
mTargetView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
|
mTargetView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
|
||||||
height = mTargetView.getMeasuredHeight();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mTargetView.isAttachedToWindow() && mTargetView.hasWindowFocus() &&
|
if (mTargetView.isAttachedToWindow() && mTargetView.hasWindowFocus() &&
|
||||||
mTargetView.getVisibility() == View.VISIBLE) {
|
mTargetView.getVisibility() == View.VISIBLE) {
|
||||||
animateFocus(hasFocus);
|
animateFocus(hasFocus);
|
||||||
} else {
|
} else {
|
||||||
setFocusImmediate(hasFocus);
|
// Set focus immediately.
|
||||||
|
if (mFocusAnimation.isStarted()) {
|
||||||
|
mFocusAnimation.cancel();
|
||||||
|
}
|
||||||
|
setFocusProgress(hasFocus ? 1.0f : 0.0f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ public class RecentsTvView extends FrameLayout {
|
|||||||
private boolean mAwaitingFirstLayout = true;
|
private boolean mAwaitingFirstLayout = true;
|
||||||
private Rect mSystemInsets = new Rect();
|
private Rect mSystemInsets = new Rect();
|
||||||
private RecentsTvTransitionHelper mTransitionHelper;
|
private RecentsTvTransitionHelper mTransitionHelper;
|
||||||
private Handler mHandler;
|
private final Handler mHandler = new Handler();
|
||||||
private OnScrollListener mScrollListener;
|
private OnScrollListener mScrollListener;
|
||||||
public RecentsTvView(Context context) {
|
public RecentsTvView(Context context) {
|
||||||
this(context, null);
|
this(context, null);
|
||||||
@@ -81,9 +81,7 @@ public class RecentsTvView extends FrameLayout {
|
|||||||
LayoutInflater inflater = LayoutInflater.from(context);
|
LayoutInflater inflater = LayoutInflater.from(context);
|
||||||
mEmptyView = inflater.inflate(R.layout.recents_tv_empty, this, false);
|
mEmptyView = inflater.inflate(R.layout.recents_tv_empty, this, false);
|
||||||
addView(mEmptyView);
|
addView(mEmptyView);
|
||||||
mEmptyViewFocusAnimationHolder = new RecentsRowFocusAnimationHolder(mEmptyView, null);
|
|
||||||
|
|
||||||
mHandler = new Handler();
|
|
||||||
mTransitionHelper = new RecentsTvTransitionHelper(mContext, mHandler);
|
mTransitionHelper = new RecentsTvTransitionHelper(mContext, mHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,20 +89,18 @@ public class RecentsTvView extends FrameLayout {
|
|||||||
protected void onFinishInflate() {
|
protected void onFinishInflate() {
|
||||||
super.onFinishInflate();
|
super.onFinishInflate();
|
||||||
mDismissPlaceholder = findViewById(R.id.dismiss_placeholder);
|
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();
|
RecentsConfiguration config = Recents.getConfiguration();
|
||||||
RecentsActivityLaunchState launchState = config.getLaunchState();
|
RecentsActivityLaunchState launchState = config.getLaunchState();
|
||||||
mStack = stack;
|
mStack = stack;
|
||||||
|
|
||||||
if (mTaskStackHorizontalView != null) {
|
mTaskStackHorizontalView.init(stack);
|
||||||
mTaskStackHorizontalView.reset();
|
|
||||||
mTaskStackHorizontalView.setStack(stack);
|
|
||||||
} else {
|
|
||||||
mTaskStackHorizontalView = (TaskStackHorizontalGridView) findViewById(R.id.task_list);
|
|
||||||
mTaskStackHorizontalView.setStack(stack);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stack.getStackTaskCount() > 0) {
|
if (stack.getStackTaskCount() > 0) {
|
||||||
hideEmptyView();
|
hideEmptyView();
|
||||||
@@ -112,6 +108,7 @@ public class RecentsTvView extends FrameLayout {
|
|||||||
showEmptyView();
|
showEmptyView();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Layout with the new stack
|
||||||
requestLayout();
|
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.
|
* Hides the task stack and shows the empty view.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -40,16 +40,18 @@ import android.widget.TextView;
|
|||||||
import com.android.systemui.R;
|
import com.android.systemui.R;
|
||||||
import com.android.systemui.recents.Recents;
|
import com.android.systemui.recents.Recents;
|
||||||
import com.android.systemui.recents.misc.SystemServicesProxy;
|
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.DismissAnimationsHolder;
|
||||||
import com.android.systemui.recents.tv.animations.RecentsRowFocusAnimationHolder;
|
import com.android.systemui.recents.tv.animations.RecentsRowFocusAnimationHolder;
|
||||||
import com.android.systemui.recents.tv.animations.ViewFocusAnimator;
|
import com.android.systemui.recents.tv.animations.ViewFocusAnimator;
|
||||||
import com.android.systemui.recents.model.Task;
|
|
||||||
|
|
||||||
public class TaskCardView extends LinearLayout {
|
public class TaskCardView extends LinearLayout {
|
||||||
|
|
||||||
private static final String TAG = "TaskCardView";
|
private static final String TAG = "TaskCardView";
|
||||||
private View mThumbnailView;
|
private View mThumbnailView;
|
||||||
private View mDismissIconView;
|
private View mDismissIconView;
|
||||||
|
private View mInfoFieldView;
|
||||||
private TextView mTitleTextView;
|
private TextView mTitleTextView;
|
||||||
private ImageView mBadgeView;
|
private ImageView mBadgeView;
|
||||||
private Task mTask;
|
private Task mTask;
|
||||||
@@ -79,14 +81,14 @@ public class TaskCardView extends LinearLayout {
|
|||||||
protected void onFinishInflate() {
|
protected void onFinishInflate() {
|
||||||
super.onFinishInflate();
|
super.onFinishInflate();
|
||||||
mThumbnailView = findViewById(R.id.card_view_thumbnail);
|
mThumbnailView = findViewById(R.id.card_view_thumbnail);
|
||||||
|
mInfoFieldView = findViewById(R.id.card_info_field);
|
||||||
mTitleTextView = (TextView) findViewById(R.id.card_title_text);
|
mTitleTextView = (TextView) findViewById(R.id.card_title_text);
|
||||||
mBadgeView = (ImageView) findViewById(R.id.card_extra_badge);
|
mBadgeView = (ImageView) findViewById(R.id.card_extra_badge);
|
||||||
mDismissIconView = findViewById(R.id.dismiss_icon);
|
mDismissIconView = findViewById(R.id.dismiss_icon);
|
||||||
mDismissAnimationsHolder = new DismissAnimationsHolder(this);
|
mDismissAnimationsHolder = new DismissAnimationsHolder(this);
|
||||||
View title = findViewById(R.id.card_info_field);
|
|
||||||
mCornerRadius = getResources().getDimensionPixelSize(
|
mCornerRadius = getResources().getDimensionPixelSize(
|
||||||
R.dimen.recents_task_view_rounded_corners_radius);
|
R.dimen.recents_task_view_rounded_corners_radius);
|
||||||
mRecentsRowFocusAnimationHolder = new RecentsRowFocusAnimationHolder(this, title);
|
mRecentsRowFocusAnimationHolder = new RecentsRowFocusAnimationHolder(this, mInfoFieldView);
|
||||||
SystemServicesProxy ssp = Recents.getSystemServices();
|
SystemServicesProxy ssp = Recents.getSystemServices();
|
||||||
if (!ssp.isTouchExplorationEnabled()) {
|
if (!ssp.isTouchExplorationEnabled()) {
|
||||||
mDismissIconView.setVisibility(VISIBLE);
|
mDismissIconView.setVisibility(VISIBLE);
|
||||||
@@ -102,6 +104,9 @@ public class TaskCardView extends LinearLayout {
|
|||||||
mBadgeView.setImageDrawable(task.icon);
|
mBadgeView.setImageDrawable(task.icon);
|
||||||
setThumbnailView();
|
setThumbnailView();
|
||||||
setContentDescription(task.titleDescription);
|
setContentDescription(task.titleDescription);
|
||||||
|
mDismissState = false;
|
||||||
|
mDismissAnimationsHolder.reset();
|
||||||
|
mRecentsRowFocusAnimationHolder.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task getTask() {
|
public Task getTask() {
|
||||||
@@ -196,40 +201,37 @@ public class TaskCardView extends LinearLayout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
public boolean dispatchKeyEvent(KeyEvent event) {
|
||||||
switch (keyCode) {
|
// Override dispatchKeyEvent() instead of onKeyDown() to prevent warning from ViewRootImpl.
|
||||||
|
switch (event.getKeyCode()) {
|
||||||
case KeyEvent.KEYCODE_DPAD_DOWN : {
|
case KeyEvent.KEYCODE_DPAD_DOWN : {
|
||||||
if (!isInDismissState()) {
|
if (!isInDismissState() && event.getAction() == KeyEvent.ACTION_DOWN) {
|
||||||
setDismissState(true);
|
setDismissState(true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case KeyEvent.KEYCODE_DPAD_UP : {
|
case KeyEvent.KEYCODE_DPAD_UP : {
|
||||||
|
if (event.getAction() == KeyEvent.ACTION_DOWN) {
|
||||||
if (isInDismissState()) {
|
if (isInDismissState()) {
|
||||||
setDismissState(false);
|
setDismissState(false);
|
||||||
return true;
|
} else {
|
||||||
|
((RecentsTvActivity) getContext()).requestPipControlsFocus();
|
||||||
}
|
}
|
||||||
break;
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Eat right and left key presses when we are in dismiss state
|
// Eat right and left key presses when we are in dismiss state
|
||||||
case KeyEvent.KEYCODE_DPAD_LEFT : {
|
case KeyEvent.KEYCODE_DPAD_LEFT :
|
||||||
if (isInDismissState()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case KeyEvent.KEYCODE_DPAD_RIGHT : {
|
case KeyEvent.KEYCODE_DPAD_RIGHT : {
|
||||||
if (isInDismissState()) {
|
if (isInDismissState()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
return super.onKeyDown(keyCode, event);
|
return super.dispatchKeyEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setDismissState(boolean dismissState) {
|
private void setDismissState(boolean dismissState) {
|
||||||
@@ -252,22 +254,14 @@ public class TaskCardView extends LinearLayout {
|
|||||||
mDismissAnimationsHolder.startDismissAnimation(listener);
|
mDismissAnimationsHolder.startDismissAnimation(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ViewFocusAnimator getViewFocusAnimator() {
|
||||||
|
return mViewFocusAnimator;
|
||||||
|
}
|
||||||
|
|
||||||
public RecentsRowFocusAnimationHolder getRecentsRowFocusAnimationHolder() {
|
public RecentsRowFocusAnimationHolder getRecentsRowFocusAnimationHolder() {
|
||||||
return mRecentsRowFocusAnimationHolder;
|
return mRecentsRowFocusAnimationHolder;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onDetachedFromWindow() {
|
|
||||||
super.onDetachedFromWindow();
|
|
||||||
setDismissState(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void reset() {
|
|
||||||
mDismissState = false;
|
|
||||||
mRecentsRowFocusAnimationHolder.reset();
|
|
||||||
mDismissAnimationsHolder.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setThumbnailView() {
|
private void setThumbnailView() {
|
||||||
ImageView screenshotView = (ImageView) findViewById(R.id.card_view_banner_icon);
|
ImageView screenshotView = (ImageView) findViewById(R.id.card_view_banner_icon);
|
||||||
PackageManager pm = getContext().getPackageManager();
|
PackageManager pm = getContext().getPackageManager();
|
||||||
@@ -332,6 +326,10 @@ public class TaskCardView extends LinearLayout {
|
|||||||
return mThumbnailView;
|
return mThumbnailView;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public View getInfoFieldView() {
|
||||||
|
return mInfoFieldView;
|
||||||
|
}
|
||||||
|
|
||||||
public View getDismissIconView() {
|
public View getDismissIconView() {
|
||||||
return mDismissIconView;
|
return mDismissIconView;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,8 +18,6 @@ package com.android.systemui.recents.tv.views;
|
|||||||
import android.animation.Animator;
|
import android.animation.Animator;
|
||||||
import android.animation.AnimatorSet;
|
import android.animation.AnimatorSet;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Handler;
|
|
||||||
import android.os.Message;
|
|
||||||
import android.support.v17.leanback.widget.HorizontalGridView;
|
import android.support.v17.leanback.widget.HorizontalGridView;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@@ -39,14 +37,6 @@ import com.android.systemui.recents.views.AnimationProps;
|
|||||||
public class TaskStackHorizontalGridView extends HorizontalGridView implements TaskStackCallbacks {
|
public class TaskStackHorizontalGridView extends HorizontalGridView implements TaskStackCallbacks {
|
||||||
private static final int ANIMATION_DELAY_MS = 50;
|
private static final int ANIMATION_DELAY_MS = 50;
|
||||||
private static final int MSG_START_RECENT_ROW_FOCUS_ANIMATION = 100;
|
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 TaskStack mStack;
|
||||||
private Task mFocusedTask;
|
private Task mFocusedTask;
|
||||||
private AnimatorSet mRecentsRowFocusAnimation;
|
private AnimatorSet mRecentsRowFocusAnimation;
|
||||||
@@ -74,38 +64,15 @@ public class TaskStackHorizontalGridView extends HorizontalGridView implements T
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resets this view for reuse.
|
* Initializes the grid view.
|
||||||
*/
|
|
||||||
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.
|
|
||||||
* @param stack
|
* @param stack
|
||||||
*/
|
*/
|
||||||
public void setStack(TaskStack stack) {
|
public void init(TaskStack stack) {
|
||||||
// Set new stack
|
// Set new stack
|
||||||
mStack = stack;
|
mStack = stack;
|
||||||
if (mStack != null) {
|
if (mStack != null) {
|
||||||
mStack.setCallbacks(this);
|
mStack.setCallbacks(this);
|
||||||
}
|
}
|
||||||
//Layout with new stack
|
|
||||||
requestLayout();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -125,13 +92,6 @@ public class TaskStackHorizontalGridView extends HorizontalGridView implements T
|
|||||||
return mFocusedTask;
|
return mFocusedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return - The focused task card view.
|
|
||||||
*/
|
|
||||||
public TaskCardView getFocusedTaskCardView() {
|
|
||||||
return ((TaskCardView)findFocus());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param task
|
* @param task
|
||||||
* @return Child view for given task
|
* @return Child view for given task
|
||||||
@@ -146,32 +106,31 @@ public class TaskStackHorizontalGridView extends HorizontalGridView implements T
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts the focus change animation.
|
* Starts the Recents row's focus gain animation.
|
||||||
*/
|
*/
|
||||||
public void startRecentsRowFocusAnimation(final boolean hasFocus) {
|
public void startFocusGainAnimation() {
|
||||||
if (getChildCount() == 0) {
|
for (int i = 0; i < getChildCount(); i++) {
|
||||||
// Animation request may happen before view is attached.
|
TaskCardView v = (TaskCardView) getChildAt(i);
|
||||||
// Post again with small dealy so animation can be run again later.
|
if (v.hasFocus()) {
|
||||||
if (getAdapter().getItemCount() > 0) {
|
v.getViewFocusAnimator().changeSize(true);
|
||||||
mHandler.sendMessageDelayed(mHandler.obtainMessage(
|
|
||||||
MSG_START_RECENT_ROW_FOCUS_ANIMATION, hasFocus ? 1 : 0),
|
|
||||||
ANIMATION_DELAY_MS);
|
|
||||||
}
|
}
|
||||||
return;
|
v.getRecentsRowFocusAnimationHolder().startFocusGainAnimation();
|
||||||
}
|
}
|
||||||
if (mRecentsRowFocusAnimation != null && mRecentsRowFocusAnimation.isStarted()) {
|
|
||||||
mRecentsRowFocusAnimation.cancel();
|
|
||||||
}
|
}
|
||||||
Animator animator = ((TaskCardView) getChildAt(0)).getRecentsRowFocusAnimationHolder()
|
|
||||||
.getFocusChangeAnimator(hasFocus);
|
/**
|
||||||
mRecentsRowFocusAnimation = new AnimatorSet();
|
* Starts the Recents row's focus loss animation.
|
||||||
AnimatorSet.Builder builder = mRecentsRowFocusAnimation.play(animator);
|
*/
|
||||||
for (int i = 1; i < getChildCount(); i++) {
|
public void startFocusLossAnimation() {
|
||||||
builder.with(((TaskCardView) getChildAt(i)).getRecentsRowFocusAnimationHolder()
|
for (int i = 0; i < getChildCount(); i++) {
|
||||||
.getFocusChangeAnimator(hasFocus));
|
TaskCardView v = (TaskCardView) getChildAt(i);
|
||||||
|
if (v.hasFocus()) {
|
||||||
|
v.getViewFocusAnimator().changeSize(false);
|
||||||
|
}
|
||||||
|
v.getRecentsRowFocusAnimationHolder().startFocusLossAnimation();
|
||||||
}
|
}
|
||||||
mRecentsRowFocusAnimation.start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -185,7 +144,7 @@ public class TaskStackHorizontalGridView extends HorizontalGridView implements T
|
|||||||
AnimationProps animation, boolean fromDockGesture) {
|
AnimationProps animation, boolean fromDockGesture) {
|
||||||
((TaskStackHorizontalViewAdapter) getAdapter()).removeTask(removedTask);
|
((TaskStackHorizontalViewAdapter) getAdapter()).removeTask(removedTask);
|
||||||
if (mFocusedTask == removedTask) {
|
if (mFocusedTask == removedTask) {
|
||||||
resetFocusedTask(removedTask);
|
mFocusedTask = null;
|
||||||
}
|
}
|
||||||
// If there are no remaining tasks, then just close recents
|
// If there are no remaining tasks, then just close recents
|
||||||
if (mStack.getStackTaskCount() == 0) {
|
if (mStack.getStackTaskCount() == 0) {
|
||||||
|
|||||||
@@ -43,18 +43,14 @@ public class TaskStackHorizontalViewAdapter extends
|
|||||||
private static final String TAG = "TaskStackViewAdapter";
|
private static final String TAG = "TaskStackViewAdapter";
|
||||||
private List<Task> mTaskList;
|
private List<Task> mTaskList;
|
||||||
private TaskStackHorizontalGridView mGridView;
|
private TaskStackHorizontalGridView mGridView;
|
||||||
private boolean mResetAddedCards;
|
|
||||||
|
|
||||||
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
|
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
|
||||||
private TaskCardView mTaskCardView;
|
private TaskCardView mTaskCardView;
|
||||||
private Task mTask;
|
private Task mTask;
|
||||||
private boolean mShouldReset;
|
|
||||||
public ViewHolder(View v) {
|
public ViewHolder(View v) {
|
||||||
super(v);
|
super(v);
|
||||||
if(v instanceof TaskCardView) {
|
|
||||||
mTaskCardView = (TaskCardView) v;
|
mTaskCardView = (TaskCardView) v;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public void init(Task task) {
|
public void init(Task task) {
|
||||||
mTaskCardView.init(task);
|
mTaskCardView.init(task);
|
||||||
@@ -90,7 +86,6 @@ public class TaskStackHorizontalViewAdapter extends
|
|||||||
public void onAnimationEnd(Animator animation) {
|
public void onAnimationEnd(Animator animation) {
|
||||||
removeTask(task);
|
removeTask(task);
|
||||||
EventBus.getDefault().send(new DeleteTaskDataEvent(task));
|
EventBus.getDefault().send(new DeleteTaskDataEvent(task));
|
||||||
mShouldReset = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -130,23 +125,6 @@ public class TaskStackHorizontalViewAdapter extends
|
|||||||
holder.init(task);
|
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
|
@Override
|
||||||
public int getItemCount() {
|
public int getItemCount() {
|
||||||
return mTaskList.size();
|
return mTaskList.size();
|
||||||
@@ -178,8 +156,4 @@ public class TaskStackHorizontalViewAdapter extends
|
|||||||
mTaskList.add(position, task);
|
mTaskList.add(position, task);
|
||||||
notifyItemInserted(position);
|
notifyItemInserted(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setResetAddedCards(boolean reset) {
|
|
||||||
mResetAddedCards = reset;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,12 +21,11 @@ import android.animation.AnimatorInflater;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.TypedArray;
|
import android.content.res.TypedArray;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.Gravity;
|
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View.OnFocusChangeListener;
|
import android.view.View.OnFocusChangeListener;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.RelativeLayout;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.android.systemui.R;
|
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.
|
* 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 OnFocusChangeListener mFocusChangeListener;
|
||||||
private ImageView mButtonImageView;
|
private ImageView mIconImageView;
|
||||||
|
ImageView mButtonImageView;
|
||||||
private TextView mDescriptionTextView;
|
private TextView mDescriptionTextView;
|
||||||
private Animator mFocusGainAnimator;
|
private Animator mTextFocusGainAnimator;
|
||||||
private Animator mFocusLoseAnimator;
|
private Animator mButtonFocusGainAnimator;
|
||||||
|
private Animator mTextFocusLossAnimator;
|
||||||
|
private Animator mButtonFocusLossAnimator;
|
||||||
|
|
||||||
private final OnFocusChangeListener mInternalFocusChangeListener =
|
private final OnFocusChangeListener mInternalFocusChangeListener =
|
||||||
new OnFocusChangeListener() {
|
new OnFocusChangeListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onFocusChange(View v, boolean hasFocus) {
|
public void onFocusChange(View v, boolean hasFocus) {
|
||||||
if (hasFocus) {
|
if (hasFocus) {
|
||||||
if (mFocusLoseAnimator.isStarted()) {
|
startFocusGainAnimation();
|
||||||
mFocusLoseAnimator.cancel();
|
|
||||||
}
|
|
||||||
mFocusGainAnimator.start();
|
|
||||||
} else {
|
} else {
|
||||||
if (mFocusGainAnimator.isStarted()) {
|
startFocusLossAnimation();
|
||||||
mFocusGainAnimator.cancel();
|
|
||||||
}
|
|
||||||
mFocusLoseAnimator.start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mFocusChangeListener != null) {
|
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);
|
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||||
inflater.inflate(R.layout.tv_pip_control_button, this);
|
inflater.inflate(R.layout.tv_pip_control_button, this);
|
||||||
|
|
||||||
setOrientation(LinearLayout.VERTICAL);
|
mIconImageView = (ImageView) findViewById(R.id.icon);
|
||||||
setGravity(Gravity.CENTER);
|
|
||||||
|
|
||||||
mButtonImageView = (ImageView) findViewById(R.id.button);
|
mButtonImageView = (ImageView) findViewById(R.id.button);
|
||||||
mDescriptionTextView = (TextView) findViewById(R.id.desc);
|
mDescriptionTextView = (TextView) findViewById(R.id.desc);
|
||||||
|
|
||||||
@@ -103,12 +97,19 @@ public class PipControlButtonView extends LinearLayout {
|
|||||||
super.onFinishInflate();
|
super.onFinishInflate();
|
||||||
mButtonImageView.setOnFocusChangeListener(mInternalFocusChangeListener);
|
mButtonImageView.setOnFocusChangeListener(mInternalFocusChangeListener);
|
||||||
|
|
||||||
mFocusGainAnimator = AnimatorInflater.loadAnimator(getContext(),
|
mTextFocusGainAnimator = AnimatorInflater.loadAnimator(getContext(),
|
||||||
R.anim.tv_pip_controls_text_focus_gain_animation);
|
R.anim.tv_pip_controls_focus_gain_animation);
|
||||||
mFocusGainAnimator.setTarget(mDescriptionTextView);
|
mTextFocusGainAnimator.setTarget(mDescriptionTextView);
|
||||||
mFocusLoseAnimator = AnimatorInflater.loadAnimator(getContext(),
|
mButtonFocusGainAnimator = AnimatorInflater.loadAnimator(getContext(),
|
||||||
R.anim.tv_pip_controls_text_focus_lose_animation);
|
R.anim.tv_pip_controls_focus_gain_animation);
|
||||||
mFocusLoseAnimator.setTarget(mDescriptionTextView);
|
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
|
@Override
|
||||||
@@ -125,7 +126,7 @@ public class PipControlButtonView extends LinearLayout {
|
|||||||
* Sets the drawable for the button with the given resource id.
|
* Sets the drawable for the button with the given resource id.
|
||||||
*/
|
*/
|
||||||
public void setImageResource(int resId) {
|
public void setImageResource(int resId) {
|
||||||
mButtonImageView.setImageResource(resId);
|
mIconImageView.setImageResource(resId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -136,8 +137,51 @@ public class PipControlButtonView extends LinearLayout {
|
|||||||
mDescriptionTextView.setText(resId);
|
mDescriptionTextView.setText(resId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private static void cancelAnimator(Animator animator) {
|
||||||
public boolean isFocused() {
|
if (animator.isStarted()) {
|
||||||
return mButtonImageView.isFocused();
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,8 +61,7 @@ public class PipControlsView extends LinearLayout {
|
|||||||
private PipControlButtonView mCloseButtonView;
|
private PipControlButtonView mCloseButtonView;
|
||||||
private PipControlButtonView mPlayPauseButtonView;
|
private PipControlButtonView mPlayPauseButtonView;
|
||||||
|
|
||||||
private boolean mHasFocus;
|
private PipControlButtonView mFocusedChild;
|
||||||
private OnFocusChangeListener mOnChildFocusChangeListener;
|
|
||||||
|
|
||||||
private MediaController.Callback mMediaControllerCallback = new MediaController.Callback() {
|
private MediaController.Callback mMediaControllerCallback = new MediaController.Callback() {
|
||||||
@Override
|
@Override
|
||||||
@@ -80,8 +79,12 @@ public class PipControlsView extends LinearLayout {
|
|||||||
|
|
||||||
private final OnFocusChangeListener mFocusChangeListener = new OnFocusChangeListener() {
|
private final OnFocusChangeListener mFocusChangeListener = new OnFocusChangeListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onFocusChange(View v, boolean hasFocus) {
|
public void onFocusChange(View view, boolean hasFocus) {
|
||||||
onChildViewFocusChanged();
|
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) {
|
public void reset() {
|
||||||
mOnChildFocusChangeListener = listener;
|
mFullButtonView.reset();
|
||||||
}
|
mCloseButtonView.reset();
|
||||||
|
mPlayPauseButtonView.reset();
|
||||||
private void onChildViewFocusChanged() {
|
mFullButtonView.requestFocus();
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -225,4 +218,11 @@ public class PipControlsView extends LinearLayout {
|
|||||||
public void setListener(Listener listener) {
|
public void setListener(Listener listener) {
|
||||||
mListener = listener;
|
mListener = listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the focused control button view to animate focused button.
|
||||||
|
*/
|
||||||
|
PipControlButtonView getFocusedButton() {
|
||||||
|
return mFocusedChild;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -126,7 +126,6 @@ public class PipManager {
|
|||||||
private int mSuspendPipResizingReason;
|
private int mSuspendPipResizingReason;
|
||||||
|
|
||||||
private Context mContext;
|
private Context mContext;
|
||||||
private SystemServicesProxy mSystemServiceProxy;
|
|
||||||
private PipRecentsOverlayManager mPipRecentsOverlayManager;
|
private PipRecentsOverlayManager mPipRecentsOverlayManager;
|
||||||
private IActivityManager mActivityManager;
|
private IActivityManager mActivityManager;
|
||||||
private MediaSessionManager mMediaSessionManager;
|
private MediaSessionManager mMediaSessionManager;
|
||||||
@@ -213,8 +212,7 @@ public class PipManager {
|
|||||||
mPipBounds = mDefaultPipBounds;
|
mPipBounds = mDefaultPipBounds;
|
||||||
|
|
||||||
mActivityManager = ActivityManagerNative.getDefault();
|
mActivityManager = ActivityManagerNative.getDefault();
|
||||||
mSystemServiceProxy = SystemServicesProxy.getInstance(context);
|
SystemServicesProxy.getInstance(context).registerTaskStackListener(mTaskStackListener);
|
||||||
mSystemServiceProxy.registerTaskStackListener(mTaskStackListener);
|
|
||||||
IntentFilter intentFilter = new IntentFilter();
|
IntentFilter intentFilter = new IntentFilter();
|
||||||
intentFilter.addAction(Intent.ACTION_MEDIA_RESOURCE_GRANTED);
|
intentFilter.addAction(Intent.ACTION_MEDIA_RESOURCE_GRANTED);
|
||||||
mContext.registerReceiver(mBroadcastReceiver, intentFilter);
|
mContext.registerReceiver(mBroadcastReceiver, intentFilter);
|
||||||
|
|||||||
@@ -48,12 +48,12 @@ public class PipRecentsControlsView extends FrameLayout {
|
|||||||
abstract void onBackPressed();
|
abstract void onBackPressed();
|
||||||
}
|
}
|
||||||
|
|
||||||
final PipManager mPipManager = PipManager.getInstance();
|
private final PipManager mPipManager = PipManager.getInstance();
|
||||||
private Listener mListener;
|
private Listener mListener;
|
||||||
private PipControlsView mPipControlsView;
|
private PipControlsView mPipControlsView;
|
||||||
private View mScrim;
|
private View mScrim;
|
||||||
private Animator mFocusGainAnimator;
|
private Animator mFocusGainAnimator;
|
||||||
private AnimatorSet mFocusLoseAnimatorSet;
|
private AnimatorSet mFocusLossAnimatorSet;
|
||||||
|
|
||||||
public PipRecentsControlsView(Context context) {
|
public PipRecentsControlsView(Context context) {
|
||||||
this(context, null, 0, 0);
|
this(context, null, 0, 0);
|
||||||
@@ -82,10 +82,10 @@ public class PipRecentsControlsView extends FrameLayout {
|
|||||||
mFocusGainAnimator = loadAnimator(mPipControlsView,
|
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();
|
mFocusLossAnimatorSet = new AnimatorSet();
|
||||||
mFocusLoseAnimatorSet.playSequentially(
|
mFocusLossAnimatorSet.playSequentially(
|
||||||
loadAnimator(mPipControlsView,
|
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));
|
loadAnimator(mScrim, R.anim.tv_pip_controls_in_recents_scrim_fade_in_animation));
|
||||||
|
|
||||||
Rect pipBounds = mPipManager.getRecentsFocusedPipBounds();
|
Rect pipBounds = mPipManager.getRecentsFocusedPipBounds();
|
||||||
@@ -99,21 +99,29 @@ public class PipRecentsControlsView extends FrameLayout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts focus gaining animation.
|
* Starts focus gain animation.
|
||||||
*/
|
*/
|
||||||
public void startFocusGainAnimation() {
|
public void startFocusGainAnimation() {
|
||||||
// Hides the scrim view as soon as possible, before the PIP resize animation starts.
|
// 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
|
// 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.
|
// shown at the bottom of the PIP.
|
||||||
mScrim.setAlpha(0);
|
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() {
|
public void startFocusLossAnimation() {
|
||||||
startAnimator(mFocusLoseAnimatorSet, mFocusGainAnimator);
|
PipControlButtonView focus = mPipControlsView.getFocusedButton();
|
||||||
|
if (focus != null) {
|
||||||
|
focus.startFocusLossAnimation();
|
||||||
|
}
|
||||||
|
startAnimator(mFocusLossAnimatorSet, mFocusGainAnimator);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -121,14 +129,14 @@ public class PipRecentsControlsView extends FrameLayout {
|
|||||||
*/
|
*/
|
||||||
public void reset() {
|
public void reset() {
|
||||||
cancelAnimator(mFocusGainAnimator);
|
cancelAnimator(mFocusGainAnimator);
|
||||||
cancelAnimator(mFocusLoseAnimatorSet);
|
cancelAnimator(mFocusLossAnimatorSet);
|
||||||
|
|
||||||
// Reset to initial state (i.e. end of focused)
|
// Reset to initial state (i.e. end of focused)
|
||||||
requestFocus();
|
mScrim.setAlpha(0);
|
||||||
mPipControlsView.setTranslationY(0);
|
mPipControlsView.setTranslationY(0);
|
||||||
mPipControlsView.setScaleX(1);
|
mPipControlsView.setScaleX(1);
|
||||||
mPipControlsView.setScaleY(1);
|
mPipControlsView.setScaleY(1);
|
||||||
mScrim.setAlpha(0);
|
mPipControlsView.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void startAnimator(Animator animator, Animator previousAnimator) {
|
private static void startAnimator(Animator animator, Animator previousAnimator) {
|
||||||
@@ -153,13 +161,20 @@ public class PipRecentsControlsView extends FrameLayout {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean dispatchKeyEvent(KeyEvent event) {
|
public boolean dispatchKeyEvent(KeyEvent event) {
|
||||||
if (!event.isCanceled()
|
if (!event.isCanceled()) {
|
||||||
&& event.getKeyCode() == KeyEvent.KEYCODE_BACK
|
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK
|
||||||
&& event.getAction() == KeyEvent.ACTION_UP) {
|
&& event.getAction() == KeyEvent.ACTION_UP) {
|
||||||
if (mPipControlsView.mListener != null) {
|
if (mPipControlsView.mListener != null) {
|
||||||
((PipRecentsControlsView.Listener) mPipControlsView.mListener).onBackPressed();
|
((PipRecentsControlsView.Listener) mPipControlsView.mListener).onBackPressed();
|
||||||
}
|
}
|
||||||
return true;
|
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 super.dispatchKeyEvent(event);
|
return super.dispatchKeyEvent(event);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,15 +18,20 @@ package com.android.systemui.tv.pip;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.PixelFormat;
|
import android.graphics.PixelFormat;
|
||||||
|
import android.graphics.Rect;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.accessibility.AccessibilityEvent;
|
|
||||||
import android.view.WindowManager.LayoutParams;
|
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
|
import android.view.WindowManager.LayoutParams;
|
||||||
|
import android.view.accessibility.AccessibilityEvent;
|
||||||
|
|
||||||
import com.android.systemui.R;
|
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_OVERLAY;
|
||||||
import static com.android.systemui.tv.pip.PipManager.STATE_PIP_RECENTS;
|
import static com.android.systemui.tv.pip.PipManager.STATE_PIP_RECENTS;
|
||||||
import static com.android.systemui.tv.pip.PipManager.STATE_PIP_RECENTS_FOCUSED;
|
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 PipManager mPipManager = PipManager.getInstance();
|
||||||
private final WindowManager mWindowManager;
|
private final WindowManager mWindowManager;
|
||||||
|
private final SystemServicesProxy mSystemServicesProxy;
|
||||||
private View mOverlayView;
|
private View mOverlayView;
|
||||||
private PipRecentsControlsView mPipControlsView;
|
private PipRecentsControlsView mPipControlsView;
|
||||||
private View mRecentsView;
|
private View mRecentsView;
|
||||||
|
private boolean mTalkBackEnabled;
|
||||||
|
|
||||||
private final LayoutParams mPipRecentsControlsViewLayoutParams;
|
private LayoutParams mPipRecentsControlsViewLayoutParams;
|
||||||
private final LayoutParams mPipRecentsControlsViewFocusedLayoutParams;
|
private LayoutParams mPipRecentsControlsViewFocusedLayoutParams;
|
||||||
|
|
||||||
|
private boolean mHasFocusableInRecents;
|
||||||
private boolean mIsPipRecentsOverlayShown;
|
private boolean mIsPipRecentsOverlayShown;
|
||||||
private boolean mIsRecentsShown;
|
private boolean mIsRecentsShown;
|
||||||
private boolean mIsPipFocusedInRecent;
|
private boolean mIsPipFocusedInRecent;
|
||||||
@@ -72,18 +80,7 @@ public class PipRecentsOverlayManager {
|
|||||||
|
|
||||||
PipRecentsOverlayManager(Context context) {
|
PipRecentsOverlayManager(Context context) {
|
||||||
mWindowManager = (WindowManager) context.getSystemService(WindowManager.class);
|
mWindowManager = (WindowManager) context.getSystemService(WindowManager.class);
|
||||||
|
mSystemServicesProxy = SystemServicesProxy.getInstance(context);
|
||||||
mPipRecentsControlsViewLayoutParams = new WindowManager.LayoutParams(
|
|
||||||
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
|
|
||||||
LayoutParams.TYPE_SYSTEM_DIALOG,
|
|
||||||
LayoutParams.FLAG_NOT_FOCUSABLE | LayoutParams.FLAG_NOT_TOUCHABLE,
|
|
||||||
PixelFormat.TRANSLUCENT);
|
|
||||||
mPipRecentsControlsViewFocusedLayoutParams = new WindowManager.LayoutParams(
|
|
||||||
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
|
|
||||||
LayoutParams.TYPE_SYSTEM_DIALOG,
|
|
||||||
0,
|
|
||||||
PixelFormat.TRANSLUCENT);
|
|
||||||
|
|
||||||
initViews(context);
|
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) {
|
if (mIsPipRecentsOverlayShown) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
mTalkBackEnabled = mSystemServicesProxy.isTouchExplorationEnabled();
|
||||||
|
mRecentsView.setVisibility(mTalkBackEnabled ? View.VISIBLE : View.GONE);
|
||||||
mIsPipRecentsOverlayShown = true;
|
mIsPipRecentsOverlayShown = true;
|
||||||
mIsPipFocusedInRecent = true;
|
mIsPipFocusedInRecent = true;
|
||||||
mPipControlsView.reset();
|
|
||||||
mWindowManager.addView(mOverlayView, mPipRecentsControlsViewFocusedLayoutParams);
|
mWindowManager.addView(mOverlayView, mPipRecentsControlsViewFocusedLayoutParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,50 +138,46 @@ public class PipRecentsOverlayManager {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mWindowManager.removeView(mOverlayView);
|
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;
|
mIsPipRecentsOverlayShown = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request focus to the PIP Recents overlay.
|
* 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}.
|
* 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) {
|
public void requestFocus(boolean hasFocusableInRecents) {
|
||||||
mRecentsView.setVisibility(allowRecentsFocusable ? View.VISIBLE : View.GONE);
|
mHasFocusableInRecents = hasFocusableInRecents;
|
||||||
if (!mIsPipRecentsOverlayShown || !mIsRecentsShown || mIsPipFocusedInRecent
|
if (!mIsPipRecentsOverlayShown || !mIsRecentsShown || mIsPipFocusedInRecent
|
||||||
|| !mPipManager.isPipShown()) {
|
|| !mPipManager.isPipShown()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mIsPipFocusedInRecent = true;
|
mIsPipFocusedInRecent = true;
|
||||||
mPipManager.resizePinnedStack(STATE_PIP_RECENTS_FOCUSED);
|
|
||||||
|
|
||||||
mWindowManager.updateViewLayout(mOverlayView, mPipRecentsControlsViewFocusedLayoutParams);
|
|
||||||
mPipControlsView.requestFocus();
|
|
||||||
mPipControlsView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
|
|
||||||
mPipControlsView.startFocusGainAnimation();
|
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.
|
* 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() {
|
public void clearFocus() {
|
||||||
if (!mIsPipRecentsOverlayShown || !mIsRecentsShown || !mIsPipFocusedInRecent
|
if (!mIsPipRecentsOverlayShown || !mIsRecentsShown || !mIsPipFocusedInRecent
|
||||||
|| !mPipManager.isPipShown()) {
|
|| !mPipManager.isPipShown() || !mHasFocusableInRecents) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!mRecentsView.hasFocus()) {
|
|
||||||
// Let mRecentsView's focus listener handle clearFocus().
|
|
||||||
mRecentsView.requestFocus();
|
|
||||||
}
|
|
||||||
mIsPipFocusedInRecent = false;
|
mIsPipFocusedInRecent = false;
|
||||||
mPipManager.resizePinnedStack(STATE_PIP_RECENTS);
|
mPipControlsView.startFocusLossAnimation();
|
||||||
mWindowManager.updateViewLayout(mOverlayView, mPipRecentsControlsViewLayoutParams);
|
mWindowManager.updateViewLayout(mOverlayView, mPipRecentsControlsViewLayoutParams);
|
||||||
mPipControlsView.startFocusLoseAnimation();
|
mPipManager.resizePinnedStack(STATE_PIP_RECENTS);
|
||||||
if (mCallback != null) {
|
if (mCallback != null) {
|
||||||
mCallback.onRecentsFocused();
|
mCallback.onRecentsFocused();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user