blob: c92041cd2725cffc916ed44ccf59e17829e69d49 [file] [log] [blame]
Winson Chung303e1ff2014-03-07 15:06:19 -08001/*
2 * Copyright (C) 2014 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
17package com.android.systemui.recents.views;
18
19import android.app.ActivityOptions;
20import android.content.Context;
21import android.content.Intent;
22import android.graphics.Bitmap;
23import android.graphics.Canvas;
24import android.graphics.Rect;
25import android.os.UserHandle;
26import android.view.View;
27import android.widget.FrameLayout;
28import com.android.systemui.recents.Console;
29import com.android.systemui.recents.Constants;
30import com.android.systemui.recents.RecentsConfiguration;
31import com.android.systemui.recents.model.SpaceNode;
32import com.android.systemui.recents.model.Task;
33import com.android.systemui.recents.model.TaskStack;
34
35import java.util.ArrayList;
36
37
38/**
39 * This view is the the top level layout that contains TaskStacks (which are laid out according
40 * to their SpaceNode bounds.
41 */
42public class RecentsView extends FrameLayout implements TaskStackViewCallbacks {
43 // The space partitioning root of this container
44 SpaceNode mBSP;
45
46 public RecentsView(Context context) {
47 super(context);
48 setWillNotDraw(false);
49 }
50
51 /** Set/get the bsp root node */
52 public void setBSP(SpaceNode n) {
53 mBSP = n;
54
55 // XXX: We shouldn't be recereating new stacks every time, but for now, that is OK
56 // Add all the stacks for this partition
57 removeAllViews();
58 ArrayList<TaskStack> stacks = mBSP.getStacks();
59 for (TaskStack stack : stacks) {
60 TaskStackView stackView = new TaskStackView(getContext(), stack);
61 stackView.setCallbacks(this);
62 addView(stackView);
63 }
64 }
65
66 /** Launches the first task from the first stack if possible */
67 public boolean launchFirstTask() {
68 int childCount = getChildCount();
69 for (int i = 0; i < childCount; i++) {
70 TaskStackView stackView = (TaskStackView) getChildAt(i);
71 TaskStack stack = stackView.mStack;
72 ArrayList<Task> tasks = stack.getTasks();
73 if (!tasks.isEmpty()) {
74 Task task = tasks.get(tasks.size() - 1);
75 TaskView tv = null;
76 if (stackView.getChildCount() > 0) {
77 TaskView stv = (TaskView) stackView.getChildAt(stackView.getChildCount() - 1);
78 if (stv.getTask() == task) {
79 tv = stv;
80 }
81 }
82 onTaskLaunched(stackView, tv, stack, task);
83 return true;
84 }
85 }
86 return false;
87 }
88
89 @Override
90 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
91 int width = MeasureSpec.getSize(widthMeasureSpec);
92 int height = MeasureSpec.getSize(heightMeasureSpec);
93 int heightMode = MeasureSpec.getMode(heightMeasureSpec);
94 Console.log(Constants.DebugFlags.UI.MeasureAndLayout, "[RecentsView|measure]", "width: " + width + " height: " + height, Console.AnsiGreen);
95
96 // We measure our stack views sans the status bar. It will handle the nav bar itself.
97 RecentsConfiguration config = RecentsConfiguration.getInstance();
98 int childHeight = height - config.systemInsets.top;
99
100 // Measure each child
101 int childCount = getChildCount();
102 for (int i = 0; i < childCount; i++) {
103 final View child = getChildAt(i);
104 if (child.getVisibility() != GONE) {
105 child.measure(widthMeasureSpec,
106 MeasureSpec.makeMeasureSpec(childHeight, heightMode));
107 }
108 }
109
110 setMeasuredDimension(width, height);
111 }
112
113 @Override
114 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
115 Console.log(Constants.DebugFlags.UI.MeasureAndLayout, "[RecentsView|layout]", new Rect(left, top, right, bottom) + " changed: " + changed, Console.AnsiGreen);
116 // We offset our stack views by the status bar height. It will handle the nav bar itself.
117 RecentsConfiguration config = RecentsConfiguration.getInstance();
118 top += config.systemInsets.top;
119
120 // Layout each child
121 // XXX: Based on the space node for that task view
122 int childCount = getChildCount();
123 for (int i = 0; i < childCount; i++) {
124 final View child = getChildAt(i);
125 if (child.getVisibility() != GONE) {
126 final int width = child.getMeasuredWidth();
127 final int height = child.getMeasuredHeight();
128 child.layout(left, top, left + width, top + height);
129 }
130 }
131 }
132
133 @Override
134 protected void dispatchDraw(Canvas canvas) {
135 Console.log(Constants.DebugFlags.UI.Draw, "[RecentsView|dispatchDraw]", "", Console.AnsiPurple);
136 super.dispatchDraw(canvas);
137 }
138
139 @Override
140 protected boolean fitSystemWindows(Rect insets) {
141 Console.log(Constants.DebugFlags.UI.MeasureAndLayout, "[RecentsView|fitSystemWindows]", "insets: " + insets, Console.AnsiGreen);
142
143 // Update the configuration with the latest system insets and trigger a relayout
144 RecentsConfiguration config = RecentsConfiguration.getInstance();
145 config.updateSystemInsets(insets);
146 requestLayout();
147
148 return true;
149 }
150
151 /** Unfilters any filtered stacks */
152 public boolean unfilterFilteredStacks() {
153 if (mBSP != null) {
154 // Check if there are any filtered stacks and unfilter them before we back out of Recents
155 boolean stacksUnfiltered = false;
156 ArrayList<TaskStack> stacks = mBSP.getStacks();
157 for (TaskStack stack : stacks) {
158 if (stack.hasFilteredTasks()) {
159 stack.unfilterTasks();
160 stacksUnfiltered = true;
161 }
162 }
163 return stacksUnfiltered;
164 }
165 return false;
166 }
167
168 /**** View.OnClickListener Implementation ****/
169
170 @Override
171 public void onTaskLaunched(final TaskStackView stackView, final TaskView tv,
172 final TaskStack stack, final Task task) {
173 final Runnable launchRunnable = new Runnable() {
174 @Override
175 public void run() {
176 TaskViewTransform transform;
177 View sourceView = tv;
178 int offsetX = 0;
179 int offsetY = 0;
180 if (tv == null) {
181 // Launch the activity
182 sourceView = stackView;
183 transform = stackView.getStackTransform(stack.indexOfTask(task));
184 offsetX = transform.rect.left;
185 offsetY = transform.rect.top;
186 } else {
187 transform = stackView.getStackTransform(stack.indexOfTask(task));
188 }
189
190 // Compute the thumbnail to scale up from
191 ActivityOptions opts = null;
192 int thumbnailWidth = transform.rect.width();
193 int thumbnailHeight = transform.rect.height();
194 if (task.thumbnail != null && thumbnailWidth > 0 && thumbnailHeight > 0 &&
195 task.thumbnail.getWidth() > 0 && task.thumbnail.getHeight() > 0) {
196 // Resize the thumbnail to the size of the view that we are animating from
197 Bitmap b = Bitmap.createBitmap(thumbnailWidth, thumbnailHeight,
198 Bitmap.Config.ARGB_8888);
199 Canvas c = new Canvas(b);
200 c.drawBitmap(task.thumbnail,
201 new Rect(0, 0, task.thumbnail.getWidth(), task.thumbnail.getHeight()),
202 new Rect(0, 0, thumbnailWidth, thumbnailHeight), null);
203 c.setBitmap(null);
204 opts = ActivityOptions.makeThumbnailScaleUpAnimation(sourceView,
205 b, offsetX, offsetY);
206 }
207
208 // Launch the activity with the desired animation
209 Intent i = new Intent(task.intent);
210 i.setFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
211 | Intent.FLAG_ACTIVITY_TASK_ON_HOME
212 | Intent.FLAG_ACTIVITY_NEW_TASK);
213 if (opts != null) {
214 getContext().startActivityAsUser(i, opts.toBundle(), UserHandle.CURRENT);
215 } else {
216 getContext().startActivityAsUser(i, UserHandle.CURRENT);
217 }
218 }
219 };
220
221 // Launch the app right away if there is no task view, otherwise, animate the icon out first
222 if (tv == null || !Constants.Values.TaskView.AnimateFrontTaskIconOnLeavingRecents) {
223 launchRunnable.run();
224 } else {
225 tv.animateOnLeavingRecents(launchRunnable);
226 }
227 }
228}