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 
17 package com.android.systemui.recents.tv;
18 
19 import android.app.ActivityManager;
20 import android.app.ActivityOptions;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.graphics.Bitmap;
24 import android.graphics.Rect;
25 import android.os.SystemClock;
26 import android.os.UserHandle;
27 
28 import com.android.systemui.SystemUIApplication;
29 import com.android.systemui.recents.Recents;
30 import com.android.systemui.recents.RecentsActivityLaunchState;
31 import com.android.systemui.recents.RecentsConfiguration;
32 import com.android.systemui.recents.RecentsImpl;
33 import com.android.systemui.recents.events.EventBus;
34 import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent;
35 import com.android.systemui.recents.misc.SystemServicesProxy;
36 import com.android.systemui.recents.model.RecentsTaskLoader;
37 import com.android.systemui.recents.model.TaskStack;
38 import com.android.systemui.recents.model.ThumbnailData;
39 import com.android.systemui.recents.tv.views.TaskCardView;
40 import com.android.systemui.statusbar.tv.TvStatusBar;
41 import com.android.systemui.tv.pip.PipManager;
42 
43 public class RecentsTvImpl extends RecentsImpl{
44     public final static String RECENTS_TV_ACTIVITY =
45             "com.android.systemui.recents.tv.RecentsTvActivity";
46 
47     private static final PipManager mPipManager = PipManager.getInstance();
48 
RecentsTvImpl(Context context)49     public RecentsTvImpl(Context context) {
50         super(context);
51     }
52 
53     @Override
startRecentsActivity(ActivityManager.RunningTaskInfo runningTask, boolean isHomeStackVisible, boolean animate, int growTarget)54     protected void startRecentsActivity(ActivityManager.RunningTaskInfo runningTask,
55             boolean isHomeStackVisible, boolean animate, int growTarget) {
56         RecentsTaskLoader loader = Recents.getTaskLoader();
57 
58         // In the case where alt-tab is triggered, we never get a preloadRecents() call, so we
59         // should always preload the tasks now. If we are dragging in recents, reload them as
60         // the stacks might have changed.
61         if (mTriggeredFromAltTab || sInstanceLoadPlan == null) {
62             // Create a new load plan if preloadRecents() was never triggered
63             sInstanceLoadPlan = loader.createLoadPlan(mContext);
64         }
65         if (mTriggeredFromAltTab || !sInstanceLoadPlan.hasTasks()) {
66             loader.preloadTasks(sInstanceLoadPlan, runningTask.id, !isHomeStackVisible);
67         }
68         TaskStack stack = sInstanceLoadPlan.getTaskStack();
69 
70         if (!animate) {
71             ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext, -1, -1);
72             startRecentsActivity(runningTask, opts, false /* fromHome */, false /* fromThumbnail*/);
73             return;
74         }
75 
76         boolean hasRecentTasks = stack.getTaskCount() > 0;
77         boolean useThumbnailTransition = (runningTask != null) && !isHomeStackVisible && hasRecentTasks;
78 
79         if (useThumbnailTransition) {
80             // Try starting with a thumbnail transition
81             ActivityOptions opts = getThumbnailTransitionActivityOptionsForTV(runningTask,
82                     stack.getTaskCount());
83             if (opts != null) {
84                 startRecentsActivity(runningTask, opts, false /* fromHome */, true /* fromThumbnail */);
85             } else {
86                 // Fall through below to the non-thumbnail transition
87                 useThumbnailTransition = false;
88             }
89         }
90 
91         if (!useThumbnailTransition) {
92             startRecentsActivity(runningTask, null, true /* fromHome */, false /* fromThumbnail */);
93         }
94         mLastToggleTime = SystemClock.elapsedRealtime();
95     }
96 
startRecentsActivity(ActivityManager.RunningTaskInfo runningTask, ActivityOptions opts, boolean fromHome, boolean fromThumbnail)97     protected void startRecentsActivity(ActivityManager.RunningTaskInfo runningTask,
98             ActivityOptions opts, boolean fromHome, boolean fromThumbnail) {
99         // Update the configuration based on the launch options
100         RecentsConfiguration config = Recents.getConfiguration();
101         RecentsActivityLaunchState launchState = config.getLaunchState();
102         launchState.launchedFromHome = fromHome;
103         launchState.launchedFromApp = fromThumbnail;
104         launchState.launchedToTaskId = (runningTask != null) ? runningTask.id : -1;
105         launchState.launchedWithAltTab = mTriggeredFromAltTab;
106 
107         Intent intent = new Intent();
108         intent.setClassName(RECENTS_PACKAGE, RECENTS_TV_ACTIVITY);
109         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
110                 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
111                 | Intent.FLAG_ACTIVITY_TASK_ON_HOME);
112 
113         if (opts != null) {
114             mContext.startActivityAsUser(intent, opts.toBundle(), UserHandle.CURRENT);
115         } else {
116             mContext.startActivityAsUser(intent, UserHandle.CURRENT);
117         }
118         EventBus.getDefault().send(new RecentsActivityStartingEvent());
119     }
120 
121     /**
122      * Creates the activity options for an app->recents transition on TV.
123      */
getThumbnailTransitionActivityOptionsForTV( ActivityManager.RunningTaskInfo runningTask, int numTasks)124     private ActivityOptions getThumbnailTransitionActivityOptionsForTV(
125             ActivityManager.RunningTaskInfo runningTask, int numTasks) {
126         Rect rect = TaskCardView.getStartingCardThumbnailRect(
127             mContext, !mPipManager.isPipShown(), numTasks);
128         SystemServicesProxy ssp = Recents.getSystemServices();
129         ThumbnailData thumbnailData = ssp.getTaskThumbnail(runningTask.id);
130         if (thumbnailData.thumbnail != null) {
131             Bitmap thumbnail = Bitmap.createScaledBitmap(thumbnailData.thumbnail, rect.width(),
132                     rect.height(), false);
133             return ActivityOptions.makeThumbnailAspectScaleDownAnimation(mDummyStackView,
134                     thumbnail, (int) rect.left, (int) rect.top, (int) rect.width(),
135                     (int) rect.height(), mHandler, null);
136         }
137         // If both the screenshot and thumbnail fails, then just fall back to the default transition
138         return getUnknownTransitionActivityOptions();
139     }
140 
141     @Override
onVisibilityChanged(Context context, boolean visible)142     public void onVisibilityChanged(Context context, boolean visible) {
143         SystemUIApplication app = (SystemUIApplication) context;
144         TvStatusBar statusBar = app.getComponent(TvStatusBar.class);
145         if (statusBar != null) {
146             statusBar.updateRecentsVisibility(visible);
147         }
148     }
149 }
150