diff options
20 files changed, 299 insertions, 471 deletions
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt index fa5c808c14a5..c3ab1773363e 100644 --- a/config/hiddenapi-light-greylist.txt +++ b/config/hiddenapi-light-greylist.txt @@ -319,6 +319,7 @@ Landroid/app/LoadedApk;->mClassLoader:Ljava/lang/ClassLoader; Landroid/app/LoadedApk;->mDataDirFile:Ljava/io/File; Landroid/app/LoadedApk;->mDataDir:Ljava/lang/String; Landroid/app/LoadedApk;->mDisplayAdjustments:Landroid/view/DisplayAdjustments; +Landroid/app/LoadedApk;->mLibDir:Ljava/lang/String; Landroid/app/LoadedApk;->mPackageName:Ljava/lang/String; Landroid/app/LoadedApk;->mReceivers:Landroid/util/ArrayMap; Landroid/app/LoadedApk;->mResDir:Ljava/lang/String; @@ -1583,6 +1584,8 @@ Landroid/os/ServiceManager;->sCache:Ljava/util/HashMap; Landroid/os/ServiceManager;->sServiceManager:Landroid/os/IServiceManager; Landroid/os/SharedMemory;->getFd()I Landroid/os/storage/DiskInfo;->getDescription()Ljava/lang/String; +Landroid/os/storage/DiskInfo;->isSd()Z +Landroid/os/storage/DiskInfo;->isUsb()Z Landroid/os/storage/IStorageManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/os/storage/IStorageManager; Landroid/os/storage/IStorageManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V Landroid/os/storage/StorageManager;->findVolumeByUuid(Ljava/lang/String;)Landroid/os/storage/VolumeInfo; @@ -1603,13 +1606,17 @@ Landroid/os/storage/StorageVolume;->getPathFile()Ljava/io/File; Landroid/os/storage/StorageVolume;->getPath()Ljava/lang/String; Landroid/os/storage/StorageVolume;->getUserLabel()Ljava/lang/String; Landroid/os/storage/StorageVolume;->mPath:Ljava/io/File; +Landroid/os/storage/VolumeInfo;->buildStorageVolume(Landroid/content/Context;IZ)Landroid/os/storage/StorageVolume; Landroid/os/storage/VolumeInfo;->getDisk()Landroid/os/storage/DiskInfo; +Landroid/os/storage/VolumeInfo;->getEnvironmentForState(I)Ljava/lang/String; Landroid/os/storage/VolumeInfo;->getFsUuid()Ljava/lang/String; Landroid/os/storage/VolumeInfo;->getPath()Ljava/io/File; Landroid/os/storage/VolumeInfo;->getState()I Landroid/os/storage/VolumeInfo;->getType()I Landroid/os/storage/VolumeInfo;->isPrimary()Z Landroid/os/storage/VolumeInfo;->isVisible()Z +Landroid/os/storage/VolumeInfo;->TYPE_EMULATED:I +Landroid/os/storage/VolumeInfo;->TYPE_PUBLIC:I Landroid/os/StrictMode;->conditionallyCheckInstanceCounts()V Landroid/os/StrictMode;->disableDeathOnFileUriExposure()V Landroid/os/StrictMode;->enterCriticalSpan(Ljava/lang/String;)Landroid/os/StrictMode$Span; @@ -3569,6 +3576,7 @@ Ljava/util/PriorityQueue;->modCount:I Ljava/util/PriorityQueue;->size:I Ljava/util/Random;->seedUniquifier()J Ljava/util/regex/Matcher;->appendPos:I +Ljava/util/UUID;->mostSigBits:J Ljava/util/Vector;->elementData(I)Ljava/lang/Object; Ljava/util/zip/Deflater;->buf:[B Ljava/util/zip/Deflater;->finished:Z diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl index 2b7221a1eb55..159d49bc0009 100644 --- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl @@ -54,12 +54,13 @@ interface IStatusBarService void onPanelHidden(); // Mark current notifications as "seen" and stop ringing, vibrating, blinking. void clearNotificationEffects(); - void onNotificationClick(String key); - void onNotificationActionClick(String key, int actionIndex); + void onNotificationClick(String key, in NotificationVisibility nv); + void onNotificationActionClick(String key, int actionIndex, in NotificationVisibility nv); void onNotificationError(String pkg, String tag, int id, int uid, int initialPid, String message, int userId); void onClearAllNotifications(int userId); - void onNotificationClear(String pkg, String tag, int id, int userId, String key, int dismissalSurface); + void onNotificationClear(String pkg, String tag, int id, int userId, String key, + int dismissalSurface, in NotificationVisibility nv); void onNotificationVisibilityChanged( in NotificationVisibility[] newlyVisibleKeys, in NotificationVisibility[] noLongerVisibleKeys); void onNotificationExpansionChanged(in String key, in boolean userAction, in boolean expanded); diff --git a/core/java/com/android/internal/statusbar/NotificationVisibility.java b/core/java/com/android/internal/statusbar/NotificationVisibility.java index 2139ad02e4f3..7fe440cf0b89 100644 --- a/core/java/com/android/internal/statusbar/NotificationVisibility.java +++ b/core/java/com/android/internal/statusbar/NotificationVisibility.java @@ -32,6 +32,7 @@ public class NotificationVisibility implements Parcelable { public String key; public int rank; + public int count; public boolean visible = true; /*package*/ int id; @@ -39,10 +40,11 @@ public class NotificationVisibility implements Parcelable { id = sNexrId++; } - private NotificationVisibility(String key, int rank, boolean visibile) { + private NotificationVisibility(String key, int rank, int count, boolean visibile) { this(); this.key = key; this.rank = rank; + this.count = count; this.visible = visibile; } @@ -51,13 +53,14 @@ public class NotificationVisibility implements Parcelable { return "NotificationVisibility(id=" + id + "key=" + key + " rank=" + rank + + " count=" + count + (visible?" visible":"") + " )"; } @Override public NotificationVisibility clone() { - return obtain(this.key, this.rank, this.visible); + return obtain(this.key, this.rank, this.count, this.visible); } @Override @@ -85,12 +88,14 @@ public class NotificationVisibility implements Parcelable { public void writeToParcel(Parcel out, int flags) { out.writeString(this.key); out.writeInt(this.rank); + out.writeInt(this.count); out.writeInt(this.visible ? 1 : 0); } private void readFromParcel(Parcel in) { this.key = in.readString(); this.rank = in.readInt(); + this.count = in.readInt(); this.visible = in.readInt() != 0; } @@ -98,10 +103,11 @@ public class NotificationVisibility implements Parcelable { * Return a new NotificationVisibility instance from the global pool. Allows us to * avoid allocating new objects in many cases. */ - public static NotificationVisibility obtain(String key, int rank, boolean visible) { + public static NotificationVisibility obtain(String key, int rank, int count, boolean visible) { NotificationVisibility vo = obtain(); vo.key = key; vo.rank = rank; + vo.count = count; vo.visible = visible; return vo; } diff --git a/packages/SystemUI/res/layout/car_volume_dialog.xml b/packages/SystemUI/res/layout/car_volume_dialog.xml index 94cc001ca01a..36bc85da0626 100644 --- a/packages/SystemUI/res/layout/car_volume_dialog.xml +++ b/packages/SystemUI/res/layout/car_volume_dialog.xml @@ -15,55 +15,24 @@ --> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:id="@+id/volume_dialog" + android:clipChildren="false" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginStart="@dimen/car_margin" android:layout_marginEnd="@dimen/car_margin" - android:background="@drawable/car_rounded_bg_bottom" - android:theme="@style/qs_theme" - android:clipChildren="false" > - <LinearLayout - android:id="@+id/volume_dialog" + android:theme="@style/qs_theme" > + <androidx.car.widget.PagedListView + android:id="@+id/volume_list" + android:background="@drawable/car_rounded_bg_bottom" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_gravity="center_horizontal|top" - android:orientation="vertical" - android:clipChildren="false" > - - <LinearLayout - android:id="@+id/main" - android:layout_width="match_parent" - android:minWidth="@dimen/volume_dialog_panel_width" - android:layout_height="wrap_content" - android:orientation="vertical" - android:clipChildren="false" - android:clipToPadding="false" - android:elevation="@dimen/volume_dialog_elevation" > - <LinearLayout - android:id="@+id/car_volume_dialog_rows" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:gravity="center" - android:orientation="vertical" > - <!-- volume rows added and removed here! :-) --> - </LinearLayout> - </LinearLayout> - </LinearLayout> - <FrameLayout - android:layout_width="wrap_content" - android:layout_height="@dimen/car_single_line_list_item_height" - android:gravity="center" - android:layout_marginEnd="@dimen/car_keyline_1" - android:layout_gravity="end"> - <com.android.keyguard.AlphaOptimizedImageButton - android:id="@+id/expand" - android:layout_gravity="center" - android:layout_width="@dimen/car_primary_icon_size" - android:layout_height="@dimen/car_primary_icon_size" - android:src="@drawable/car_ic_arrow_drop_up" - android:background="?android:attr/selectableItemBackground" - android:tint="@color/car_tint" - android:scaleType="fitCenter" - /> - </FrameLayout> -</FrameLayout>
\ No newline at end of file + android:minWidth="@dimen/volume_dialog_panel_width" + android:theme="?attr/dialogListTheme" + app:dividerStartMargin="@dimen/car_keyline_1" + app:dividerEndMargin="@dimen/car_keyline_1" + app:gutter="none" + app:showPagedListViewDivider="true" + app:scrollBarEnabled="false" /> +</FrameLayout> diff --git a/packages/SystemUI/res/layout/car_volume_dialog_row.xml b/packages/SystemUI/res/layout/car_volume_dialog_row.xml deleted file mode 100644 index 33cecfacaae3..000000000000 --- a/packages/SystemUI/res/layout/car_volume_dialog_row.xml +++ /dev/null @@ -1,48 +0,0 @@ -<!-- - Copyright (C) 2018 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> -<FrameLayout - xmlns:android="http://schemas.android.com/apk/res/android" - android:tag="row" - android:layout_height="@dimen/car_single_line_list_item_height" - android:layout_width="match_parent" - android:clipChildren="false" - android:clipToPadding="false" - android:theme="@style/qs_theme"> - - <LinearLayout - android:layout_height="match_parent" - android:layout_width="match_parent" - android:gravity="center" - android:layout_gravity="center" - android:orientation="horizontal" > - <com.android.keyguard.AlphaOptimizedImageButton - android:id="@+id/volume_row_icon" - android:layout_width="@dimen/car_primary_icon_size" - android:layout_height="@dimen/car_primary_icon_size" - android:layout_marginStart="@dimen/car_keyline_1" - android:background="?android:attr/selectableItemBackground" - android:tint="@color/car_tint" - android:scaleType="fitCenter" - android:soundEffectsEnabled="false" /> - <SeekBar - android:id="@+id/volume_row_slider" - android:clickable="true" - android:layout_marginStart="@dimen/car_keyline_1_keyline_3_diff" - android:layout_marginEnd="@dimen/car_keyline_3" - android:layout_width="match_parent" - android:layout_height="@dimen/car_single_line_list_item_height"/> - </LinearLayout> -</FrameLayout> diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java index 37d92d92edfc..b442bb4d8572 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java @@ -519,6 +519,14 @@ public class NotificationData { return null; } + public int getRank(String key) { + if (mRankingMap != null) { + getRanking(key, mTmpRanking); + return mTmpRanking.getRank(); + } + return 0; + } + public boolean shouldHide(String key) { if (mRankingMap != null) { getRanking(key, mTmpRanking); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java index 6437a3a4e89b..3a79e70bfc7d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java @@ -46,6 +46,7 @@ import android.view.ViewGroup; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.MetricsLogger; import com.android.internal.statusbar.IStatusBarService; +import com.android.internal.statusbar.NotificationVisibility; import com.android.internal.util.NotificationMessagingUtil; import com.android.systemui.DejankUtils; import com.android.systemui.Dependency; @@ -367,6 +368,10 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. } public void performRemoveNotification(StatusBarNotification n) { + final int rank = mNotificationData.getRank(n.getKey()); + final int count = mNotificationData.getActiveNotifications().size(); + final NotificationVisibility nv = NotificationVisibility.obtain(n.getKey(), rank, count, + true); NotificationData.Entry entry = mNotificationData.get(n.getKey()); mRemoteInputManager.onPerformRemoveNotification(n, entry); final String pkg = n.getPackageName(); @@ -380,7 +385,7 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. } else if (mListContainer.hasPulsingNotifications()) { dismissalSurface = NotificationStats.DISMISSAL_AOD; } - mBarService.onNotificationClear(pkg, tag, id, userId, n.getKey(), dismissalSurface); + mBarService.onNotificationClear(pkg, tag, id, userId, n.getKey(), dismissalSurface, nv); removeNotification(n.getKey(), null); } catch (RemoteException ex) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java index e24bf6762b4c..c4cc494a9429 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java @@ -38,6 +38,7 @@ import android.widget.TextView; import android.widget.Toast; import com.android.internal.statusbar.IStatusBarService; +import com.android.internal.statusbar.NotificationVisibility; import com.android.internal.widget.LockPatternUtils; import com.android.systemui.Dependency; import com.android.systemui.Dumpable; @@ -129,8 +130,13 @@ public class NotificationLockscreenUserManager implements Dumpable { } } if (notificationKey != null) { + final int count = + mEntryManager.getNotificationData().getActiveNotifications().size(); + final int rank = mEntryManager.getNotificationData().getRank(notificationKey); + final NotificationVisibility nv = NotificationVisibility.obtain(notificationKey, + rank, count, true); try { - mBarService.onNotificationClick(notificationKey); + mBarService.onNotificationClick(notificationKey, nv); } catch (RemoteException e) { /* ignore */ } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLogger.java index 4225f83c5b11..01ec46151b38 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLogger.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLogger.java @@ -107,7 +107,7 @@ public class NotificationLogger { NotificationData.Entry entry = activeNotifications.get(i); String key = entry.notification.getKey(); boolean isVisible = mListContainer.isInVisibleLocation(entry.row); - NotificationVisibility visObj = NotificationVisibility.obtain(key, i, isVisible); + NotificationVisibility visObj = NotificationVisibility.obtain(key, i, N, isVisible); boolean previouslyVisible = mCurrentlyVisibleNotifications.contains(visObj); if (isVisible) { // Build new set of visible notifications. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java index 3c480d80dea8..a33365481318 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java @@ -39,6 +39,7 @@ import android.widget.TextView; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.statusbar.IStatusBarService; +import com.android.internal.statusbar.NotificationVisibility; import com.android.systemui.Dependency; import com.android.systemui.Dumpable; import com.android.systemui.statusbar.policy.RemoteInputView; @@ -132,8 +133,11 @@ public class NotificationRemoteInputManager implements Dumpable { ViewGroup actionGroup = (ViewGroup) parent; index = actionGroup.indexOfChild(view); } + final int count = mEntryManager.getNotificationData().getActiveNotifications().size(); + final int rank = mEntryManager.getNotificationData().getRank(key); + final NotificationVisibility nv = NotificationVisibility.obtain(key, rank, count, true); try { - mBarService.onNotificationActionClick(key, index); + mBarService.onNotificationActionClick(key, index, nv); } catch (RemoteException e) { // Ignore } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index 235b1a96fcf9..17cdf4d84858 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -131,6 +131,7 @@ import com.android.internal.colorextraction.ColorExtractor; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.statusbar.IStatusBarService; +import com.android.internal.statusbar.NotificationVisibility; import com.android.internal.statusbar.StatusBarIcon; import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.MessagingGroup; @@ -5121,8 +5122,13 @@ public class StatusBar extends SystemUI implements DemoMode, collapseOnMainThread(); } + final int count = + mEntryManager.getNotificationData().getActiveNotifications().size(); + final int rank = mEntryManager.getNotificationData().getRank(notificationKey); + final NotificationVisibility nv = NotificationVisibility.obtain(notificationKey, + rank, count, true); try { - mBarService.onNotificationClick(notificationKey); + mBarService.onNotificationClick(notificationKey, nv); } catch (RemoteException ex) { // system process is dead if we're here. } diff --git a/packages/SystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java index 41b094a32682..64abfe243693 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java +++ b/packages/SystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java @@ -16,27 +16,21 @@ package com.android.systemui.volume; -import android.animation.ObjectAnimator; -import android.annotation.SuppressLint; +import android.annotation.Nullable; import android.app.Dialog; import android.app.KeyguardManager; import android.content.Context; import android.content.DialogInterface; -import android.content.res.ColorStateList; -import android.content.res.Resources; import android.graphics.Color; -import android.graphics.PixelFormat; import android.graphics.drawable.ColorDrawable; +import android.graphics.PixelFormat; import android.media.AudioManager; import android.media.AudioSystem; import android.os.Debug; import android.os.Handler; import android.os.Looper; import android.os.Message; -import android.os.SystemClock; -import android.provider.Settings.Global; import android.util.Log; -import android.util.Slog; import android.util.SparseBooleanArray; import android.view.ContextThemeWrapper; import android.view.Gravity; @@ -45,16 +39,21 @@ import android.view.View; import android.view.ViewGroup; import android.view.Window; import android.view.WindowManager; -import android.view.animation.DecelerateInterpolator; -import android.widget.ImageButton; import android.widget.SeekBar; import android.widget.SeekBar.OnSeekBarChangeListener; +import androidx.car.widget.ListItem; +import androidx.car.widget.ListItemAdapter; +import androidx.car.widget.ListItemAdapter.BackgroundStyle; +import androidx.car.widget.ListItemProvider.ListProvider; +import androidx.car.widget.PagedListView; +import androidx.car.widget.SeekbarListItem; + import java.io.PrintWriter; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; -import com.android.settingslib.Utils; import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.plugins.VolumeDialog; @@ -73,42 +72,61 @@ public class CarVolumeDialogImpl implements VolumeDialog { private static final String TAG = Util.logTag(CarVolumeDialogImpl.class); private static final long USER_ATTEMPT_GRACE_PERIOD = 1000; - private static final int UPDATE_ANIMATION_DURATION = 80; private final Context mContext; private final H mHandler = new H(); private final VolumeDialogController mController; + private final AudioManager mAudioManager; private Window mWindow; private CustomDialog mDialog; private ViewGroup mDialogView; - private ViewGroup mDialogRowsView; + private PagedListView mListView; + private ListItemAdapter mPagedListAdapter; + private final List<ListItem> mVolumeLineItems = new ArrayList<>(); private final List<VolumeRow> mRows = new ArrayList<>(); private ConfigurableTexts mConfigurableTexts; private final SparseBooleanArray mDynamic = new SparseBooleanArray(); private final KeyguardManager mKeyguard; private final Object mSafetyWarningLock = new Object(); - private final ColorStateList mActiveSliderTint; - private final ColorStateList mInactiveSliderTint; private boolean mShowing; - private int mActiveStream; - private int mPrevActiveStream; private boolean mAutomute = VolumePrefs.DEFAULT_ENABLE_AUTOMUTE; private boolean mSilentMode = VolumePrefs.DEFAULT_ENABLE_SILENT_MODE; private State mState; private SafetyWarningDialog mSafetyWarning; private boolean mHovering = false; - private boolean mExpanded = false; - private View mExpandBtn; + private boolean mExpanded; + + private final View.OnClickListener mSupplementalIconListener = v -> { + mExpanded = !mExpanded; + if (mExpanded) { + for (VolumeRow row : mRows) { + // Adding the items which are not coming from default stream. + if (!row.defaultStream) { + addSeekbarListItem(row, null); + } + } + } else { + // Only keeping the default stream if it is not expended. + Iterator itr = mVolumeLineItems.iterator(); + while (itr.hasNext()) { + SeekbarListItem item = (SeekbarListItem) itr.next(); + VolumeRow row = findRow(item); + if (!row.defaultStream) { + itr.remove(); + } + } + } + mPagedListAdapter.notifyDataSetChanged(); + }; public CarVolumeDialogImpl(Context context) { mContext = new ContextThemeWrapper(context, com.android.systemui.R.style.qs_theme); mController = Dependency.get(VolumeDialogController.class); mKeyguard = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE); - mActiveSliderTint = ColorStateList.valueOf(Utils.getColorAccent(mContext)); - mInactiveSliderTint = loadColorStateList(R.color.volume_slider_inactive); + mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); } public void init(int windowType, Callback callback) { @@ -125,11 +143,14 @@ public class CarVolumeDialogImpl implements VolumeDialog { } private void initDialog() { + mRows.clear(); + mVolumeLineItems.clear(); mDialog = new CustomDialog(mContext); mConfigurableTexts = new ConfigurableTexts(mContext); mHovering = false; mShowing = false; + mExpanded = false; mWindow = mDialog.getWindow(); mWindow.requestFeature(Window.FEATURE_NO_TITLE); mWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); @@ -163,12 +184,7 @@ public class CarVolumeDialogImpl implements VolumeDialog { .setInterpolator(new SystemUIInterpolators.LogDecelerateInterpolator()) .start(); }); - mExpandBtn = mDialog.findViewById(R.id.expand); - mExpandBtn.setOnClickListener(v -> { - mExpanded = !mExpanded; - updateRowsH(getActiveRow()); - }); - mDialogView = mDialog.findViewById(R.id.volume_dialog); + mDialogView = (ViewGroup) mDialog.findViewById(R.id.volume_dialog); mDialogView.setOnHoverListener((v, event) -> { int action = event.getActionMasked(); mHovering = (action == MotionEvent.ACTION_HOVER_ENTER) @@ -176,25 +192,20 @@ public class CarVolumeDialogImpl implements VolumeDialog { rescheduleTimeoutH(); return true; }); + mListView = (PagedListView) mWindow.findViewById(R.id.volume_list); - mDialogRowsView = mDialog.findViewById(R.id.car_volume_dialog_rows); - - if (mRows.isEmpty()) { - addRow(AudioManager.STREAM_MUSIC, - R.drawable.ic_volume_media, R.drawable.ic_volume_media_mute, true, true); - addRow(AudioManager.STREAM_RING, - R.drawable.ic_volume_ringer, R.drawable.ic_volume_ringer_mute, true, false); - addRow(AudioManager.STREAM_ALARM, - R.drawable.ic_volume_alarm, R.drawable.ic_volume_alarm_mute, true, false); - } else { - addExistingRows(); - } - - updateRowsH(getActiveRow()); - } + // TODO: apply tint to the supplement icon. + addSeekbarListItem(addVolumeRow(AudioManager.STREAM_MUSIC, R.drawable.ic_volume_media, + R.drawable.car_ic_arrow_drop_up, true, true), mSupplementalIconListener); + addVolumeRow(AudioManager.STREAM_RING, R.drawable.ic_volume_ringer, 0, + true, false); + addVolumeRow(AudioManager.STREAM_ALARM, R.drawable.ic_volume_alarm, 0, + true, false); - private ColorStateList loadColorStateList(int colorResId) { - return ColorStateList.valueOf(mContext.getColor(colorResId)); + mPagedListAdapter = new ListItemAdapter(mContext, new ListProvider(mVolumeLineItems), + BackgroundStyle.PANEL); + mListView.setAdapter(mPagedListAdapter); + mListView.setMaxPages(PagedListView.UNLIMITED_PAGES); } public void setStreamImportant(int stream, boolean important) { @@ -202,65 +213,52 @@ public class CarVolumeDialogImpl implements VolumeDialog { } public void setAutomute(boolean automute) { - if (mAutomute == automute) return; + if (mAutomute == automute) { + return; + } mAutomute = automute; mHandler.sendEmptyMessage(H.RECHECK_ALL); } public void setSilentMode(boolean silentMode) { - if (mSilentMode == silentMode) return; + if (mSilentMode == silentMode) { + return; + } mSilentMode = silentMode; mHandler.sendEmptyMessage(H.RECHECK_ALL); } - private void addRow(int stream, int iconRes, int iconMuteRes, boolean important, - boolean defaultStream) { - addRow(stream, iconRes, iconMuteRes, important, defaultStream, false); - } - - private void addRow(int stream, int iconRes, int iconMuteRes, boolean important, - boolean defaultStream, boolean dynamic) { - if (D.BUG) Slog.d(TAG, "Adding row for stream " + stream); - VolumeRow row = new VolumeRow(); - initRow(row, stream, iconRes, iconMuteRes, important, defaultStream); - mDialogRowsView.addView(row.view); - mRows.add(row); - } - - private void addExistingRows() { - int N = mRows.size(); - for (int i = 0; i < N; i++) { - final VolumeRow row = mRows.get(i); - initRow(row, row.stream, row.iconRes, row.iconMuteRes, row.important, - row.defaultStream); - mDialogRowsView.addView(row.view); - updateVolumeRowH(row); - } - } - - private VolumeRow getActiveRow() { - for (VolumeRow row : mRows) { - if (row.stream == mActiveStream) { - return row; - } + private VolumeRow addVolumeRow(int stream, int primaryActionIcon, int supplementalIcon, + boolean important, boolean defaultStream) { + VolumeRow volumeRow = new VolumeRow(); + volumeRow.stream = stream; + volumeRow.primaryActionIcon = primaryActionIcon; + volumeRow.supplementalIcon = supplementalIcon; + volumeRow.important = important; + volumeRow.defaultStream = defaultStream; + volumeRow.listItem = null; + mRows.add(volumeRow); + return volumeRow; + } + + private SeekbarListItem addSeekbarListItem( + VolumeRow volumeRow, @Nullable View.OnClickListener supplementalIconOnClickListener) { + int volumeMax = mAudioManager.getStreamMaxVolume(volumeRow.stream); + int currentVolume = mAudioManager.getStreamVolume(volumeRow.stream); + SeekbarListItem listItem = + new SeekbarListItem(mContext, volumeMax, currentVolume, + new VolumeSeekBarChangeListener(volumeRow), null); + listItem.setPrimaryActionIcon(volumeRow.primaryActionIcon); + if (volumeRow.supplementalIcon != 0) { + listItem.setSupplementalIcon(volumeRow.supplementalIcon, true, supplementalIconOnClickListener); + } else { + listItem.setSupplementalEmptyIcon(true); } - return mRows.get(0); - } - private VolumeRow findRow(int stream) { - for (VolumeRow row : mRows) { - if (row.stream == stream) return row; - } - return null; - } + mVolumeLineItems.add(listItem); + volumeRow.listItem = listItem; - public void dump(PrintWriter writer) { - writer.println(VolumeDialogImpl.class.getSimpleName() + " state:"); - writer.print(" mShowing: "); writer.println(mShowing); - writer.print(" mActiveStream: "); writer.println(mActiveStream); - writer.print(" mDynamic: "); writer.println(mDynamic); - writer.print(" mAutomute: "); writer.println(mAutomute); - writer.print(" mSilentMode: "); writer.println(mSilentMode); + return listItem; } private static int getImpliedLevel(SeekBar seekBar, int progress) { @@ -271,25 +269,6 @@ public class CarVolumeDialogImpl implements VolumeDialog { return level; } - @SuppressLint("InflateParams") - private void initRow(final VolumeRow row, final int stream, int iconRes, int iconMuteRes, - boolean important, boolean defaultStream) { - row.stream = stream; - row.iconRes = iconRes; - row.iconMuteRes = iconMuteRes; - row.important = important; - row.defaultStream = defaultStream; - row.view = mDialog.getLayoutInflater().inflate(R.layout.car_volume_dialog_row, null); - row.view.setId(row.stream); - row.view.setTag(row); - row.slider = row.view.findViewById(R.id.volume_row_slider); - row.slider.setOnSeekBarChangeListener(new VolumeSeekBarChangeListener(row)); - row.anim = null; - - row.icon = row.view.findViewById(R.id.volume_row_icon); - row.icon.setImageResource(iconRes); - } - public void show(int reason) { mHandler.obtainMessage(H.SHOW, reason, 0).sendToTarget(); } @@ -356,243 +335,87 @@ public class CarVolumeDialogImpl implements VolumeDialog { } } - private boolean shouldBeVisibleH(VolumeRow row) { - if (mExpanded) { - return true; - } - return row.defaultStream; - } - - private void updateRowsH(final VolumeRow activeRow) { - if (D.BUG) Log.d(TAG, "updateRowsH"); - if (!mShowing) { - trimObsoleteH(); - } - // apply changes to all rows - for (final VolumeRow row : mRows) { - final boolean isActive = row == activeRow; - final boolean shouldBeVisible = shouldBeVisibleH(row); - Util.setVisOrGone(row.view, shouldBeVisible); - if (row.view.isShown()) { - updateVolumeRowSliderTintH(row, isActive); - } - } - } - private void trimObsoleteH() { - if (D.BUG) Log.d(TAG, "trimObsoleteH"); + int initialVolumeItemSize = mVolumeLineItems.size(); for (int i = mRows.size() - 1; i >= 0; i--) { final VolumeRow row = mRows.get(i); if (row.ss == null || !row.ss.dynamic) continue; if (!mDynamic.get(row.stream)) { mRows.remove(i); - mDialogRowsView.removeView(row.view); + mVolumeLineItems.remove(row.listItem); } } + + if (mVolumeLineItems.size() != initialVolumeItemSize) { + mPagedListAdapter.notifyDataSetChanged(); + } } - protected void onStateChangedH(State state) { + private void onStateChangedH(State state) { mState = state; mDynamic.clear(); // add any new dynamic rows for (int i = 0; i < state.states.size(); i++) { final int stream = state.states.keyAt(i); final StreamState ss = state.states.valueAt(i); - if (!ss.dynamic) continue; + if (!ss.dynamic) { + continue; + } mDynamic.put(stream, true); if (findRow(stream) == null) { - addRow(stream, R.drawable.ic_volume_remote, R.drawable.ic_volume_remote_mute, true, - false, true); + VolumeRow row = addVolumeRow(stream, R.drawable.ic_volume_remote, + 0, true,false); + if (mExpanded) { + addSeekbarListItem(row, null); + } } } - if (mActiveStream != state.activeStream) { - mPrevActiveStream = mActiveStream; - mActiveStream = state.activeStream; - updateRowsH(getActiveRow()); - rescheduleTimeoutH(); - } for (VolumeRow row : mRows) { updateVolumeRowH(row); } - } private void updateVolumeRowH(VolumeRow row) { if (D.BUG) Log.d(TAG, "updateVolumeRowH s=" + row.stream); - if (mState == null) return; + if (mState == null) { + return; + } final StreamState ss = mState.states.get(row.stream); - if (ss == null) return; - row.ss = ss; - if (ss.level > 0) { - row.lastAudibleLevel = ss.level; + if (ss == null) { + return; } + row.ss = ss; if (ss.level == row.requestedLevel) { row.requestedLevel = -1; } - final boolean isRingStream = row.stream == AudioManager.STREAM_RING; - final boolean isSystemStream = row.stream == AudioManager.STREAM_SYSTEM; - final boolean isAlarmStream = row.stream == AudioManager.STREAM_ALARM; - final boolean isMusicStream = row.stream == AudioManager.STREAM_MUSIC; - final boolean isRingVibrate = isRingStream - && mState.ringerModeInternal == AudioManager.RINGER_MODE_VIBRATE; - final boolean isRingSilent = isRingStream - && mState.ringerModeInternal == AudioManager.RINGER_MODE_SILENT; - final boolean isZenPriorityOnly = mState.zenMode == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; - final boolean isZenAlarms = mState.zenMode == Global.ZEN_MODE_ALARMS; - final boolean isZenNone = mState.zenMode == Global.ZEN_MODE_NO_INTERRUPTIONS; - final boolean zenMuted = isZenAlarms ? (isRingStream || isSystemStream) - : isZenNone ? (isRingStream || isSystemStream || isAlarmStream || isMusicStream) - : isZenPriorityOnly ? ((isAlarmStream && mState.disallowAlarms) || - (isMusicStream && mState.disallowMedia) || - (isRingStream && mState.disallowRinger) || - (isSystemStream && mState.disallowSystem)) - : false; - - // update slider max - final int max = ss.levelMax * 100; - if (max != row.slider.getMax()) { - row.slider.setMax(max); - } - - // update icon - final boolean iconEnabled = (mAutomute || ss.muteSupported) && !zenMuted; - row.icon.setEnabled(iconEnabled); - row.icon.setAlpha(iconEnabled ? 1 : 0.5f); - final int iconRes = - isRingVibrate ? R.drawable.ic_volume_ringer_vibrate - : isRingSilent || zenMuted ? row.iconMuteRes - : ss.routedToBluetooth ? - (ss.muted ? R.drawable.ic_volume_media_bt_mute - : R.drawable.ic_volume_media_bt) - : mAutomute && ss.level == 0 ? row.iconMuteRes - : (ss.muted ? row.iconMuteRes : row.iconRes); - row.icon.setImageResource(iconRes); - row.iconState = - iconRes == R.drawable.ic_volume_ringer_vibrate ? Events.ICON_STATE_VIBRATE - : (iconRes == R.drawable.ic_volume_media_bt_mute || iconRes == row.iconMuteRes) - ? Events.ICON_STATE_MUTE - : (iconRes == R.drawable.ic_volume_media_bt || iconRes == row.iconRes) - ? Events.ICON_STATE_UNMUTE - : Events.ICON_STATE_UNKNOWN; - if (iconEnabled) { - if (isRingStream) { - if (isRingVibrate) { - row.icon.setContentDescription(mContext.getString( - R.string.volume_stream_content_description_unmute, - getStreamLabelH(ss))); - } else { - if (mController.hasVibrator()) { - row.icon.setContentDescription(mContext.getString( - R.string.volume_stream_content_description_vibrate, - getStreamLabelH(ss))); - } else { - row.icon.setContentDescription(mContext.getString( - R.string.volume_stream_content_description_mute, - getStreamLabelH(ss))); - } - } - } else { - if (ss.muted || mAutomute && ss.level == 0) { - row.icon.setContentDescription(mContext.getString( - R.string.volume_stream_content_description_unmute, - getStreamLabelH(ss))); - } else { - row.icon.setContentDescription(mContext.getString( - R.string.volume_stream_content_description_mute, - getStreamLabelH(ss))); - } - } - } else { - row.icon.setContentDescription(getStreamLabelH(ss)); - } - - // ensure tracking is disabled if zenMuted - if (zenMuted) { - row.tracking = false; - } - - // update slider - final boolean enableSlider = !zenMuted; - final int vlevel = row.ss.muted && (!isRingStream && !zenMuted) ? 0 - : row.ss.level; - updateVolumeRowSliderH(row, enableSlider, vlevel); + // TODO: update Seekbar progress and change the mute icon if necessary. } - private String getStreamLabelH(StreamState ss) { - if (ss.remoteLabel != null) { - return ss.remoteLabel; - } - try { - return mContext.getResources().getString(ss.name); - } catch (Resources.NotFoundException e) { - Slog.e(TAG, "Can't find translation for stream " + ss); - return ""; + private VolumeRow findRow(int stream) { + for (VolumeRow row : mRows) { + if (row.stream == stream) { + return row; + } } + return null; } - private void updateVolumeRowSliderTintH(VolumeRow row, boolean isActive) { - if (isActive) { - row.slider.requestFocus(); + private VolumeRow findRow(SeekbarListItem targetItem) { + for (VolumeRow row : mRows) { + if (row.listItem == targetItem) { + return row; + } } - final ColorStateList tint = isActive && row.slider.isEnabled() ? mActiveSliderTint - : mInactiveSliderTint; - if (tint == row.cachedSliderTint) return; - row.cachedSliderTint = tint; - row.slider.setProgressTintList(tint); - row.slider.setThumbTintList(tint); + return null; } - private void updateVolumeRowSliderH(VolumeRow row, boolean enable, int vlevel) { - row.slider.setEnabled(enable); - updateVolumeRowSliderTintH(row, row.stream == mActiveStream); - if (row.tracking) { - return; // don't update if user is sliding - } - final int progress = row.slider.getProgress(); - final int level = getImpliedLevel(row.slider, progress); - final boolean rowVisible = row.view.getVisibility() == View.VISIBLE; - final boolean inGracePeriod = (SystemClock.uptimeMillis() - row.userAttempt) - < USER_ATTEMPT_GRACE_PERIOD; - mHandler.removeMessages(H.RECHECK, row); - if (mShowing && rowVisible && inGracePeriod) { - if (D.BUG) Log.d(TAG, "inGracePeriod"); - mHandler.sendMessageAtTime(mHandler.obtainMessage(H.RECHECK, row), - row.userAttempt + USER_ATTEMPT_GRACE_PERIOD); - return; // don't update if visible and in grace period - } - if (vlevel == level) { - if (mShowing && rowVisible) { - return; // don't clamp if visible - } - } - final int newProgress = vlevel * 100; - if (progress != newProgress) { - if (mShowing && rowVisible) { - // animate! - if (row.anim != null && row.anim.isRunning() - && row.animTargetProgress == newProgress) { - return; // already animating to the target progress - } - // start/update animation - if (row.anim == null) { - row.anim = ObjectAnimator.ofInt(row.slider, "progress", progress, newProgress); - row.anim.setInterpolator(new DecelerateInterpolator()); - } else { - row.anim.cancel(); - row.anim.setIntValues(progress, newProgress); - } - row.animTargetProgress = newProgress; - row.anim.setDuration(UPDATE_ANIMATION_DURATION); - row.anim.start(); - } else { - // update slider directly to clamped value - if (row.anim != null) { - row.anim.cancel(); - } - row.slider.setProgress(newProgress, true); - } - } + public void dump(PrintWriter writer) { + writer.println(VolumeDialogImpl.class.getSimpleName() + " state:"); + writer.print(" mShowing: "); writer.println(mShowing); + writer.print(" mDynamic: "); writer.println(mDynamic); + writer.print(" mAutomute: "); writer.println(mAutomute); + writer.print(" mSilentMode: "); writer.println(mSilentMode); } private void recheckH(VolumeRow row) { @@ -641,7 +464,7 @@ public class CarVolumeDialogImpl implements VolumeDialog { } private final VolumeDialogController.Callbacks mControllerCallbackH - = new VolumeDialogController.Callbacks() { + = new VolumeDialogController.Callbacks() { @Override public void onShowRequested(int reason) { showH(reason); @@ -763,18 +586,24 @@ public class CarVolumeDialogImpl implements VolumeDialog { private final class VolumeSeekBarChangeListener implements OnSeekBarChangeListener { private final VolumeRow mRow; - private VolumeSeekBarChangeListener(VolumeRow row) { - mRow = row; + private VolumeSeekBarChangeListener(VolumeRow volumeRow) { + mRow = volumeRow; } @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { - if (mRow.ss == null) return; - if (D.BUG) Log.d(TAG, AudioSystem.streamToString(mRow.stream) - + " onProgressChanged " + progress + " fromUser=" + fromUser); - if (!fromUser) return; + if (mRow.ss == null) { + return; + } + if (D.BUG) { + Log.d(TAG, AudioSystem.streamToString(mRow.stream) + + " onProgressChanged " + progress + " fromUser=" + fromUser); + } + if (!fromUser) { + return; + } if (mRow.ss.levelMin > 0) { - final int minProgress = mRow.ss.levelMin * 100; + final int minProgress = mRow.ss.levelMin; if (progress < minProgress) { seekBar.setProgress(minProgress); progress = minProgress; @@ -782,7 +611,6 @@ public class CarVolumeDialogImpl implements VolumeDialog { } final int userLevel = getImpliedLevel(seekBar, progress); if (mRow.ss.level != userLevel || mRow.ss.muted && userLevel > 0) { - mRow.userAttempt = SystemClock.uptimeMillis(); if (mRow.requestedLevel != userLevel) { mController.setStreamVolume(mRow.stream, userLevel); mRow.requestedLevel = userLevel; @@ -794,16 +622,17 @@ public class CarVolumeDialogImpl implements VolumeDialog { @Override public void onStartTrackingTouch(SeekBar seekBar) { - if (D.BUG) Log.d(TAG, "onStartTrackingTouch"+ " " + mRow.stream); + if (D.BUG) { + Log.d(TAG, "onStartTrackingTouch"+ " " + mRow.stream); + } mController.setActiveStream(mRow.stream); - mRow.tracking = true; } @Override public void onStopTrackingTouch(SeekBar seekBar) { - if (D.BUG) Log.d(TAG, "onStopTrackingTouch"+ " " + mRow.stream); - mRow.tracking = false; - mRow.userAttempt = SystemClock.uptimeMillis(); + if (D.BUG) { + Log.d(TAG, "onStopTrackingTouch"+ " " + mRow.stream); + } final int userLevel = getImpliedLevel(seekBar, seekBar.getProgress()); Events.writeEvent(mContext, Events.EVENT_TOUCH_LEVEL_DONE, mRow.stream, userLevel); if (mRow.ss.level != userLevel) { @@ -814,22 +643,13 @@ public class CarVolumeDialogImpl implements VolumeDialog { } private static class VolumeRow { - private View view; - private ImageButton icon; - private SeekBar slider; private int stream; private StreamState ss; - private long userAttempt; // last user-driven slider change - private boolean tracking; // tracking slider touch - private int requestedLevel = -1; // pending user-requested level via progress changed - private int iconRes; - private int iconMuteRes; private boolean important; private boolean defaultStream; - private ColorStateList cachedSliderTint; - private int iconState; // from Events - private ObjectAnimator anim; // slider progress animation for non-touch-related updates - private int animTargetProgress; - private int lastAudibleLevel = 1; + private int primaryActionIcon; + private int supplementalIcon; + private SeekbarListItem listItem; + private int requestedLevel = -1; // pending user-requested level via progress changed } }
\ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLoggerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLoggerTest.java index 726810e3e177..14fada5b7cd0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLoggerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLoggerTest.java @@ -93,7 +93,7 @@ public class NotificationLoggerTest extends SysuiTestCase { waitForUiOffloadThread(); NotificationVisibility[] newlyVisibleKeys = { - NotificationVisibility.obtain(mEntry.key, 0, true) + NotificationVisibility.obtain(mEntry.key, 0, 1, true) }; NotificationVisibility[] noLongerVisibleKeys = {}; verify(mBarService).onNotificationVisibilityChanged(newlyVisibleKeys, noLongerVisibleKeys); diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto index 93de08cee5c6..1f1ed59f72ef 100644 --- a/proto/src/metrics_constants.proto +++ b/proto/src/metrics_constants.proto @@ -5664,6 +5664,10 @@ message MetricsEvent { // OS: P BLUETOOTH_FRAGMENT = 1390; + // This value should never appear in log outputs - it is reserved for + // internal platform metrics use. + NOTIFICATION_SHADE_COUNT = 1395; + // ---- End P Constants, all P constants go above this line ---- // Add new aosp constants above this line. // END OF AOSP CONSTANTS diff --git a/services/core/java/com/android/server/EventLogTags.logtags b/services/core/java/com/android/server/EventLogTags.logtags index 48bb409e8975..2465ba2e21bd 100644 --- a/services/core/java/com/android/server/EventLogTags.logtags +++ b/services/core/java/com/android/server/EventLogTags.logtags @@ -72,11 +72,11 @@ option java_package com.android.server # when notifications are expanded, or contracted 27511 notification_expansion (key|3),(user_action|1),(expanded|1),(lifespan|1),(freshness|1),(exposure|1) # when a notification has been clicked -27520 notification_clicked (key|3),(lifespan|1),(freshness|1),(exposure|1) +27520 notification_clicked (key|3),(lifespan|1),(freshness|1),(exposure|1),(rank|1),(count|1) # when a notification action button has been clicked -27521 notification_action_clicked (key|3),(action_index|1),(lifespan|1),(freshness|1),(exposure|1) +27521 notification_action_clicked (key|3),(action_index|1),(lifespan|1),(freshness|1),(exposure|1),(rank|1),(count|1) # when a notification has been canceled -27530 notification_canceled (key|3),(reason|1),(lifespan|1),(freshness|1),(exposure|1),(listener|3) +27530 notification_canceled (key|3),(reason|1),(lifespan|1),(freshness|1),(exposure|1),(rank|1),(count|1),(listener|3) # replaces 27510 with a row per notification 27531 notification_visibility (key|3),(visibile|1),(lifespan|1),(freshness|1),(exposure|1),(rank|1) # a notification emited noise, vibration, or light diff --git a/services/core/java/com/android/server/notification/NotificationDelegate.java b/services/core/java/com/android/server/notification/NotificationDelegate.java index b61a27ac6c6d..8be8450b3413 100644 --- a/services/core/java/com/android/server/notification/NotificationDelegate.java +++ b/services/core/java/com/android/server/notification/NotificationDelegate.java @@ -23,11 +23,14 @@ import com.android.internal.statusbar.NotificationVisibility; public interface NotificationDelegate { void onSetDisabled(int status); void onClearAll(int callingUid, int callingPid, int userId); - void onNotificationClick(int callingUid, int callingPid, String key); - void onNotificationActionClick(int callingUid, int callingPid, String key, int actionIndex); + void onNotificationClick(int callingUid, int callingPid, String key, + NotificationVisibility nv); + void onNotificationActionClick(int callingUid, int callingPid, String key, int actionIndex, + NotificationVisibility nv); void onNotificationClear(int callingUid, int callingPid, String pkg, String tag, int id, int userId, String key, - @NotificationStats.DismissalSurface int dismissalSurface); + @NotificationStats.DismissalSurface int dismissalSurface, + NotificationVisibility nv); void onNotificationError(int callingUid, int callingPid, String pkg, String tag, int id, int uid, int initialPid, String message, int userId); diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 8a6430869288..aee4d28b8001 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -693,7 +693,7 @@ public class NotificationManagerService extends SystemService { } @Override - public void onNotificationClick(int callingUid, int callingPid, String key) { + public void onNotificationClick(int callingUid, int callingPid, String key, NotificationVisibility nv) { exitIdle(); synchronized (mNotificationLock) { NotificationRecord r = mNotificationsByKey.get(key); @@ -704,22 +704,26 @@ public class NotificationManagerService extends SystemService { final long now = System.currentTimeMillis(); MetricsLogger.action(r.getLogMaker(now) .setCategory(MetricsEvent.NOTIFICATION_ITEM) - .setType(MetricsEvent.TYPE_ACTION)); + .setType(MetricsEvent.TYPE_ACTION) + .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, nv.rank) + .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, nv.count)); EventLogTags.writeNotificationClicked(key, - r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now)); + r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now), + nv.rank, nv.count); StatusBarNotification sbn = r.sbn; cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(), sbn.getId(), Notification.FLAG_AUTO_CANCEL, Notification.FLAG_FOREGROUND_SERVICE, false, r.getUserId(), - REASON_CLICK, null); + REASON_CLICK, nv.rank, nv.count, null); + nv.recycle(); reportUserInteraction(r); } } @Override public void onNotificationActionClick(int callingUid, int callingPid, String key, - int actionIndex) { + int actionIndex, NotificationVisibility nv) { exitIdle(); synchronized (mNotificationLock) { NotificationRecord r = mNotificationsByKey.get(key); @@ -731,9 +735,13 @@ public class NotificationManagerService extends SystemService { MetricsLogger.action(r.getLogMaker(now) .setCategory(MetricsEvent.NOTIFICATION_ITEM_ACTION) .setType(MetricsEvent.TYPE_ACTION) - .setSubtype(actionIndex)); + .setSubtype(actionIndex) + .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, nv.rank) + .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, nv.count)); EventLogTags.writeNotificationActionClicked(key, actionIndex, - r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now)); + r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now), + nv.rank, nv.count); + nv.recycle(); reportUserInteraction(r); } } @@ -741,7 +749,8 @@ public class NotificationManagerService extends SystemService { @Override public void onNotificationClear(int callingUid, int callingPid, String pkg, String tag, int id, int userId, String key, - @NotificationStats.DismissalSurface int dismissalSurface) { + @NotificationStats.DismissalSurface int dismissalSurface, + NotificationVisibility nv) { synchronized (mNotificationLock) { NotificationRecord r = mNotificationsByKey.get(key); if (r != null) { @@ -750,7 +759,8 @@ public class NotificationManagerService extends SystemService { } cancelNotification(callingUid, callingPid, pkg, tag, id, 0, Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE, - true, userId, REASON_CANCEL, null); + true, userId, REASON_CANCEL, nv.rank, nv.count,null); + nv.recycle(); } @Override @@ -810,7 +820,7 @@ public class NotificationManagerService extends SystemService { mMetricsLogger.write(logMaker); } } - r.setVisibility(true, nv.rank); + r.setVisibility(true, nv.rank, nv.count); nv.recycle(); } // Note that we might receive this event after notifications @@ -820,7 +830,7 @@ public class NotificationManagerService extends SystemService { for (NotificationVisibility nv : noLongerVisibleKeys) { NotificationRecord r = mNotificationsByKey.get(nv.key); if (r == null) continue; - r.setVisibility(false, nv.rank); + r.setVisibility(false, nv.rank, nv.count); nv.recycle(); } } @@ -5289,6 +5299,12 @@ public class NotificationManagerService extends SystemService { @GuardedBy("mNotificationLock") private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason, boolean wasPosted, String listenerName) { + cancelNotificationLocked(r, sendDelete, reason, -1, -1, wasPosted, listenerName); + } + + @GuardedBy("mNotificationLock") + private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason, + int rank, int count, boolean wasPosted, String listenerName) { final String canceledKey = r.getKey(); // Record caller. @@ -5390,12 +5406,18 @@ public class NotificationManagerService extends SystemService { mArchive.record(r.sbn); final long now = System.currentTimeMillis(); - MetricsLogger.action(r.getLogMaker(now) + final LogMaker logMaker = r.getLogMaker(now) .setCategory(MetricsEvent.NOTIFICATION_ITEM) .setType(MetricsEvent.TYPE_DISMISS) - .setSubtype(reason)); + .setSubtype(reason); + if (rank != -1 && count != -1) { + logMaker.addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, rank) + .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, count); + } + MetricsLogger.action(logMaker); EventLogTags.writeNotificationCanceled(canceledKey, reason, - r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now), listenerName); + r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now), + rank, count, listenerName); } void revokeUriPermissions(NotificationRecord newRecord, NotificationRecord oldRecord) { @@ -5430,6 +5452,18 @@ public class NotificationManagerService extends SystemService { final String pkg, final String tag, final int id, final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete, final int userId, final int reason, final ManagedServiceInfo listener) { + cancelNotification(callingUid, callingPid, pkg, tag, id, mustHaveFlags, mustNotHaveFlags, + sendDelete, userId, reason, -1 /* rank */, -1 /* count */, listener); + } + + /** + * Cancels a notification ONLY if it has all of the {@code mustHaveFlags} + * and none of the {@code mustNotHaveFlags}. + */ + void cancelNotification(final int callingUid, final int callingPid, + final String pkg, final String tag, final int id, + final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete, + final int userId, final int reason, int rank, int count, final ManagedServiceInfo listener) { // In enqueueNotificationInternal notifications are added by scheduling the // work on the worker handler. Hence, we also schedule the cancel on this @@ -5463,7 +5497,7 @@ public class NotificationManagerService extends SystemService { // Cancel the notification. boolean wasPosted = removeFromNotificationListsLocked(r); - cancelNotificationLocked(r, sendDelete, reason, wasPosted, listenerName); + cancelNotificationLocked(r, sendDelete, reason, rank, count, wasPosted, listenerName); cancelGroupChildrenLocked(r, callingUid, callingPid, listenerName, sendDelete, null); updateLightsLocked(); diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java index 9745be3c5c2f..57af2ceef594 100644 --- a/services/core/java/com/android/server/notification/NotificationRecord.java +++ b/services/core/java/com/android/server/notification/NotificationRecord.java @@ -778,14 +778,15 @@ public final class NotificationRecord { /** * Set the visibility of the notification. */ - public void setVisibility(boolean visible, int rank) { + public void setVisibility(boolean visible, int rank, int count) { final long now = System.currentTimeMillis(); mVisibleSinceMs = visible ? now : mVisibleSinceMs; stats.onVisibilityChanged(visible); MetricsLogger.action(getLogMaker(now) .setCategory(MetricsEvent.NOTIFICATION_ITEM) .setType(visible ? MetricsEvent.TYPE_OPEN : MetricsEvent.TYPE_CLOSE) - .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, rank)); + .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, rank) + .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, count)); if (visible) { setSeen(); MetricsLogger.histogram(mContext, "note_freshness", getFreshnessMs(now)); diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index 36fa868ba0e4..738b0ca4a74f 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -1000,27 +1000,27 @@ public class StatusBarManagerService extends IStatusBarService.Stub { } @Override - public void onNotificationClick(String key) { + public void onNotificationClick(String key, NotificationVisibility nv) { enforceStatusBarService(); final int callingUid = Binder.getCallingUid(); final int callingPid = Binder.getCallingPid(); long identity = Binder.clearCallingIdentity(); try { - mNotificationDelegate.onNotificationClick(callingUid, callingPid, key); + mNotificationDelegate.onNotificationClick(callingUid, callingPid, key, nv); } finally { Binder.restoreCallingIdentity(identity); } } @Override - public void onNotificationActionClick(String key, int actionIndex) { + public void onNotificationActionClick(String key, int actionIndex, NotificationVisibility nv) { enforceStatusBarService(); final int callingUid = Binder.getCallingUid(); final int callingPid = Binder.getCallingPid(); long identity = Binder.clearCallingIdentity(); try { mNotificationDelegate.onNotificationActionClick(callingUid, callingPid, key, - actionIndex); + actionIndex, nv); } finally { Binder.restoreCallingIdentity(identity); } @@ -1044,14 +1044,14 @@ public class StatusBarManagerService extends IStatusBarService.Stub { @Override public void onNotificationClear(String pkg, String tag, int id, int userId, String key, - @NotificationStats.DismissalSurface int dismissalSurface) { + @NotificationStats.DismissalSurface int dismissalSurface, NotificationVisibility nv) { enforceStatusBarService(); final int callingUid = Binder.getCallingUid(); final int callingPid = Binder.getCallingPid(); long identity = Binder.clearCallingIdentity(); try { - mNotificationDelegate.onNotificationClear( - callingUid, callingPid, pkg, tag, id, userId, key, dismissalSurface); + mNotificationDelegate.onNotificationClear(callingUid, callingPid, pkg, tag, id, userId, + key, dismissalSurface, nv); } finally { Binder.restoreCallingIdentity(identity); } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java index 9d5d263ad5af..1a9b7db3c8b4 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -2335,7 +2335,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); mService.addNotification(r); - NotificationVisibility nv = NotificationVisibility.obtain(r.getKey(), 1, true); + final NotificationVisibility nv = NotificationVisibility.obtain(r.getKey(), 1, 2, true); mService.mNotificationDelegate.onNotificationVisibilityChanged( new NotificationVisibility[] {nv}, new NotificationVisibility[]{}); assertTrue(mService.getNotificationRecord(r.getKey()).getStats().hasSeen()); @@ -2349,8 +2349,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); mService.addNotification(r); + final NotificationVisibility nv = NotificationVisibility.obtain(r.getKey(), 0, 1, true); mService.mNotificationDelegate.onNotificationClear(mUid, 0, PKG, r.sbn.getTag(), - r.sbn.getId(), r.getUserId(), r.getKey(), NotificationStats.DISMISSAL_AOD); + r.sbn.getId(), r.getUserId(), r.getKey(), NotificationStats.DISMISSAL_AOD, nv); waitForIdle(); assertEquals(NotificationStats.DISMISSAL_AOD, r.getStats().getDismissalSurface()); |