blob: 2bfe015c2787b827be0414b48e5a5b225774e54f [file] [log] [blame]
Mady Mellordea7ecf2018-12-10 15:47:40 -08001/*
2 * Copyright (C) 2018 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.bubbles;
18
Yuncheol Heo5d62e752020-04-08 14:54:24 -070019import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
Mady Mellorc41ed322019-09-25 11:19:26 -070020import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
21import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
Yunfan Chenb83940c2020-04-06 16:43:09 +090022import static android.graphics.PixelFormat.TRANSPARENT;
Mady Mellor390bff42019-04-05 15:09:01 -070023import static android.view.Display.INVALID_DISPLAY;
Yunfan Chenb83940c2020-04-06 16:43:09 +090024import static android.view.InsetsState.ITYPE_IME;
Joshua Tsuji06785ab2020-06-08 11:18:40 -040025import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
Jorim Jaggi924ef752020-01-29 17:26:55 +010026import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
27import static android.view.ViewRootImpl.sNewInsetsMode;
Yunfan Chenb83940c2020-04-06 16:43:09 +090028import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
29import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
30import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
31import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
Beverlya53fb0d2020-01-29 15:26:13 -050032
Mark Renoufdb861c92019-07-26 13:58:17 -040033import static com.android.systemui.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_EXPANDED_VIEW;
Issei Suzukia8d07312019-06-07 12:56:19 +020034import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES;
35import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
Mady Mellorca0c24c2019-05-16 16:14:32 -070036
Joshua Tsuji847b1d422020-06-01 13:42:19 -040037import android.annotation.SuppressLint;
Tony Huang86724102020-06-11 17:51:55 +080038import android.app.ActivityManager;
Mady Mellor60101c92019-04-11 19:04:00 -070039import android.app.ActivityOptions;
Mark Renouf5c732b32019-06-12 15:14:54 -040040import android.app.ActivityTaskManager;
Mady Mellor3dff9e62019-02-05 18:12:53 -080041import android.app.ActivityView;
Mady Mellor9801e852019-01-22 14:50:28 -080042import android.app.PendingIntent;
Mark Renouf5c732b32019-06-12 15:14:54 -040043import android.content.ComponentName;
Mady Mellordea7ecf2018-12-10 15:47:40 -080044import android.content.Context;
Mady Mellor9801e852019-01-22 14:50:28 -080045import android.content.Intent;
Lyn Han26bb1982020-06-08 15:38:01 -070046import android.content.res.Configuration;
Mady Mellordea7ecf2018-12-10 15:47:40 -080047import android.content.res.Resources;
Mady Mellordd497052019-01-30 17:23:48 -080048import android.content.res.TypedArray;
Mady Mellordea7ecf2018-12-10 15:47:40 -080049import android.graphics.Color;
Mady Mellor3dff9e62019-02-05 18:12:53 -080050import android.graphics.Insets;
Joshua Tsuji06785ab2020-06-08 11:18:40 -040051import android.graphics.Outline;
Mady Mellor3dff9e62019-02-05 18:12:53 -080052import android.graphics.Point;
Mady Mellor47b11e32019-07-11 19:06:21 -070053import android.graphics.Rect;
Mady Mellordea7ecf2018-12-10 15:47:40 -080054import android.graphics.drawable.ShapeDrawable;
Yunfan Chenb83940c2020-04-06 16:43:09 +090055import android.hardware.display.VirtualDisplay;
56import android.os.Binder;
Mark Renouf5c732b32019-06-12 15:14:54 -040057import android.os.RemoteException;
Mady Mellordea7ecf2018-12-10 15:47:40 -080058import android.util.AttributeSet;
Mady Mellor9801e852019-01-22 14:50:28 -080059import android.util.Log;
Yunfan Chenb83940c2020-04-06 16:43:09 +090060import android.view.Gravity;
Joshua Tsuji06785ab2020-06-08 11:18:40 -040061import android.view.SurfaceControl;
62import android.view.SurfaceView;
Mady Mellordea7ecf2018-12-10 15:47:40 -080063import android.view.View;
Joshua Tsuji06785ab2020-06-08 11:18:40 -040064import android.view.ViewGroup;
65import android.view.ViewOutlineProvider;
Mady Mellor3dff9e62019-02-05 18:12:53 -080066import android.view.WindowInsets;
Mady Mellora96c9ed2019-06-07 12:55:26 -070067import android.view.WindowManager;
Lyn Han670fa802020-05-05 12:56:33 -070068import android.view.accessibility.AccessibilityNodeInfo;
Joshua Tsuji06785ab2020-06-08 11:18:40 -040069import android.widget.FrameLayout;
Mady Mellordea7ecf2018-12-10 15:47:40 -080070import android.widget.LinearLayout;
71
Joshua Tsuji06785ab2020-06-08 11:18:40 -040072import androidx.annotation.Nullable;
73
Mark Renouf34d04f32019-05-13 15:53:18 -040074import com.android.internal.policy.ScreenDecorationsUtils;
Mady Mellor3dff9e62019-02-05 18:12:53 -080075import com.android.systemui.Dependency;
Mady Mellordea7ecf2018-12-10 15:47:40 -080076import com.android.systemui.R;
77import com.android.systemui.recents.TriangleShape;
Lyn Han754e77b2019-04-30 14:34:49 -070078import com.android.systemui.statusbar.AlphaOptimizedButton;
Mady Mellordea7ecf2018-12-10 15:47:40 -080079
80/**
Lyn Han02cca812019-04-02 16:27:32 -070081 * Container for the expanded bubble view, handles rendering the caret and settings icon.
Mady Mellordea7ecf2018-12-10 15:47:40 -080082 */
Joshua Tsuji6855cab2020-04-16 01:05:39 -040083public class BubbleExpandedView extends LinearLayout {
Issei Suzukia8d07312019-06-07 12:56:19 +020084 private static final String TAG = TAG_WITH_CLASS_NAME ? "BubbleExpandedView" : TAG_BUBBLES;
Yunfan Chenb83940c2020-04-06 16:43:09 +090085 private static final String WINDOW_TITLE = "ImeInsetsWindowWithoutContent";
Mady Mellordea7ecf2018-12-10 15:47:40 -080086
Issei Suzuki734bc942019-06-05 13:59:52 +020087 private enum ActivityViewStatus {
88 // ActivityView is being initialized, cannot start an activity yet.
89 INITIALIZING,
90 // ActivityView is initialized, and ready to start an activity.
91 INITIALIZED,
92 // Activity runs in the ActivityView.
93 ACTIVITY_STARTED,
94 // ActivityView is released, so activity launching will no longer be permitted.
95 RELEASED,
96 }
Mady Mellordea7ecf2018-12-10 15:47:40 -080097
98 // The triangle pointing to the expanded view
99 private View mPointerView;
Mady Mellor44ee2fe2019-01-30 17:51:16 -0800100 private int mPointerMargin;
Joshua Tsuji06785ab2020-06-08 11:18:40 -0400101 @Nullable private int[] mExpandedViewContainerLocation;
Mady Mellore8e07712019-01-23 12:45:33 -0800102
Lyn Han754e77b2019-04-30 14:34:49 -0700103 private AlphaOptimizedButton mSettingsIcon;
Mady Mellore8e07712019-01-23 12:45:33 -0800104
Mady Mellor3dff9e62019-02-05 18:12:53 -0800105 // Views for expanded state
Mady Mellor3dff9e62019-02-05 18:12:53 -0800106 private ActivityView mActivityView;
107
Issei Suzuki734bc942019-06-05 13:59:52 +0200108 private ActivityViewStatus mActivityViewStatus = ActivityViewStatus.INITIALIZING;
Mark Renouf5c732b32019-06-12 15:14:54 -0400109 private int mTaskId = -1;
110
Lyn Hanb58c7562020-01-07 14:29:20 -0800111 private PendingIntent mPendingIntent;
Mady Mellor3dff9e62019-02-05 18:12:53 -0800112
Mady Mellor5d8f1402019-02-21 18:23:52 -0800113 private boolean mKeyboardVisible;
114 private boolean mNeedsNewHeight;
115
Mady Mellora96c9ed2019-06-07 12:55:26 -0700116 private Point mDisplaySize;
Mady Mellorfe7ec032019-01-30 17:32:49 -0800117 private int mMinHeight;
Lyn Hancd4f87e2020-02-19 20:33:45 -0800118 private int mOverflowHeight;
Lyn Han02cca812019-04-02 16:27:32 -0700119 private int mSettingsIconHeight;
Lyn Han02cca812019-04-02 16:27:32 -0700120 private int mPointerWidth;
121 private int mPointerHeight;
Mark Renouf34d04f32019-05-13 15:53:18 -0400122 private ShapeDrawable mPointerDrawable;
Lyn Han39892602020-06-18 21:15:28 -0700123 private int mExpandedViewPadding;
124
Mady Mellordea7ecf2018-12-10 15:47:40 -0800125
Lyn Hanb58c7562020-01-07 14:29:20 -0800126 @Nullable private Bubble mBubble;
127
128 private boolean mIsOverflow;
Mady Mellore8e07712019-01-23 12:45:33 -0800129
Mady Mellor3dff9e62019-02-05 18:12:53 -0800130 private BubbleController mBubbleController = Dependency.get(BubbleController.class);
Mady Mellor9be3bed2019-08-21 17:26:26 -0700131 private WindowManager mWindowManager;
Tony Huang86724102020-06-11 17:51:55 +0800132 private ActivityManager mActivityManager;
Mady Mellor9801e852019-01-22 14:50:28 -0800133
Mady Mellor9801e852019-01-22 14:50:28 -0800134 private BubbleStackView mStackView;
Yunfan Chenb83940c2020-04-06 16:43:09 +0900135 private View mVirtualImeView;
136 private WindowManager mVirtualDisplayWindowManager;
137 private boolean mImeShowing = false;
Joshua Tsuji06785ab2020-06-08 11:18:40 -0400138 private float mCornerRadius = 0f;
139
140 /**
141 * Container for the ActivityView that has a solid, round-rect background that shows if the
142 * ActivityView hasn't loaded.
143 */
144 private FrameLayout mActivityViewContainer = new FrameLayout(getContext());
145
146 /** The SurfaceView that the ActivityView draws to. */
147 @Nullable private SurfaceView mActivitySurface;
Mady Mellor9801e852019-01-22 14:50:28 -0800148
Mady Mellor3dff9e62019-02-05 18:12:53 -0800149 private ActivityView.StateCallback mStateCallback = new ActivityView.StateCallback() {
150 @Override
151 public void onActivityViewReady(ActivityView view) {
Mark Renoufdb861c92019-07-26 13:58:17 -0400152 if (DEBUG_BUBBLE_EXPANDED_VIEW) {
153 Log.d(TAG, "onActivityViewReady: mActivityViewStatus=" + mActivityViewStatus
154 + " bubble=" + getBubbleKey());
155 }
Issei Suzuki734bc942019-06-05 13:59:52 +0200156 switch (mActivityViewStatus) {
157 case INITIALIZING:
158 case INITIALIZED:
159 // Custom options so there is no activity transition animation
160 ActivityOptions options = ActivityOptions.makeCustomAnimation(getContext(),
161 0 /* enterResId */, 0 /* exitResId */);
Winson Chung06200522020-03-31 22:47:02 -0700162 options.setTaskAlwaysOnTop(true);
Yuncheol Heo5d62e752020-04-08 14:54:24 -0700163 options.setLaunchWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
Issei Suzuki734bc942019-06-05 13:59:52 +0200164 // Post to keep the lifecycle normal
Mark Renoufdb861c92019-07-26 13:58:17 -0400165 post(() -> {
166 if (DEBUG_BUBBLE_EXPANDED_VIEW) {
167 Log.d(TAG, "onActivityViewReady: calling startActivity, "
168 + "bubble=" + getBubbleKey());
169 }
Mady Mellorc1a75a92020-06-11 22:24:24 -0700170 if (mActivityView == null) {
171 mBubbleController.removeBubble(getBubbleKey(),
172 BubbleController.DISMISS_INVALID_INTENT);
173 return;
174 }
Mady Mellor8454ddf2019-08-15 11:16:23 -0700175 try {
Lyn Hanefbaa972020-06-23 14:59:39 -0700176 if (!mIsOverflow && mBubble.hasMetadataShortcutId()
177 && mBubble.getShortcutInfo() != null) {
Mady Mellor80d5ed12020-04-10 21:17:30 -0700178 options.setApplyActivityFlagsForBubbles(true);
Mady Mellorb547e5e2019-12-02 10:15:56 -0800179 mActivityView.startShortcutActivity(mBubble.getShortcutInfo(),
180 options, null /* sourceBounds */);
181 } else {
182 Intent fillInIntent = new Intent();
183 // Apply flags to make behaviour match documentLaunchMode=always.
184 fillInIntent.addFlags(FLAG_ACTIVITY_NEW_DOCUMENT);
185 fillInIntent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK);
Lyn Hanb58c7562020-01-07 14:29:20 -0800186 mActivityView.startActivity(mPendingIntent, fillInIntent, options);
Mady Mellorb547e5e2019-12-02 10:15:56 -0800187 }
Mady Mellor8454ddf2019-08-15 11:16:23 -0700188 } catch (RuntimeException e) {
189 // If there's a runtime exception here then there's something
190 // wrong with the intent, we can't really recover / try to populate
191 // the bubble again so we'll just remove it.
192 Log.w(TAG, "Exception while displaying bubble: " + getBubbleKey()
193 + ", " + e.getMessage() + "; removing bubble");
Pinyao Ting3c930612020-05-19 00:26:03 +0000194 mBubbleController.removeBubble(getBubbleKey(),
Mady Mellor8454ddf2019-08-15 11:16:23 -0700195 BubbleController.DISMISS_INVALID_INTENT);
196 }
Mark Renoufdb861c92019-07-26 13:58:17 -0400197 });
Issei Suzuki734bc942019-06-05 13:59:52 +0200198 mActivityViewStatus = ActivityViewStatus.ACTIVITY_STARTED;
Tony Huang86724102020-06-11 17:51:55 +0800199 break;
200 case ACTIVITY_STARTED:
201 post(() -> mActivityManager.moveTaskToFront(mTaskId, 0));
202 break;
Mady Mellor6d002032019-02-13 13:45:17 -0800203 }
Mady Mellor3dff9e62019-02-05 18:12:53 -0800204 }
205
206 @Override
207 public void onActivityViewDestroyed(ActivityView view) {
Mark Renoufdb861c92019-07-26 13:58:17 -0400208 if (DEBUG_BUBBLE_EXPANDED_VIEW) {
209 Log.d(TAG, "onActivityViewDestroyed: mActivityViewStatus=" + mActivityViewStatus
210 + " bubble=" + getBubbleKey());
211 }
Issei Suzuki734bc942019-06-05 13:59:52 +0200212 mActivityViewStatus = ActivityViewStatus.RELEASED;
Mady Mellor3dff9e62019-02-05 18:12:53 -0800213 }
214
Mark Renouf5c732b32019-06-12 15:14:54 -0400215 @Override
216 public void onTaskCreated(int taskId, ComponentName componentName) {
Mark Renoufdb861c92019-07-26 13:58:17 -0400217 if (DEBUG_BUBBLE_EXPANDED_VIEW) {
218 Log.d(TAG, "onTaskCreated: taskId=" + taskId
219 + " bubble=" + getBubbleKey());
220 }
Mark Renouf5c732b32019-06-12 15:14:54 -0400221 // Since Bubble ActivityView applies singleTaskDisplay this is
222 // guaranteed to only be called once per ActivityView. The taskId is
223 // saved to use for removeTask, preventing appearance in recent tasks.
224 mTaskId = taskId;
Mady Mellor3dff9e62019-02-05 18:12:53 -0800225 }
226
227 /**
228 * This is only called for tasks on this ActivityView, which is also set to
229 * single-task mode -- meaning never more than one task on this display. If a task
230 * is being removed, it's the top Activity finishing and this bubble should
231 * be removed or collapsed.
232 */
233 @Override
234 public void onTaskRemovalStarted(int taskId) {
Mark Renoufdb861c92019-07-26 13:58:17 -0400235 if (DEBUG_BUBBLE_EXPANDED_VIEW) {
236 Log.d(TAG, "onTaskRemovalStarted: taskId=" + taskId
237 + " mActivityViewStatus=" + mActivityViewStatus
238 + " bubble=" + getBubbleKey());
239 }
Mady Mellordd6fe612020-04-15 11:47:55 -0700240 if (mBubble != null) {
Mady Mellorff076eb2019-11-13 10:12:06 -0800241 // Must post because this is called from a binder thread.
Pinyao Ting3c930612020-05-19 00:26:03 +0000242 post(() -> mBubbleController.removeBubble(mBubble.getKey(),
Mady Mellorff076eb2019-11-13 10:12:06 -0800243 BubbleController.DISMISS_TASK_FINISHED));
Mady Mellor3dff9e62019-02-05 18:12:53 -0800244 }
245 }
246 };
Mady Mellore8e07712019-01-23 12:45:33 -0800247
Mady Mellor3d82e682019-02-05 13:34:48 -0800248 public BubbleExpandedView(Context context) {
Mady Mellordea7ecf2018-12-10 15:47:40 -0800249 this(context, null);
250 }
251
Mady Mellor3d82e682019-02-05 13:34:48 -0800252 public BubbleExpandedView(Context context, AttributeSet attrs) {
Mady Mellordea7ecf2018-12-10 15:47:40 -0800253 this(context, attrs, 0);
254 }
255
Mady Mellor3d82e682019-02-05 13:34:48 -0800256 public BubbleExpandedView(Context context, AttributeSet attrs, int defStyleAttr) {
Mady Mellordea7ecf2018-12-10 15:47:40 -0800257 this(context, attrs, defStyleAttr, 0);
258 }
259
Mady Mellor3d82e682019-02-05 13:34:48 -0800260 public BubbleExpandedView(Context context, AttributeSet attrs, int defStyleAttr,
Mady Mellordea7ecf2018-12-10 15:47:40 -0800261 int defStyleRes) {
262 super(context, attrs, defStyleAttr, defStyleRes);
Lyn Hanbc985c52020-05-18 17:57:58 -0700263 updateDimensions();
Tony Huang86724102020-06-11 17:51:55 +0800264 mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
Lyn Hanbc985c52020-05-18 17:57:58 -0700265 }
266
267 void updateDimensions() {
Mady Mellora96c9ed2019-06-07 12:55:26 -0700268 mDisplaySize = new Point();
Lyn Hanbc985c52020-05-18 17:57:58 -0700269 mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
Mady Mellor8fe411d2019-08-16 11:27:53 -0700270 // Get the real size -- this includes screen decorations (notches, statusbar, navbar).
Mady Mellor9be3bed2019-08-21 17:26:26 -0700271 mWindowManager.getDefaultDisplay().getRealSize(mDisplaySize);
Mady Mellor47b11e32019-07-11 19:06:21 -0700272 Resources res = getResources();
273 mMinHeight = res.getDimensionPixelSize(R.dimen.bubble_expanded_default_height);
Lyn Hancd4f87e2020-02-19 20:33:45 -0800274 mOverflowHeight = res.getDimensionPixelSize(R.dimen.bubble_overflow_height);
Mady Mellor47b11e32019-07-11 19:06:21 -0700275 mPointerMargin = res.getDimensionPixelSize(R.dimen.bubble_pointer_margin);
Mady Mellordea7ecf2018-12-10 15:47:40 -0800276 }
277
Joshua Tsuji847b1d422020-06-01 13:42:19 -0400278 @SuppressLint("ClickableViewAccessibility")
Mady Mellordea7ecf2018-12-10 15:47:40 -0800279 @Override
280 protected void onFinishInflate() {
281 super.onFinishInflate();
Mark Renoufdb861c92019-07-26 13:58:17 -0400282 if (DEBUG_BUBBLE_EXPANDED_VIEW) {
283 Log.d(TAG, "onFinishInflate: bubble=" + getBubbleKey());
284 }
Mady Mellordea7ecf2018-12-10 15:47:40 -0800285
286 Resources res = getResources();
287 mPointerView = findViewById(R.id.pointer_view);
Lyn Han02cca812019-04-02 16:27:32 -0700288 mPointerWidth = res.getDimensionPixelSize(R.dimen.bubble_pointer_width);
289 mPointerHeight = res.getDimensionPixelSize(R.dimen.bubble_pointer_height);
Mady Mellordd497052019-01-30 17:23:48 -0800290
Mark Renouf34d04f32019-05-13 15:53:18 -0400291 mPointerDrawable = new ShapeDrawable(TriangleShape.create(
Lyn Han5aa27e22019-05-15 10:55:07 -0700292 mPointerWidth, mPointerHeight, true /* pointUp */));
Mady Mellora96c9ed2019-06-07 12:55:26 -0700293 mPointerView.setVisibility(INVISIBLE);
Mady Mellor9801e852019-01-22 14:50:28 -0800294
Lyn Han02cca812019-04-02 16:27:32 -0700295 mSettingsIconHeight = getContext().getResources().getDimensionPixelSize(
Mady Mellor5a3e94b2020-02-07 12:16:21 -0800296 R.dimen.bubble_manage_button_height);
Lyn Han02cca812019-04-02 16:27:32 -0700297 mSettingsIcon = findViewById(R.id.settings_button);
Lyn Han02cca812019-04-02 16:27:32 -0700298
Mady Mellor3dff9e62019-02-05 18:12:53 -0800299 mActivityView = new ActivityView(mContext, null /* attrs */, 0 /* defStyle */,
shawnlinba532af2020-06-02 17:48:37 +0800300 true /* singleTaskInstance */, false /* usePublicVirtualDisplay*/,
301 true /* disableSurfaceViewBackgroundLayer */);
Lyn Hanb58c7562020-01-07 14:29:20 -0800302
lumarkdc9b3192019-07-23 21:18:17 +0800303 // Set ActivityView's alpha value as zero, since there is no view content to be shown.
Issei Suzukicac2a502019-04-16 16:52:50 +0200304 setContentVisibility(false);
Joshua Tsuji06785ab2020-06-08 11:18:40 -0400305
306 mActivityViewContainer.setBackgroundColor(Color.WHITE);
307 mActivityViewContainer.setOutlineProvider(new ViewOutlineProvider() {
308 @Override
309 public void getOutline(View view, Outline outline) {
310 outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), mCornerRadius);
311 }
312 });
313 mActivityViewContainer.setClipToOutline(true);
314 mActivityViewContainer.addView(mActivityView);
315 mActivityViewContainer.setLayoutParams(
316 new ViewGroup.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
317 addView(mActivityViewContainer);
318
319 if (mActivityView != null
320 && mActivityView.getChildCount() > 0
321 && mActivityView.getChildAt(0) instanceof SurfaceView) {
322 // Retrieve the surface from the ActivityView so we can screenshot it and change its
323 // z-ordering. This should always be possible, since ActivityView's constructor adds the
324 // SurfaceView as its first child.
325 mActivitySurface = (SurfaceView) mActivityView.getChildAt(0);
326 }
Mady Mellor3dff9e62019-02-05 18:12:53 -0800327
Lyn Han5aa27e22019-05-15 10:55:07 -0700328 // Expanded stack layout, top to bottom:
329 // Expanded view container
330 // ==> bubble row
331 // ==> expanded view
332 // ==> activity view
333 // ==> manage button
334 bringChildToFront(mActivityView);
335 bringChildToFront(mSettingsIcon);
Mady Mellor52b1ac62019-04-10 16:59:03 -0700336
Mark Renouf34d04f32019-05-13 15:53:18 -0400337 applyThemeAttrs();
338
Mady Mellor5d8f1402019-02-21 18:23:52 -0800339 setOnApplyWindowInsetsListener((View view, WindowInsets insets) -> {
340 // Keep track of IME displaying because we should not make any adjustments that might
341 // cause a config change while the IME is displayed otherwise it'll loose focus.
Mady Mellor3dff9e62019-02-05 18:12:53 -0800342 final int keyboardHeight = insets.getSystemWindowInsetBottom()
343 - insets.getStableInsetBottom();
Mady Mellor5d8f1402019-02-21 18:23:52 -0800344 mKeyboardVisible = keyboardHeight != 0;
345 if (!mKeyboardVisible && mNeedsNewHeight) {
346 updateHeight();
347 }
Mady Mellor3dff9e62019-02-05 18:12:53 -0800348 return view.onApplyWindowInsets(insets);
349 });
Joshua Tsuji847b1d422020-06-01 13:42:19 -0400350
Lyn Han39892602020-06-18 21:15:28 -0700351 mExpandedViewPadding = res.getDimensionPixelSize(R.dimen.bubble_expanded_view_padding);
352 setPadding(mExpandedViewPadding, mExpandedViewPadding, mExpandedViewPadding,
353 mExpandedViewPadding);
Joshua Tsuji847b1d422020-06-01 13:42:19 -0400354 setOnTouchListener((view, motionEvent) -> {
355 if (!usingActivityView()) {
356 return false;
357 }
358
359 final Rect avBounds = new Rect();
360 mActivityView.getBoundsOnScreen(avBounds);
361
362 // Consume and ignore events on the expanded view padding that are within the
363 // ActivityView's vertical bounds. These events are part of a back gesture, and so they
364 // should not collapse the stack (which all other touches on areas around the AV would
365 // do).
Josh Tsuji5421eb62020-06-10 18:24:56 -0400366 if (motionEvent.getRawY() >= avBounds.top
367 && motionEvent.getRawY() <= avBounds.bottom
368 && (motionEvent.getRawX() < avBounds.left
369 || motionEvent.getRawX() > avBounds.right)) {
Joshua Tsuji847b1d422020-06-01 13:42:19 -0400370 return true;
371 }
372
373 return false;
374 });
Joshua Tsuji519d4c12020-05-29 15:22:31 -0400375
376 // BubbleStackView is forced LTR, but we want to respect the locale for expanded view layout
377 // so the Manage button appears on the right.
378 setLayoutDirection(LAYOUT_DIRECTION_LOCALE);
Mady Mellore8e07712019-01-23 12:45:33 -0800379 }
380
Mark Renoufdb861c92019-07-26 13:58:17 -0400381 private String getBubbleKey() {
382 return mBubble != null ? mBubble.getKey() : "null";
383 }
384
Joshua Tsuji06785ab2020-06-08 11:18:40 -0400385 /**
386 * Asks the ActivityView's surface to draw on top of all other views in the window. This is
387 * useful for ordering surfaces during animations, but should otherwise be set to false so that
388 * bubbles and menus can draw over the ActivityView.
389 */
390 void setSurfaceZOrderedOnTop(boolean onTop) {
391 if (mActivitySurface == null) {
392 return;
393 }
394
395 mActivitySurface.setZOrderedOnTop(onTop, true);
396 }
397
398 /** Return a GraphicBuffer with the contents of the ActivityView's underlying surface. */
399 @Nullable SurfaceControl.ScreenshotGraphicBuffer snapshotActivitySurface() {
400 if (mActivitySurface == null) {
401 return null;
402 }
403
404 return SurfaceControl.captureLayers(
405 mActivitySurface.getSurfaceControl(),
406 new Rect(0, 0, mActivityView.getWidth(), mActivityView.getHeight()),
407 1 /* scale */);
408 }
409
410 int[] getActivityViewLocationOnScreen() {
411 if (mActivityView != null) {
412 return mActivityView.getLocationOnScreen();
413 } else {
414 return new int[]{0, 0};
415 }
416 }
417
Joshua Tsuji6855cab2020-04-16 01:05:39 -0400418 void setManageClickListener(OnClickListener manageClickListener) {
419 findViewById(R.id.settings_button).setOnClickListener(manageClickListener);
420 }
421
422 /**
423 * Updates the ActivityView's obscured touchable region. This calls onLocationChanged, which
424 * results in a call to {@link BubbleStackView#subtractObscuredTouchableRegion}. This is useful
425 * if a view has been added or removed from on top of the ActivityView, such as the manage menu.
426 */
427 void updateObscuredTouchableRegion() {
Mady Mellor64db51a2020-05-27 19:00:14 -0700428 if (mActivityView != null) {
429 mActivityView.onLocationChanged();
430 }
Joshua Tsuji6855cab2020-04-16 01:05:39 -0400431 }
432
Mark Renouf34d04f32019-05-13 15:53:18 -0400433 void applyThemeAttrs() {
Lyn Han61bfdb32019-12-10 14:34:12 -0800434 final TypedArray ta = mContext.obtainStyledAttributes(
Joshua Tsujidd082b62020-05-20 22:26:24 -0400435 new int[] {android.R.attr.dialogCornerRadius});
Joshua Tsuji06785ab2020-06-08 11:18:40 -0400436 mCornerRadius = ta.getDimensionPixelSize(0, 0);
Mark Renouf34d04f32019-05-13 15:53:18 -0400437 ta.recycle();
438
Lyn Hanedb55e22020-02-12 18:55:39 -0800439 if (mActivityView != null && ScreenDecorationsUtils.supportsRoundedCornersOnWindows(
440 mContext.getResources())) {
Joshua Tsuji06785ab2020-06-08 11:18:40 -0400441 mActivityView.setCornerRadius(mCornerRadius);
Mark Renouf34d04f32019-05-13 15:53:18 -0400442 }
Lyn Han26bb1982020-06-08 15:38:01 -0700443
444 final int mode =
445 getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
446 switch (mode) {
447 case Configuration.UI_MODE_NIGHT_NO:
Lyn Han79d10bf2020-06-11 14:36:06 -0700448 mPointerDrawable.setTint(getResources().getColor(R.color.bubbles_light));
Lyn Han26bb1982020-06-08 15:38:01 -0700449 break;
450 case Configuration.UI_MODE_NIGHT_YES:
Lyn Han79d10bf2020-06-11 14:36:06 -0700451 mPointerDrawable.setTint(getResources().getColor(R.color.bubbles_dark));
Lyn Han26bb1982020-06-08 15:38:01 -0700452 break;
453 }
454 mPointerView.setBackground(mPointerDrawable);
Mark Renouf34d04f32019-05-13 15:53:18 -0400455 }
456
Joshua Tsuji847b1d422020-06-01 13:42:19 -0400457 /**
458 * Hides the IME if it's showing. This is currently done by dispatching a back press to the AV.
459 */
460 void hideImeIfVisible() {
461 if (mKeyboardVisible) {
462 performBackPressIfNeeded();
463 }
464 }
465
Mady Mellor5d8f1402019-02-21 18:23:52 -0800466 @Override
467 protected void onDetachedFromWindow() {
468 super.onDetachedFromWindow();
469 mKeyboardVisible = false;
470 mNeedsNewHeight = false;
471 if (mActivityView != null) {
Mady Melloraf02fa42020-03-04 14:22:16 -0800472 if (sNewInsetsMode == NEW_INSETS_MODE_FULL) {
Yunfan Chenb83940c2020-04-06 16:43:09 +0900473 setImeWindowToDisplay(0, 0);
Mady Melloraf02fa42020-03-04 14:22:16 -0800474 } else {
475 mActivityView.setForwardedInsets(Insets.of(0, 0, 0, 0));
476 }
Mady Mellor5d8f1402019-02-21 18:23:52 -0800477 }
Mark Renoufdb861c92019-07-26 13:58:17 -0400478 if (DEBUG_BUBBLE_EXPANDED_VIEW) {
479 Log.d(TAG, "onDetachedFromWindow: bubble=" + getBubbleKey());
480 }
Mady Mellor5d8f1402019-02-21 18:23:52 -0800481 }
482
483 /**
Issei Suzukicac2a502019-04-16 16:52:50 +0200484 * Set visibility of contents in the expanded state.
485 *
486 * @param visibility {@code true} if the contents should be visible on the screen.
487 *
488 * Note that this contents visibility doesn't affect visibility at {@link android.view.View},
489 * and setting {@code false} actually means rendering the contents in transparent.
490 */
491 void setContentVisibility(boolean visibility) {
Mark Renoufdb861c92019-07-26 13:58:17 -0400492 if (DEBUG_BUBBLE_EXPANDED_VIEW) {
493 Log.d(TAG, "setContentVisibility: visibility=" + visibility
494 + " bubble=" + getBubbleKey());
495 }
Issei Suzukicac2a502019-04-16 16:52:50 +0200496 final float alpha = visibility ? 1f : 0f;
Joshua Tsujiffa76032020-06-19 17:11:10 -0400497
498 if (alpha == mActivityView.getAlpha()) {
499 return;
500 }
501
Issei Suzukicac2a502019-04-16 16:52:50 +0200502 mPointerView.setAlpha(alpha);
503 if (mActivityView != null) {
504 mActivityView.setAlpha(alpha);
Joshua Tsuji06785ab2020-06-08 11:18:40 -0400505 mActivityView.bringToFront();
Issei Suzukicac2a502019-04-16 16:52:50 +0200506 }
507 }
508
Josh Tsuji7da996a2020-06-25 11:45:26 -0400509 @Nullable ActivityView getActivityView() {
510 return mActivityView;
511 }
512
513 int getTaskId() {
514 return mTaskId;
515 }
516
Issei Suzukicac2a502019-04-16 16:52:50 +0200517 /**
Mady Mellor5d8f1402019-02-21 18:23:52 -0800518 * Called by {@link BubbleStackView} when the insets for the expanded state should be updated.
519 * This should be done post-move and post-animation.
520 */
521 void updateInsets(WindowInsets insets) {
522 if (usingActivityView()) {
Mady Mellor8fe411d2019-08-16 11:27:53 -0700523 int[] screenLoc = mActivityView.getLocationOnScreen();
524 final int activityViewBottom = screenLoc[1] + mActivityView.getHeight();
Mady Mellor9be3bed2019-08-21 17:26:26 -0700525 final int keyboardTop = mDisplaySize.y - Math.max(insets.getSystemWindowInsetBottom(),
526 insets.getDisplayCutout() != null
527 ? insets.getDisplayCutout().getSafeInsetBottom()
528 : 0);
Mady Mellor8fe411d2019-08-16 11:27:53 -0700529 final int insetsBottom = Math.max(activityViewBottom - keyboardTop, 0);
Jorim Jaggi924ef752020-01-29 17:26:55 +0100530
Jorim Jaggi924ef752020-01-29 17:26:55 +0100531 if (sNewInsetsMode == NEW_INSETS_MODE_FULL) {
Yunfan Chenb83940c2020-04-06 16:43:09 +0900532 setImeWindowToDisplay(getWidth(), insetsBottom);
Jorim Jaggi924ef752020-01-29 17:26:55 +0100533 } else {
534 mActivityView.setForwardedInsets(Insets.of(0, 0, 0, insetsBottom));
535 }
Mady Mellor5d8f1402019-02-21 18:23:52 -0800536 }
537 }
538
Yunfan Chenb83940c2020-04-06 16:43:09 +0900539 private void setImeWindowToDisplay(int w, int h) {
540 if (getVirtualDisplayId() == INVALID_DISPLAY) {
541 return;
542 }
543 if (h == 0 || w == 0) {
544 if (mImeShowing) {
545 mVirtualImeView.setVisibility(GONE);
546 mImeShowing = false;
547 }
548 return;
549 }
550 final Context virtualDisplayContext = mContext.createDisplayContext(
551 getVirtualDisplay().getDisplay());
552
553 if (mVirtualDisplayWindowManager == null) {
554 mVirtualDisplayWindowManager =
555 (WindowManager) virtualDisplayContext.getSystemService(Context.WINDOW_SERVICE);
556 }
557 if (mVirtualImeView == null) {
558 mVirtualImeView = new View(virtualDisplayContext);
559 mVirtualImeView.setVisibility(VISIBLE);
560 mVirtualDisplayWindowManager.addView(mVirtualImeView,
561 getVirtualImeViewAttrs(w, h));
562 } else {
563 mVirtualDisplayWindowManager.updateViewLayout(mVirtualImeView,
564 getVirtualImeViewAttrs(w, h));
565 mVirtualImeView.setVisibility(VISIBLE);
566 }
567
568 mImeShowing = true;
569 }
570
571 private WindowManager.LayoutParams getVirtualImeViewAttrs(int w, int h) {
572 // To use TYPE_NAVIGATION_BAR_PANEL instead of TYPE_IME_BAR to bypass the IME window type
573 // token check when adding the window.
574 final WindowManager.LayoutParams attrs =
575 new WindowManager.LayoutParams(w, h, TYPE_NAVIGATION_BAR_PANEL,
576 FLAG_LAYOUT_NO_LIMITS | FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCHABLE,
577 TRANSPARENT);
578 attrs.gravity = Gravity.BOTTOM;
579 attrs.setTitle(WINDOW_TITLE);
580 attrs.token = new Binder();
581 attrs.providesInsetsTypes = new int[]{ITYPE_IME};
582 attrs.alpha = 0.0f;
583 return attrs;
584 }
585
Mady Mellor247ca2c2019-12-02 16:18:59 -0800586 void setStackView(BubbleStackView stackView) {
Mady Mellor9801e852019-01-22 14:50:28 -0800587 mStackView = stackView;
Mady Mellor6d002032019-02-13 13:45:17 -0800588 }
589
Lyn Hanb58c7562020-01-07 14:29:20 -0800590 public void setOverflow(boolean overflow) {
591 mIsOverflow = overflow;
592
593 Intent target = new Intent(mContext, BubbleOverflowActivity.class);
594 mPendingIntent = PendingIntent.getActivity(mContext, /* requestCode */ 0,
595 target, PendingIntent.FLAG_UPDATE_CURRENT);
596 mSettingsIcon.setVisibility(GONE);
597 }
598
Mady Mellor6d002032019-02-13 13:45:17 -0800599 /**
Mady Mellor247ca2c2019-12-02 16:18:59 -0800600 * Sets the bubble used to populate this view.
Mady Mellor6d002032019-02-13 13:45:17 -0800601 */
Mady Mellor247ca2c2019-12-02 16:18:59 -0800602 void update(Bubble bubble) {
603 if (DEBUG_BUBBLE_EXPANDED_VIEW) {
604 Log.d(TAG, "update: bubble=" + (bubble != null ? bubble.getKey() : "null"));
605 }
Mady Mellor458a6262020-06-07 21:09:19 -0700606 boolean isNew = mBubble == null || didBackingContentChange(bubble);
Lyn Hanb58c7562020-01-07 14:29:20 -0800607 if (isNew || bubble != null && bubble.getKey().equals(mBubble.getKey())) {
Mady Mellor247ca2c2019-12-02 16:18:59 -0800608 mBubble = bubble;
609 mSettingsIcon.setContentDescription(getResources().getString(
610 R.string.bubbles_settings_button_description, bubble.getAppName()));
611
Lyn Han670fa802020-05-05 12:56:33 -0700612 mSettingsIcon.setAccessibilityDelegate(
613 new AccessibilityDelegate() {
614 @Override
615 public void onInitializeAccessibilityNodeInfo(View host,
616 AccessibilityNodeInfo info) {
617 super.onInitializeAccessibilityNodeInfo(host, info);
618 // On focus, have TalkBack say
619 // "Actions available. Use swipe up then right to view."
620 // in addition to the default "double tap to activate".
621 mStackView.setupLocalMenu(info);
622 }
623 });
624
Mady Mellor247ca2c2019-12-02 16:18:59 -0800625 if (isNew) {
Lyn Hanb58c7562020-01-07 14:29:20 -0800626 mPendingIntent = mBubble.getBubbleIntent();
Lyn Hanefbaa972020-06-23 14:59:39 -0700627 if (mPendingIntent != null || mBubble.hasMetadataShortcutId()) {
Mady Mellor247ca2c2019-12-02 16:18:59 -0800628 setContentVisibility(false);
629 mActivityView.setVisibility(VISIBLE);
630 }
631 }
632 applyThemeAttrs();
633 } else {
634 Log.w(TAG, "Trying to update entry with different key, new bubble: "
635 + bubble.getKey() + " old bubble: " + bubble.getKey());
636 }
637 }
638
Mady Mellor458a6262020-06-07 21:09:19 -0700639 private boolean didBackingContentChange(Bubble newBubble) {
640 boolean prevWasIntentBased = mBubble != null && mPendingIntent != null;
641 boolean newIsIntentBased = newBubble.getBubbleIntent() != null;
642 return prevWasIntentBased != newIsIntentBased;
643 }
644
Mady Mellor247ca2c2019-12-02 16:18:59 -0800645 /**
646 * Lets activity view know it should be shown / populated with activity content.
647 */
648 void populateExpandedView() {
Mark Renoufdb861c92019-07-26 13:58:17 -0400649 if (DEBUG_BUBBLE_EXPANDED_VIEW) {
650 Log.d(TAG, "populateExpandedView: "
651 + "bubble=" + getBubbleKey());
652 }
653
Mady Mellor5029fa62019-03-05 12:16:21 -0800654 if (usingActivityView()) {
655 mActivityView.setCallback(mStateCallback);
656 } else {
Issei Suzukia91f3962019-06-07 11:48:23 +0200657 Log.e(TAG, "Cannot populate expanded view.");
Mady Mellor5029fa62019-03-05 12:16:21 -0800658 }
Mady Mellor9801e852019-01-22 14:50:28 -0800659 }
660
Mark Renouf041d7262019-02-06 12:09:41 -0500661 boolean performBackPressIfNeeded() {
Mady Mellor323fb0b2019-03-25 12:15:22 -0700662 if (!usingActivityView()) {
Mark Renouf041d7262019-02-06 12:09:41 -0500663 return false;
664 }
665 mActivityView.performBackPress();
666 return true;
667 }
668
Mady Mellorfe7ec032019-01-30 17:32:49 -0800669 void updateHeight() {
Mark Renoufdb861c92019-07-26 13:58:17 -0400670 if (DEBUG_BUBBLE_EXPANDED_VIEW) {
671 Log.d(TAG, "updateHeight: bubble=" + getBubbleKey());
672 }
Joshua Tsuji06785ab2020-06-08 11:18:40 -0400673
674 if (mExpandedViewContainerLocation == null) {
675 return;
676 }
677
Mady Mellorfe7ec032019-01-30 17:32:49 -0800678 if (usingActivityView()) {
Lyn Hancd4f87e2020-02-19 20:33:45 -0800679 float desiredHeight = mOverflowHeight;
Lyn Hanb58c7562020-01-07 14:29:20 -0800680 if (!mIsOverflow) {
681 desiredHeight = Math.max(mBubble.getDesiredHeight(mContext), mMinHeight);
682 }
Mady Mellor8fe411d2019-08-16 11:27:53 -0700683 float height = Math.min(desiredHeight, getMaxExpandedHeight());
Lyn Han55f53a52020-06-12 01:19:05 -0700684 height = Math.max(height, mMinHeight);
Joshua Tsuji06785ab2020-06-08 11:18:40 -0400685 ViewGroup.LayoutParams lp = mActivityView.getLayoutParams();
Lyn Hancd4f87e2020-02-19 20:33:45 -0800686 mNeedsNewHeight = lp.height != height;
Mady Mellor5d8f1402019-02-21 18:23:52 -0800687 if (!mKeyboardVisible) {
688 // If the keyboard is visible... don't adjust the height because that will cause
689 // a configuration change and the keyboard will be lost.
Mady Mellor7af771a2019-03-07 15:04:54 -0800690 lp.height = (int) height;
Mady Mellor5d8f1402019-02-21 18:23:52 -0800691 mActivityView.setLayoutParams(lp);
692 mNeedsNewHeight = false;
693 }
Mark Renoufdb861c92019-07-26 13:58:17 -0400694 if (DEBUG_BUBBLE_EXPANDED_VIEW) {
Joshua Tsuji06785ab2020-06-08 11:18:40 -0400695 Log.d(TAG, "updateHeight: bubble=" + getBubbleKey()
696 + " height=" + height
Mark Renoufdb861c92019-07-26 13:58:17 -0400697 + " mNeedsNewHeight=" + mNeedsNewHeight);
698 }
Mady Mellorfe7ec032019-01-30 17:32:49 -0800699 }
700 }
701
Mady Mellora96c9ed2019-06-07 12:55:26 -0700702 private int getMaxExpandedHeight() {
Mady Mellor9be3bed2019-08-21 17:26:26 -0700703 mWindowManager.getDefaultDisplay().getRealSize(mDisplaySize);
Mady Mellor8fe411d2019-08-16 11:27:53 -0700704 int bottomInset = getRootWindowInsets() != null
705 ? getRootWindowInsets().getStableInsetBottom()
706 : 0;
Joshua Tsuji06785ab2020-06-08 11:18:40 -0400707
708 return mDisplaySize.y
709 - mExpandedViewContainerLocation[1]
710 - getPaddingTop()
711 - getPaddingBottom()
712 - mSettingsIconHeight
713 - mPointerHeight
Mady Mellor8fe411d2019-08-16 11:27:53 -0700714 - mPointerMargin - bottomInset;
Mady Mellora96c9ed2019-06-07 12:55:26 -0700715 }
716
Mady Mellor47b11e32019-07-11 19:06:21 -0700717 /**
Mady Mellor3dff9e62019-02-05 18:12:53 -0800718 * Update appearance of the expanded view being displayed.
Joshua Tsuji06785ab2020-06-08 11:18:40 -0400719 *
720 * @param containerLocationOnScreen The location on-screen of the container the expanded view is
721 * added to. This allows us to calculate max height without
722 * waiting for layout.
Mady Mellor3dff9e62019-02-05 18:12:53 -0800723 */
Joshua Tsuji06785ab2020-06-08 11:18:40 -0400724 public void updateView(int[] containerLocationOnScreen) {
Mark Renoufdb861c92019-07-26 13:58:17 -0400725 if (DEBUG_BUBBLE_EXPANDED_VIEW) {
726 Log.d(TAG, "updateView: bubble="
727 + getBubbleKey());
728 }
Joshua Tsuji06785ab2020-06-08 11:18:40 -0400729
730 mExpandedViewContainerLocation = containerLocationOnScreen;
731
Mady Mellor3dff9e62019-02-05 18:12:53 -0800732 if (usingActivityView()
733 && mActivityView.getVisibility() == VISIBLE
734 && mActivityView.isAttachedToWindow()) {
735 mActivityView.onLocationChanged();
Joshua Tsuji06785ab2020-06-08 11:18:40 -0400736 updateHeight();
Mady Mellor3dff9e62019-02-05 18:12:53 -0800737 }
738 }
739
740 /**
Mady Mellordea7ecf2018-12-10 15:47:40 -0800741 * Set the x position that the tip of the triangle should point to.
742 */
Mady Mellor3dff9e62019-02-05 18:12:53 -0800743 public void setPointerPosition(float x) {
Lyn Han9a2f5cf2019-05-23 11:01:41 -0700744 float halfPointerWidth = mPointerWidth / 2f;
Lyn Han39892602020-06-18 21:15:28 -0700745 float pointerLeft = x - halfPointerWidth - mExpandedViewPadding;
Lyn Han9a2f5cf2019-05-23 11:01:41 -0700746 mPointerView.setTranslationX(pointerLeft);
Lyn Hanf74ba672019-05-20 16:08:48 -0700747 mPointerView.setVisibility(VISIBLE);
Mady Mellordea7ecf2018-12-10 15:47:40 -0800748 }
749
750 /**
Mady Mellor5a3e94b2020-02-07 12:16:21 -0800751 * Position of the manage button displayed in the expanded view. Used for placing user
752 * education about the manage button.
753 */
Joshua Tsuji6855cab2020-04-16 01:05:39 -0400754 public void getManageButtonBoundsOnScreen(Rect rect) {
755 mSettingsIcon.getBoundsOnScreen(rect);
Mady Mellor5a3e94b2020-02-07 12:16:21 -0800756 }
757
758 /**
Mady Mellor3dff9e62019-02-05 18:12:53 -0800759 * Removes and releases an ActivityView if one was previously created for this bubble.
Mady Mellordea7ecf2018-12-10 15:47:40 -0800760 */
Mady Mellor94d94a72019-03-05 18:16:59 -0800761 public void cleanUpExpandedState() {
Mark Renoufdb861c92019-07-26 13:58:17 -0400762 if (DEBUG_BUBBLE_EXPANDED_VIEW) {
763 Log.d(TAG, "cleanUpExpandedState: mActivityViewStatus=" + mActivityViewStatus
764 + ", bubble=" + getBubbleKey());
765 }
Mady Mellor3dff9e62019-02-05 18:12:53 -0800766 if (mActivityView == null) {
Mark Renouf89b1a4a2018-12-04 14:59:45 -0500767 return;
768 }
shawnlin28062692020-06-15 13:55:51 +0800769 mActivityView.release();
Mark Renouf5c732b32019-06-12 15:14:54 -0400770 if (mTaskId != -1) {
771 try {
772 ActivityTaskManager.getService().removeTask(mTaskId);
773 } catch (RemoteException e) {
774 Log.w(TAG, "Failed to remove taskId " + mTaskId);
775 }
776 mTaskId = -1;
Mady Mellordea7ecf2018-12-10 15:47:40 -0800777 }
Mark Renouf28c250d2019-02-25 16:47:34 -0500778 removeView(mActivityView);
Mark Renouf5c732b32019-06-12 15:14:54 -0400779
Mady Mellor3dff9e62019-02-05 18:12:53 -0800780 mActivityView = null;
Issei Suzuki734bc942019-06-05 13:59:52 +0200781 }
782
783 /**
784 * Called when the last task is removed from a {@link android.hardware.display.VirtualDisplay}
785 * which {@link ActivityView} uses.
786 */
787 void notifyDisplayEmpty() {
Mark Renoufdb861c92019-07-26 13:58:17 -0400788 if (DEBUG_BUBBLE_EXPANDED_VIEW) {
789 Log.d(TAG, "notifyDisplayEmpty: bubble="
790 + getBubbleKey()
791 + " mActivityViewStatus=" + mActivityViewStatus);
792 }
Issei Suzuki734bc942019-06-05 13:59:52 +0200793 if (mActivityViewStatus == ActivityViewStatus.ACTIVITY_STARTED) {
794 mActivityViewStatus = ActivityViewStatus.INITIALIZED;
795 }
Mady Mellordea7ecf2018-12-10 15:47:40 -0800796 }
797
Mady Mellor3dff9e62019-02-05 18:12:53 -0800798 private boolean usingActivityView() {
Lyn Hanefbaa972020-06-23 14:59:39 -0700799 return (mPendingIntent != null || mBubble.hasMetadataShortcutId())
Mady Mellor2ac2d3a2020-01-08 17:18:54 -0800800 && mActivityView != null;
Mady Mellor3dff9e62019-02-05 18:12:53 -0800801 }
802
Mady Mellor390bff42019-04-05 15:09:01 -0700803 /**
804 * @return the display id of the virtual display.
805 */
806 public int getVirtualDisplayId() {
807 if (usingActivityView()) {
808 return mActivityView.getVirtualDisplayId();
809 }
810 return INVALID_DISPLAY;
811 }
Yunfan Chenb83940c2020-04-06 16:43:09 +0900812
813 private VirtualDisplay getVirtualDisplay() {
814 if (usingActivityView()) {
815 return mActivityView.getVirtualDisplay();
816 }
817 return null;
818 }
Mady Mellordea7ecf2018-12-10 15:47:40 -0800819}