blob: af68ddb099ced769d3f6d6c0d0141fbf8950f7ac [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
Mady Mellor390bff42019-04-05 15:09:01 -070019import static android.view.Display.INVALID_DISPLAY;
Mady Mellor3dff9e62019-02-05 18:12:53 -080020
Issei Suzukia8d07312019-06-07 12:56:19 +020021import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES;
22import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
Mady Mellorca0c24c2019-05-16 16:14:32 -070023
Mady Mellordea7ecf2018-12-10 15:47:40 -080024import android.annotation.Nullable;
Mady Mellor60101c92019-04-11 19:04:00 -070025import android.app.ActivityOptions;
Mark Renouf5c732b32019-06-12 15:14:54 -040026import android.app.ActivityTaskManager;
Mady Mellor3dff9e62019-02-05 18:12:53 -080027import android.app.ActivityView;
Mady Mellor9801e852019-01-22 14:50:28 -080028import android.app.Notification;
29import android.app.PendingIntent;
Mark Renouf5c732b32019-06-12 15:14:54 -040030import android.content.ComponentName;
Mady Mellordea7ecf2018-12-10 15:47:40 -080031import android.content.Context;
Mady Mellor9801e852019-01-22 14:50:28 -080032import android.content.Intent;
33import android.content.pm.ApplicationInfo;
34import android.content.pm.PackageManager;
Mady Mellordea7ecf2018-12-10 15:47:40 -080035import android.content.res.Resources;
Mady Mellordd497052019-01-30 17:23:48 -080036import android.content.res.TypedArray;
Mady Mellordea7ecf2018-12-10 15:47:40 -080037import android.graphics.Color;
Mady Mellor3dff9e62019-02-05 18:12:53 -080038import android.graphics.Insets;
39import android.graphics.Point;
Mady Mellore8e07712019-01-23 12:45:33 -080040import android.graphics.drawable.Drawable;
Mady Mellordea7ecf2018-12-10 15:47:40 -080041import android.graphics.drawable.ShapeDrawable;
Mark Renouf5c732b32019-06-12 15:14:54 -040042import android.os.RemoteException;
Mady Mellor7af771a2019-03-07 15:04:54 -080043import android.os.UserHandle;
Mady Mellor9801e852019-01-22 14:50:28 -080044import android.provider.Settings;
Steven Wub00225b2019-02-08 14:27:42 -050045import android.service.notification.StatusBarNotification;
Mady Mellordea7ecf2018-12-10 15:47:40 -080046import android.util.AttributeSet;
Mady Mellor9801e852019-01-22 14:50:28 -080047import android.util.Log;
Steven Wub00225b2019-02-08 14:27:42 -050048import android.util.StatsLog;
Mady Mellordea7ecf2018-12-10 15:47:40 -080049import android.view.View;
Mady Mellor3dff9e62019-02-05 18:12:53 -080050import android.view.WindowInsets;
Mady Mellora96c9ed2019-06-07 12:55:26 -070051import android.view.WindowManager;
Mady Mellordea7ecf2018-12-10 15:47:40 -080052import android.widget.LinearLayout;
53
Mark Renouf34d04f32019-05-13 15:53:18 -040054import com.android.internal.policy.ScreenDecorationsUtils;
Mady Mellor3dff9e62019-02-05 18:12:53 -080055import com.android.systemui.Dependency;
Mady Mellordea7ecf2018-12-10 15:47:40 -080056import com.android.systemui.R;
57import com.android.systemui.recents.TriangleShape;
Lyn Han754e77b2019-04-30 14:34:49 -070058import com.android.systemui.statusbar.AlphaOptimizedButton;
Mady Mellor9801e852019-01-22 14:50:28 -080059import com.android.systemui.statusbar.notification.collection.NotificationEntry;
Mady Mellordea7ecf2018-12-10 15:47:40 -080060
61/**
Lyn Han02cca812019-04-02 16:27:32 -070062 * Container for the expanded bubble view, handles rendering the caret and settings icon.
Mady Mellordea7ecf2018-12-10 15:47:40 -080063 */
Mady Mellor3d82e682019-02-05 13:34:48 -080064public class BubbleExpandedView extends LinearLayout implements View.OnClickListener {
Issei Suzukia8d07312019-06-07 12:56:19 +020065 private static final String TAG = TAG_WITH_CLASS_NAME ? "BubbleExpandedView" : TAG_BUBBLES;
Mady Mellordea7ecf2018-12-10 15:47:40 -080066
Issei Suzuki734bc942019-06-05 13:59:52 +020067 private enum ActivityViewStatus {
68 // ActivityView is being initialized, cannot start an activity yet.
69 INITIALIZING,
70 // ActivityView is initialized, and ready to start an activity.
71 INITIALIZED,
72 // Activity runs in the ActivityView.
73 ACTIVITY_STARTED,
74 // ActivityView is released, so activity launching will no longer be permitted.
75 RELEASED,
76 }
77
Mady Mellordea7ecf2018-12-10 15:47:40 -080078 // The triangle pointing to the expanded view
79 private View mPointerView;
Mady Mellor44ee2fe2019-01-30 17:51:16 -080080 private int mPointerMargin;
Mady Mellore8e07712019-01-23 12:45:33 -080081
Lyn Han754e77b2019-04-30 14:34:49 -070082 private AlphaOptimizedButton mSettingsIcon;
Mady Mellore8e07712019-01-23 12:45:33 -080083
Mady Mellor3dff9e62019-02-05 18:12:53 -080084 // Views for expanded state
Mady Mellor3dff9e62019-02-05 18:12:53 -080085 private ActivityView mActivityView;
86
Issei Suzuki734bc942019-06-05 13:59:52 +020087 private ActivityViewStatus mActivityViewStatus = ActivityViewStatus.INITIALIZING;
Mark Renouf5c732b32019-06-12 15:14:54 -040088 private int mTaskId = -1;
89
Mady Mellor3dff9e62019-02-05 18:12:53 -080090 private PendingIntent mBubbleIntent;
91
Mady Mellor5d8f1402019-02-21 18:23:52 -080092 private boolean mKeyboardVisible;
93 private boolean mNeedsNewHeight;
94
Mady Mellora96c9ed2019-06-07 12:55:26 -070095 private Point mDisplaySize;
Mady Mellorfe7ec032019-01-30 17:32:49 -080096 private int mMinHeight;
Lyn Han02cca812019-04-02 16:27:32 -070097 private int mSettingsIconHeight;
Lyn Han02cca812019-04-02 16:27:32 -070098 private int mPointerWidth;
99 private int mPointerHeight;
Mark Renouf34d04f32019-05-13 15:53:18 -0400100 private ShapeDrawable mPointerDrawable;
Mady Mellordea7ecf2018-12-10 15:47:40 -0800101
Mady Mellor9801e852019-01-22 14:50:28 -0800102 private NotificationEntry mEntry;
103 private PackageManager mPm;
104 private String mAppName;
Mady Mellore8e07712019-01-23 12:45:33 -0800105 private Drawable mAppIcon;
106
Mady Mellor3dff9e62019-02-05 18:12:53 -0800107 private BubbleController mBubbleController = Dependency.get(BubbleController.class);
Mady Mellor9801e852019-01-22 14:50:28 -0800108
Mady Mellor9801e852019-01-22 14:50:28 -0800109 private BubbleStackView mStackView;
110
Mady Mellor3dff9e62019-02-05 18:12:53 -0800111 private ActivityView.StateCallback mStateCallback = new ActivityView.StateCallback() {
112 @Override
113 public void onActivityViewReady(ActivityView view) {
Issei Suzuki734bc942019-06-05 13:59:52 +0200114 switch (mActivityViewStatus) {
115 case INITIALIZING:
116 case INITIALIZED:
117 // Custom options so there is no activity transition animation
118 ActivityOptions options = ActivityOptions.makeCustomAnimation(getContext(),
119 0 /* enterResId */, 0 /* exitResId */);
120 // Post to keep the lifecycle normal
121 post(() -> mActivityView.startActivity(mBubbleIntent, options));
122 mActivityViewStatus = ActivityViewStatus.ACTIVITY_STARTED;
Mady Mellor6d002032019-02-13 13:45:17 -0800123 }
Mady Mellor3dff9e62019-02-05 18:12:53 -0800124 }
125
126 @Override
127 public void onActivityViewDestroyed(ActivityView view) {
Issei Suzuki734bc942019-06-05 13:59:52 +0200128 mActivityViewStatus = ActivityViewStatus.RELEASED;
Mady Mellor3dff9e62019-02-05 18:12:53 -0800129 }
130
Mark Renouf5c732b32019-06-12 15:14:54 -0400131 @Override
132 public void onTaskCreated(int taskId, ComponentName componentName) {
133 // Since Bubble ActivityView applies singleTaskDisplay this is
134 // guaranteed to only be called once per ActivityView. The taskId is
135 // saved to use for removeTask, preventing appearance in recent tasks.
136 mTaskId = taskId;
137 }
138
Mady Mellor3dff9e62019-02-05 18:12:53 -0800139 /**
140 * This is only called for tasks on this ActivityView, which is also set to
141 * single-task mode -- meaning never more than one task on this display. If a task
142 * is being removed, it's the top Activity finishing and this bubble should
143 * be removed or collapsed.
144 */
145 @Override
146 public void onTaskRemovalStarted(int taskId) {
147 if (mEntry != null) {
148 // Must post because this is called from a binder thread.
Mark Renouf08bc42a2019-03-07 13:01:59 -0500149 post(() -> mBubbleController.removeBubble(mEntry.key,
150 BubbleController.DISMISS_TASK_FINISHED));
Mady Mellor3dff9e62019-02-05 18:12:53 -0800151 }
152 }
153 };
Mady Mellore8e07712019-01-23 12:45:33 -0800154
Mady Mellor3d82e682019-02-05 13:34:48 -0800155 public BubbleExpandedView(Context context) {
Mady Mellordea7ecf2018-12-10 15:47:40 -0800156 this(context, null);
157 }
158
Mady Mellor3d82e682019-02-05 13:34:48 -0800159 public BubbleExpandedView(Context context, AttributeSet attrs) {
Mady Mellordea7ecf2018-12-10 15:47:40 -0800160 this(context, attrs, 0);
161 }
162
Mady Mellor3d82e682019-02-05 13:34:48 -0800163 public BubbleExpandedView(Context context, AttributeSet attrs, int defStyleAttr) {
Mady Mellordea7ecf2018-12-10 15:47:40 -0800164 this(context, attrs, defStyleAttr, 0);
165 }
166
Mady Mellor3d82e682019-02-05 13:34:48 -0800167 public BubbleExpandedView(Context context, AttributeSet attrs, int defStyleAttr,
Mady Mellordea7ecf2018-12-10 15:47:40 -0800168 int defStyleRes) {
169 super(context, attrs, defStyleAttr, defStyleRes);
Mady Mellor9801e852019-01-22 14:50:28 -0800170 mPm = context.getPackageManager();
Mady Mellora96c9ed2019-06-07 12:55:26 -0700171 mDisplaySize = new Point();
172 WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
173 wm.getDefaultDisplay().getSize(mDisplaySize);
Mady Mellorfe7ec032019-01-30 17:32:49 -0800174 mMinHeight = getResources().getDimensionPixelSize(
Mady Mellor3dff9e62019-02-05 18:12:53 -0800175 R.dimen.bubble_expanded_default_height);
Mady Mellor44ee2fe2019-01-30 17:51:16 -0800176 mPointerMargin = getResources().getDimensionPixelSize(R.dimen.bubble_pointer_margin);
Mady Mellordea7ecf2018-12-10 15:47:40 -0800177 }
178
179 @Override
180 protected void onFinishInflate() {
181 super.onFinishInflate();
182
183 Resources res = getResources();
184 mPointerView = findViewById(R.id.pointer_view);
Lyn Han02cca812019-04-02 16:27:32 -0700185 mPointerWidth = res.getDimensionPixelSize(R.dimen.bubble_pointer_width);
186 mPointerHeight = res.getDimensionPixelSize(R.dimen.bubble_pointer_height);
Mady Mellordd497052019-01-30 17:23:48 -0800187
Mady Mellordd497052019-01-30 17:23:48 -0800188
Mark Renouf34d04f32019-05-13 15:53:18 -0400189 mPointerDrawable = new ShapeDrawable(TriangleShape.create(
Lyn Han5aa27e22019-05-15 10:55:07 -0700190 mPointerWidth, mPointerHeight, true /* pointUp */));
Mark Renouf34d04f32019-05-13 15:53:18 -0400191 mPointerView.setBackground(mPointerDrawable);
Mady Mellora96c9ed2019-06-07 12:55:26 -0700192 mPointerView.setVisibility(INVISIBLE);
Mady Mellor9801e852019-01-22 14:50:28 -0800193
Lyn Han02cca812019-04-02 16:27:32 -0700194 mSettingsIconHeight = getContext().getResources().getDimensionPixelSize(
Mady Mellorfe7ec032019-01-30 17:32:49 -0800195 R.dimen.bubble_expanded_header_height);
Lyn Han02cca812019-04-02 16:27:32 -0700196 mSettingsIcon = findViewById(R.id.settings_button);
Lyn Han02cca812019-04-02 16:27:32 -0700197 mSettingsIcon.setOnClickListener(this);
Lyn Han02cca812019-04-02 16:27:32 -0700198
Mady Mellor3dff9e62019-02-05 18:12:53 -0800199 mActivityView = new ActivityView(mContext, null /* attrs */, 0 /* defStyle */,
200 true /* singleTaskInstance */);
Issei Suzukicac2a502019-04-16 16:52:50 +0200201
202 setContentVisibility(false);
Mady Mellor3dff9e62019-02-05 18:12:53 -0800203 addView(mActivityView);
204
Lyn Han5aa27e22019-05-15 10:55:07 -0700205 // Expanded stack layout, top to bottom:
206 // Expanded view container
207 // ==> bubble row
208 // ==> expanded view
209 // ==> activity view
210 // ==> manage button
211 bringChildToFront(mActivityView);
212 bringChildToFront(mSettingsIcon);
Mady Mellor52b1ac62019-04-10 16:59:03 -0700213
Mark Renouf34d04f32019-05-13 15:53:18 -0400214 applyThemeAttrs();
215
Mady Mellor5d8f1402019-02-21 18:23:52 -0800216 setOnApplyWindowInsetsListener((View view, WindowInsets insets) -> {
217 // Keep track of IME displaying because we should not make any adjustments that might
218 // cause a config change while the IME is displayed otherwise it'll loose focus.
Mady Mellor3dff9e62019-02-05 18:12:53 -0800219 final int keyboardHeight = insets.getSystemWindowInsetBottom()
220 - insets.getStableInsetBottom();
Mady Mellor5d8f1402019-02-21 18:23:52 -0800221 mKeyboardVisible = keyboardHeight != 0;
222 if (!mKeyboardVisible && mNeedsNewHeight) {
223 updateHeight();
224 }
Mady Mellor3dff9e62019-02-05 18:12:53 -0800225 return view.onApplyWindowInsets(insets);
226 });
Mady Mellore8e07712019-01-23 12:45:33 -0800227 }
228
Mark Renouf34d04f32019-05-13 15:53:18 -0400229 void applyThemeAttrs() {
230 TypedArray ta = getContext().obtainStyledAttributes(R.styleable.BubbleExpandedView);
231 int bgColor = ta.getColor(
232 R.styleable.BubbleExpandedView_android_colorBackgroundFloating, Color.WHITE);
233 float cornerRadius = ta.getDimension(
234 R.styleable.BubbleExpandedView_android_dialogCornerRadius, 0);
235 ta.recycle();
236
237 // Update triangle color.
238 mPointerDrawable.setTint(bgColor);
239
240 // Update ActivityView cornerRadius
241 if (ScreenDecorationsUtils.supportsRoundedCornersOnWindows(mContext.getResources())) {
242 mActivityView.setCornerRadius(cornerRadius);
243 }
244 }
245
Mady Mellor5d8f1402019-02-21 18:23:52 -0800246 @Override
247 protected void onDetachedFromWindow() {
248 super.onDetachedFromWindow();
249 mKeyboardVisible = false;
250 mNeedsNewHeight = false;
251 if (mActivityView != null) {
252 mActivityView.setForwardedInsets(Insets.of(0, 0, 0, 0));
253 }
254 }
255
256 /**
Issei Suzukicac2a502019-04-16 16:52:50 +0200257 * Set visibility of contents in the expanded state.
258 *
259 * @param visibility {@code true} if the contents should be visible on the screen.
260 *
261 * Note that this contents visibility doesn't affect visibility at {@link android.view.View},
262 * and setting {@code false} actually means rendering the contents in transparent.
263 */
264 void setContentVisibility(boolean visibility) {
265 final float alpha = visibility ? 1f : 0f;
266 mPointerView.setAlpha(alpha);
267 if (mActivityView != null) {
268 mActivityView.setAlpha(alpha);
269 }
270 }
271
272 /**
Mady Mellor5d8f1402019-02-21 18:23:52 -0800273 * Called by {@link BubbleStackView} when the insets for the expanded state should be updated.
274 * This should be done post-move and post-animation.
275 */
276 void updateInsets(WindowInsets insets) {
277 if (usingActivityView()) {
Mady Mellor5d8f1402019-02-21 18:23:52 -0800278 int[] windowLocation = mActivityView.getLocationOnScreen();
279 final int windowBottom = windowLocation[1] + mActivityView.getHeight();
280 final int keyboardHeight = insets.getSystemWindowInsetBottom()
281 - insets.getStableInsetBottom();
282 final int insetsBottom = Math.max(0,
Mady Mellora96c9ed2019-06-07 12:55:26 -0700283 windowBottom + keyboardHeight - mDisplaySize.y);
Mady Mellor5d8f1402019-02-21 18:23:52 -0800284 mActivityView.setForwardedInsets(Insets.of(0, 0, 0, insetsBottom));
285 }
286 }
287
Mady Mellore8e07712019-01-23 12:45:33 -0800288 /**
Mady Mellor9801e852019-01-22 14:50:28 -0800289 * Sets the notification entry used to populate this view.
290 */
Lyn Han6c40fe72019-05-08 14:06:33 -0700291 public void setEntry(NotificationEntry entry, BubbleStackView stackView, String appName) {
Mady Mellor9801e852019-01-22 14:50:28 -0800292 mStackView = stackView;
293 mEntry = entry;
Lyn Han6c40fe72019-05-08 14:06:33 -0700294 mAppName = appName;
Mady Mellor9801e852019-01-22 14:50:28 -0800295
Mady Mellor9801e852019-01-22 14:50:28 -0800296 try {
Issei Suzukia91f3962019-06-07 11:48:23 +0200297 ApplicationInfo info = mPm.getApplicationInfo(
Mady Mellor9801e852019-01-22 14:50:28 -0800298 entry.notification.getPackageName(),
299 PackageManager.MATCH_UNINSTALLED_PACKAGES
300 | PackageManager.MATCH_DISABLED_COMPONENTS
301 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
302 | PackageManager.MATCH_DIRECT_BOOT_AWARE);
Issei Suzukia91f3962019-06-07 11:48:23 +0200303 mAppIcon = mPm.getApplicationIcon(info);
Mady Mellor9801e852019-01-22 14:50:28 -0800304 } catch (PackageManager.NameNotFoundException e) {
Lyn Han6c40fe72019-05-08 14:06:33 -0700305 // Do nothing.
Mady Mellor9801e852019-01-22 14:50:28 -0800306 }
Mady Mellore8e07712019-01-23 12:45:33 -0800307 if (mAppIcon == null) {
308 mAppIcon = mPm.getDefaultActivityIcon();
309 }
Mark Renouf34d04f32019-05-13 15:53:18 -0400310 applyThemeAttrs();
Lyn Han69149122019-04-30 12:03:12 -0700311 showSettingsIcon();
Mady Mellor3dff9e62019-02-05 18:12:53 -0800312 updateExpandedView();
Mady Mellor6d002032019-02-13 13:45:17 -0800313 }
314
315 /**
316 * Lets activity view know it should be shown / populated.
317 */
Mady Mellor5029fa62019-03-05 12:16:21 -0800318 public void populateExpandedView() {
319 if (usingActivityView()) {
320 mActivityView.setCallback(mStateCallback);
321 } else {
Issei Suzukia91f3962019-06-07 11:48:23 +0200322 Log.e(TAG, "Cannot populate expanded view.");
Mady Mellor5029fa62019-03-05 12:16:21 -0800323 }
Mady Mellor9801e852019-01-22 14:50:28 -0800324 }
325
Mady Mellorfe7ec032019-01-30 17:32:49 -0800326 /**
327 * Updates the entry backing this view. This will not re-populate ActivityView, it will
Lyn Han02cca812019-04-02 16:27:32 -0700328 * only update the deep-links in the title, and the height of the view.
Mady Mellorfe7ec032019-01-30 17:32:49 -0800329 */
330 public void update(NotificationEntry entry) {
331 if (entry.key.equals(mEntry.key)) {
332 mEntry = entry;
Lyn Han02cca812019-04-02 16:27:32 -0700333 updateSettingsContentDescription();
Mady Mellorfe7ec032019-01-30 17:32:49 -0800334 updateHeight();
335 } else {
336 Log.w(TAG, "Trying to update entry with different key, new entry: "
337 + entry.key + " old entry: " + mEntry.key);
338 }
339 }
340
Mady Mellor3dff9e62019-02-05 18:12:53 -0800341 private void updateExpandedView() {
342 mBubbleIntent = getBubbleIntent(mEntry);
343 if (mBubbleIntent != null) {
Issei Suzukicac2a502019-04-16 16:52:50 +0200344 setContentVisibility(false);
Mady Mellor3dff9e62019-02-05 18:12:53 -0800345 mActivityView.setVisibility(VISIBLE);
Mady Mellor3dff9e62019-02-05 18:12:53 -0800346 }
347 updateView();
348 }
349
Mark Renouf041d7262019-02-06 12:09:41 -0500350 boolean performBackPressIfNeeded() {
Mady Mellor323fb0b2019-03-25 12:15:22 -0700351 if (!usingActivityView()) {
Mark Renouf041d7262019-02-06 12:09:41 -0500352 return false;
353 }
354 mActivityView.performBackPress();
355 return true;
356 }
357
Mady Mellorfe7ec032019-01-30 17:32:49 -0800358 void updateHeight() {
359 if (usingActivityView()) {
360 Notification.BubbleMetadata data = mEntry.getBubbleMetadata();
Mady Mellor7af771a2019-03-07 15:04:54 -0800361 float desiredHeight;
Mady Mellorfe7ec032019-01-30 17:32:49 -0800362 if (data == null) {
363 // This is a contentIntent based bubble, lets allow it to be the max height
364 // as it was forced into this mode and not prepared to be small
Mady Mellora96c9ed2019-06-07 12:55:26 -0700365 desiredHeight = getMaxExpandedHeight();
Mady Mellorfe7ec032019-01-30 17:32:49 -0800366 } else {
Mady Mellor7af771a2019-03-07 15:04:54 -0800367 boolean useRes = data.getDesiredHeightResId() != 0;
368 float desiredPx;
369 if (useRes) {
370 desiredPx = getDimenForPackageUser(data.getDesiredHeightResId(),
371 mEntry.notification.getPackageName(),
372 mEntry.notification.getUser().getIdentifier());
373 } else {
374 desiredPx = data.getDesiredHeight()
375 * getContext().getResources().getDisplayMetrics().density;
376 }
377 desiredHeight = desiredPx > 0 ? desiredPx : mMinHeight;
Mady Mellorfe7ec032019-01-30 17:32:49 -0800378 }
Mady Mellora96c9ed2019-06-07 12:55:26 -0700379 float height = Math.min(desiredHeight, getMaxExpandedHeight());
Mady Mellorfe7ec032019-01-30 17:32:49 -0800380 height = Math.max(height, mMinHeight);
381 LayoutParams lp = (LayoutParams) mActivityView.getLayoutParams();
Mady Mellor5d8f1402019-02-21 18:23:52 -0800382 mNeedsNewHeight = lp.height != height;
383 if (!mKeyboardVisible) {
384 // If the keyboard is visible... don't adjust the height because that will cause
385 // a configuration change and the keyboard will be lost.
Mady Mellor7af771a2019-03-07 15:04:54 -0800386 lp.height = (int) height;
Mady Mellor5d8f1402019-02-21 18:23:52 -0800387 mActivityView.setLayoutParams(lp);
388 mNeedsNewHeight = false;
389 }
Mady Mellorfe7ec032019-01-30 17:32:49 -0800390 }
391 }
392
Mady Mellora96c9ed2019-06-07 12:55:26 -0700393 private int getMaxExpandedHeight() {
394 int[] windowLocation = mActivityView.getLocationOnScreen();
395 return mDisplaySize.y - windowLocation[1] - mSettingsIconHeight;
396 }
397
Mady Mellor9801e852019-01-22 14:50:28 -0800398 @Override
399 public void onClick(View view) {
400 if (mEntry == null) {
401 return;
402 }
403 Notification n = mEntry.notification.getNotification();
404 int id = view.getId();
Lyn Hanc26ff122019-03-29 16:46:07 -0700405 if (id == R.id.settings_button) {
Mady Mellor9801e852019-01-22 14:50:28 -0800406 Intent intent = getSettingsIntent(mEntry.notification.getPackageName(),
407 mEntry.notification.getUid());
Steven Wub00225b2019-02-08 14:27:42 -0500408 mStackView.collapseStack(() -> {
Mark Renouf76176192019-05-20 09:29:44 -0400409 mContext.startActivityAsUser(intent, mEntry.notification.getUser());
Steven Wu45e38ae2019-03-25 16:16:59 -0400410 logBubbleClickEvent(mEntry,
Steven Wub00225b2019-02-08 14:27:42 -0500411 StatsLog.BUBBLE_UICHANGED__ACTION__HEADER_GO_TO_SETTINGS);
412 });
Mady Mellor9801e852019-01-22 14:50:28 -0800413 }
Mady Mellordea7ecf2018-12-10 15:47:40 -0800414 }
415
Lyn Han02cca812019-04-02 16:27:32 -0700416 private void updateSettingsContentDescription() {
417 mSettingsIcon.setContentDescription(getResources().getString(
418 R.string.bubbles_settings_button_description, mAppName));
419 }
420
Lyn Hanc26ff122019-03-29 16:46:07 -0700421 void showSettingsIcon() {
Lyn Han02cca812019-04-02 16:27:32 -0700422 updateSettingsContentDescription();
Lyn Hanc26ff122019-03-29 16:46:07 -0700423 mSettingsIcon.setVisibility(VISIBLE);
424 }
425
Mady Mellordea7ecf2018-12-10 15:47:40 -0800426 /**
Mady Mellor3dff9e62019-02-05 18:12:53 -0800427 * Update appearance of the expanded view being displayed.
428 */
429 public void updateView() {
430 if (usingActivityView()
431 && mActivityView.getVisibility() == VISIBLE
432 && mActivityView.isAttachedToWindow()) {
433 mActivityView.onLocationChanged();
Mady Mellor3dff9e62019-02-05 18:12:53 -0800434 }
Mady Mellorfe7ec032019-01-30 17:32:49 -0800435 updateHeight();
Mady Mellor3dff9e62019-02-05 18:12:53 -0800436 }
437
438 /**
Mady Mellordea7ecf2018-12-10 15:47:40 -0800439 * Set the x position that the tip of the triangle should point to.
440 */
Mady Mellor3dff9e62019-02-05 18:12:53 -0800441 public void setPointerPosition(float x) {
Lyn Han9a2f5cf2019-05-23 11:01:41 -0700442 float halfPointerWidth = mPointerWidth / 2f;
443 float pointerLeft = x - halfPointerWidth;
444 mPointerView.setTranslationX(pointerLeft);
Lyn Hanf74ba672019-05-20 16:08:48 -0700445 mPointerView.setVisibility(VISIBLE);
Mady Mellordea7ecf2018-12-10 15:47:40 -0800446 }
447
448 /**
Mady Mellor3dff9e62019-02-05 18:12:53 -0800449 * Removes and releases an ActivityView if one was previously created for this bubble.
Mady Mellordea7ecf2018-12-10 15:47:40 -0800450 */
Mady Mellor94d94a72019-03-05 18:16:59 -0800451 public void cleanUpExpandedState() {
Mady Mellor3dff9e62019-02-05 18:12:53 -0800452 if (mActivityView == null) {
Mark Renouf89b1a4a2018-12-04 14:59:45 -0500453 return;
454 }
Issei Suzuki734bc942019-06-05 13:59:52 +0200455 switch (mActivityViewStatus) {
456 case INITIALIZED:
457 case ACTIVITY_STARTED:
458 mActivityView.release();
Mady Mellordea7ecf2018-12-10 15:47:40 -0800459 }
Mark Renouf5c732b32019-06-12 15:14:54 -0400460 if (mTaskId != -1) {
461 try {
462 ActivityTaskManager.getService().removeTask(mTaskId);
463 } catch (RemoteException e) {
464 Log.w(TAG, "Failed to remove taskId " + mTaskId);
465 }
466 mTaskId = -1;
467 }
Mark Renouf28c250d2019-02-25 16:47:34 -0500468 removeView(mActivityView);
Mark Renouf5c732b32019-06-12 15:14:54 -0400469
Mady Mellor3dff9e62019-02-05 18:12:53 -0800470 mActivityView = null;
Issei Suzuki734bc942019-06-05 13:59:52 +0200471 }
472
473 /**
474 * Called when the last task is removed from a {@link android.hardware.display.VirtualDisplay}
475 * which {@link ActivityView} uses.
476 */
477 void notifyDisplayEmpty() {
478 if (mActivityViewStatus == ActivityViewStatus.ACTIVITY_STARTED) {
479 mActivityViewStatus = ActivityViewStatus.INITIALIZED;
480 }
Mady Mellordea7ecf2018-12-10 15:47:40 -0800481 }
482
Mady Mellor3dff9e62019-02-05 18:12:53 -0800483 private boolean usingActivityView() {
Mady Mellor323fb0b2019-03-25 12:15:22 -0700484 return mBubbleIntent != null && mActivityView != null;
Mady Mellor3dff9e62019-02-05 18:12:53 -0800485 }
486
Mady Mellor390bff42019-04-05 15:09:01 -0700487 /**
488 * @return the display id of the virtual display.
489 */
490 public int getVirtualDisplayId() {
491 if (usingActivityView()) {
492 return mActivityView.getVirtualDisplayId();
493 }
494 return INVALID_DISPLAY;
495 }
496
Mady Mellor9801e852019-01-22 14:50:28 -0800497 private Intent getSettingsIntent(String packageName, final int appUid) {
Lyn Han754e77b2019-04-30 14:34:49 -0700498 final Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_BUBBLE_SETTINGS);
Mady Mellor9801e852019-01-22 14:50:28 -0800499 intent.putExtra(Settings.EXTRA_APP_PACKAGE, packageName);
500 intent.putExtra(Settings.EXTRA_APP_UID, appUid);
501 intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
502 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Lyn Han754e77b2019-04-30 14:34:49 -0700503 intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
Mady Mellor9801e852019-01-22 14:50:28 -0800504 return intent;
505 }
Mady Mellore8e07712019-01-23 12:45:33 -0800506
Mady Mellor3dff9e62019-02-05 18:12:53 -0800507 @Nullable
508 private PendingIntent getBubbleIntent(NotificationEntry entry) {
509 Notification notif = entry.notification.getNotification();
Mady Mellor3dff9e62019-02-05 18:12:53 -0800510 Notification.BubbleMetadata data = notif.getBubbleMetadata();
Mady Mellorca0c24c2019-05-16 16:14:32 -0700511 if (BubbleController.canLaunchInActivityView(mContext, entry) && data != null) {
Mady Mellor3dff9e62019-02-05 18:12:53 -0800512 return data.getIntent();
Mady Mellor3dff9e62019-02-05 18:12:53 -0800513 }
514 return null;
515 }
516
517 /**
Steven Wub00225b2019-02-08 14:27:42 -0500518 * Logs bubble UI click event.
519 *
Steven Wu45e38ae2019-03-25 16:16:59 -0400520 * @param entry the bubble notification entry that user is interacting with.
Steven Wub00225b2019-02-08 14:27:42 -0500521 * @param action the user interaction enum.
522 */
Steven Wu45e38ae2019-03-25 16:16:59 -0400523 private void logBubbleClickEvent(NotificationEntry entry, int action) {
524 StatusBarNotification notification = entry.notification;
Steven Wub00225b2019-02-08 14:27:42 -0500525 StatsLog.write(StatsLog.BUBBLE_UI_CHANGED,
526 notification.getPackageName(),
527 notification.getNotification().getChannelId(),
528 notification.getId(),
529 mStackView.getBubbleIndex(mStackView.getExpandedBubble()),
530 mStackView.getBubbleCount(),
531 action,
532 mStackView.getNormalizedXPosition(),
Steven Wu45e38ae2019-03-25 16:16:59 -0400533 mStackView.getNormalizedYPosition(),
Steven Wu8ba8ca92019-04-11 10:47:42 -0400534 entry.showInShadeWhenBubble(),
535 entry.isForegroundService(),
536 BubbleController.isForegroundApp(mContext, notification.getPackageName()));
Steven Wub00225b2019-02-08 14:27:42 -0500537 }
Mady Mellor7af771a2019-03-07 15:04:54 -0800538
539 private int getDimenForPackageUser(int resId, String pkg, int userId) {
540 Resources r;
541 if (pkg != null) {
542 try {
543 if (userId == UserHandle.USER_ALL) {
544 userId = UserHandle.USER_SYSTEM;
545 }
546 r = mPm.getResourcesForApplicationAsUser(pkg, userId);
547 return r.getDimensionPixelSize(resId);
548 } catch (PackageManager.NameNotFoundException ex) {
549 // Uninstalled, don't care
550 } catch (Resources.NotFoundException e) {
551 // Invalid res id, return 0 and user our default
552 Log.e(TAG, "Couldn't find desired height res id", e);
553 }
554 }
555 return 0;
556 }
Mady Mellordea7ecf2018-12-10 15:47:40 -0800557}