summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/aconfig/systemui.aconfig10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/AsyncRowInflater.kt90
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/BasicRowInflater.kt51
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowInflaterTask.java51
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt3
5 files changed, 167 insertions, 38 deletions
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index 099d6b645a6d..29b578ae6e48 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -984,6 +984,16 @@ flag {
}
flag {
+ name: "use_notif_inflation_thread_for_row"
+ namespace: "systemui"
+ description: "use the @NotifInflation thread for ExpandableNotificationRow inflation"
+ bug: "375320642"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "notify_power_manager_user_activity_background"
namespace: "systemui"
description: "Decide whether to notify the user activity to power manager in the background thread."
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/AsyncRowInflater.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/AsyncRowInflater.kt
new file mode 100644
index 000000000000..c3b241154e0e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/AsyncRowInflater.kt
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.row
+
+import android.content.Context
+import android.util.Log
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.annotation.LayoutRes
+import androidx.annotation.UiThread
+import com.android.app.tracing.coroutines.launchTraced
+import com.android.app.tracing.coroutines.withContextTraced
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.dagger.qualifiers.NotifInflation
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Job
+
+@SysUISingleton
+class AsyncRowInflater
+@Inject
+constructor(
+ @Application private val applicationScope: CoroutineScope,
+ @Main private val mainCoroutineDispatcher: CoroutineDispatcher,
+ @NotifInflation private val inflationCoroutineDispatcher: CoroutineDispatcher,
+) {
+ /**
+ * Inflate the layout on the background thread, and invoke the listener on the main thread when
+ * finished.
+ *
+ * If the inflation fails on the background, it will be retried once on the main thread.
+ */
+ @UiThread
+ fun inflate(
+ context: Context,
+ layoutFactory: LayoutInflater.Factory2,
+ @LayoutRes resId: Int,
+ parent: ViewGroup,
+ listener: OnInflateFinishedListener,
+ ): Job {
+ val inflater = BasicRowInflater(context).apply { factory2 = layoutFactory }
+ return applicationScope.launchTraced("AsyncRowInflater-bg", inflationCoroutineDispatcher) {
+ val view =
+ try {
+ inflater.inflate(resId, parent, false)
+ } catch (ex: RuntimeException) {
+ // Probably a Looper failure, retry on the UI thread
+ Log.w(
+ "AsyncRowInflater",
+ "Failed to inflate resource in the background!" +
+ " Retrying on the UI thread",
+ ex,
+ )
+ null
+ }
+ withContextTraced("AsyncRowInflater-ui", mainCoroutineDispatcher) {
+ // If the inflate failed on the inflation thread, try again on the main thread
+ val finalView = view ?: inflater.inflate(resId, parent, false)
+ // Inform the listener of the completion
+ listener.onInflateFinished(finalView, resId, parent)
+ }
+ }
+ }
+
+ /**
+ * Callback interface (identical to the one from AsyncLayoutInflater) for receiving the inflated
+ * view
+ */
+ interface OnInflateFinishedListener {
+ @UiThread fun onInflateFinished(view: View, @LayoutRes resId: Int, parent: ViewGroup?)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/BasicRowInflater.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/BasicRowInflater.kt
new file mode 100644
index 000000000000..79d50b8398bc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/BasicRowInflater.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.statusbar.notification.row
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.LayoutInflater
+import android.view.View
+
+/**
+ * A [LayoutInflater] that is copy of
+ * [androidx.asynclayoutinflater.view.AsyncLayoutInflater.BasicInflater]
+ */
+internal class BasicRowInflater(context: Context) : LayoutInflater(context) {
+ override fun cloneInContext(newContext: Context): LayoutInflater {
+ return BasicRowInflater(newContext)
+ }
+
+ @Throws(ClassNotFoundException::class)
+ override fun onCreateView(name: String, attrs: AttributeSet): View {
+ for (prefix in sClassPrefixList) {
+ try {
+ val view = createView(name, prefix, attrs)
+ if (view != null) {
+ return view
+ }
+ } catch (e: ClassNotFoundException) {
+ // In this case we want to let the base class take a crack at it.
+ }
+ }
+
+ return super.onCreateView(name, attrs)
+ }
+
+ companion object {
+ private val sClassPrefixList = arrayOf("android.widget.", "android.webkit.", "android.app.")
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowInflaterTask.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowInflaterTask.java
index d60e37423e5c..3971661fa787 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowInflaterTask.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowInflaterTask.java
@@ -30,6 +30,7 @@ import androidx.annotation.VisibleForTesting;
import androidx.asynclayoutinflater.view.AsyncLayoutFactory;
import androidx.asynclayoutinflater.view.AsyncLayoutInflater;
+import com.android.systemui.Flags;
import com.android.systemui.res.R;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.InflationTask;
@@ -44,7 +45,8 @@ import javax.inject.Inject;
/**
* An inflater task that asynchronously inflates a ExpandableNotificationRow
*/
-public class RowInflaterTask implements InflationTask, AsyncLayoutInflater.OnInflateFinishedListener {
+public class RowInflaterTask implements InflationTask,
+ AsyncLayoutInflater.OnInflateFinishedListener, AsyncRowInflater.OnInflateFinishedListener {
private static final String TAG = "RowInflaterTask";
private static final boolean TRACE_ORIGIN = true;
@@ -55,15 +57,17 @@ public class RowInflaterTask implements InflationTask, AsyncLayoutInflater.OnInf
private Throwable mInflateOrigin;
private final SystemClock mSystemClock;
private final RowInflaterTaskLogger mLogger;
+ private final AsyncRowInflater mAsyncRowInflater;
private long mInflateStartTimeMs;
private UserTracker mUserTracker;
@Inject
public RowInflaterTask(SystemClock systemClock, RowInflaterTaskLogger logger,
- UserTracker userTracker) {
+ UserTracker userTracker, AsyncRowInflater asyncRowInflater) {
mSystemClock = systemClock;
mLogger = logger;
mUserTracker = userTracker;
+ mAsyncRowInflater = asyncRowInflater;
}
/**
@@ -87,13 +91,19 @@ public class RowInflaterTask implements InflationTask, AsyncLayoutInflater.OnInf
mInflateOrigin = new Throwable("inflate requested here");
}
mListener = listener;
- AsyncLayoutInflater inflater = new AsyncLayoutInflater(context, makeRowInflater(entry));
+ RowAsyncLayoutInflater asyncLayoutFactory = makeRowInflater(entry);
mEntry = entry;
entry.setInflationTask(this);
mLogger.logInflateStart(entry);
mInflateStartTimeMs = mSystemClock.elapsedRealtime();
- inflater.inflate(R.layout.status_bar_notification_row, parent, listenerExecutor, this);
+ if (Flags.useNotifInflationThreadForRow()) {
+ mAsyncRowInflater.inflate(context, asyncLayoutFactory,
+ R.layout.status_bar_notification_row, parent, this);
+ } else {
+ AsyncLayoutInflater inflater = new AsyncLayoutInflater(context, asyncLayoutFactory);
+ inflater.inflate(R.layout.status_bar_notification_row, parent, listenerExecutor, this);
+ }
}
/**
@@ -117,39 +127,6 @@ public class RowInflaterTask implements InflationTask, AsyncLayoutInflater.OnInf
entry, mSystemClock, mLogger, mUserTracker.getUserHandle());
}
- /**
- * A {@link LayoutInflater} that is copy of BasicLayoutInflater.
- */
- private static class BasicRowInflater extends LayoutInflater {
- private static final String[] sClassPrefixList =
- {"android.widget.", "android.webkit.", "android.app."};
- BasicRowInflater(Context context) {
- super(context);
- }
-
- @Override
- public LayoutInflater cloneInContext(Context newContext) {
- return new BasicRowInflater(newContext);
- }
-
- @Override
- protected View onCreateView(String name, AttributeSet attrs) throws ClassNotFoundException {
- for (String prefix : sClassPrefixList) {
- try {
- View view = createView(name, prefix, attrs);
- if (view != null) {
- return view;
- }
- } catch (ClassNotFoundException e) {
- // In this case we want to let the base class take a crack
- // at it.
- }
- }
-
- return super.onCreateView(name, attrs);
- }
- }
-
@VisibleForTesting
public static class RowAsyncLayoutInflater implements AsyncLayoutFactory {
private final NotificationEntry mEntry;
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt
index 2543ca95eb3b..8b19491bfdf8 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt
@@ -354,7 +354,8 @@ class ExpandableNotificationRowBuilder(
RowInflaterTask(
mFakeSystemClock,
Mockito.mock(RowInflaterTaskLogger::class.java, STUB_ONLY),
- userTracker
+ userTracker,
+ Mockito.mock(AsyncRowInflater::class.java, STUB_ONLY),
)
val row = rowInflaterTask.inflateSynchronously(context, null, entry)