diff options
50 files changed, 877 insertions, 344 deletions
diff --git a/apex/media/framework/java/android/media/MediaParser.java b/apex/media/framework/java/android/media/MediaParser.java index d22e998f6cab..a9ed6d82b873 100644 --- a/apex/media/framework/java/android/media/MediaParser.java +++ b/apex/media/framework/java/android/media/MediaParser.java @@ -1288,7 +1288,11 @@ public final class MediaParser { } @Override - public int sampleData(DataReader input, int length, boolean allowEndOfInput) + public int sampleData( + DataReader input, + int length, + boolean allowEndOfInput, + @SampleDataPart int sampleDataPart) throws IOException { mScratchDataReaderAdapter.setDataReader(input, length); long positionBeforeReading = mScratchDataReaderAdapter.getPosition(); @@ -1297,7 +1301,8 @@ public final class MediaParser { } @Override - public void sampleData(ParsableByteArray data, int length) { + public void sampleData( + ParsableByteArray data, int length, @SampleDataPart int sampleDataPart) { mScratchParsableByteArrayAdapter.resetWithByteArray(data, length); try { mOutputConsumer.onSampleDataFound(mTrackIndex, mScratchParsableByteArrayAdapter); diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index 674978b50d91..9a73fddebad4 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -427,6 +427,7 @@ message Atom { AccessibilityShortcutReported accessibility_shortcut_reported = 266 [(module) = "framework"]; AccessibilityServiceReported accessibility_service_reported = 267 [(module) = "settings"]; + DocsUIDragAndDropReported docs_ui_drag_and_drop_reported = 268 [(module) = "docsui"]; SdkExtensionStatus sdk_extension_status = 354; // StatsdStats tracks platform atoms with ids upto 500. @@ -6481,6 +6482,15 @@ message DocsUIPickResultReported { optional int32 repeatedly_pick_times = 7; } +/** Logs the drag and drop of files. + + * Logged from: + * package/app/DocumentsUI/src/com/android/documentsui/Metrics.java + */ +message DocsUIDragAndDropReported { + optional bool drag_initiated_from_docsui = 1; +} + /** * Logs when an app's memory is compacted. * diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index d1b6efd3e23a..49cc621cf2b2 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -1719,31 +1719,50 @@ public class ActivityManager { configuration.windowConfiguration.getActivityType()); pw.println(); pw.print(" "); - pw.print(" id=" + persistentId); - pw.print(" stackId=" + stackId); - pw.print(" userId=" + userId); - pw.print(" hasTask=" + (id != -1)); - pw.print(" lastActiveTime=" + lastActiveTime); - pw.println(); pw.print(" "); - pw.print(" baseIntent=" + baseIntent); - pw.println(); pw.print(" "); - pw.print(" isExcluded=" - + ((baseIntent.getFlags() & FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) != 0)); - pw.print(" activityType=" + activityType); - pw.print(" windowingMode=" + windowingMode); - pw.print(" supportsSplitScreenMultiWindow=" + supportsSplitScreenMultiWindow); + pw.print(" id="); pw.print(persistentId); + pw.print(" stackId="); pw.print(stackId); + pw.print(" userId="); pw.print(userId); + pw.print(" hasTask="); pw.print((id != -1)); + pw.print(" lastActiveTime="); pw.println(lastActiveTime); + pw.print(" "); pw.print(" baseIntent="); pw.println(baseIntent); + if (baseActivity != null) { + pw.print(" "); pw.print(" baseActivity="); + pw.println(baseActivity.toShortString()); + } + if (topActivity != null) { + pw.print(" "); pw.print(" topActivity="); pw.println(topActivity.toShortString()); + } + if (origActivity != null) { + pw.print(" "); pw.print(" origActivity="); + pw.println(origActivity.toShortString()); + } + if (realActivity != null) { + pw.print(" "); pw.print(" realActivity="); + pw.println(realActivity.toShortString()); + } + pw.print(" "); + pw.print(" isExcluded="); + pw.print(((baseIntent.getFlags() & FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) != 0)); + pw.print(" activityType="); pw.print(activityType); + pw.print(" windowingMode="); pw.print(windowingMode); + pw.print(" supportsSplitScreenMultiWindow="); + pw.println(supportsSplitScreenMultiWindow); if (taskDescription != null) { - pw.println(); pw.print(" "); + pw.print(" "); final ActivityManager.TaskDescription td = taskDescription; pw.print(" taskDescription {"); - pw.print(" colorBackground=#" + Integer.toHexString(td.getBackgroundColor())); - pw.print(" colorPrimary=#" + Integer.toHexString(td.getPrimaryColor())); - pw.print(" iconRes=" + td.getIconResourcePackage() + "/" + td.getIconResource()); - pw.print(" iconBitmap=" + (td.getIconFilename() != null - || td.getInMemoryIcon() != null)); - pw.print(" resizeMode=" + ActivityInfo.resizeModeToString(td.getResizeMode())); - pw.print(" minWidth=" + td.getMinWidth()); - pw.print(" minHeight=" + td.getMinHeight()); + pw.print(" colorBackground=#"); + pw.print(Integer.toHexString(td.getBackgroundColor())); + pw.print(" colorPrimary=#"); + pw.print(Integer.toHexString(td.getPrimaryColor())); + pw.print(" iconRes="); + pw.print(td.getIconResourcePackage() + "/" + td.getIconResource()); + pw.print(" iconBitmap="); + pw.print(td.getIconFilename() != null || td.getInMemoryIcon() != null); + pw.print(" resizeMode="); + pw.print(ActivityInfo.resizeModeToString(td.getResizeMode())); + pw.print(" minWidth="); pw.print(td.getMinWidth()); + pw.print(" minHeight="); pw.print(td.getMinHeight()); pw.println(" }"); } } diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java index aba74e518a22..ed56b4398c22 100755 --- a/media/java/android/mtp/MtpDatabase.java +++ b/media/java/android/mtp/MtpDatabase.java @@ -165,6 +165,7 @@ public class MtpDatabase implements AutoCloseable { MtpConstants.PROPERTY_TRACK, MtpConstants.PROPERTY_ORIGINAL_RELEASE_DATE, MtpConstants.PROPERTY_DURATION, + MtpConstants.PROPERTY_GENRE, MtpConstants.PROPERTY_COMPOSER, MtpConstants.PROPERTY_AUDIO_WAVE_CODEC, MtpConstants.PROPERTY_BITRATE_TYPE, diff --git a/media/java/android/mtp/MtpPropertyGroup.java b/media/java/android/mtp/MtpPropertyGroup.java index 5bb0c1b4ef27..aff2e1b4cf31 100644 --- a/media/java/android/mtp/MtpPropertyGroup.java +++ b/media/java/android/mtp/MtpPropertyGroup.java @@ -122,15 +122,21 @@ class MtpPropertyGroup { type = MtpConstants.TYPE_STR; break; case MtpConstants.PROPERTY_ARTIST: + column = Audio.AudioColumns.ARTIST; type = MtpConstants.TYPE_STR; break; case MtpConstants.PROPERTY_ALBUM_NAME: + column = Audio.AudioColumns.ALBUM; type = MtpConstants.TYPE_STR; break; case MtpConstants.PROPERTY_ALBUM_ARTIST: column = Audio.AudioColumns.ALBUM_ARTIST; type = MtpConstants.TYPE_STR; break; + case MtpConstants.PROPERTY_GENRE: + column = Audio.AudioColumns.GENRE; + type = MtpConstants.TYPE_STR; + break; case MtpConstants.PROPERTY_COMPOSER: column = Audio.AudioColumns.COMPOSER; type = MtpConstants.TYPE_STR; diff --git a/packages/SystemUI/res/layout/controls_app_item.xml b/packages/SystemUI/res/layout/controls_app_item.xml index d54cd6db867a..a208098b59c9 100644 --- a/packages/SystemUI/res/layout/controls_app_item.xml +++ b/packages/SystemUI/res/layout/controls_app_item.xml @@ -16,33 +16,25 @@ <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" - android:layout_height="wrap_content" + android:layout_height="64dp" android:background="?android:attr/selectableItemBackground"> <LinearLayout android:layout_width="match_parent" - android:layout_height="wrap_content" + android:layout_height="match_parent" android:layout_gravity="start|top" - android:gravity="center_vertical" - android:minHeight="?android:attr/listPreferredItemHeightSmall" - android:paddingStart="?android:attr/listPreferredItemPaddingStart" - android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" - android:layout_marginBottom="@dimen/controls_app_bottom_margin"> + android:gravity="center_vertical"> <FrameLayout android:id="@+id/icon_frame" android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:gravity="start|center_vertical" - android:minWidth="56dp" + android:layout_height="match_parent" android:orientation="horizontal" - android:paddingTop="@dimen/controls_app_icon_frame_top_padding" - android:paddingBottom="@dimen/controls_app_icon_frame_top_padding" - android:paddingEnd="@dimen/controls_app_icon_frame_side_padding" - android:paddingStart="@dimen/controls_app_icon_frame_side_padding" > + android:paddingEnd="@dimen/controls_app_icon_frame_side_padding"> <ImageView android:id="@android:id/icon" + android:layout_gravity="start|center_vertical" android:layout_width="@dimen/controls_app_icon_size" android:layout_height="@dimen/controls_app_icon_size" /> </FrameLayout> @@ -51,9 +43,7 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" - android:orientation="vertical" - android:paddingTop="@dimen/controls_app_text_padding" - android:paddingBottom="@dimen/controls_app_text_padding"> + android:orientation="vertical"> <TextView android:id="@android:id/title" @@ -62,8 +52,7 @@ android:ellipsize="end" android:fadingEdge="horizontal" android:singleLine="true" - android:textAppearance="?android:attr/textAppearanceMedium" - android:textColor="?android:attr/textColorPrimary"/> + android:textAppearance="@style/TextAppearance.Control.Management.Subtitle"/> <TextView android:id="@+id/favorites" @@ -81,7 +70,5 @@ android:layout_width="match_parent" android:layout_height="@dimen/controls_app_divider_height" android:layout_gravity="center_horizontal|bottom" - android:layout_marginStart="@dimen/controls_app_divider_side_margin" - android:layout_marginEnd="@dimen/controls_app_divider_side_margin" android:background="?android:attr/listDivider" /> </FrameLayout>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/controls_base_item.xml b/packages/SystemUI/res/layout/controls_base_item.xml index e7bb3afc25af..477a70f4c7ad 100644 --- a/packages/SystemUI/res/layout/controls_base_item.xml +++ b/packages/SystemUI/res/layout/controls_base_item.xml @@ -98,15 +98,15 @@ <CheckBox android:id="@+id/favorite" android:visibility="invisible" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="bottom|end" + android:layout_width="@dimen/controls_management_checkbox_size" + android:layout_height="@dimen/controls_management_checkbox_size" + android:minHeight="0dp" + android:minWidth="0dp" + android:gravity="center" android:background="@android:color/transparent" android:clickable="false" android:selectable="false" android:importantForAccessibility="no" - android:layout_marginTop="4dp" - android:layout_marginStart="4dp" app:layout_constraintStart_toEndOf="@id/subtitle" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintBottom_toBottomOf="parent"/> diff --git a/packages/SystemUI/res/layout/controls_horizontal_divider_with_empty.xml b/packages/SystemUI/res/layout/controls_horizontal_divider_with_empty.xml index 90b3398e3de2..11144f6a94b4 100644 --- a/packages/SystemUI/res/layout/controls_horizontal_divider_with_empty.xml +++ b/packages/SystemUI/res/layout/controls_horizontal_divider_with_empty.xml @@ -22,23 +22,17 @@ > <View - android:layout_width="match_parent" - android:layout_height="@dimen/controls_management_list_margin" - /> - - <FrameLayout android:id="@+id/frame" android:layout_width="match_parent" android:layout_height="@dimen/control_height" android:visibility="gone" > - </FrameLayout> + </View> <View android:id="@+id/divider" android:layout_width="match_parent" android:layout_height="1dp" - android:layout_marginBottom="10dp" - android:layout_marginStart="40dp" - android:layout_marginEnd="40dp" + android:layout_marginBottom="@dimen/controls_management_editing_divider_margin" + android:layout_marginTop="@dimen/controls_management_editing_divider_margin" android:background="#4dffffff" /> </LinearLayout> diff --git a/packages/SystemUI/res/layout/controls_management.xml b/packages/SystemUI/res/layout/controls_management.xml index 835e54e9e433..46f79deff109 100644 --- a/packages/SystemUI/res/layout/controls_management.xml +++ b/packages/SystemUI/res/layout/controls_management.xml @@ -31,18 +31,15 @@ android:id="@+id/title" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:textAppearance="?android:attr/textAppearanceLarge" - android:textSize="@dimen/controls_title_size" + android:textAppearance="@style/TextAppearance.Control.Management.Title" android:textAlignment="center" /> - - <TextView android:id="@+id/subtitle" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="@dimen/controls_management_titles_margin" - android:textAppearance="?android:attr/textAppearanceSmall" + android:textAppearance="@style/TextAppearance.Control.Management.Subtitle" android:textAlignment="center" /> <ViewStub @@ -53,7 +50,7 @@ <FrameLayout android:layout_width="match_parent" - android:layout_height="64dp"> + android:layout_height="72dp"> <View android:layout_width="match_parent" @@ -64,7 +61,7 @@ <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent" - android:padding="4dp"> + android:padding="@dimen/controls_management_footer_side_margin"> <Button android:id="@+id/other_apps" diff --git a/packages/SystemUI/res/layout/controls_management_apps.xml b/packages/SystemUI/res/layout/controls_management_apps.xml index 94df9d8f4775..4348ffe40087 100644 --- a/packages/SystemUI/res/layout/controls_management_apps.xml +++ b/packages/SystemUI/res/layout/controls_management_apps.xml @@ -19,6 +19,8 @@ android:id="@+id/list" android:layout_width="match_parent" android:layout_height="match_parent" - android:layout_marginTop="@dimen/controls_management_list_margin" + android:layout_marginTop="@dimen/controls_management_apps_list_margin" + android:layout_marginStart="@dimen/controls_management_apps_extra_side_margin" + android:layout_marginEnd="@dimen/controls_management_apps_extra_side_margin" /> diff --git a/packages/SystemUI/res/layout/controls_management_editing.xml b/packages/SystemUI/res/layout/controls_management_editing.xml index 8a14ec3666b2..7356b290380a 100644 --- a/packages/SystemUI/res/layout/controls_management_editing.xml +++ b/packages/SystemUI/res/layout/controls_management_editing.xml @@ -22,6 +22,6 @@ android:layout_height="match_parent" android:clipChildren="false" android:clipToPadding="false" - android:paddingTop="@dimen/controls_management_list_margin" + android:paddingTop="@dimen/controls_management_editing_list_margin" /> diff --git a/packages/SystemUI/res/layout/controls_management_favorites.xml b/packages/SystemUI/res/layout/controls_management_favorites.xml index d2ccfcb11c5c..a0d8ae42f584 100644 --- a/packages/SystemUI/res/layout/controls_management_favorites.xml +++ b/packages/SystemUI/res/layout/controls_management_favorites.xml @@ -32,10 +32,10 @@ <com.android.systemui.controls.management.ManagementPageIndicator android:id="@+id/structure_page_indicator" android:layout_width="wrap_content" - android:layout_height="match_parent" + android:layout_height="@dimen/controls_management_page_indicator_height" android:layout_gravity="center" android:layout_marginTop="@dimen/controls_management_list_margin" - android:visibility="gone" /> + android:visibility="invisible" /> <androidx.viewpager2.widget.ViewPager2 android:id="@+id/structure_pager" diff --git a/packages/SystemUI/res/layout/controls_structure_page.xml b/packages/SystemUI/res/layout/controls_structure_page.xml index 047ab98eb191..f048d62d46d7 100644 --- a/packages/SystemUI/res/layout/controls_structure_page.xml +++ b/packages/SystemUI/res/layout/controls_structure_page.xml @@ -21,4 +21,4 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" - android:layout_marginTop="@dimen/controls_management_list_margin"/>
\ No newline at end of file + android:layout_marginTop="@dimen/controls_management_zone_top_margin"/>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/controls_zone_header.xml b/packages/SystemUI/res/layout/controls_zone_header.xml index 93f99b12fd31..74c020a29c60 100644 --- a/packages/SystemUI/res/layout/controls_zone_header.xml +++ b/packages/SystemUI/res/layout/controls_zone_header.xml @@ -18,10 +18,7 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" - android:textAppearance="@style/TextAppearance.Control.Title" - android:layout_marginStart="12dp" - android:layout_marginEnd="2dp" - android:layout_marginTop="8dp" + android:textAppearance="@style/TextAppearance.Control.Management.Subtitle" + android:layout_marginTop="@dimen/controls_management_zone_top_margin" android:layout_marginBottom="4dp"> - </TextView>
\ No newline at end of file diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 2c2e7244ce2e..c68c814532fe 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -1283,13 +1283,23 @@ <!-- Home Controls management screens --> <dimen name="controls_management_top_padding">48dp</dimen> - <dimen name="controls_management_side_padding">8dp</dimen> - <dimen name="controls_management_titles_margin">8dp</dimen> + <dimen name="controls_management_side_padding">16dp</dimen> + <dimen name="controls_management_titles_margin">16dp</dimen> + <dimen name="controls_management_footer_side_margin">8dp</dimen> <dimen name="controls_management_list_margin">16dp</dimen> - <dimen name="controls_title_size">26sp</dimen> - - <dimen name="controls_app_icon_size">32dp</dimen> - <dimen name="controls_app_icon_frame_side_padding">8dp</dimen> + <dimen name="controls_management_apps_list_margin">64dp</dimen> + <dimen name="controls_management_editing_list_margin">48dp</dimen> + <dimen name="controls_management_editing_divider_margin">24dp</dimen> + <dimen name="controls_management_apps_extra_side_margin">8dp</dimen> + <dimen name="controls_management_apps_top_margin"></dimen> + <dimen name="controls_management_zone_top_margin">32dp</dimen> + <dimen name="controls_management_page_indicator_height">24dp</dimen> + <dimen name="controls_management_checkbox_size">25dp</dimen> + <dimen name="controls_title_size">24sp</dimen> + <dimen name="controls_subtitle_size">16sp</dimen> + + <dimen name="controls_app_icon_size">24dp</dimen> + <dimen name="controls_app_icon_frame_side_padding">16dp</dimen> <dimen name="controls_app_icon_frame_top_padding">4dp</dimen> <dimen name="controls_app_icon_frame_bottom_padding">@dimen/controls_app_icon_frame_top_padding</dimen> <dimen name="controls_app_bottom_margin">8dp</dimen> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index d3a5f04b7285..6e25625d3b88 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -734,6 +734,18 @@ <item name="android:textSize">@dimen/control_text_size</item> <item name="android:textColor">@color/control_secondary_text</item> </style> + <style name="TextAppearance.Control.Management" > + <item name="android:textColor">?android:attr/textColorPrimary</item> + </style> + <style name="TextAppearance.Control.Management.Title"> + <item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item> + <item name="android:textSize">@dimen/controls_title_size</item> + </style> + <style name="TextAppearance.Control.Management.Subtitle"> + <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item> + <item name="android:textSize">@dimen/controls_subtitle_size</item> + </style> + <style name="Control.ListPopupWindow" parent="@*android:style/Widget.DeviceDefault.ListPopupWindow"> <item name="android:overlapAnchor">true</item> diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java index 0af026eb3509..02d2b8e4ef0f 100644 --- a/packages/SystemUI/src/com/android/systemui/Dependency.java +++ b/packages/SystemUI/src/com/android/systemui/Dependency.java @@ -76,7 +76,6 @@ import com.android.systemui.statusbar.notification.NotificationEntryManager.Keyg import com.android.systemui.statusbar.notification.NotificationFilter; import com.android.systemui.statusbar.notification.VisualStabilityManager; import com.android.systemui.statusbar.notification.logging.NotificationLogger; -import com.android.systemui.statusbar.notification.row.ChannelEditorDialogController; import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.phone.AutoHideController; @@ -308,7 +307,6 @@ public class Dependency { @Inject Lazy<PackageManagerWrapper> mPackageManagerWrapper; @Inject Lazy<SensorPrivacyController> mSensorPrivacyController; @Inject Lazy<DockManager> mDockManager; - @Inject Lazy<ChannelEditorDialogController> mChannelEditorDialogController; @Inject Lazy<INotificationManager> mINotificationManager; @Inject Lazy<SysUiState> mSysUiStateFlagsContainer; @Inject Lazy<AlarmManager> mAlarmManager; @@ -498,7 +496,6 @@ public class Dependency { mProviders.put(PackageManagerWrapper.class, mPackageManagerWrapper::get); mProviders.put(SensorPrivacyController.class, mSensorPrivacyController::get); mProviders.put(DockManager.class, mDockManager::get); - mProviders.put(ChannelEditorDialogController.class, mChannelEditorDialogController::get); mProviders.put(INotificationManager.class, mINotificationManager::get); mProviders.put(SysUiState.class, mSysUiStateFlagsContainer::get); mProviders.put(AlarmManager.class, mAlarmManager::get); diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt index 03ca3931e68c..79dd9edef0f0 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt @@ -18,6 +18,7 @@ package com.android.systemui.controls.management import android.content.ComponentName import android.graphics.Rect +import android.service.controls.Control import android.service.controls.DeviceTypes import android.view.LayoutInflater import android.view.View @@ -46,9 +47,9 @@ class ControlAdapter( ) : RecyclerView.Adapter<Holder>() { companion object { - private const val TYPE_ZONE = 0 - private const val TYPE_CONTROL = 1 - private const val TYPE_DIVIDER = 2 + const val TYPE_ZONE = 0 + const val TYPE_CONTROL = 1 + const val TYPE_DIVIDER = 2 } val spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() { @@ -142,7 +143,7 @@ sealed class Holder(view: View) : RecyclerView.ViewHolder(view) { /** * Holder for using with [DividerWrapper] to display a divider between zones. * - * The divider can be shown or hidden. It also has a frame view the height of a control, that can + * The divider can be shown or hidden. It also has a view the height of a control, that can * be toggled visible or gone. */ private class DividerHolder(view: View) : Holder(view) { @@ -229,10 +230,25 @@ class MarginItemDecorator( parent: RecyclerView, state: RecyclerView.State ) { - outRect.apply { - top = topMargin - left = sideMargins - right = sideMargins + val position = parent.getChildAdapterPosition(view) + if (position == RecyclerView.NO_POSITION) return + val type = parent.adapter?.getItemViewType(position) + if (type == ControlAdapter.TYPE_CONTROL) { + outRect.apply { + top = topMargin + left = sideMargins + right = sideMargins + bottom = 0 + } + } else if (type == ControlAdapter.TYPE_ZONE && position == 0) { + // add negative padding to the first zone to counteract the margin + val margin = (view.layoutParams as ViewGroup.MarginLayoutParams).topMargin + outRect.apply { + top = -margin + left = 0 + right = 0 + bottom = 0 + } } } } diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt index e3175aafb1b1..bd75116984ab 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt @@ -104,7 +104,9 @@ class ControlsFavoritingActivity @Inject constructor( override fun onServicesUpdated(serviceInfos: List<ControlsServiceInfo>) { if (serviceInfos.size > 1) { - otherAppsButton.visibility = View.VISIBLE + otherAppsButton.post { + otherAppsButton.visibility = View.VISIBLE + } } } } @@ -170,7 +172,7 @@ class ControlsFavoritingActivity @Inject constructor( pageIndicator.setNumPages(listOfStructures.size) pageIndicator.setLocation(0f) pageIndicator.visibility = - if (listOfStructures.size > 1) View.VISIBLE else View.GONE + if (listOfStructures.size > 1) View.VISIBLE else View.INVISIBLE ControlsAnimations.enterAnimation(pageIndicator).apply { addListener(object : AnimatorListenerAdapter() { diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java index f87605382913..557132bdf08e 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java +++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java @@ -98,6 +98,7 @@ public class MediaControlPanel { private SharedPreferences mSharedPrefs; private boolean mCheckedForResumption = false; private boolean mIsRemotePlayback; + private QSMediaBrowser mQSMediaBrowser; // Button IDs used in notifications protected static final int[] NOTIF_ACTION_IDS = { @@ -232,6 +233,11 @@ public class MediaControlPanel { String key) { // Ensure that component names are updated if token has changed if (mToken == null || !mToken.equals(token)) { + if (mQSMediaBrowser != null) { + Log.d(TAG, "Disconnecting old media browser"); + mQSMediaBrowser.disconnect(); + mQSMediaBrowser = null; + } mToken = token; mServiceComponent = null; mCheckedForResumption = false; @@ -618,8 +624,22 @@ public class MediaControlPanel { ImageButton btn = mMediaNotifView.findViewById(mActionIds[0]); btn.setOnClickListener(v -> { Log.d(TAG, "Attempting to restart session"); - QSMediaBrowser browser = new QSMediaBrowser(mContext, null, mServiceComponent); - browser.restart(); + if (mQSMediaBrowser != null) { + mQSMediaBrowser.disconnect(); + } + mQSMediaBrowser = new QSMediaBrowser(mContext, new QSMediaBrowser.Callback(){ + @Override + public void onConnected() { + Log.d(TAG, "Successfully restarted"); + } + @Override + public void onError() { + Log.e(TAG, "Error restarting"); + mQSMediaBrowser.disconnect(); + mQSMediaBrowser = null; + } + }, mServiceComponent); + mQSMediaBrowser.restart(); }); btn.setImageDrawable(mContext.getResources().getDrawable(R.drawable.lb_ic_play)); btn.setImageTintList(ColorStateList.valueOf(mForegroundColor)); @@ -654,13 +674,18 @@ public class MediaControlPanel { */ private void tryUpdateResumptionList(ComponentName componentName) { Log.d(TAG, "Testing if we can connect to " + componentName); - QSMediaBrowser.testConnection(mContext, + if (mQSMediaBrowser != null) { + mQSMediaBrowser.disconnect(); + } + mQSMediaBrowser = new QSMediaBrowser(mContext, new QSMediaBrowser.Callback() { @Override public void onConnected() { Log.d(TAG, "yes we can resume with " + componentName); mServiceComponent = componentName; updateResumptionList(componentName); + mQSMediaBrowser.disconnect(); + mQSMediaBrowser = null; } @Override @@ -671,9 +696,12 @@ public class MediaControlPanel { // If it's not active and we can't resume, remove removePlayer(); } + mQSMediaBrowser.disconnect(); + mQSMediaBrowser = null; } }, componentName); + mQSMediaBrowser.testConnection(); } /** diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSMediaBrowser.java b/packages/SystemUI/src/com/android/systemui/qs/QSMediaBrowser.java index 9e532868427f..a5b73dcbd289 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSMediaBrowser.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSMediaBrowser.java @@ -58,21 +58,25 @@ public class QSMediaBrowser { mContext = context; mCallback = callback; mComponentName = componentName; - - Bundle rootHints = new Bundle(); - rootHints.putBoolean(MediaBrowserService.BrowserRoot.EXTRA_RECENT, true); - mMediaBrowser = new MediaBrowser(mContext, - mComponentName, - mConnectionCallback, - rootHints); } /** * Connects to the MediaBrowserService and looks for valid media. If a media item is returned - * by the service, QSMediaBrowser.Callback#addTrack will be called with its MediaDescription + * by the service, QSMediaBrowser.Callback#addTrack will be called with its MediaDescription. + * QSMediaBrowser.Callback#onConnected and QSMediaBrowser.Callback#onError will also be called + * when the initial connection is successful, or an error occurs. Note that it is possible for + * the service to connect but for no playable tracks to be found later. + * QSMediaBrowser#disconnect will be called automatically with this function. */ public void findRecentMedia() { Log.d(TAG, "Connecting to " + mComponentName); + disconnect(); + Bundle rootHints = new Bundle(); + rootHints.putBoolean(MediaBrowserService.BrowserRoot.EXTRA_RECENT, true); + mMediaBrowser = new MediaBrowser(mContext, + mComponentName, + mConnectionCallback, + rootHints); mMediaBrowser.connect(); } @@ -94,20 +98,22 @@ public class QSMediaBrowser { } else { Log.e(TAG, "Child found but not playable for " + mComponentName); } - mMediaBrowser.disconnect(); + disconnect(); } @Override public void onError(String parentId) { Log.e(TAG, "Subscribe error for " + mComponentName + ": " + parentId); - mMediaBrowser.disconnect(); + mCallback.onError(); + disconnect(); } @Override public void onError(String parentId, Bundle options) { Log.e(TAG, "Subscribe error for " + mComponentName + ": " + parentId + ", options: " + options); - mMediaBrowser.disconnect(); + mCallback.onError(); + disconnect(); } }; @@ -134,6 +140,8 @@ public class QSMediaBrowser { @Override public void onConnectionSuspended() { Log.d(TAG, "Connection suspended for " + mComponentName); + mCallback.onError(); + disconnect(); } /** @@ -143,16 +151,28 @@ public class QSMediaBrowser { public void onConnectionFailed() { Log.e(TAG, "Connection failed for " + mComponentName); mCallback.onError(); + disconnect(); } }; /** - * Connects to the MediaBrowserService and starts playback + * Disconnect the media browser. This should be called after restart or testConnection have + * completed to close the connection. */ - public void restart() { - if (mMediaBrowser.isConnected()) { + public void disconnect() { + if (mMediaBrowser != null) { mMediaBrowser.disconnect(); } + mMediaBrowser = null; + } + + /** + * Connects to the MediaBrowserService and starts playback. QSMediaBrowser.Callback#onError or + * QSMediaBrowser.Callback#onConnected will be called depending on whether it was successful. + * QSMediaBrowser#disconnect should be called after this to ensure the connection is closed. + */ + public void restart() { + disconnect(); Bundle rootHints = new Bundle(); rootHints.putBoolean(MediaBrowserService.BrowserRoot.EXTRA_RECENT, true); mMediaBrowser = new MediaBrowser(mContext, mComponentName, @@ -165,6 +185,17 @@ public class QSMediaBrowser { controller.getTransportControls(); controller.getTransportControls().prepare(); controller.getTransportControls().play(); + mCallback.onConnected(); + } + + @Override + public void onConnectionFailed() { + mCallback.onError(); + } + + @Override + public void onConnectionSuspended() { + mCallback.onError(); } }, rootHints); mMediaBrowser.connect(); @@ -192,42 +223,44 @@ public class QSMediaBrowser { } /** - * Used to test if SystemUI is allowed to connect to the given component as a MediaBrowser - * @param mContext the context - * @param callback methods onConnected or onError will be called to indicate whether the - * connection was successful or not - * @param mComponentName Component name of the MediaBrowserService this browser will connect to + * Used to test if SystemUI is allowed to connect to the given component as a MediaBrowser. + * QSMediaBrowser.Callback#onError or QSMediaBrowser.Callback#onConnected will be called + * depending on whether it was successful. + * QSMediaBrowser#disconnect should be called after this to ensure the connection is closed. */ - public static MediaBrowser testConnection(Context mContext, Callback callback, - ComponentName mComponentName) { - final MediaBrowser.ConnectionCallback mConnectionCallback = + public void testConnection() { + disconnect(); + final MediaBrowser.ConnectionCallback connectionCallback = new MediaBrowser.ConnectionCallback() { @Override public void onConnected() { Log.d(TAG, "connected"); - callback.onConnected(); + if (mMediaBrowser.getRoot() == null) { + mCallback.onError(); + } else { + mCallback.onConnected(); + } } @Override public void onConnectionSuspended() { Log.d(TAG, "suspended"); - callback.onError(); + mCallback.onError(); } @Override public void onConnectionFailed() { Log.d(TAG, "failed"); - callback.onError(); + mCallback.onError(); } }; Bundle rootHints = new Bundle(); rootHints.putBoolean(MediaBrowserService.BrowserRoot.EXTRA_RECENT, true); - MediaBrowser browser = new MediaBrowser(mContext, + mMediaBrowser = new MediaBrowser(mContext, mComponentName, - mConnectionCallback, + connectionCallback, rootHints); - browser.connect(); - return browser; + mMediaBrowser.connect(); } /** diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java index a3004bdc004d..e8f6c9668e9b 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java @@ -270,27 +270,8 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne return; } - QSMediaPlayer player = null; String packageName = notif.getPackageName(); - for (QSMediaPlayer p : mMediaPlayers) { - if (p.getKey() == null) { - // No notification key = loaded via mediabrowser, so just match on package - if (packageName.equals(p.getMediaPlayerPackage())) { - Log.d(TAG, "Found matching resume player by package: " + packageName); - player = p; - break; - } - } else if (p.getMediaSessionToken().equals(token)) { - Log.d(TAG, "Found matching player by token " + packageName); - player = p; - break; - } else if (packageName.equals(p.getMediaPlayerPackage()) && key.equals(p.getKey())) { - // Also match if it's the same package and notification key - Log.d(TAG, "Found matching player by package " + packageName + ", " + key); - player = p; - break; - } - } + QSMediaPlayer player = findMediaPlayer(packageName, token, key); int playerWidth = (int) getResources().getDimension(R.dimen.qs_media_width); int padding = (int) getResources().getDimension(R.dimen.qs_media_padding); @@ -299,7 +280,7 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne lp.setMarginEnd(padding); if (player == null) { - Log.d(TAG, "creating new player"); + Log.d(TAG, "creating new player for " + packageName); // Set up listener for device changes // TODO: integrate with MediaTransferManager? InfoMediaManager imm = new InfoMediaManager(mContext, notif.getPackageName(), @@ -331,6 +312,35 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne } } + /** + * Check for an existing media player using the given information + * @param packageName + * @param token + * @param key + * @return a player, or null if no match found + */ + private QSMediaPlayer findMediaPlayer(String packageName, MediaSession.Token token, + String key) { + for (QSMediaPlayer player : mMediaPlayers) { + if (player.getKey() == null || key == null) { + // No notification key = loaded via mediabrowser, so just match on package + if (packageName.equals(player.getMediaPlayerPackage())) { + Log.d(TAG, "Found matching resume player by package: " + packageName); + return player; + } + } else if (player.getMediaSessionToken().equals(token)) { + Log.d(TAG, "Found matching player by token " + packageName); + return player; + } else if (packageName.equals(player.getMediaPlayerPackage()) + && key.equals(player.getKey())) { + // Also match if it's the same package and notification key + Log.d(TAG, "Found matching player by package " + packageName + ", " + key); + return player; + } + } + return null; + } + protected View getMediaPanel() { return mMediaCarousel; } @@ -369,26 +379,30 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne } Log.d(TAG, "adding track from browser: " + desc + ", " + component); - QSMediaPlayer player = new QSMediaPlayer(mContext, QSPanel.this, - null, mForegroundExecutor, mBackgroundExecutor, mActivityStarter); + // Check if there's an old player for this app String pkgName = component.getPackageName(); - - // Add controls to carousel - int playerWidth = (int) getResources().getDimension(R.dimen.qs_media_width); - int padding = (int) getResources().getDimension(R.dimen.qs_media_padding); - LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(playerWidth, - LayoutParams.MATCH_PARENT); - lp.setMarginStart(padding); - lp.setMarginEnd(padding); - mMediaCarousel.addView(player.getView(), lp); - ((View) mMediaCarousel.getParent()).setVisibility(View.VISIBLE); - mMediaPlayers.add(player); + MediaSession.Token token = browser.getToken(); + QSMediaPlayer player = findMediaPlayer(pkgName, token, null); + + if (player == null) { + player = new QSMediaPlayer(mContext, QSPanel.this, + null, mForegroundExecutor, mBackgroundExecutor, mActivityStarter); + + // Add to carousel + int playerWidth = (int) getResources().getDimension(R.dimen.qs_media_width); + int padding = (int) getResources().getDimension(R.dimen.qs_media_padding); + LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(playerWidth, + LayoutParams.MATCH_PARENT); + lp.setMarginStart(padding); + lp.setMarginEnd(padding); + mMediaCarousel.addView(player.getView(), lp); + ((View) mMediaCarousel.getParent()).setVisibility(View.VISIBLE); + mMediaPlayers.add(player); + } int iconColor = Color.DKGRAY; int bgColor = Color.LTGRAY; - - MediaSession.Token token = browser.getToken(); player.setMediaSession(token, desc, iconColor, bgColor, browser.getAppIntent(), pkgName); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java index 90dc38f3ad12..b15c6a3e3b59 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java @@ -138,6 +138,7 @@ public class QuickStatusBarHeader extends RelativeLayout implements private Clock mClockView; private DateView mDateView; private BatteryMeterView mBatteryRemainingIcon; + private RingerModeTracker mRingerModeTracker; // Used for RingerModeTracker private final LifecycleRegistry mLifecycle = new LifecycleRegistry(this); @@ -159,10 +160,7 @@ public class QuickStatusBarHeader extends RelativeLayout implements mDualToneHandler = new DualToneHandler( new ContextThemeWrapper(context, R.style.QSHeaderTheme)); mCommandQueue = commandQueue; - ringerModeTracker.getRingerModeInternal().observe(this, ringer -> { - mRingerMode = ringer; - updateStatusText(); - }); + mRingerModeTracker = ringerModeTracker; } @Override @@ -429,6 +427,10 @@ public class QuickStatusBarHeader extends RelativeLayout implements @Override public void onAttachedToWindow() { super.onAttachedToWindow(); + mRingerModeTracker.getRingerModeInternal().observe(this, ringer -> { + mRingerMode = ringer; + updateStatusText(); + }); mStatusBarIconController.addIconGroup(mIconManager); requestApplyInsets(); } @@ -466,6 +468,7 @@ public class QuickStatusBarHeader extends RelativeLayout implements @VisibleForTesting public void onDetachedFromWindow() { setListening(false); + mRingerModeTracker.getRingerModeInternal().removeObservers(this); mStatusBarIconController.removeIconGroup(mIconManager); super.onDetachedFromWindow(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java index 1dbfa32cdf41..f55ce77060a5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java @@ -49,6 +49,7 @@ import com.android.systemui.statusbar.notification.interruption.NotificationInte import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.logging.NotificationPanelLogger; import com.android.systemui.statusbar.notification.logging.NotificationPanelLoggerImpl; +import com.android.systemui.statusbar.notification.row.ChannelEditorDialogController; import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.notification.row.PriorityOnboardingDialogController; @@ -109,6 +110,7 @@ public interface NotificationsModule { INotificationManager notificationManager, LauncherApps launcherApps, ShortcutManager shortcutManager, + ChannelEditorDialogController channelEditorDialogController, CurrentUserContextTracker contextTracker, Provider<PriorityOnboardingDialogController.Builder> builderProvider) { return new NotificationGutsManager( @@ -121,6 +123,7 @@ public interface NotificationsModule { notificationManager, launcherApps, shortcutManager, + channelEditorDialogController, contextTracker, builderProvider); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt index e75b70511250..b163818f68a8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt @@ -22,8 +22,8 @@ import android.app.NotificationChannel import android.app.NotificationChannel.DEFAULT_CHANNEL_ID import android.app.NotificationChannelGroup import android.app.NotificationManager.IMPORTANCE_NONE +import android.app.NotificationManager.Importance import android.content.Context -import android.content.DialogInterface import android.graphics.Color import android.graphics.PixelFormat import android.graphics.drawable.ColorDrawable @@ -37,8 +37,10 @@ import android.view.Window import android.view.WindowInsets.Type.statusBars import android.view.WindowManager import android.widget.TextView + import com.android.internal.annotations.VisibleForTesting import com.android.systemui.R + import javax.inject.Inject import javax.inject.Singleton @@ -59,11 +61,13 @@ private const val TAG = "ChannelDialogController" @Singleton class ChannelEditorDialogController @Inject constructor( c: Context, - private val noMan: INotificationManager + private val noMan: INotificationManager, + private val dialogBuilder: ChannelEditorDialog.Builder ) { val context: Context = c.applicationContext - lateinit var dialog: Dialog + private var prepared = false + private lateinit var dialog: ChannelEditorDialog private var appIcon: Drawable? = null private var appUid: Int? = null @@ -74,13 +78,16 @@ class ChannelEditorDialogController @Inject constructor( // Caller should set this if they care about when we dismiss var onFinishListener: OnChannelEditorDialogFinishedListener? = null - // Channels handed to us from NotificationInfo @VisibleForTesting - internal val providedChannels = mutableListOf<NotificationChannel>() + internal val paddedChannels = mutableListOf<NotificationChannel>() + // Channels handed to us from NotificationInfo + private val providedChannels = mutableListOf<NotificationChannel>() // Map from NotificationChannel to importance private val edits = mutableMapOf<NotificationChannel, Int>() - var appNotificationsEnabled = true + private var appNotificationsEnabled = true + // System settings for app notifications + private var appNotificationsCurrentlyEnabled: Boolean? = null // Keep a mapping of NotificationChannel.getGroup() to the actual group name for display @VisibleForTesting @@ -106,10 +113,18 @@ class ChannelEditorDialogController @Inject constructor( this.appNotificationsEnabled = checkAreAppNotificationsOn() this.onSettingsClickListener = onSettingsClickListener + // These will always start out the same + appNotificationsCurrentlyEnabled = appNotificationsEnabled + channelGroupList.clear() channelGroupList.addAll(fetchNotificationChannelGroups()) buildGroupNameLookup() + providedChannels.clear() + providedChannels.addAll(channels) padToFourChannels(channels) + initDialog() + + prepared = true } private fun buildGroupNameLookup() { @@ -121,21 +136,21 @@ class ChannelEditorDialogController @Inject constructor( } private fun padToFourChannels(channels: Set<NotificationChannel>) { - providedChannels.clear() + paddedChannels.clear() // First, add all of the given channels - providedChannels.addAll(channels.asSequence().take(4)) + paddedChannels.addAll(channels.asSequence().take(4)) // Then pad to 4 if we haven't been given that many - providedChannels.addAll(getDisplayableChannels(channelGroupList.asSequence()) - .filterNot { providedChannels.contains(it) } + paddedChannels.addAll(getDisplayableChannels(channelGroupList.asSequence()) + .filterNot { paddedChannels.contains(it) } .distinct() - .take(4 - providedChannels.size)) + .take(4 - paddedChannels.size)) // If we only got one channel and it has the default miscellaneous tag, then we actually // are looking at an app with a targetSdk <= O, and it doesn't make much sense to show the // channel - if (providedChannels.size == 1 && DEFAULT_CHANNEL_ID == providedChannels[0].id) { - providedChannels.clear() + if (paddedChannels.size == 1 && DEFAULT_CHANNEL_ID == paddedChannels[0].id) { + paddedChannels.clear() } } @@ -157,7 +172,9 @@ class ChannelEditorDialogController @Inject constructor( } fun show() { - initDialog() + if (!prepared) { + throw IllegalStateException("Must call prepareDialogForApp() before calling show()") + } dialog.show() } @@ -178,8 +195,10 @@ class ChannelEditorDialogController @Inject constructor( appUid = null packageName = null appName = null + appNotificationsCurrentlyEnabled = null edits.clear() + paddedChannels.clear() providedChannels.clear() groupNameLookup.clear() } @@ -188,12 +207,27 @@ class ChannelEditorDialogController @Inject constructor( return groupNameLookup[groupId] ?: "" } - fun proposeEditForChannel(channel: NotificationChannel, edit: Int) { + fun proposeEditForChannel(channel: NotificationChannel, @Importance edit: Int) { if (channel.importance == edit) { edits.remove(channel) } else { edits[channel] = edit } + + dialog.updateDoneButtonText(hasChanges()) + } + + fun proposeSetAppNotificationsEnabled(enabled: Boolean) { + appNotificationsEnabled = enabled + dialog.updateDoneButtonText(hasChanges()) + } + + fun areAppNotificationsEnabled(): Boolean { + return appNotificationsEnabled + } + + private fun hasChanges(): Boolean { + return edits.isNotEmpty() || (appNotificationsEnabled != appNotificationsCurrentlyEnabled) } @Suppress("unchecked_cast") @@ -241,7 +275,7 @@ class ChannelEditorDialogController @Inject constructor( } } - if (appNotificationsEnabled != checkAreAppNotificationsOn()) { + if (appNotificationsEnabled != appNotificationsCurrentlyEnabled) { applyAppNotificationsOn(appNotificationsEnabled) } } @@ -252,7 +286,8 @@ class ChannelEditorDialogController @Inject constructor( } private fun initDialog() { - dialog = Dialog(context) + dialogBuilder.setContext(context) + dialog = dialogBuilder.build() dialog.window?.requestFeature(Window.FEATURE_NO_TITLE) // Prevent a11y readers from reading the first element in the dialog twice @@ -260,16 +295,21 @@ class ChannelEditorDialogController @Inject constructor( dialog.apply { setContentView(R.layout.notif_half_shelf) setCanceledOnTouchOutside(true) - setOnDismissListener(object : DialogInterface.OnDismissListener { - override fun onDismiss(dialog: DialogInterface?) { - onFinishListener?.onChannelEditorDialogFinished() - } - }) - findViewById<ChannelEditorListView>(R.id.half_shelf_container).apply { + setOnDismissListener { onFinishListener?.onChannelEditorDialogFinished() } + + val listView = findViewById<ChannelEditorListView>(R.id.half_shelf_container) + listView?.apply { controller = this@ChannelEditorDialogController appIcon = this@ChannelEditorDialogController.appIcon appName = this@ChannelEditorDialogController.appName - channels = providedChannels + channels = paddedChannels + } + + setOnShowListener { + // play a highlight animation for the given channels + for (channel in providedChannels) { + listView?.highlightChannel(channel) + } } findViewById<TextView>(R.id.done_button)?.setOnClickListener { @@ -306,6 +346,28 @@ class ChannelEditorDialogController @Inject constructor( or WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) } +class ChannelEditorDialog(context: Context) : Dialog(context) { + fun updateDoneButtonText(hasChanges: Boolean) { + findViewById<TextView>(R.id.done_button)?.setText( + if (hasChanges) + R.string.inline_ok_button + else + R.string.inline_done_button) + } + + class Builder @Inject constructor() { + private lateinit var context: Context + fun setContext(context: Context): Builder { + this.context = context + return this + } + + fun build(): ChannelEditorDialog { + return ChannelEditorDialog(context) + } + } +} + interface OnChannelEditorDialogFinishedListener { fun onChannelEditorDialogFinished() } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorListView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorListView.kt index 983315ed98e7..38a1579222b1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorListView.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorListView.kt @@ -16,6 +16,8 @@ package com.android.systemui.statusbar.notification.row +import android.animation.ArgbEvaluator +import android.animation.ValueAnimator import android.app.NotificationChannel import android.app.NotificationManager.IMPORTANCE_DEFAULT import android.app.NotificationManager.IMPORTANCE_NONE @@ -33,8 +35,10 @@ import android.widget.ImageView import android.widget.LinearLayout import android.widget.Switch import android.widget.TextView +import com.android.settingslib.Utils import com.android.systemui.R +import com.android.systemui.util.Assert /** * Half-shelf for notification channel controls @@ -51,6 +55,7 @@ class ChannelEditorListView(c: Context, attrs: AttributeSet) : LinearLayout(c, a // The first row is for the entire app private lateinit var appControlRow: AppControlView + private val channelRows = mutableListOf<ChannelRow>() override fun onFinishInflate() { super.onFinishInflate() @@ -58,8 +63,21 @@ class ChannelEditorListView(c: Context, attrs: AttributeSet) : LinearLayout(c, a appControlRow = findViewById(R.id.app_control) } + /** + * Play a highlight animation for the given channel (it really should exist but this will just + * fail silently if it doesn't) + */ + fun highlightChannel(channel: NotificationChannel) { + Assert.isMainThread() + for (row in channelRows) { + if (row.channel == channel) { + row.playHighlight() + } + } + } + private fun updateRows() { - val enabled = controller.appNotificationsEnabled + val enabled = controller.areAppNotificationsEnabled() val transition = AutoTransition() transition.duration = 200 @@ -83,13 +101,10 @@ class ChannelEditorListView(c: Context, attrs: AttributeSet) : LinearLayout(c, a TransitionManager.beginDelayedTransition(this, transition) // Remove any rows - val n = childCount - for (i in n.downTo(0)) { - val child = getChildAt(i) - if (child is ChannelRow) { - removeView(child) - } + for (row in channelRows) { + removeView(row) } + channelRows.clear() updateAppControlRow(enabled) @@ -105,6 +120,8 @@ class ChannelEditorListView(c: Context, attrs: AttributeSet) : LinearLayout(c, a val row = inflater.inflate(R.layout.notif_half_shelf_row, null) as ChannelRow row.controller = controller row.channel = channel + + channelRows.add(row) addView(row) } @@ -114,7 +131,7 @@ class ChannelEditorListView(c: Context, attrs: AttributeSet) : LinearLayout(c, a .getString(R.string.notification_channel_dialog_title, appName) appControlRow.switch.isChecked = enabled appControlRow.switch.setOnCheckedChangeListener { _, b -> - controller.appNotificationsEnabled = b + controller.proposeSetAppNotificationsEnabled(b) updateRows() } } @@ -140,8 +157,14 @@ class ChannelRow(c: Context, attrs: AttributeSet) : LinearLayout(c, attrs) { private lateinit var channelName: TextView private lateinit var channelDescription: TextView private lateinit var switch: Switch + private val highlightColor: Int var gentle = false + init { + highlightColor = Utils.getColorAttrDefaultColor( + context, android.R.attr.colorControlHighlight) + } + var channel: NotificationChannel? = null set(newValue) { field = newValue @@ -150,6 +173,7 @@ class ChannelRow(c: Context, attrs: AttributeSet) : LinearLayout(c, attrs) { } override fun onFinishInflate() { + super.onFinishInflate() channelName = findViewById(R.id.channel_name) channelDescription = findViewById(R.id.channel_description) switch = findViewById(R.id.toggle) @@ -161,6 +185,22 @@ class ChannelRow(c: Context, attrs: AttributeSet) : LinearLayout(c, attrs) { setOnClickListener { switch.toggle() } } + /** + * Play an animation that highlights this row + */ + fun playHighlight() { + // Use 0 for the start value because our background is given to us by our parent + val fadeInLoop = ValueAnimator.ofObject(ArgbEvaluator(), 0, highlightColor) + fadeInLoop.duration = 200L + fadeInLoop.addUpdateListener { animator -> + setBackgroundColor(animator.animatedValue as Int) + } + fadeInLoop.repeatMode = ValueAnimator.REVERSE + // Repeat an odd number of times to we end up normal + fadeInLoop.repeatCount = 5 + fadeInLoop.start() + } + private fun updateViews() { val nc = channel ?: return diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java index 75affdf20364..3f7c7ca799d6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java @@ -87,6 +87,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx private final VisualStabilityManager mVisualStabilityManager; private final AccessibilityManager mAccessibilityManager; private final HighPriorityProvider mHighPriorityProvider; + private final ChannelEditorDialogController mChannelEditorDialogController; // Dependencies: private final NotificationLockscreenUserManager mLockscreenUserManager = @@ -127,6 +128,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx INotificationManager notificationManager, LauncherApps launcherApps, ShortcutManager shortcutManager, + ChannelEditorDialogController channelEditorDialogController, CurrentUserContextTracker contextTracker, Provider<PriorityOnboardingDialogController.Builder> builderProvider) { mContext = context; @@ -140,6 +142,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx mShortcutManager = shortcutManager; mContextTracker = contextTracker; mBuilderProvider = builderProvider; + mChannelEditorDialogController = channelEditorDialogController; } public void setUpWithPresenter(NotificationPresenter presenter, @@ -348,6 +351,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx pmUser, mNotificationManager, mVisualStabilityManager, + mChannelEditorDialogController, packageName, row.getEntry().getChannel(), row.getUniqueChannels(), @@ -390,6 +394,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx notificationInfoView.bindNotification( pmUser, mNotificationManager, + mChannelEditorDialogController, packageName, row.getEntry().getChannel(), row.getUniqueChannels(), diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java index 12aa4dfaf6fa..08affa868073 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java @@ -174,6 +174,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G PackageManager pm, INotificationManager iNotificationManager, VisualStabilityManager visualStabilityManager, + ChannelEditorDialogController channelEditorDialogController, String pkg, NotificationChannel notificationChannel, Set<NotificationChannel> uniqueChannelsInRow, @@ -187,7 +188,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G mINotificationManager = iNotificationManager; mMetricsLogger = Dependency.get(MetricsLogger.class); mVisualStabilityManager = visualStabilityManager; - mChannelEditorDialogController = Dependency.get(ChannelEditorDialogController.class); + mChannelEditorDialogController = channelEditorDialogController; mPackageName = pkg; mUniqueChannelsInRow = uniqueChannelsInRow; mNumUniqueChannelsInRow = uniqueChannelsInRow.size(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java index 2189b872da43..cc5de6529358 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java @@ -17,10 +17,6 @@ package com.android.systemui.statusbar.notification.row; import static android.app.Notification.EXTRA_IS_GROUP_CONVERSATION; -import static android.app.NotificationManager.IMPORTANCE_LOW; -import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED; - -import static com.android.systemui.Interpolators.FAST_OUT_SLOW_IN; import static java.lang.annotation.RetentionPolicy.SOURCE; @@ -39,10 +35,6 @@ import android.os.Parcelable; import android.os.RemoteException; import android.service.notification.StatusBarNotification; import android.text.TextUtils; -import android.transition.ChangeBounds; -import android.transition.Fade; -import android.transition.TransitionManager; -import android.transition.TransitionSet; import android.util.AttributeSet; import android.view.View; import android.view.accessibility.AccessibilityEvent; @@ -51,7 +43,6 @@ import android.widget.LinearLayout; import android.widget.TextView; import com.android.internal.annotations.VisibleForTesting; -import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.statusbar.notification.collection.NotificationEntry; @@ -108,6 +99,7 @@ public class PartialConversationInfo extends LinearLayout implements public void bindNotification( PackageManager pm, INotificationManager iNotificationManager, + ChannelEditorDialogController channelEditorDialogController, String pkg, NotificationChannel notificationChannel, Set<NotificationChannel> uniqueChannelsInRow, @@ -127,7 +119,7 @@ public class PartialConversationInfo extends LinearLayout implements mDelegatePkg = mSbn.getOpPkg(); mIsDeviceProvisioned = isDeviceProvisioned; mIsNonBlockable = isNonBlockable; - mChannelEditorDialogController = Dependency.get(ChannelEditorDialogController.class); + mChannelEditorDialogController = channelEditorDialogController; mUniqueChannelsInRow = uniqueChannelsInRow; bindHeader(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java index 6061b1e73d1c..06b7d1a34b5a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java @@ -39,6 +39,7 @@ import android.util.Log; import com.android.systemui.Dumpable; import com.android.systemui.dagger.qualifiers.UiBackground; import com.android.systemui.shared.system.ActivityManagerWrapper; +import com.android.systemui.statusbar.policy.DeviceProvisionedController; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -71,20 +72,38 @@ public class NavigationModeController implements Dumpable { private BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { + if (DEBUG) { + Log.d(TAG, "ACTION_OVERLAY_CHANGED"); + } + updateCurrentInteractionMode(true /* notify */); + } + }; + + private final DeviceProvisionedController.DeviceProvisionedListener mDeviceProvisionedCallback = + new DeviceProvisionedController.DeviceProvisionedListener() { + @Override + public void onUserSwitched() { if (DEBUG) { - Log.d(TAG, "ACTION_OVERLAY_CHANGED"); + Log.d(TAG, "onUserSwitched: " + + ActivityManagerWrapper.getInstance().getCurrentUserId()); } + + // Update the nav mode for the current user updateCurrentInteractionMode(true /* notify */); - } - }; + } + }; + @Inject - public NavigationModeController(Context context, @UiBackground Executor uiBgExecutor) { + public NavigationModeController(Context context, + DeviceProvisionedController deviceProvisionedController, + @UiBackground Executor uiBgExecutor) { mContext = context; mCurrentUserContext = context; mOverlayManager = IOverlayManager.Stub.asInterface( ServiceManager.getService(Context.OVERLAY_SERVICE)); mUiBgExecutor = uiBgExecutor; + deviceProvisionedController.addCallback(mDeviceProvisionedCallback); IntentFilter overlayFilter = new IntentFilter(ACTION_OVERLAY_CHANGED); overlayFilter.addDataScheme("package"); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java index 45e47f1f763f..f8da03a49b50 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java @@ -46,6 +46,8 @@ public class KeyguardUserSwitcher { private static final String TAG = "KeyguardUserSwitcher"; private static final boolean ALWAYS_ON = false; + private static final float USER_SWITCH_ENABLED_ALPHA = 1.0f; + private static final float USER_SWITCH_DISABLED_ALPHA = 0.38f; private final Container mUserSwitcherContainer; private final KeyguardStatusBarView mStatusBarView; @@ -293,6 +295,9 @@ public class KeyguardUserSwitcher { mCurrentUserView = convertView; } convertView.setTag(item); + convertView.setAlpha( + item.isCurrent || item.isSwitchToEnabled ? USER_SWITCH_ENABLED_ALPHA + : USER_SWITCH_DISABLED_ALPHA); return convertView; } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogControllerTest.kt index 8b81a7a29f84..64d025628754 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogControllerTest.kt @@ -36,12 +36,14 @@ import org.junit.Assert.assertEquals import org.junit.Before import org.junit.runner.RunWith import org.junit.Test +import org.mockito.Answers import org.mockito.ArgumentMatchers.anyBoolean import org.mockito.ArgumentMatchers.eq import org.mockito.Mock +import org.mockito.Mockito +import org.mockito.Mockito.`when` import org.mockito.Mockito.times import org.mockito.Mockito.verify -import org.mockito.Mockito.`when` import org.mockito.MockitoAnnotations @SmallTest @@ -59,11 +61,16 @@ class ChannelEditorDialogControllerTest : SysuiTestCase() { @Mock private lateinit var mockNoMan: INotificationManager + @Mock(answer = Answers.RETURNS_SELF) + private lateinit var dialogBuilder: ChannelEditorDialog.Builder + @Mock + private lateinit var dialog: ChannelEditorDialog @Before fun setup() { MockitoAnnotations.initMocks(this) - controller = ChannelEditorDialogController(mContext, mockNoMan) + `when`(dialogBuilder.build()).thenReturn(dialog) + controller = ChannelEditorDialogController(mContext, mockNoMan, dialogBuilder) channel1 = NotificationChannel(TEST_CHANNEL, TEST_CHANNEL_NAME, IMPORTANCE_DEFAULT) channel2 = NotificationChannel(TEST_CHANNEL2, TEST_CHANNEL_NAME2, IMPORTANCE_DEFAULT) @@ -86,7 +93,7 @@ class ChannelEditorDialogControllerTest : SysuiTestCase() { controller.prepareDialogForApp(TEST_APP_NAME, TEST_PACKAGE_NAME, TEST_UID, setOf(channel1, channel2), appIcon, clickListener) - assertEquals(2, controller.providedChannels.size) + assertEquals(2, controller.paddedChannels.size) } @Test @@ -97,7 +104,7 @@ class ChannelEditorDialogControllerTest : SysuiTestCase() { setOf(channelDefault), appIcon, clickListener) assertEquals("No channels should be shown when there is only the miscellaneous channel", - 0, controller.providedChannels.size) + 0, controller.paddedChannels.size) } @Test @@ -119,7 +126,7 @@ class ChannelEditorDialogControllerTest : SysuiTestCase() { setOf(channel1), appIcon, clickListener) assertEquals("ChannelEditorDialog should fetch enough channels to show 4", - 4, controller.providedChannels.size) + 4, controller.paddedChannels.size) } @Test @@ -147,7 +154,7 @@ class ChannelEditorDialogControllerTest : SysuiTestCase() { controller.prepareDialogForApp(TEST_APP_NAME, TEST_PACKAGE_NAME, TEST_UID, setOf(channel1, channel2), appIcon, clickListener) - controller.appNotificationsEnabled = false + controller.proposeSetAppNotificationsEnabled(false) controller.apply() verify(mockNoMan, times(1)).setNotificationsEnabledForPackage( @@ -162,7 +169,7 @@ class ChannelEditorDialogControllerTest : SysuiTestCase() { controller.prepareDialogForApp(TEST_APP_NAME, TEST_PACKAGE_NAME, TEST_UID, setOf(channel1, channel2), appIcon, clickListener) - controller.appNotificationsEnabled = true + controller.proposeSetAppNotificationsEnabled(true) controller.apply() verify(mockNoMan, times(1)).setNotificationsEnabledForPackage( @@ -171,12 +178,52 @@ class ChannelEditorDialogControllerTest : SysuiTestCase() { @Test fun testSettingsClickListenerNull_noCrash() { + // GIVEN editor dialog group.channels = listOf(channel1, channel2) controller.prepareDialogForApp(TEST_APP_NAME, TEST_PACKAGE_NAME, TEST_UID, setOf(channel1, channel2), appIcon, null) + // WHEN user taps settings // Pass in any old view, it should never actually be used controller.launchSettings(View(context)) + + // THEN no crash + } + + @Test + fun testDoneButtonSaysDone_noChanges() { + // GIVEN the editor dialog with no changes + `when`(dialogBuilder.build()).thenReturn(dialog) + + group.channels = listOf(channel1, channel2) + controller.prepareDialogForApp(TEST_APP_NAME, TEST_PACKAGE_NAME, TEST_UID, + setOf(channel1, channel2), appIcon, null) + + // WHEN the user proposes a change + controller.proposeEditForChannel(channel1, IMPORTANCE_NONE) + + // THEN the "done" button has been updated to "apply" + verify(dialog).updateDoneButtonText(true /* hasChanges */) + } + + @Test + fun testDoneButtonGoesBackToNormal_changeThenNoChange() { + val inOrderDialog = Mockito.inOrder(dialog) + // GIVEN the editor dialog with no changes + `when`(dialogBuilder.build()).thenReturn(dialog) + + group.channels = listOf(channel1, channel2) + controller.prepareDialogForApp(TEST_APP_NAME, TEST_PACKAGE_NAME, TEST_UID, + setOf(channel1, channel2), appIcon, null) + + // WHEN the user proposes a change + controller.proposeEditForChannel(channel1, IMPORTANCE_NONE) + // and WHEN the user sets the importance back to its original value + controller.proposeEditForChannel(channel1, channel1.importance) + + // THEN the "done" button has been changed back to done + inOrderDialog.verify(dialog, times(1)).updateDoneButtonText(eq(true)) + inOrderDialog.verify(dialog, times(1)).updateDoneButtonText(eq(false)) } private val clickListener = object : NotificationInfo.OnSettingsClickListener { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java index 5813740712b6..eeb912e7aac8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java @@ -123,6 +123,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase { @Mock private INotificationManager mINotificationManager; @Mock private LauncherApps mLauncherApps; @Mock private ShortcutManager mShortcutManager; + @Mock private ChannelEditorDialogController mChannelEditorDialogController; @Mock private PeopleNotificationIdentifier mPeopleNotificationIdentifier; @Mock private CurrentUserContextTracker mContextTracker; @Mock(answer = Answers.RETURNS_SELF) @@ -144,7 +145,8 @@ public class NotificationGutsManagerTest extends SysuiTestCase { mGutsManager = new NotificationGutsManager(mContext, mVisualStabilityManager, () -> mStatusBar, mHandler, mAccessibilityManager, mHighPriorityProvider, - mINotificationManager, mLauncherApps, mShortcutManager, mContextTracker, mProvider); + mINotificationManager, mLauncherApps, mShortcutManager, + mChannelEditorDialogController, mContextTracker, mProvider); mGutsManager.setUpWithPresenter(mPresenter, mStackScroller, mCheckSaveListener, mOnSettingsClickListener); mGutsManager.setNotificationActivityStarter(mNotificationActivityStarter); @@ -350,6 +352,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase { any(PackageManager.class), any(INotificationManager.class), eq(mVisualStabilityManager), + eq(mChannelEditorDialogController), eq(statusBarNotification.getPackageName()), any(NotificationChannel.class), anySet(), @@ -381,6 +384,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase { any(PackageManager.class), any(INotificationManager.class), eq(mVisualStabilityManager), + eq(mChannelEditorDialogController), eq(statusBarNotification.getPackageName()), any(NotificationChannel.class), anySet(), @@ -410,6 +414,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase { any(PackageManager.class), any(INotificationManager.class), eq(mVisualStabilityManager), + eq(mChannelEditorDialogController), eq(statusBarNotification.getPackageName()), any(NotificationChannel.class), anySet(), diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java index 98ef691ee28c..8ee86a237e32 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java @@ -30,17 +30,13 @@ import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyBoolean; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.anyString; -import static org.mockito.Mockito.doCallRealMethod; -import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; -import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -53,13 +49,11 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.graphics.drawable.Drawable; -import android.os.IBinder; import android.os.UserHandle; import android.provider.Settings; import android.service.notification.StatusBarNotification; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; -import android.testing.PollingCheck; import android.testing.TestableLooper; import android.testing.UiThreadTest; import android.view.LayoutInflater; @@ -68,7 +62,6 @@ import android.widget.ImageView; import android.widget.TextView; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; @@ -120,6 +113,8 @@ public class NotificationInfoTest extends SysuiTestCase { private PackageManager mMockPackageManager; @Mock private VisualStabilityManager mVisualStabilityManager; + @Mock + private ChannelEditorDialogController mChannelEditorDialogController; @Before public void setUp() throws Exception { @@ -185,6 +180,7 @@ public class NotificationInfoTest extends SysuiTestCase { mMockPackageManager, mMockINotificationManager, mVisualStabilityManager, + mChannelEditorDialogController, TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, @@ -208,6 +204,7 @@ public class NotificationInfoTest extends SysuiTestCase { mMockPackageManager, mMockINotificationManager, mVisualStabilityManager, + mChannelEditorDialogController, TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, @@ -227,6 +224,7 @@ public class NotificationInfoTest extends SysuiTestCase { mMockPackageManager, mMockINotificationManager, mVisualStabilityManager, + mChannelEditorDialogController, TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, @@ -257,6 +255,7 @@ public class NotificationInfoTest extends SysuiTestCase { mMockPackageManager, mMockINotificationManager, mVisualStabilityManager, + mChannelEditorDialogController, TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, @@ -277,6 +276,7 @@ public class NotificationInfoTest extends SysuiTestCase { mMockPackageManager, mMockINotificationManager, mVisualStabilityManager, + mChannelEditorDialogController, TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, @@ -304,6 +304,7 @@ public class NotificationInfoTest extends SysuiTestCase { mMockPackageManager, mMockINotificationManager, mVisualStabilityManager, + mChannelEditorDialogController, TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, @@ -326,6 +327,7 @@ public class NotificationInfoTest extends SysuiTestCase { mMockPackageManager, mMockINotificationManager, mVisualStabilityManager, + mChannelEditorDialogController, TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, @@ -345,6 +347,7 @@ public class NotificationInfoTest extends SysuiTestCase { mMockPackageManager, mMockINotificationManager, mVisualStabilityManager, + mChannelEditorDialogController, TEST_PACKAGE_NAME, mDefaultNotificationChannel, mDefaultNotificationChannelSet, @@ -368,6 +371,7 @@ public class NotificationInfoTest extends SysuiTestCase { mMockPackageManager, mMockINotificationManager, mVisualStabilityManager, + mChannelEditorDialogController, TEST_PACKAGE_NAME, mDefaultNotificationChannel, mDefaultNotificationChannelSet, @@ -387,6 +391,7 @@ public class NotificationInfoTest extends SysuiTestCase { mMockPackageManager, mMockINotificationManager, mVisualStabilityManager, + mChannelEditorDialogController, TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, @@ -407,6 +412,7 @@ public class NotificationInfoTest extends SysuiTestCase { mMockPackageManager, mMockINotificationManager, mVisualStabilityManager, + mChannelEditorDialogController, TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, @@ -432,6 +438,7 @@ public class NotificationInfoTest extends SysuiTestCase { mMockPackageManager, mMockINotificationManager, mVisualStabilityManager, + mChannelEditorDialogController, TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, @@ -452,6 +459,7 @@ public class NotificationInfoTest extends SysuiTestCase { mMockPackageManager, mMockINotificationManager, mVisualStabilityManager, + mChannelEditorDialogController, TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, @@ -473,6 +481,7 @@ public class NotificationInfoTest extends SysuiTestCase { mMockPackageManager, mMockINotificationManager, mVisualStabilityManager, + mChannelEditorDialogController, TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, @@ -486,6 +495,7 @@ public class NotificationInfoTest extends SysuiTestCase { mMockPackageManager, mMockINotificationManager, mVisualStabilityManager, + mChannelEditorDialogController, TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, @@ -506,6 +516,7 @@ public class NotificationInfoTest extends SysuiTestCase { mMockPackageManager, mMockINotificationManager, mVisualStabilityManager, + mChannelEditorDialogController, TEST_PACKAGE_NAME, mNotificationChannel, createMultipleChannelSet(MULTIPLE_CHANNEL_COUNT), mEntry, @@ -531,6 +542,7 @@ public class NotificationInfoTest extends SysuiTestCase { mMockPackageManager, mMockINotificationManager, mVisualStabilityManager, + mChannelEditorDialogController, TEST_PACKAGE_NAME, mNotificationChannel, createMultipleChannelSet(MULTIPLE_CHANNEL_COUNT), @@ -552,6 +564,7 @@ public class NotificationInfoTest extends SysuiTestCase { mMockPackageManager, mMockINotificationManager, mVisualStabilityManager, + mChannelEditorDialogController, TEST_PACKAGE_NAME, mNotificationChannel, createMultipleChannelSet(MULTIPLE_CHANNEL_COUNT), @@ -573,6 +586,7 @@ public class NotificationInfoTest extends SysuiTestCase { mMockPackageManager, mMockINotificationManager, mVisualStabilityManager, + mChannelEditorDialogController, TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, @@ -596,6 +610,7 @@ public class NotificationInfoTest extends SysuiTestCase { mMockPackageManager, mMockINotificationManager, mVisualStabilityManager, + mChannelEditorDialogController, TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, @@ -614,6 +629,7 @@ public class NotificationInfoTest extends SysuiTestCase { mMockPackageManager, mMockINotificationManager, mVisualStabilityManager, + mChannelEditorDialogController, TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, @@ -632,6 +648,7 @@ public class NotificationInfoTest extends SysuiTestCase { mMockPackageManager, mMockINotificationManager, mVisualStabilityManager, + mChannelEditorDialogController, TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, @@ -653,6 +670,7 @@ public class NotificationInfoTest extends SysuiTestCase { mMockPackageManager, mMockINotificationManager, mVisualStabilityManager, + mChannelEditorDialogController, TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, @@ -677,6 +695,7 @@ public class NotificationInfoTest extends SysuiTestCase { mMockPackageManager, mMockINotificationManager, mVisualStabilityManager, + mChannelEditorDialogController, TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, @@ -701,6 +720,7 @@ public class NotificationInfoTest extends SysuiTestCase { mMockPackageManager, mMockINotificationManager, mVisualStabilityManager, + mChannelEditorDialogController, TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, @@ -726,6 +746,7 @@ public class NotificationInfoTest extends SysuiTestCase { mMockPackageManager, mMockINotificationManager, mVisualStabilityManager, + mChannelEditorDialogController, TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, @@ -751,6 +772,7 @@ public class NotificationInfoTest extends SysuiTestCase { mMockPackageManager, mMockINotificationManager, mVisualStabilityManager, + mChannelEditorDialogController, TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, @@ -782,6 +804,7 @@ public class NotificationInfoTest extends SysuiTestCase { mMockPackageManager, mMockINotificationManager, mVisualStabilityManager, + mChannelEditorDialogController, TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, @@ -814,6 +837,7 @@ public class NotificationInfoTest extends SysuiTestCase { mMockPackageManager, mMockINotificationManager, mVisualStabilityManager, + mChannelEditorDialogController, TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, @@ -846,6 +870,7 @@ public class NotificationInfoTest extends SysuiTestCase { mMockPackageManager, mMockINotificationManager, mVisualStabilityManager, + mChannelEditorDialogController, TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, @@ -881,6 +906,7 @@ public class NotificationInfoTest extends SysuiTestCase { mMockPackageManager, mMockINotificationManager, mVisualStabilityManager, + mChannelEditorDialogController, TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, @@ -915,6 +941,7 @@ public class NotificationInfoTest extends SysuiTestCase { mMockPackageManager, mMockINotificationManager, mVisualStabilityManager, + mChannelEditorDialogController, TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, @@ -940,6 +967,7 @@ public class NotificationInfoTest extends SysuiTestCase { mMockPackageManager, mMockINotificationManager, mVisualStabilityManager, + mChannelEditorDialogController, TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, @@ -968,6 +996,7 @@ public class NotificationInfoTest extends SysuiTestCase { mMockPackageManager, mMockINotificationManager, mVisualStabilityManager, + mChannelEditorDialogController, TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, @@ -999,6 +1028,7 @@ public class NotificationInfoTest extends SysuiTestCase { mMockPackageManager, mMockINotificationManager, mVisualStabilityManager, + mChannelEditorDialogController, TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, @@ -1025,6 +1055,7 @@ public class NotificationInfoTest extends SysuiTestCase { mMockPackageManager, mMockINotificationManager, mVisualStabilityManager, + mChannelEditorDialogController, TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, @@ -1056,6 +1087,7 @@ public class NotificationInfoTest extends SysuiTestCase { mMockPackageManager, mMockINotificationManager, mVisualStabilityManager, + mChannelEditorDialogController, TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, @@ -1080,6 +1112,7 @@ public class NotificationInfoTest extends SysuiTestCase { mMockPackageManager, mMockINotificationManager, mVisualStabilityManager, + mChannelEditorDialogController, TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java index c390e3933d7a..1bfebfb412e7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java @@ -98,6 +98,8 @@ public class PartialConversationInfoTest extends SysuiTestCase { private INotificationManager mMockINotificationManager; @Mock private PackageManager mMockPackageManager; + @Mock + private ChannelEditorDialogController mChannelEditorDialogController; @Mock private Icon mIcon; @@ -160,6 +162,7 @@ public class PartialConversationInfoTest extends SysuiTestCase { mInfo.bindNotification( mMockPackageManager, mMockINotificationManager, + mChannelEditorDialogController, TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, @@ -181,6 +184,7 @@ public class PartialConversationInfoTest extends SysuiTestCase { mInfo.bindNotification( mMockPackageManager, mMockINotificationManager, + mChannelEditorDialogController, TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, @@ -207,6 +211,7 @@ public class PartialConversationInfoTest extends SysuiTestCase { mInfo.bindNotification( mMockPackageManager, mMockINotificationManager, + mChannelEditorDialogController, TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, @@ -223,6 +228,7 @@ public class PartialConversationInfoTest extends SysuiTestCase { mInfo.bindNotification( mMockPackageManager, mMockINotificationManager, + mChannelEditorDialogController, TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, @@ -250,6 +256,7 @@ public class PartialConversationInfoTest extends SysuiTestCase { mInfo.bindNotification( mMockPackageManager, mMockINotificationManager, + mChannelEditorDialogController, TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, @@ -267,6 +274,7 @@ public class PartialConversationInfoTest extends SysuiTestCase { mInfo.bindNotification( mMockPackageManager, mMockINotificationManager, + mChannelEditorDialogController, TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, @@ -291,6 +299,7 @@ public class PartialConversationInfoTest extends SysuiTestCase { mInfo.bindNotification( mMockPackageManager, mMockINotificationManager, + mChannelEditorDialogController, TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, @@ -310,6 +319,7 @@ public class PartialConversationInfoTest extends SysuiTestCase { mInfo.bindNotification( mMockPackageManager, mMockINotificationManager, + mChannelEditorDialogController, TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, @@ -327,6 +337,7 @@ public class PartialConversationInfoTest extends SysuiTestCase { mInfo.bindNotification( mMockPackageManager, mMockINotificationManager, + mChannelEditorDialogController, TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, @@ -349,6 +360,7 @@ public class PartialConversationInfoTest extends SysuiTestCase { mInfo.bindNotification( mMockPackageManager, mMockINotificationManager, + mChannelEditorDialogController, TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, @@ -365,6 +377,7 @@ public class PartialConversationInfoTest extends SysuiTestCase { mInfo.bindNotification( mMockPackageManager, mMockINotificationManager, + mChannelEditorDialogController, TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, @@ -383,6 +396,7 @@ public class PartialConversationInfoTest extends SysuiTestCase { mInfo.bindNotification( mMockPackageManager, mMockINotificationManager, + mChannelEditorDialogController, TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 0bd134c8dfac..8d3515202126 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -10535,12 +10535,14 @@ public class ActivityManagerService extends IActivityManager.Stub } mAtmInternal.dump( DUMP_STARTER_CMD, fd, pw, args, opti, dumpAll, dumpClient, dumpPackage); - pw.println(); - if (dumpAll) { - pw.println("-------------------------------------------------------------------------------"); + if (dumpPackage == null) { + pw.println(); + if (dumpAll) { + pw.println("-------------------------------------------------------------------------------"); + } + mAtmInternal.dump( + DUMP_CONTAINERS_CMD, fd, pw, args, opti, dumpAll, dumpClient, dumpPackage); } - mAtmInternal.dump( - DUMP_CONTAINERS_CMD, fd, pw, args, opti, dumpAll, dumpClient, dumpPackage); // Activities section is dumped as part of the Critical priority dump. Exclude the // section if priority is Normal. if (!dumpNormalPriority) { @@ -10558,6 +10560,11 @@ public class ActivityManagerService extends IActivityManager.Stub } dumpAssociationsLocked(fd, pw, args, opti, dumpAll, dumpClient, dumpPackage); } + pw.println(); + if (dumpAll) { + pw.println("-------------------------------------------------------------------------------"); + } + mProcessList.mAppExitInfoTracker.dumpHistoryProcessExitInfo(pw, dumpPackage); if (dumpPackage == null) { pw.println(); if (dumpAll) { @@ -10574,17 +10581,6 @@ public class ActivityManagerService extends IActivityManager.Stub if (dumpAll) { pw.println("-------------------------------------------------------------------------------"); } - dumpLruLocked(pw, dumpPackage); - pw.println(); - if (dumpAll) { - pw.println("-------------------------------------------------------------------------------"); - } - mProcessList.mAppExitInfoTracker.dumpHistoryProcessExitInfo(pw, dumpPackage); - pw.println(); - if (dumpAll) { - pw.println("-------------------------------------------------------------------" - + "------------"); - } dumpProcessesLocked(fd, pw, args, opti, dumpAll, dumpPackage, dumpAppId); pw.println(); if (dumpAll) { @@ -10788,7 +10784,7 @@ public class ActivityManagerService extends IActivityManager.Stub } } else if ("oom".equals(cmd) || "o".equals(cmd)) { synchronized (this) { - dumpOomLocked(fd, pw, args, opti, true); + dumpOomLocked(fd, pw, false, args, opti, true, dumpPackage, true); } } else if ("lmk".equals(cmd)) { synchronized (this) { @@ -10796,11 +10792,11 @@ public class ActivityManagerService extends IActivityManager.Stub } } else if ("lru".equals(cmd)) { synchronized (this) { - dumpLruLocked(pw, null); + dumpLruLocked(pw, dumpPackage, null); } } else if ("permissions".equals(cmd) || "perm".equals(cmd)) { synchronized (this) { - dumpPermissionsLocked(fd, pw, args, opti, true, null); + dumpPermissionsLocked(fd, pw, args, opti, true, dumpPackage); } } else if ("provider".equals(cmd)) { String[] newArgs; @@ -10820,7 +10816,7 @@ public class ActivityManagerService extends IActivityManager.Stub } } else if ("providers".equals(cmd) || "prov".equals(cmd)) { synchronized (this) { - dumpProvidersLocked(fd, pw, args, opti, true, null); + dumpProvidersLocked(fd, pw, args, opti, true, dumpPackage); } } else if ("service".equals(cmd)) { String[] newArgs; @@ -11106,8 +11102,9 @@ public class ActivityManagerService extends IActivityManager.Stub " Counts of Binder Proxies held by SYSTEM"); } - void dumpLruEntryLocked(PrintWriter pw, int index, ProcessRecord proc) { - pw.print(" #"); + void dumpLruEntryLocked(PrintWriter pw, int index, ProcessRecord proc, String prefix) { + pw.print(prefix); + pw.print("#"); pw.print(index); pw.print(": "); pw.print(ProcessList.makeOomAdjString(proc.setAdj, false)); @@ -11149,9 +11146,29 @@ public class ActivityManagerService extends IActivityManager.Stub } // TODO: Move to ProcessList? - void dumpLruLocked(PrintWriter pw, String dumpPackage) { - pw.println("ACTIVITY MANAGER LRU PROCESSES (dumpsys activity lru)"); + boolean dumpLruLocked(PrintWriter pw, String dumpPackage, String prefix) { final int N = mProcessList.mLruProcesses.size(); + final String innerPrefix; + if (prefix == null) { + pw.println("ACTIVITY MANAGER LRU PROCESSES (dumpsys activity lru)"); + innerPrefix = " "; + } else { + boolean haveAny = false; + for (int i = N - 1; i >= 0; i--) { + final ProcessRecord r = mProcessList.mLruProcesses.get(i); + if (dumpPackage != null && !r.pkgList.containsKey(dumpPackage)) { + continue; + } + haveAny = true; + break; + } + if (!haveAny) { + return false; + } + pw.print(prefix); + pw.println("Raw LRU list (dumpsys activity lru):"); + innerPrefix = prefix + " "; + } int i; boolean first = true; for (i = N - 1; i >= mProcessList.mLruProcessActivityStart; i--) { @@ -11160,10 +11177,11 @@ public class ActivityManagerService extends IActivityManager.Stub continue; } if (first) { - pw.println(" Activities:"); + pw.print(innerPrefix); + pw.println("Activities:"); first = false; } - dumpLruEntryLocked(pw, i, r); + dumpLruEntryLocked(pw, i, r, innerPrefix); } first = true; for (; i >= mProcessList.mLruProcessServiceStart; i--) { @@ -11172,10 +11190,11 @@ public class ActivityManagerService extends IActivityManager.Stub continue; } if (first) { - pw.println(" Services:"); + pw.print(innerPrefix); + pw.println("Services:"); first = false; } - dumpLruEntryLocked(pw, i, r); + dumpLruEntryLocked(pw, i, r, innerPrefix); } first = true; for (; i >= 0; i--) { @@ -11184,11 +11203,13 @@ public class ActivityManagerService extends IActivityManager.Stub continue; } if (first) { - pw.println(" Other:"); + pw.print(innerPrefix); + pw.println("Other:"); first = false; } - dumpLruEntryLocked(pw, i, r); + dumpLruEntryLocked(pw, i, r, innerPrefix); } + return true; } // TODO: Move to ProcessList? @@ -11200,7 +11221,7 @@ public class ActivityManagerService extends IActivityManager.Stub pw.println("ACTIVITY MANAGER RUNNING PROCESSES (dumpsys activity processes)"); - if (dumpAll) { + if (dumpAll || dumpPackage != null) { final int NP = mProcessList.mProcessNames.getMap().size(); for (int ip=0; ip<NP; ip++) { SparseArray<ProcessRecord> procs = mProcessList.mProcessNames.getMap().valueAt(ip); @@ -11267,6 +11288,12 @@ public class ActivityManagerService extends IActivityManager.Stub } } + if (dumpOomLocked(fd, pw, needSep, args, opti, dumpAll, dumpPackage, false)) { + needSep = true; + } + + needSep = dumpProcessesToGc(pw, needSep, dumpPackage); + if (mProcessList.mActiveUids.size() > 0) { if (dumpUids(pw, dumpPackage, dumpAppId, mProcessList.mActiveUids, "UID states:", needSep)) { @@ -11283,6 +11310,13 @@ public class ActivityManagerService extends IActivityManager.Stub } } + if (needSep) { + pw.println(); + } + if (dumpLruLocked(pw, dumpPackage, " ")) { + needSep = true; + } + if (mProcessList.getLruSizeLocked() > 0) { if (needSep) { pw.println(); @@ -11387,8 +11421,6 @@ public class ActivityManagerService extends IActivityManager.Stub "OnHold Norm", "OnHold PERS", dumpPackage); } - needSep = dumpProcessesToGc(pw, needSep, dumpPackage); - needSep = mAppErrors.dumpLocked(fd, pw, needSep, dumpPackage); needSep = mAtmInternal.dumpForProcesses(fd, pw, dumpAll, dumpPackage, dumpAppId, needSep, @@ -11931,10 +11963,8 @@ public class ActivityManagerService extends IActivityManager.Stub pw.println(")"); } - boolean dumpOomLocked(FileDescriptor fd, PrintWriter pw, String[] args, - int opti, boolean dumpAll) { - boolean needSep = false; - + boolean dumpOomLocked(FileDescriptor fd, PrintWriter pw, boolean needSep, String[] args, + int opti, boolean dumpAll, String dumpPackage, boolean inclGc) { if (mProcessList.getLruSizeLocked() > 0) { if (needSep) pw.println(); needSep = true; @@ -11965,11 +11995,11 @@ public class ActivityManagerService extends IActivityManager.Stub - mProcessList.mLruProcessServiceStart); pw.println("):"); dumpProcessOomList(pw, this, mProcessList.mLruProcesses, " ", "Proc", "PERS", true, - null); + dumpPackage); needSep = true; } - dumpProcessesToGc(pw, needSep, null); + dumpProcessesToGc(pw, needSep, dumpPackage); pw.println(); mAtmInternal.dumpForOom(pw); diff --git a/services/core/java/com/android/server/am/AppExitInfoTracker.java b/services/core/java/com/android/server/am/AppExitInfoTracker.java index 0c3d02d678bd..02fb34e73f7f 100644 --- a/services/core/java/com/android/server/am/AppExitInfoTracker.java +++ b/services/core/java/com/android/server/am/AppExitInfoTracker.java @@ -785,7 +785,7 @@ public final class AppExitInfoTracker { } void dumpHistoryProcessExitInfo(PrintWriter pw, String packageName) { - pw.println("ACTIVITY MANAGER LRU PROCESSES (dumpsys activity exit-info)"); + pw.println("ACTIVITY MANAGER PROCESS EXIT INFO (dumpsys activity exit-info)"); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); synchronized (mLock) { pw.println("Last Timestamp of Persistence Into Persistent Storage: " diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 76acf57db408..d007b77c3203 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -235,6 +235,7 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.compat.IPlatformCompat; import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; +import com.android.internal.logging.InstanceId; import com.android.internal.logging.InstanceIdSequence; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto; @@ -6490,7 +6491,7 @@ public class NotificationManagerService extends SystemService { // Log event to statsd mNotificationRecordLogger.maybeLogNotificationPosted(r, old, position, - buzzBeepBlinkLoggingCode); + buzzBeepBlinkLoggingCode, getGroupInstanceId(n.getGroupKey())); } finally { int N = mEnqueuedNotifications.size(); for (int i = 0; i < N; i++) { @@ -6506,6 +6507,21 @@ public class NotificationManagerService extends SystemService { } /** + * + */ + @GuardedBy("mNotificationLock") + InstanceId getGroupInstanceId(String groupKey) { + if (groupKey == null) { + return null; + } + NotificationRecord group = mSummaryByGroupKey.get(groupKey); + if (group == null) { + return null; + } + return group.getSbn().getInstanceId(); + } + + /** * If the notification differs enough visually, consider it a new interruptive notification. */ @GuardedBy("mNotificationLock") diff --git a/services/core/java/com/android/server/notification/NotificationRecordLogger.java b/services/core/java/com/android/server/notification/NotificationRecordLogger.java index eba57304124a..34e6ec18be88 100644 --- a/services/core/java/com/android/server/notification/NotificationRecordLogger.java +++ b/services/core/java/com/android/server/notification/NotificationRecordLogger.java @@ -27,6 +27,7 @@ import android.os.Bundle; import android.service.notification.NotificationListenerService; import android.service.notification.NotificationStats; +import com.android.internal.logging.InstanceId; import com.android.internal.logging.UiEvent; import com.android.internal.logging.UiEventLogger; @@ -48,10 +49,12 @@ public interface NotificationRecordLogger { * @param old The previous NotificationRecord. Null if there was no previous record. * @param position The position at which this notification is ranked. * @param buzzBeepBlink Logging code reflecting whether this notification alerted the user. + * @param groupId The instance Id of the group summary notification, or null. */ void maybeLogNotificationPosted(@Nullable NotificationRecord r, @Nullable NotificationRecord old, - int position, int buzzBeepBlink); + int position, int buzzBeepBlink, + InstanceId groupId); /** * Logs a notification cancel / dismiss event using UiEventReported (event ids from the diff --git a/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java b/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java index 494ff314a8aa..c6ec95a2e1d5 100644 --- a/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java +++ b/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java @@ -16,6 +16,7 @@ package com.android.server.notification; +import com.android.internal.logging.InstanceId; import com.android.internal.logging.UiEventLogger; import com.android.internal.logging.UiEventLoggerImpl; import com.android.internal.util.FrameworkStatsLog; @@ -30,7 +31,8 @@ public class NotificationRecordLoggerImpl implements NotificationRecordLogger { @Override public void maybeLogNotificationPosted(NotificationRecord r, NotificationRecord old, - int position, int buzzBeepBlink) { + int position, int buzzBeepBlink, + InstanceId groupId) { NotificationRecordPair p = new NotificationRecordPair(r, old); if (!p.shouldLogReported(buzzBeepBlink)) { return; @@ -43,7 +45,7 @@ public class NotificationRecordLoggerImpl implements NotificationRecordLogger { /* int32 notification_id_hash = 5 */ p.getNotificationIdHash(), /* int32 channel_id_hash = 6 */ p.getChannelIdHash(), /* string group_id_hash = 7 */ p.getGroupIdHash(), - /* int32 group_instance_id = 8 */ 0, // TODO generate and fill instance ids + /* int32 group_instance_id = 8 */ (groupId == null) ? 0 : groupId.getId(), /* bool is_group_summary = 9 */ r.getSbn().getNotification().isGroupSummary(), /* string category = 10 */ r.getSbn().getNotification().category, /* int32 style = 11 */ p.getStyle(), diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 9edc03eaf3c3..5df84f299509 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -803,7 +803,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A pw.print(" icon=0x"); pw.print(Integer.toHexString(icon)); pw.print(" theme=0x"); pw.println(Integer.toHexString(theme)); pw.println(prefix + "mLastReportedConfigurations:"); - mLastReportedConfiguration.dump(pw, prefix + " "); + mLastReportedConfiguration.dump(pw, prefix + " "); pw.print(prefix); pw.print("CurrentConfiguration="); pw.println(getConfiguration()); if (!getRequestedOverrideConfiguration().equals(EMPTY)) { @@ -839,7 +839,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A pw.print(" iconFilename="); pw.print(taskDescription.getIconFilename()); pw.print(" primaryColor="); pw.println(Integer.toHexString(taskDescription.getPrimaryColor())); - pw.print(prefix + " backgroundColor="); + pw.print(prefix); pw.print(" backgroundColor="); pw.print(Integer.toHexString(taskDescription.getBackgroundColor())); pw.print(" statusBarColor="); pw.print(Integer.toHexString(taskDescription.getStatusBarColor())); diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java index 68c6627c3d24..d71381ea0d79 100644 --- a/services/core/java/com/android/server/wm/ActivityStack.java +++ b/services/core/java/com/android/server/wm/ActivityStack.java @@ -162,6 +162,7 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; import java.util.Objects; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Consumer; /** @@ -2802,67 +2803,91 @@ class ActivityStack extends Task { } boolean dump(FileDescriptor fd, PrintWriter pw, boolean dumpAll, boolean dumpClient, - String dumpPackage, boolean needSep) { - pw.println(" Stack #" + getRootTaskId() - + ": type=" + activityTypeToString(getActivityType()) - + " mode=" + windowingModeToString(getWindowingMode())); - pw.println(" isSleeping=" + shouldSleepActivities()); - pw.println(" mBounds=" + getRequestedOverrideBounds()); - - boolean printed = dumpActivities(fd, pw, dumpAll, dumpClient, dumpPackage, needSep); - - needSep = printed; - boolean pr = printThisActivity(pw, mPausingActivity, dumpPackage, needSep, - " mPausingActivity: "); - if (pr) { - printed = true; - needSep = false; - } - pr = printThisActivity(pw, getResumedActivity(), dumpPackage, needSep, - " mResumedActivity: "); - if (pr) { + String dumpPackage, final boolean needSep) { + Runnable headerPrinter = () -> { + if (needSep) { + pw.println(); + } + pw.println(" Stack #" + getRootTaskId() + + ": type=" + activityTypeToString(getActivityType()) + + " mode=" + windowingModeToString(getWindowingMode())); + pw.println(" isSleeping=" + shouldSleepActivities()); + pw.println(" mBounds=" + getRequestedOverrideBounds()); + }; + + boolean printed = false; + + if (dumpPackage == null) { + // If we are not filtering by package, we want to print absolutely everything, + // so always print the header even if there are no tasks/activities inside. + headerPrinter.run(); + headerPrinter = null; printed = true; - needSep = false; } + + printed |= printThisActivity(pw, mPausingActivity, dumpPackage, false, + " mPausingActivity: ", null); + printed |= printThisActivity(pw, getResumedActivity(), dumpPackage, false, + " mResumedActivity: ", null); if (dumpAll) { - pr = printThisActivity(pw, mLastPausedActivity, dumpPackage, needSep, - " mLastPausedActivity: "); - if (pr) { - printed = true; - needSep = true; - } + printed |= printThisActivity(pw, mLastPausedActivity, dumpPackage, false, + " mLastPausedActivity: ", null); printed |= printThisActivity(pw, mLastNoHistoryActivity, dumpPackage, - needSep, " mLastNoHistoryActivity: "); + false, " mLastNoHistoryActivity: ", null); } + + printed |= dumpActivities(fd, pw, dumpAll, dumpClient, dumpPackage, false, headerPrinter); + return printed; } private boolean dumpActivities(FileDescriptor fd, PrintWriter pw, boolean dumpAll, - boolean dumpClient, String dumpPackage, boolean needSep) { + boolean dumpClient, String dumpPackage, boolean needSep, Runnable header) { if (!hasChild()) { return false; } - final String prefix = " "; + final AtomicBoolean printedHeader = new AtomicBoolean(false); + final AtomicBoolean printed = new AtomicBoolean(false); forAllLeafTasks((task) -> { - if (needSep) { - pw.println(""); - } - pw.println(prefix + "Task id #" + task.mTaskId); - pw.println(prefix + "mBounds=" + task.getRequestedOverrideBounds()); - pw.println(prefix + "mMinWidth=" + task.mMinWidth); - pw.println(prefix + "mMinHeight=" + task.mMinHeight); - pw.println(prefix + "mLastNonFullscreenBounds=" + task.mLastNonFullscreenBounds); - pw.println(prefix + "* " + task); - task.dump(pw, prefix + " "); + final String prefix = " "; + Runnable headerPrinter = () -> { + printed.set(true); + if (!printedHeader.get()) { + if (needSep) { + pw.println(""); + } + if (header != null) { + header.run(); + } + printedHeader.set(true); + } + pw.print(prefix); pw.print("* "); pw.println(task); + pw.print(prefix); pw.print(" mBounds="); + pw.println(task.getRequestedOverrideBounds()); + pw.print(prefix); pw.print(" mMinWidth="); pw.print(task.mMinWidth); + pw.print(" mMinHeight="); pw.println(task.mMinHeight); + if (mLastNonFullscreenBounds != null) { + pw.print(prefix); + pw.print(" mLastNonFullscreenBounds="); + pw.println(task.mLastNonFullscreenBounds); + } + task.dump(pw, prefix + " "); + }; + if (dumpPackage == null) { + // If we are not filtering by package, we want to print absolutely everything, + // so always print the header even if there are no activities inside. + headerPrinter.run(); + headerPrinter = null; + } final ArrayList<ActivityRecord> activities = new ArrayList<>(); // Add activities by traversing the hierarchy from bottom to top, since activities // are dumped in reverse order in {@link ActivityStackSupervisor#dumpHistoryList()}. task.forAllActivities((Consumer<ActivityRecord>) activities::add, false /* traverseTopToBottom */); dumpHistoryList(fd, pw, activities, prefix, "Hist", true, !dumpAll, dumpClient, - dumpPackage, false, null, task); + dumpPackage, false, headerPrinter, task); }, true /* traverseTopToBottom */); - return true; + return printed.get(); } ArrayList<ActivityRecord> getDumpActivitiesLocked(String name) { diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java index 03ff80ae0a21..9026b81c4f2a 100644 --- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java @@ -1936,12 +1936,15 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { } static boolean printThisActivity(PrintWriter pw, ActivityRecord activity, String dumpPackage, - boolean needSep, String prefix) { + boolean needSep, String prefix, Runnable header) { if (activity != null) { if (dumpPackage == null || dumpPackage.equals(activity.packageName)) { if (needSep) { pw.println(); } + if (header != null) { + header.run(); + } pw.print(prefix); pw.println(activity); return true; @@ -1952,7 +1955,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { static boolean dumpHistoryList(FileDescriptor fd, PrintWriter pw, List<ActivityRecord> list, String prefix, String label, boolean complete, boolean brief, boolean client, - String dumpPackage, boolean needNL, String header, Task lastTask) { + String dumpPackage, boolean needNL, Runnable header, Task lastTask) { String innerPrefix = null; String[] args = null; boolean printed = false; @@ -1972,7 +1975,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { needNL = false; } if (header != null) { - pw.println(header); + header.run(); header = null; } if (lastTask != r.getTask()) { diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java index 7fad395fb51d..dfa3fe088770 100644 --- a/services/core/java/com/android/server/wm/ActivityStartController.java +++ b/services/core/java/com/android/server/wm/ActivityStartController.java @@ -549,19 +549,28 @@ public class ActivityStartController { return mPendingRemoteAnimationRegistry; } - void dump(PrintWriter pw, String prefix, String dumpPackage) { + void dumpLastHomeActivityStartResult(PrintWriter pw, String prefix) { pw.print(prefix); pw.print("mLastHomeActivityStartResult="); pw.println(mLastHomeActivityStartResult); + } + + void dump(PrintWriter pw, String prefix, String dumpPackage) { + boolean dumped = false; + + final boolean dumpPackagePresent = dumpPackage != null; - if (mLastHomeActivityStartRecord != null) { + if (mLastHomeActivityStartRecord != null && (!dumpPackagePresent + || dumpPackage.equals(mLastHomeActivityStartRecord.packageName))) { + if (!dumped) { + dumped = true; + dumpLastHomeActivityStartResult(pw, prefix); + } pw.print(prefix); pw.println("mLastHomeActivityStartRecord:"); mLastHomeActivityStartRecord.dump(pw, prefix + " ", true /* dumpAll */); } - final boolean dumpPackagePresent = dumpPackage != null; - if (mLastStarter != null) { final boolean dump = !dumpPackagePresent || mLastStarter.relatedToPackage(dumpPackage) @@ -569,6 +578,10 @@ public class ActivityStartController { && dumpPackage.equals(mLastHomeActivityStartRecord.packageName)); if (dump) { + if (!dumped) { + dumped = true; + dumpLastHomeActivityStartResult(pw, prefix); + } pw.print(prefix); mLastStarter.dump(pw, prefix + " "); @@ -578,7 +591,7 @@ public class ActivityStartController { } } - if (dumpPackagePresent) { + if (!dumped) { pw.print(prefix); pw.println("(nothing)"); } diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 511baa540d5a..6a8d5d905a00 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -4926,7 +4926,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { boolean printed = ActivityStackSupervisor.printThisActivity(pw, mRootWindowContainer.getTopResumedActivity(), dumpPackage, needSep, - " ResumedActivity: "); + " ResumedActivity: ", null); if (printed) { printedAnything = true; needSep = false; diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java index 09700c56deba..ccd51de28c88 100644 --- a/services/core/java/com/android/server/wm/RecentTasks.java +++ b/services/core/java/com/android/server/wm/RecentTasks.java @@ -1718,9 +1718,31 @@ class RecentTasks { final int size = mTasks.size(); for (int i = 0; i < size; i++) { final Task task = mTasks.get(i); - if (dumpPackage != null && (task.realActivity == null || - !dumpPackage.equals(task.realActivity.getPackageName()))) { - continue; + if (dumpPackage != null) { + boolean match = task.intent != null + && task.intent.getComponent() != null + && dumpPackage.equals( + task.intent.getComponent().getPackageName()); + if (!match) { + match |= task.affinityIntent != null + && task.affinityIntent.getComponent() != null + && dumpPackage.equals( + task.affinityIntent.getComponent().getPackageName()); + } + if (!match) { + match |= task.origActivity != null + && dumpPackage.equals(task.origActivity.getPackageName()); + } + if (!match) { + match |= task.realActivity != null + && dumpPackage.equals(task.realActivity.getPackageName()); + } + if (!match) { + match |= dumpPackage.equals(task.mCallingPackage); + } + if (!match) { + continue; + } } if (!printedHeader) { @@ -1743,6 +1765,31 @@ class RecentTasks { 0, true /* getTasksAllowed */, mService.getCurrentUserId(), SYSTEM_UID); for (int i = 0; i < tasks.size(); i++) { final ActivityManager.RecentTaskInfo taskInfo = tasks.get(i); + if (dumpPackage != null) { + boolean match = taskInfo.baseIntent != null + && taskInfo.baseIntent.getComponent() != null + && dumpPackage.equals( + taskInfo.baseIntent.getComponent().getPackageName()); + if (!match) { + match |= taskInfo.baseActivity != null + && dumpPackage.equals(taskInfo.baseActivity.getPackageName()); + } + if (!match) { + match |= taskInfo.topActivity != null + && dumpPackage.equals(taskInfo.topActivity.getPackageName()); + } + if (!match) { + match |= taskInfo.origActivity != null + && dumpPackage.equals(taskInfo.origActivity.getPackageName()); + } + if (!match) { + match |= taskInfo.realActivity != null + && dumpPackage.equals(taskInfo.realActivity.getPackageName()); + } + if (!match) { + continue; + } + } if (!printedHeader) { if (printedAnything) { // Separate from the last block if it printed diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index 77841dc2c0bf..a691736e754a 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -3602,31 +3602,40 @@ class RootWindowContainer extends WindowContainer<DisplayContent> boolean needSep = false; for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) { DisplayContent displayContent = getChildAt(displayNdx); + if (printed) { + pw.println(); + } pw.print("Display #"); pw.print(displayContent.mDisplayId); pw.println(" (activities from top to bottom):"); for (int tdaNdx = displayContent.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) { final TaskDisplayArea taskDisplayArea = displayContent.getTaskDisplayAreaAt(tdaNdx); for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { final ActivityStack stack = taskDisplayArea.getStackAt(sNdx); - pw.println(); - printed = stack.dump(fd, pw, dumpAll, dumpClient, dumpPackage, needSep); - needSep = printed; + if (needSep) { + pw.println(); + } + needSep = stack.dump(fd, pw, dumpAll, dumpClient, dumpPackage, false); + printed |= needSep; } } - pw.println(" (resumed activities in task display areas from top to bottom):"); for (int tdaNdx = displayContent.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) { final TaskDisplayArea taskDisplayArea = displayContent.getTaskDisplayAreaAt(tdaNdx); - printThisActivity(pw, taskDisplayArea.getFocusedActivity(), dumpPackage, needSep, - " ResumedActivity:"); + printed |= printThisActivity(pw, taskDisplayArea.getFocusedActivity(), + dumpPackage, needSep, " Resumed: ", () -> { + pw.println(" Resumed activities in task display areas" + + " (from top to bottom):"); + }); } } printed |= dumpHistoryList(fd, pw, mStackSupervisor.mFinishingActivities, " ", "Fin", false, !dumpAll, - false, dumpPackage, true, " Activities waiting to finish:", null); + false, dumpPackage, true, + () -> { pw.println(" Activities waiting to finish:"); }, null); printed |= dumpHistoryList(fd, pw, mStackSupervisor.mStoppingActivities, " ", "Stop", false, !dumpAll, - false, dumpPackage, true, " Activities waiting to stop:", null); + false, dumpPackage, true, + () -> { pw.println(" Activities waiting to stop:"); }, null); return printed; } diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 8f8ca7707eb5..6c872a6319d7 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -3875,11 +3875,12 @@ class Task extends WindowContainer<WindowContainer> { pw.print(prefix); pw.print("mRootProcess="); pw.println(mRootProcess); } pw.print(prefix); pw.print("taskId=" + mTaskId); pw.println(" stackId=" + getRootTaskId()); - pw.print(prefix + "mHasBeenVisible=" + getHasBeenVisible()); - pw.print(" mResizeMode=" + ActivityInfo.resizeModeToString(mResizeMode)); - pw.print(" mSupportsPictureInPicture=" + mSupportsPictureInPicture); - pw.print(" isResizeable=" + isResizeable()); - pw.print(" lastActiveTime=" + lastActiveTime); + pw.print(prefix); pw.print("mHasBeenVisible="); pw.println(getHasBeenVisible()); + pw.print(prefix); pw.print("mResizeMode="); + pw.print(ActivityInfo.resizeModeToString(mResizeMode)); + pw.print(" mSupportsPictureInPicture="); pw.print(mSupportsPictureInPicture); + pw.print(" isResizeable="); pw.println(isResizeable()); + pw.print(prefix); pw.print("lastActiveTime="); pw.print(lastActiveTime); pw.println(" (inactive for " + (getInactiveDuration() / 1000) + "s)"); } 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 d5ecfeb55e95..e644f64cf307 100755 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -1772,6 +1772,28 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @Test + public void testGroupInstanceIds() throws Exception { + final NotificationRecord group1 = generateNotificationRecord( + mTestNotificationChannel, 1, "group1", true); + mBinderService.enqueueNotificationWithTag(PKG, PKG, "testFindGroupNotificationsLocked", + group1.getSbn().getId(), group1.getSbn().getNotification(), + group1.getSbn().getUserId()); + waitForIdle(); + + // same group, child, should be returned + final NotificationRecord group1Child = generateNotificationRecord( + mTestNotificationChannel, 2, "group1", false); + mBinderService.enqueueNotificationWithTag(PKG, PKG, "testFindGroupNotificationsLocked", + group1Child.getSbn().getId(), + group1Child.getSbn().getNotification(), group1Child.getSbn().getUserId()); + waitForIdle(); + + assertEquals(2, mNotificationRecordLogger.numCalls()); + assertEquals(mNotificationRecordLogger.get(0).getInstanceId(), + mNotificationRecordLogger.get(1).groupInstanceId.getId()); + } + + @Test public void testFindGroupNotificationsLocked() throws Exception { // make sure the same notification can be found in both lists and returned final NotificationRecord group1 = generateNotificationRecord( diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordLoggerFake.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordLoggerFake.java index 6b18cc64c5fb..64fd19e69009 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordLoggerFake.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordLoggerFake.java @@ -16,6 +16,7 @@ package com.android.server.notification; +import com.android.internal.logging.InstanceId; import com.android.internal.logging.UiEventLogger; import java.util.ArrayList; @@ -32,14 +33,16 @@ class NotificationRecordLoggerFake implements NotificationRecordLogger { static final int INVALID = -1; public int position = INVALID, buzzBeepBlink = INVALID; public boolean wasLogged; + public InstanceId groupInstanceId; CallRecord(NotificationRecord r, NotificationRecord old, int position, - int buzzBeepBlink) { + int buzzBeepBlink, InstanceId groupId) { super(r, old); this.position = position; this.buzzBeepBlink = buzzBeepBlink; wasLogged = shouldLogReported(buzzBeepBlink); event = wasLogged ? NotificationReportedEvent.fromRecordPair(this) : null; + groupInstanceId = groupId; } CallRecord(NotificationRecord r, UiEventLogger.UiEventEnum event) { @@ -67,8 +70,8 @@ class NotificationRecordLoggerFake implements NotificationRecordLogger { @Override public void maybeLogNotificationPosted(NotificationRecord r, NotificationRecord old, - int position, int buzzBeepBlink) { - mCalls.add(new CallRecord(r, old, position, buzzBeepBlink)); + int position, int buzzBeepBlink, InstanceId groupId) { + mCalls.add(new CallRecord(r, old, position, buzzBeepBlink, groupId)); } @Override |