Home | History | Annotate | Download | only in views
      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  */
     16 package com.android.systemui.recents.tv.views;
     17 
     18 import android.content.Context;
     19 import android.graphics.Rect;
     20 import android.os.Handler;
     21 import android.support.v7.widget.RecyclerView;
     22 import android.util.AttributeSet;
     23 import android.util.Log;
     24 import android.view.LayoutInflater;
     25 import android.view.View;
     26 import android.view.WindowInsets;
     27 import android.widget.FrameLayout;
     28 
     29 import com.android.systemui.R;
     30 import com.android.systemui.recents.Recents;
     31 import com.android.systemui.recents.RecentsActivity;
     32 import com.android.systemui.recents.RecentsActivityLaunchState;
     33 import com.android.systemui.recents.RecentsConfiguration;
     34 import com.android.systemui.recents.events.EventBus;
     35 import com.android.systemui.recents.events.activity.CancelEnterRecentsWindowAnimationEvent;
     36 import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted;
     37 import com.android.systemui.recents.events.activity.LaunchTvTaskEvent;
     38 import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
     39 import com.android.systemui.recents.misc.SystemServicesProxy;
     40 import com.android.systemui.recents.model.Task;
     41 import com.android.systemui.recents.model.TaskStack;
     42 import com.android.systemui.recents.tv.animations.RecentsRowFocusAnimationHolder;
     43 import android.support.v7.widget.RecyclerView.OnScrollListener;
     44 import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
     45 
     46 /**
     47  * Top level layout of recents for TV. This will show the TaskStacks using a HorizontalGridView.
     48  */
     49 public class RecentsTvView extends FrameLayout {
     50 
     51     private static final String TAG = "RecentsTvView";
     52     private static final boolean DEBUG = false;
     53 
     54     private TaskStack mStack;
     55     private TaskStackHorizontalGridView mTaskStackHorizontalView;
     56     private View mEmptyView;
     57     private View mDismissPlaceholder;
     58     private RecentsRowFocusAnimationHolder mEmptyViewFocusAnimationHolder;
     59     private boolean mAwaitingFirstLayout = true;
     60     private Rect mSystemInsets = new Rect();
     61     private RecentsTvTransitionHelper mTransitionHelper;
     62     private final Handler mHandler = new Handler();
     63     private OnScrollListener mScrollListener;
     64     public RecentsTvView(Context context) {
     65         this(context, null);
     66     }
     67 
     68     public RecentsTvView(Context context, AttributeSet attrs) {
     69         this(context, attrs, 0);
     70     }
     71 
     72     public RecentsTvView(Context context, AttributeSet attrs, int defStyleAttr) {
     73         this(context, attrs, defStyleAttr, 0);
     74     }
     75 
     76     public RecentsTvView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
     77         super(context, attrs, defStyleAttr, defStyleRes);
     78 
     79         setWillNotDraw(false);
     80 
     81         LayoutInflater inflater = LayoutInflater.from(context);
     82         mEmptyView = inflater.inflate(R.layout.recents_tv_empty, this, false);
     83         addView(mEmptyView);
     84 
     85         mTransitionHelper = new RecentsTvTransitionHelper(mContext, mHandler);
     86     }
     87 
     88     @Override
     89     protected void onFinishInflate() {
     90         super.onFinishInflate();
     91         mDismissPlaceholder = findViewById(R.id.dismiss_placeholder);
     92         mTaskStackHorizontalView = (TaskStackHorizontalGridView) findViewById(R.id.task_list);
     93     }
     94 
     95     /**
     96      * Initialize the view.
     97      */
     98     public void init(TaskStack stack) {
     99         RecentsConfiguration config = Recents.getConfiguration();
    100         RecentsActivityLaunchState launchState = config.getLaunchState();
    101         mStack = stack;
    102 
    103         mTaskStackHorizontalView.init(stack);
    104 
    105         if (stack.getStackTaskCount() > 0) {
    106             hideEmptyView();
    107         } else {
    108             showEmptyView();
    109         }
    110 
    111         // Layout with the new stack
    112         requestLayout();
    113     }
    114 
    115     public boolean launchFocusedTask() {
    116         if (mTaskStackHorizontalView != null) {
    117             Task task = mTaskStackHorizontalView.getFocusedTask();
    118             if (task != null) {
    119                 launchTaskFomRecents(task, true);
    120                 return true;
    121             }
    122         }
    123         return false;
    124     }
    125 
    126     /** Launches the task that recents was launched from if possible */
    127     public boolean launchPreviousTask(boolean animate) {
    128         if (mTaskStackHorizontalView != null) {
    129             TaskStack stack = mTaskStackHorizontalView.getStack();
    130             Task task = stack.getLaunchTarget();
    131             if (task != null) {
    132                 launchTaskFomRecents(task, animate);
    133                 return true;
    134             }
    135         }
    136         return false;
    137     }
    138 
    139     /**
    140      * Launch the given task from recents with animation. If the task is not focused, this will
    141      * attempt to scroll to focus the task before launching.
    142      * @param task
    143      */
    144     private void launchTaskFomRecents(final Task task, boolean animate) {
    145         if (!animate) {
    146             SystemServicesProxy ssp = Recents.getSystemServices();
    147             ssp.startActivityFromRecents(getContext(), task.key, task.title, null);
    148             return;
    149         }
    150         mTaskStackHorizontalView.requestFocus();
    151         Task focusedTask = mTaskStackHorizontalView.getFocusedTask();
    152         if (focusedTask != null && task != focusedTask) {
    153             if (mScrollListener != null) {
    154                 mTaskStackHorizontalView.removeOnScrollListener(mScrollListener);
    155             }
    156             mScrollListener = new OnScrollListener() {
    157                 @Override
    158                 public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
    159                     super.onScrollStateChanged(recyclerView, newState);
    160                     if (newState == RecyclerView.SCROLL_STATE_IDLE) {
    161                         TaskCardView cardView = mTaskStackHorizontalView.getChildViewForTask(task);
    162                         if (cardView != null) {
    163                             mTransitionHelper.launchTaskFromRecents(mStack, task,
    164                                     mTaskStackHorizontalView, cardView, null, INVALID_STACK_ID);
    165                         } else {
    166                             // This should not happen normally. If this happens then the data in
    167                             // the grid view was altered during the scroll. Log error and launch
    168                             // task with no animation.
    169                             Log.e(TAG, "Card view for task : " + task + ", returned null.");
    170                             SystemServicesProxy ssp = Recents.getSystemServices();
    171                             ssp.startActivityFromRecents(getContext(), task.key, task.title, null);
    172                         }
    173                         mTaskStackHorizontalView.removeOnScrollListener(mScrollListener);
    174                     }
    175                 }
    176             };
    177             mTaskStackHorizontalView.addOnScrollListener(mScrollListener);
    178             mTaskStackHorizontalView.setSelectedPositionSmooth(
    179                     ((TaskStackHorizontalViewAdapter) mTaskStackHorizontalView.getAdapter())
    180                             .getPositionOfTask(task));
    181         } else {
    182             mTransitionHelper.launchTaskFromRecents(mStack, task, mTaskStackHorizontalView,
    183                     mTaskStackHorizontalView.getChildViewForTask(task), null,
    184                     INVALID_STACK_ID);
    185         }
    186     }
    187 
    188     /**
    189      * Hides the task stack and shows the empty view.
    190      */
    191     public void showEmptyView() {
    192         mEmptyView.setVisibility(View.VISIBLE);
    193         mTaskStackHorizontalView.setVisibility(View.GONE);
    194         if (Recents.getSystemServices().isTouchExplorationEnabled()) {
    195             mDismissPlaceholder.setVisibility(View.GONE);
    196         }
    197     }
    198 
    199     /**
    200      * Shows the task stack and hides the empty view.
    201      */
    202     public void hideEmptyView() {
    203         mEmptyView.setVisibility(View.GONE);
    204         mTaskStackHorizontalView.setVisibility(View.VISIBLE);
    205         if (Recents.getSystemServices().isTouchExplorationEnabled()) {
    206             mDismissPlaceholder.setVisibility(View.VISIBLE);
    207         }
    208     }
    209 
    210     /**
    211      * Returns the last known system insets.
    212      */
    213     public Rect getSystemInsets() {
    214         return mSystemInsets;
    215     }
    216 
    217     @Override
    218     protected void onAttachedToWindow() {
    219         EventBus.getDefault().register(this, RecentsActivity.EVENT_BUS_PRIORITY + 1);
    220         super.onAttachedToWindow();
    221     }
    222 
    223     @Override
    224     protected void onDetachedFromWindow() {
    225         super.onDetachedFromWindow();
    226         EventBus.getDefault().unregister(this);
    227     }
    228 
    229     @Override
    230     public WindowInsets onApplyWindowInsets(WindowInsets insets) {
    231         mSystemInsets.set(insets.getSystemWindowInsets());
    232         requestLayout();
    233         return insets;
    234     }
    235 
    236     /**** EventBus Events ****/
    237 
    238     public final void onBusEvent(LaunchTvTaskEvent event) {
    239         mTransitionHelper.launchTaskFromRecents(mStack, event.task, mTaskStackHorizontalView,
    240                 event.taskView, event.targetTaskBounds, event.targetTaskStack);
    241     }
    242 
    243     public final void onBusEvent(DismissRecentsToHomeAnimationStarted event) {
    244         // If we are going home, cancel the previous task's window transition
    245         EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(null));
    246     }
    247 
    248     public final void onBusEvent(RecentsVisibilityChangedEvent event) {
    249         if (!event.visible) {
    250             // Reset the view state
    251             mAwaitingFirstLayout = true;
    252         }
    253     }
    254 
    255     public TaskStackHorizontalGridView setTaskStackViewAdapter(
    256             TaskStackHorizontalViewAdapter taskStackViewAdapter) {
    257         if (mTaskStackHorizontalView != null) {
    258             mTaskStackHorizontalView.setAdapter(taskStackViewAdapter);
    259             taskStackViewAdapter.setTaskStackHorizontalGridView(mTaskStackHorizontalView);
    260         }
    261         return mTaskStackHorizontalView;
    262     }
    263 
    264     public TaskStackHorizontalGridView getGridView() {
    265         return mTaskStackHorizontalView;
    266     }
    267 }
    268