Mady Mellor | dea7ecf | 2018-12-10 15:47:40 -0800 | [diff] [blame] | 1 | /* |
| 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 | |
| 17 | package com.android.systemui.bubbles; |
| 18 | |
Mady Mellor | e8e0771 | 2019-01-23 12:45:33 -0800 | [diff] [blame] | 19 | import android.animation.LayoutTransition; |
| 20 | import android.animation.ObjectAnimator; |
Mady Mellor | dea7ecf | 2018-12-10 15:47:40 -0800 | [diff] [blame] | 21 | import android.annotation.Nullable; |
Mady Mellor | e8e0771 | 2019-01-23 12:45:33 -0800 | [diff] [blame] | 22 | import android.app.INotificationManager; |
Mady Mellor | 9801e85 | 2019-01-22 14:50:28 -0800 | [diff] [blame] | 23 | import android.app.Notification; |
| 24 | import android.app.PendingIntent; |
Mady Mellor | dea7ecf | 2018-12-10 15:47:40 -0800 | [diff] [blame] | 25 | import android.content.Context; |
Mady Mellor | 9801e85 | 2019-01-22 14:50:28 -0800 | [diff] [blame] | 26 | import android.content.Intent; |
| 27 | import android.content.pm.ApplicationInfo; |
| 28 | import android.content.pm.PackageManager; |
Mady Mellor | dea7ecf | 2018-12-10 15:47:40 -0800 | [diff] [blame] | 29 | import android.content.res.Resources; |
Mady Mellor | dd49705 | 2019-01-30 17:23:48 -0800 | [diff] [blame] | 30 | import android.content.res.TypedArray; |
Mady Mellor | dea7ecf | 2018-12-10 15:47:40 -0800 | [diff] [blame] | 31 | import android.graphics.Color; |
Mady Mellor | e8e0771 | 2019-01-23 12:45:33 -0800 | [diff] [blame] | 32 | import android.graphics.drawable.Drawable; |
Mady Mellor | dea7ecf | 2018-12-10 15:47:40 -0800 | [diff] [blame] | 33 | import android.graphics.drawable.ShapeDrawable; |
Mady Mellor | e8e0771 | 2019-01-23 12:45:33 -0800 | [diff] [blame] | 34 | import android.os.RemoteException; |
| 35 | import android.os.ServiceManager; |
Mady Mellor | 9801e85 | 2019-01-22 14:50:28 -0800 | [diff] [blame] | 36 | import android.provider.Settings; |
Steven Wu | b00225b | 2019-02-08 14:27:42 -0500 | [diff] [blame^] | 37 | import android.service.notification.StatusBarNotification; |
Mady Mellor | dea7ecf | 2018-12-10 15:47:40 -0800 | [diff] [blame] | 38 | import android.util.AttributeSet; |
Mady Mellor | 9801e85 | 2019-01-22 14:50:28 -0800 | [diff] [blame] | 39 | import android.util.Log; |
Steven Wu | b00225b | 2019-02-08 14:27:42 -0500 | [diff] [blame^] | 40 | import android.util.StatsLog; |
Mady Mellor | dea7ecf | 2018-12-10 15:47:40 -0800 | [diff] [blame] | 41 | import android.view.View; |
Mady Mellor | e8e0771 | 2019-01-23 12:45:33 -0800 | [diff] [blame] | 42 | import android.widget.FrameLayout; |
Mady Mellor | 9801e85 | 2019-01-22 14:50:28 -0800 | [diff] [blame] | 43 | import android.widget.ImageButton; |
Mady Mellor | e8e0771 | 2019-01-23 12:45:33 -0800 | [diff] [blame] | 44 | import android.widget.ImageView; |
Mady Mellor | dea7ecf | 2018-12-10 15:47:40 -0800 | [diff] [blame] | 45 | import android.widget.LinearLayout; |
Mark Renouf | 89b1a4a | 2018-12-04 14:59:45 -0500 | [diff] [blame] | 46 | import android.widget.TextView; |
Mady Mellor | dea7ecf | 2018-12-10 15:47:40 -0800 | [diff] [blame] | 47 | |
Mady Mellor | e8e0771 | 2019-01-23 12:45:33 -0800 | [diff] [blame] | 48 | import com.android.systemui.Interpolators; |
Mady Mellor | dea7ecf | 2018-12-10 15:47:40 -0800 | [diff] [blame] | 49 | import com.android.systemui.R; |
| 50 | import com.android.systemui.recents.TriangleShape; |
Mady Mellor | 9801e85 | 2019-01-22 14:50:28 -0800 | [diff] [blame] | 51 | import com.android.systemui.statusbar.notification.collection.NotificationEntry; |
Mady Mellor | dea7ecf | 2018-12-10 15:47:40 -0800 | [diff] [blame] | 52 | |
| 53 | /** |
| 54 | * Container for the expanded bubble view, handles rendering the caret and header of the view. |
| 55 | */ |
Mady Mellor | 3d82e68 | 2019-02-05 13:34:48 -0800 | [diff] [blame] | 56 | public class BubbleExpandedView extends LinearLayout implements View.OnClickListener { |
Mady Mellor | 9801e85 | 2019-01-22 14:50:28 -0800 | [diff] [blame] | 57 | private static final String TAG = "BubbleExpandedView"; |
Mady Mellor | dea7ecf | 2018-12-10 15:47:40 -0800 | [diff] [blame] | 58 | |
| 59 | // The triangle pointing to the expanded view |
| 60 | private View mPointerView; |
Mady Mellor | e8e0771 | 2019-01-23 12:45:33 -0800 | [diff] [blame] | 61 | |
| 62 | // Header |
| 63 | private View mHeaderView; |
| 64 | private TextView mHeaderTextView; |
Mady Mellor | 9801e85 | 2019-01-22 14:50:28 -0800 | [diff] [blame] | 65 | private ImageButton mDeepLinkIcon; |
Mady Mellor | 9801e85 | 2019-01-22 14:50:28 -0800 | [diff] [blame] | 66 | private ImageButton mSettingsIcon; |
Mady Mellor | e8e0771 | 2019-01-23 12:45:33 -0800 | [diff] [blame] | 67 | |
| 68 | // Permission view |
| 69 | private View mPermissionView; |
| 70 | |
Mady Mellor | dea7ecf | 2018-12-10 15:47:40 -0800 | [diff] [blame] | 71 | // The view that is being displayed for the expanded state |
| 72 | private View mExpandedView; |
| 73 | |
Mady Mellor | 9801e85 | 2019-01-22 14:50:28 -0800 | [diff] [blame] | 74 | private NotificationEntry mEntry; |
| 75 | private PackageManager mPm; |
| 76 | private String mAppName; |
Mady Mellor | e8e0771 | 2019-01-23 12:45:33 -0800 | [diff] [blame] | 77 | private Drawable mAppIcon; |
| 78 | |
| 79 | private INotificationManager mNotificationManagerService; |
Mady Mellor | 9801e85 | 2019-01-22 14:50:28 -0800 | [diff] [blame] | 80 | |
| 81 | // Need reference to let it know to collapse when new task is launched |
| 82 | private BubbleStackView mStackView; |
| 83 | |
Mady Mellor | e8e0771 | 2019-01-23 12:45:33 -0800 | [diff] [blame] | 84 | private OnBubbleBlockedListener mOnBubbleBlockedListener; |
| 85 | |
Mady Mellor | 3d82e68 | 2019-02-05 13:34:48 -0800 | [diff] [blame] | 86 | public BubbleExpandedView(Context context) { |
Mady Mellor | dea7ecf | 2018-12-10 15:47:40 -0800 | [diff] [blame] | 87 | this(context, null); |
| 88 | } |
| 89 | |
Mady Mellor | 3d82e68 | 2019-02-05 13:34:48 -0800 | [diff] [blame] | 90 | public BubbleExpandedView(Context context, AttributeSet attrs) { |
Mady Mellor | dea7ecf | 2018-12-10 15:47:40 -0800 | [diff] [blame] | 91 | this(context, attrs, 0); |
| 92 | } |
| 93 | |
Mady Mellor | 3d82e68 | 2019-02-05 13:34:48 -0800 | [diff] [blame] | 94 | public BubbleExpandedView(Context context, AttributeSet attrs, int defStyleAttr) { |
Mady Mellor | dea7ecf | 2018-12-10 15:47:40 -0800 | [diff] [blame] | 95 | this(context, attrs, defStyleAttr, 0); |
| 96 | } |
| 97 | |
Mady Mellor | 3d82e68 | 2019-02-05 13:34:48 -0800 | [diff] [blame] | 98 | public BubbleExpandedView(Context context, AttributeSet attrs, int defStyleAttr, |
Mady Mellor | dea7ecf | 2018-12-10 15:47:40 -0800 | [diff] [blame] | 99 | int defStyleRes) { |
| 100 | super(context, attrs, defStyleAttr, defStyleRes); |
Mady Mellor | 9801e85 | 2019-01-22 14:50:28 -0800 | [diff] [blame] | 101 | mPm = context.getPackageManager(); |
Mady Mellor | e8e0771 | 2019-01-23 12:45:33 -0800 | [diff] [blame] | 102 | try { |
| 103 | mNotificationManagerService = INotificationManager.Stub.asInterface( |
| 104 | ServiceManager.getServiceOrThrow(Context.NOTIFICATION_SERVICE)); |
| 105 | } catch (ServiceManager.ServiceNotFoundException e) { |
| 106 | Log.w(TAG, e); |
| 107 | } |
Mady Mellor | dea7ecf | 2018-12-10 15:47:40 -0800 | [diff] [blame] | 108 | } |
| 109 | |
| 110 | @Override |
| 111 | protected void onFinishInflate() { |
| 112 | super.onFinishInflate(); |
| 113 | |
| 114 | Resources res = getResources(); |
| 115 | mPointerView = findViewById(R.id.pointer_view); |
| 116 | int width = res.getDimensionPixelSize(R.dimen.bubble_pointer_width); |
| 117 | int height = res.getDimensionPixelSize(R.dimen.bubble_pointer_height); |
Mady Mellor | dd49705 | 2019-01-30 17:23:48 -0800 | [diff] [blame] | 118 | |
| 119 | TypedArray ta = getContext().obtainStyledAttributes( |
| 120 | new int[] {android.R.attr.colorBackgroundFloating}); |
| 121 | int bgColor = ta.getColor(0, Color.WHITE); |
| 122 | ta.recycle(); |
| 123 | |
Mady Mellor | dea7ecf | 2018-12-10 15:47:40 -0800 | [diff] [blame] | 124 | ShapeDrawable triangleDrawable = new ShapeDrawable( |
| 125 | TriangleShape.create(width, height, true /* pointUp */)); |
Mady Mellor | dd49705 | 2019-01-30 17:23:48 -0800 | [diff] [blame] | 126 | triangleDrawable.setTint(bgColor); |
Mady Mellor | dea7ecf | 2018-12-10 15:47:40 -0800 | [diff] [blame] | 127 | mPointerView.setBackground(triangleDrawable); |
Mady Mellor | 9801e85 | 2019-01-22 14:50:28 -0800 | [diff] [blame] | 128 | |
Mady Mellor | e8e0771 | 2019-01-23 12:45:33 -0800 | [diff] [blame] | 129 | FrameLayout viewWrapper = findViewById(R.id.header_permission_wrapper); |
| 130 | LayoutTransition transition = new LayoutTransition(); |
| 131 | transition.setDuration(200); |
| 132 | |
| 133 | ObjectAnimator appearAnimator = ObjectAnimator.ofFloat(null, View.ALPHA, 0f, 1f); |
| 134 | transition.setAnimator(LayoutTransition.APPEARING, appearAnimator); |
| 135 | transition.setInterpolator(LayoutTransition.APPEARING, Interpolators.ALPHA_IN); |
| 136 | |
| 137 | ObjectAnimator disappearAnimator = ObjectAnimator.ofFloat(null, View.ALPHA, 1f, 0f); |
| 138 | transition.setAnimator(LayoutTransition.DISAPPEARING, disappearAnimator); |
| 139 | transition.setInterpolator(LayoutTransition.DISAPPEARING, Interpolators.ALPHA_OUT); |
| 140 | |
| 141 | transition.setAnimateParentHierarchy(false); |
| 142 | viewWrapper.setLayoutTransition(transition); |
| 143 | viewWrapper.getLayoutTransition().enableTransitionType(LayoutTransition.CHANGING); |
| 144 | |
| 145 | mHeaderView = findViewById(R.id.header_layout); |
| 146 | mHeaderTextView = findViewById(R.id.header_text); |
Mady Mellor | 9801e85 | 2019-01-22 14:50:28 -0800 | [diff] [blame] | 147 | mDeepLinkIcon = findViewById(R.id.deep_link_button); |
| 148 | mSettingsIcon = findViewById(R.id.settings_button); |
| 149 | mDeepLinkIcon.setOnClickListener(this); |
| 150 | mSettingsIcon.setOnClickListener(this); |
Mady Mellor | e8e0771 | 2019-01-23 12:45:33 -0800 | [diff] [blame] | 151 | |
| 152 | mPermissionView = findViewById(R.id.permission_layout); |
| 153 | findViewById(R.id.no_bubbles_button).setOnClickListener(this); |
| 154 | findViewById(R.id.yes_bubbles_button).setOnClickListener(this); |
| 155 | } |
| 156 | |
| 157 | /** |
| 158 | * Sets the listener to notify when a bubble has been blocked. |
| 159 | */ |
| 160 | public void setOnBlockedListener(OnBubbleBlockedListener listener) { |
| 161 | mOnBubbleBlockedListener = listener; |
Mady Mellor | 9801e85 | 2019-01-22 14:50:28 -0800 | [diff] [blame] | 162 | } |
| 163 | |
| 164 | /** |
| 165 | * Sets the notification entry used to populate this view. |
| 166 | */ |
| 167 | public void setEntry(NotificationEntry entry, BubbleStackView stackView) { |
| 168 | mStackView = stackView; |
| 169 | mEntry = entry; |
| 170 | |
| 171 | ApplicationInfo info; |
| 172 | try { |
| 173 | info = mPm.getApplicationInfo( |
| 174 | entry.notification.getPackageName(), |
| 175 | PackageManager.MATCH_UNINSTALLED_PACKAGES |
| 176 | | PackageManager.MATCH_DISABLED_COMPONENTS |
| 177 | | PackageManager.MATCH_DIRECT_BOOT_UNAWARE |
| 178 | | PackageManager.MATCH_DIRECT_BOOT_AWARE); |
| 179 | if (info != null) { |
| 180 | mAppName = String.valueOf(mPm.getApplicationLabel(info)); |
Mady Mellor | e8e0771 | 2019-01-23 12:45:33 -0800 | [diff] [blame] | 181 | mAppIcon = mPm.getApplicationIcon(info); |
Mady Mellor | 9801e85 | 2019-01-22 14:50:28 -0800 | [diff] [blame] | 182 | } |
| 183 | } catch (PackageManager.NameNotFoundException e) { |
| 184 | // Ahh... just use package name |
| 185 | mAppName = entry.notification.getPackageName(); |
| 186 | } |
Mady Mellor | e8e0771 | 2019-01-23 12:45:33 -0800 | [diff] [blame] | 187 | if (mAppIcon == null) { |
| 188 | mAppIcon = mPm.getDefaultActivityIcon(); |
| 189 | } |
Mady Mellor | 9801e85 | 2019-01-22 14:50:28 -0800 | [diff] [blame] | 190 | updateHeaderView(); |
Mady Mellor | e8e0771 | 2019-01-23 12:45:33 -0800 | [diff] [blame] | 191 | updatePermissionView(); |
Mady Mellor | 9801e85 | 2019-01-22 14:50:28 -0800 | [diff] [blame] | 192 | } |
| 193 | |
| 194 | private void updateHeaderView() { |
| 195 | mSettingsIcon.setContentDescription(getResources().getString( |
| 196 | R.string.bubbles_settings_button_description, mAppName)); |
| 197 | mDeepLinkIcon.setContentDescription(getResources().getString( |
| 198 | R.string.bubbles_deep_link_button_description, mAppName)); |
| 199 | if (mEntry != null && mEntry.getBubbleMetadata() != null) { |
Mady Mellor | e8e0771 | 2019-01-23 12:45:33 -0800 | [diff] [blame] | 200 | mHeaderTextView.setText(mEntry.getBubbleMetadata().getTitle()); |
Mady Mellor | 9801e85 | 2019-01-22 14:50:28 -0800 | [diff] [blame] | 201 | } else { |
| 202 | // This should only happen if we're auto-bubbling notification content that isn't |
| 203 | // explicitly a bubble |
Mady Mellor | e8e0771 | 2019-01-23 12:45:33 -0800 | [diff] [blame] | 204 | mHeaderTextView.setText(mAppName); |
| 205 | } |
| 206 | } |
| 207 | |
| 208 | private void updatePermissionView() { |
| 209 | boolean hasUserApprovedBubblesForPackage = false; |
| 210 | try { |
| 211 | hasUserApprovedBubblesForPackage = |
| 212 | mNotificationManagerService.hasUserApprovedBubblesForPackage( |
| 213 | mEntry.notification.getPackageName(), mEntry.notification.getUid()); |
| 214 | } catch (RemoteException e) { |
| 215 | Log.w(TAG, e); |
| 216 | } |
| 217 | if (hasUserApprovedBubblesForPackage) { |
| 218 | mHeaderView.setVisibility(VISIBLE); |
| 219 | mPermissionView.setVisibility(GONE); |
| 220 | } else { |
| 221 | mHeaderView.setVisibility(GONE); |
| 222 | mPermissionView.setVisibility(VISIBLE); |
| 223 | ((ImageView) mPermissionView.findViewById(R.id.pkgicon)).setImageDrawable(mAppIcon); |
| 224 | ((TextView) mPermissionView.findViewById(R.id.pkgname)).setText(mAppName); |
Mady Mellor | 9801e85 | 2019-01-22 14:50:28 -0800 | [diff] [blame] | 225 | } |
| 226 | } |
| 227 | |
| 228 | @Override |
| 229 | public void onClick(View view) { |
| 230 | if (mEntry == null) { |
| 231 | return; |
| 232 | } |
| 233 | Notification n = mEntry.notification.getNotification(); |
| 234 | int id = view.getId(); |
| 235 | if (id == R.id.deep_link_button) { |
| 236 | mStackView.collapseStack(() -> { |
| 237 | try { |
| 238 | n.contentIntent.send(); |
Steven Wu | b00225b | 2019-02-08 14:27:42 -0500 | [diff] [blame^] | 239 | logBubbleClickEvent(mEntry.notification, |
| 240 | StatsLog.BUBBLE_UICHANGED__ACTION__HEADER_GO_TO_APP); |
Mady Mellor | 9801e85 | 2019-01-22 14:50:28 -0800 | [diff] [blame] | 241 | } catch (PendingIntent.CanceledException e) { |
| 242 | Log.w(TAG, "Failed to send intent for bubble with key: " |
| 243 | + (mEntry != null ? mEntry.key : " null entry")); |
| 244 | } |
| 245 | }); |
| 246 | } else if (id == R.id.settings_button) { |
| 247 | Intent intent = getSettingsIntent(mEntry.notification.getPackageName(), |
| 248 | mEntry.notification.getUid()); |
Steven Wu | b00225b | 2019-02-08 14:27:42 -0500 | [diff] [blame^] | 249 | mStackView.collapseStack(() -> { |
| 250 | mContext.startActivity(intent); |
| 251 | logBubbleClickEvent(mEntry.notification, |
| 252 | StatsLog.BUBBLE_UICHANGED__ACTION__HEADER_GO_TO_SETTINGS); |
| 253 | }); |
Mady Mellor | e8e0771 | 2019-01-23 12:45:33 -0800 | [diff] [blame] | 254 | } else if (id == R.id.no_bubbles_button) { |
| 255 | setBubblesAllowed(false); |
| 256 | } else if (id == R.id.yes_bubbles_button) { |
| 257 | setBubblesAllowed(true); |
| 258 | } |
| 259 | } |
| 260 | |
| 261 | private void setBubblesAllowed(boolean allowed) { |
| 262 | try { |
| 263 | mNotificationManagerService.setBubblesAllowed( |
| 264 | mEntry.notification.getPackageName(), |
| 265 | mEntry.notification.getUid(), |
| 266 | allowed); |
| 267 | if (allowed) { |
| 268 | mPermissionView.setVisibility(GONE); |
| 269 | mHeaderView.setVisibility(VISIBLE); |
| 270 | } else if (mOnBubbleBlockedListener != null) { |
| 271 | mOnBubbleBlockedListener.onBubbleBlocked(mEntry); |
| 272 | } |
Steven Wu | b00225b | 2019-02-08 14:27:42 -0500 | [diff] [blame^] | 273 | logBubbleClickEvent(mEntry.notification, |
| 274 | allowed ? StatsLog.BUBBLE_UICHANGED__ACTION__PERMISSION_OPT_IN : |
| 275 | StatsLog.BUBBLE_UICHANGED__ACTION__PERMISSION_OPT_OUT); |
Mady Mellor | e8e0771 | 2019-01-23 12:45:33 -0800 | [diff] [blame] | 276 | } catch (RemoteException e) { |
| 277 | Log.w(TAG, e); |
Mady Mellor | 9801e85 | 2019-01-22 14:50:28 -0800 | [diff] [blame] | 278 | } |
Mady Mellor | dea7ecf | 2018-12-10 15:47:40 -0800 | [diff] [blame] | 279 | } |
| 280 | |
| 281 | /** |
| 282 | * Set the x position that the tip of the triangle should point to. |
| 283 | */ |
| 284 | public void setPointerPosition(int x) { |
| 285 | // Adjust for the pointer size |
| 286 | x -= (mPointerView.getWidth() / 2); |
| 287 | mPointerView.setTranslationX(x); |
| 288 | } |
| 289 | |
| 290 | /** |
| 291 | * Set the view to display for the expanded state. Passing null will clear the view. |
| 292 | */ |
| 293 | public void setExpandedView(View view) { |
Mark Renouf | 89b1a4a | 2018-12-04 14:59:45 -0500 | [diff] [blame] | 294 | if (mExpandedView == view) { |
| 295 | return; |
| 296 | } |
Mady Mellor | dea7ecf | 2018-12-10 15:47:40 -0800 | [diff] [blame] | 297 | if (mExpandedView != null) { |
| 298 | removeView(mExpandedView); |
| 299 | } |
| 300 | mExpandedView = view; |
| 301 | if (mExpandedView != null) { |
| 302 | addView(mExpandedView); |
| 303 | } |
| 304 | } |
| 305 | |
| 306 | /** |
| 307 | * @return the view containing the expanded content, can be null. |
| 308 | */ |
| 309 | @Nullable |
| 310 | public View getExpandedView() { |
| 311 | return mExpandedView; |
| 312 | } |
Mady Mellor | 9801e85 | 2019-01-22 14:50:28 -0800 | [diff] [blame] | 313 | |
| 314 | private Intent getSettingsIntent(String packageName, final int appUid) { |
| 315 | final Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS); |
| 316 | intent.putExtra(Settings.EXTRA_APP_PACKAGE, packageName); |
| 317 | intent.putExtra(Settings.EXTRA_APP_UID, appUid); |
| 318 | intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK); |
| 319 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); |
| 320 | return intent; |
| 321 | } |
Mady Mellor | e8e0771 | 2019-01-23 12:45:33 -0800 | [diff] [blame] | 322 | |
| 323 | /** |
| 324 | * Listener that is notified when a bubble is blocked. |
| 325 | */ |
| 326 | public interface OnBubbleBlockedListener { |
| 327 | /** |
| 328 | * Called when a bubble is blocked for the provided entry. |
| 329 | */ |
| 330 | void onBubbleBlocked(NotificationEntry entry); |
| 331 | } |
Steven Wu | b00225b | 2019-02-08 14:27:42 -0500 | [diff] [blame^] | 332 | |
| 333 | /** |
| 334 | * Logs bubble UI click event. |
| 335 | * |
| 336 | * @param notification the bubble notification that user is interacting with. |
| 337 | * @param action the user interaction enum. |
| 338 | */ |
| 339 | private void logBubbleClickEvent(StatusBarNotification notification, int action) { |
| 340 | StatsLog.write(StatsLog.BUBBLE_UI_CHANGED, |
| 341 | notification.getPackageName(), |
| 342 | notification.getNotification().getChannelId(), |
| 343 | notification.getId(), |
| 344 | mStackView.getBubbleIndex(mStackView.getExpandedBubble()), |
| 345 | mStackView.getBubbleCount(), |
| 346 | action, |
| 347 | mStackView.getNormalizedXPosition(), |
| 348 | mStackView.getNormalizedYPosition()); |
| 349 | } |
Mady Mellor | dea7ecf | 2018-12-10 15:47:40 -0800 | [diff] [blame] | 350 | } |