RecentsTvView.java revision c81082b7ee925aeeb7edddbb181dc365a4600be1
1/* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16package com.android.systemui.recents.tv.views; 17 18import android.content.Context; 19import android.graphics.Rect; 20import android.os.Handler; 21import android.support.v7.widget.DefaultItemAnimator; 22import android.support.v7.widget.RecyclerView; 23import android.util.AttributeSet; 24import android.util.Log; 25import android.view.LayoutInflater; 26import android.view.View; 27import android.view.WindowInsets; 28import android.widget.FrameLayout; 29 30import com.android.systemui.R; 31import com.android.systemui.recents.Recents; 32import com.android.systemui.recents.RecentsActivity; 33import com.android.systemui.recents.RecentsActivityLaunchState; 34import com.android.systemui.recents.RecentsConfiguration; 35import com.android.systemui.recents.events.EventBus; 36import com.android.systemui.recents.events.activity.CancelEnterRecentsWindowAnimationEvent; 37import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted; 38import com.android.systemui.recents.events.activity.ExitRecentsWindowFirstAnimationFrameEvent; 39import com.android.systemui.recents.events.activity.LaunchTvTaskEvent; 40import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent; 41import com.android.systemui.recents.misc.SystemServicesProxy; 42import com.android.systemui.recents.model.Task; 43import com.android.systemui.recents.model.TaskStack; 44import com.android.systemui.recents.tv.animations.RecentsRowFocusAnimationHolder; 45import android.support.v7.widget.RecyclerView.OnScrollListener; 46import static android.app.ActivityManager.StackId.INVALID_STACK_ID; 47 48/** 49 * Top level layout of recents for TV. This will show the TaskStacks using a HorizontalGridView. 50 */ 51public class RecentsTvView extends FrameLayout { 52 53 private static final String TAG = "RecentsTvView"; 54 private static final boolean DEBUG = false; 55 56 private TaskStack mStack; 57 private TaskStackHorizontalGridView mTaskStackHorizontalView; 58 private View mEmptyView; 59 private RecentsRowFocusAnimationHolder mEmptyViewFocusAnimationHolder; 60 private boolean mAwaitingFirstLayout = true; 61 private Rect mSystemInsets = new Rect(); 62 private RecentsTvTransitionHelper mTransitionHelper; 63 private Handler mHandler; 64 private OnScrollListener mScrollListener; 65 public RecentsTvView(Context context) { 66 this(context, null); 67 } 68 69 public RecentsTvView(Context context, AttributeSet attrs) { 70 this(context, attrs, 0); 71 } 72 73 public RecentsTvView(Context context, AttributeSet attrs, int defStyleAttr) { 74 this(context, attrs, defStyleAttr, 0); 75 } 76 77 public RecentsTvView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 78 super(context, attrs, defStyleAttr, defStyleRes); 79 80 setWillNotDraw(false); 81 82 LayoutInflater inflater = LayoutInflater.from(context); 83 mEmptyView = inflater.inflate(R.layout.recents_empty, this, false); 84 addView(mEmptyView); 85 mEmptyViewFocusAnimationHolder = new RecentsRowFocusAnimationHolder(mEmptyView, null); 86 87 mHandler = new Handler(); 88 mTransitionHelper = new RecentsTvTransitionHelper(mContext, mHandler); 89 } 90 91 public void setTaskStack(TaskStack stack) { 92 RecentsConfiguration config = Recents.getConfiguration(); 93 RecentsActivityLaunchState launchState = config.getLaunchState(); 94 mStack = stack; 95 96 if (mTaskStackHorizontalView != null) { 97 mTaskStackHorizontalView.reset(); 98 mTaskStackHorizontalView.setStack(stack); 99 } else { 100 mTaskStackHorizontalView = (TaskStackHorizontalGridView) findViewById(R.id.task_list); 101 mTaskStackHorizontalView.setStack(stack); 102 } 103 104 if (stack.getStackTaskCount() > 0) { 105 hideEmptyView(); 106 } else { 107 showEmptyView(); 108 } 109 110 requestLayout(); 111 } 112 113 public boolean launchFocusedTask() { 114 if (mTaskStackHorizontalView != null) { 115 Task task = mTaskStackHorizontalView.getFocusedTask(); 116 if (task != null) { 117 launchTaskFomRecents(task); 118 return true; 119 } 120 } 121 return false; 122 } 123 124 /** Launches the task that recents was launched from if possible */ 125 public boolean launchPreviousTask() { 126 if (mTaskStackHorizontalView != null) { 127 TaskStack stack = mTaskStackHorizontalView.getStack(); 128 Task task = stack.getLaunchTarget(); 129 if (task != null) { 130 launchTaskFomRecents(task); 131 return true; 132 } 133 } 134 return false; 135 } 136 137 /** 138 * Launch the given task from recents with animation. If the task is not focused, this will 139 * attempt to scroll to focus the task before launching. 140 * @param task 141 */ 142 private void launchTaskFomRecents(final Task task) { 143 if(task != mTaskStackHorizontalView.getFocusedTask()) { 144 if(mScrollListener != null) { 145 mTaskStackHorizontalView.removeOnScrollListener(mScrollListener); 146 } 147 mScrollListener = new OnScrollListener() { 148 @Override 149 public void onScrollStateChanged(RecyclerView recyclerView, int newState) { 150 super.onScrollStateChanged(recyclerView, newState); 151 if(newState == RecyclerView.SCROLL_STATE_IDLE) { 152 TaskCardView cardView = mTaskStackHorizontalView.getChildViewForTask(task); 153 if(cardView != null) { 154 mTransitionHelper.launchTaskFromRecents(mStack, task, 155 mTaskStackHorizontalView, cardView, null, INVALID_STACK_ID); 156 } else { 157 // This should not happen normally. If this happens then the data in 158 // the grid view was altered during the scroll. Log error and launch 159 // task with no animation. 160 Log.e(TAG, "Card view for task : " + task + ", returned null."); 161 SystemServicesProxy ssp = Recents.getSystemServices(); 162 ssp.startActivityFromRecents(getContext(), task.key, task.title, null); 163 } 164 mTaskStackHorizontalView.removeOnScrollListener(mScrollListener); 165 } 166 } 167 }; 168 mTaskStackHorizontalView.addOnScrollListener(mScrollListener); 169 mTaskStackHorizontalView.setSelectedPositionSmooth( 170 ((TaskStackHorizontalViewAdapter) mTaskStackHorizontalView.getAdapter()) 171 .getPositionOfTask(task)); 172 } else { 173 mTransitionHelper.launchTaskFromRecents(mStack, task, mTaskStackHorizontalView, 174 mTaskStackHorizontalView.getChildViewForTask(task), null, 175 INVALID_STACK_ID); 176 } 177 } 178 179 /** 180 * Starts the focus change animation. 181 */ 182 public void startRecentsRowFocusAnimation(boolean hasFocus) { 183 if (mEmptyView.getVisibility() == View.VISIBLE) { 184 mEmptyViewFocusAnimationHolder.getFocusChangeAnimator(hasFocus).start(); 185 } else { 186 mTaskStackHorizontalView.startRecentsRowFocusAnimation(hasFocus); 187 } 188 } 189 190 /** 191 * Hides the task stack and shows the empty view. 192 */ 193 public void showEmptyView() { 194 mEmptyView.setVisibility(View.VISIBLE); 195 mTaskStackHorizontalView.setVisibility(View.GONE); 196 } 197 198 /** 199 * Shows the task stack and hides the empty view. 200 */ 201 public void hideEmptyView() { 202 mEmptyView.setVisibility(View.GONE); 203 mTaskStackHorizontalView.setVisibility(View.VISIBLE); 204 } 205 206 /** 207 * Returns the last known system insets. 208 */ 209 public Rect getSystemInsets() { 210 return mSystemInsets; 211 } 212 213 @Override 214 protected void onAttachedToWindow() { 215 EventBus.getDefault().register(this, RecentsActivity.EVENT_BUS_PRIORITY + 1); 216 super.onAttachedToWindow(); 217 } 218 219 @Override 220 protected void onDetachedFromWindow() { 221 super.onDetachedFromWindow(); 222 EventBus.getDefault().unregister(this); 223 } 224 225 @Override 226 public WindowInsets onApplyWindowInsets(WindowInsets insets) { 227 mSystemInsets.set(insets.getSystemWindowInsets()); 228 requestLayout(); 229 return insets; 230 } 231 232 /**** EventBus Events ****/ 233 234 public final void onBusEvent(LaunchTvTaskEvent event) { 235 mTransitionHelper.launchTaskFromRecents(mStack, event.task, mTaskStackHorizontalView, 236 event.taskView, event.targetTaskBounds, event.targetTaskStack); 237 } 238 239 public final void onBusEvent(DismissRecentsToHomeAnimationStarted event) { 240 // If we are going home, cancel the previous task's window transition 241 EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(null)); 242 } 243 244 public final void onBusEvent(RecentsVisibilityChangedEvent event) { 245 if (!event.visible) { 246 // Reset the view state 247 mAwaitingFirstLayout = true; 248 } 249 } 250 251 public void setTaskStackViewAdapter(TaskStackHorizontalViewAdapter taskStackViewAdapter) { 252 if(mTaskStackHorizontalView != null) { 253 mTaskStackHorizontalView.setAdapter(taskStackViewAdapter); 254 } 255 } 256} 257