blob: 4a094237b0378c3c5ff375cf94fd345b344b0ae8 [file] [log] [blame]
Jorim Jaggi02886a82016-12-06 09:10:06 -08001/*
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
17package com.android.server.wm;
18
19import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
20import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
21import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
22import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
23import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
24import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TASK_SNAPSHOT;
25import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
26import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
27import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
28
29import android.content.res.Configuration;
30import android.graphics.Bitmap;
31import android.graphics.Canvas;
32import android.graphics.GraphicBuffer;
33import android.graphics.Rect;
34import android.os.Handler;
35import android.os.Message;
36import android.os.RemoteException;
37import android.util.Slog;
Jorim Jaggi02886a82016-12-06 09:10:06 -080038import android.view.IWindowSession;
39import android.view.Surface;
40import android.view.View;
41import android.view.ViewGroup.LayoutParams;
42import android.view.WindowManager;
43import android.view.WindowManagerGlobal;
44import android.view.WindowManagerPolicy.StartingSurface;
45
46import com.android.internal.view.BaseIWindow;
47
48/**
49 * This class represents a starting window that shows a snapshot.
50 * <p>
51 * DO NOT HOLD THE WINDOW MANAGER LOCK WHEN CALLING METHODS OF THIS CLASS!
52 */
53class TaskSnapshotSurface implements StartingSurface {
54
55 private static final String TAG = TAG_WITH_CLASS_NAME ? "SnapshotStartingWindow" : TAG_WM;
56 private static final int MSG_REPORT_DRAW = 0;
57 private static final String TITLE_FORMAT = "SnapshotStartingWindow for taskId=%s";
58 private final Window mWindow;
59 private final Surface mSurface;
60 private final IWindowSession mSession;
61 private final WindowManagerService mService;
62 private boolean mHasDrawn;
63 private boolean mReportNextDraw;
64
65 static TaskSnapshotSurface create(WindowManagerService service, AppWindowToken token,
66 GraphicBuffer snapshot) {
67
68 final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
69 final Window window = new Window();
70 final IWindowSession session = WindowManagerGlobal.getWindowSession();
71 window.setSession(session);
72 final Surface surface = new Surface();
73 final Rect tmpRect = new Rect();
74 final Rect tmpFrame = new Rect();
75 final Configuration tmpConfiguration = new Configuration();
76 synchronized (service.mWindowMap) {
77 layoutParams.type = TYPE_APPLICATION_STARTING;
78 layoutParams.format = snapshot.getFormat();
79 layoutParams.flags = FLAG_LAYOUT_INSET_DECOR
80 | FLAG_LAYOUT_IN_SCREEN
81 | FLAG_NOT_FOCUSABLE
82 | FLAG_NOT_TOUCHABLE
83 | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
84 layoutParams.privateFlags = PRIVATE_FLAG_TASK_SNAPSHOT;
85 layoutParams.token = token.token;
86 layoutParams.width = LayoutParams.MATCH_PARENT;
87 layoutParams.height = LayoutParams.MATCH_PARENT;
88
89 // TODO: Inherit behavior whether to draw behind status bar/nav bar.
90 layoutParams.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
91 | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
92 layoutParams.setTitle(String.format(TITLE_FORMAT, token.mTask.mTaskId));
93 }
94 try {
95 final int res = session.addToDisplay(window, window.mSeq, layoutParams,
96 View.VISIBLE, token.getDisplayContent().getDisplayId(), tmpRect, tmpRect,
97 tmpRect, null);
98 if (res < 0) {
99 Slog.w(TAG, "Failed to add snapshot starting window res=" + res);
100 return null;
101 }
102 } catch (RemoteException e) {
103 // Local call.
104 }
105 final TaskSnapshotSurface snapshotSurface = new TaskSnapshotSurface(service, window,
106 surface);
107 window.setOuter(snapshotSurface);
108 try {
109 session.relayout(window, window.mSeq, layoutParams, -1, -1, View.VISIBLE, 0, tmpFrame,
110 tmpRect, tmpRect, tmpRect, tmpRect, tmpRect, tmpRect, tmpConfiguration,
111 surface);
112 } catch (RemoteException e) {
113 // Local call.
114 }
115 snapshotSurface.drawSnapshot(snapshot);
116 return snapshotSurface;
117 }
118
119 private TaskSnapshotSurface(WindowManagerService service, Window window, Surface surface) {
120 mService = service;
121 mSession = WindowManagerGlobal.getWindowSession();
122 mWindow = window;
123 mSurface = surface;
124 }
125
126 @Override
127 public void remove() {
128 try {
129 mSession.remove(mWindow);
130 } catch (RemoteException e) {
131 // Local call.
132 }
133 }
134
135 private void drawSnapshot(GraphicBuffer snapshot) {
136
137 // TODO: Just wrap the buffer here without any copying.
138 final Canvas c = mSurface.lockHardwareCanvas();
139 c.drawBitmap(Bitmap.createHardwareBitmap(snapshot), 0, 0, null);
140 mSurface.unlockCanvasAndPost(c);
141 final boolean reportNextDraw;
142 synchronized (mService.mWindowMap) {
143 mHasDrawn = true;
144 reportNextDraw = mReportNextDraw;
145 }
146 if (reportNextDraw) {
147 reportDrawn();
148 }
Jorim Jaggi2f24b652017-01-18 02:17:37 +0100149 mSurface.release();
Jorim Jaggi02886a82016-12-06 09:10:06 -0800150 }
151
152 private void reportDrawn() {
153 synchronized (mService.mWindowMap) {
154 mReportNextDraw = false;
155 }
156 try {
157 mSession.finishDrawing(mWindow);
158 } catch (RemoteException e) {
159 // Local call.
160 }
161 }
162
163 private static Handler sHandler = new Handler() {
164
165 @Override
166 public void handleMessage(Message msg) {
167 switch (msg.what) {
168 case MSG_REPORT_DRAW:
169 final boolean hasDrawn;
170 final TaskSnapshotSurface surface = (TaskSnapshotSurface) msg.obj;
171 synchronized (surface.mService.mWindowMap) {
172 hasDrawn = surface.mHasDrawn;
173 if (!hasDrawn) {
174 surface.mReportNextDraw = true;
175 }
176 }
177 if (hasDrawn) {
178 surface.reportDrawn();
179 }
180 break;
181 }
182 }
183 };
184
185 private static class Window extends BaseIWindow {
186
187 private TaskSnapshotSurface mOuter;
188
189 public void setOuter(TaskSnapshotSurface outer) {
190 mOuter = outer;
191 }
192
193 @Override
194 public void resized(Rect frame, Rect overscanInsets, Rect contentInsets, Rect visibleInsets,
195 Rect stableInsets, Rect outsets, boolean reportDraw, Configuration newConfig,
196 Rect backDropFrame, boolean forceLayout, boolean alwaysConsumeNavBar) {
197 if (reportDraw) {
198 sHandler.obtainMessage(MSG_REPORT_DRAW, mOuter).sendToTarget();
199 }
200 }
201 }
202}