diff options
47 files changed, 738 insertions, 679 deletions
diff --git a/apct-tests/perftests/protolog/Android.bp b/apct-tests/perftests/protolog/Android.bp new file mode 100644 index 000000000000..08e365be514a --- /dev/null +++ b/apct-tests/perftests/protolog/Android.bp @@ -0,0 +1,33 @@ +// Copyright (C) 2024 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. + +android_test { + name: "ProtologPerfTests", + team: "trendy_team_windowing_tools", + srcs: ["src/**/*.java"], + static_libs: [ + "androidx.test.rules", + "androidx.annotation_annotation", + "apct-perftests-utils", + "collector-device-lib", + "platform-test-annotations", + ], + test_suites: [ + "device-tests", + "automotive-tests", + ], + data: [":perfetto_artifacts"], + platform_apis: true, + certificate: "platform", +} diff --git a/apct-tests/perftests/protolog/AndroidManifest.xml b/apct-tests/perftests/protolog/AndroidManifest.xml new file mode 100644 index 000000000000..68125df99ec3 --- /dev/null +++ b/apct-tests/perftests/protolog/AndroidManifest.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2020 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. +--> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.perftests.protolog"> + + <!-- For perfetto trace files --> + <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" /> + <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> + + <application> + <uses-library android:name="android.test.runner" /> + </application> + + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="com.android.perftests.protolog"> + <!-- <meta-data android:name="listener" android:value="android.protolog.ProtologPerfRunListener" /> --> + </instrumentation> +</manifest> diff --git a/apct-tests/perftests/protolog/AndroidTest.xml b/apct-tests/perftests/protolog/AndroidTest.xml new file mode 100644 index 000000000000..871a20ce4cef --- /dev/null +++ b/apct-tests/perftests/protolog/AndroidTest.xml @@ -0,0 +1,67 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2024 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. +--> +<configuration description="Runs ProtologPerfTests metric instrumentation."> + <option name="test-suite-tag" value="apct" /> + <option name="test-suite-tag" value="apct-metric-instrumentation" /> + <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> + <option name="cleanup-apks" value="true" /> + <option name="test-file-name" value="ProtologPerfTests.apk" /> + </target_preparer> + + <target_preparer class="com.android.tradefed.targetprep.DeviceSetup"> + <option name="force-skip-system-props" value="true" /> + <option name="run-command" value="input keyevent KEYCODE_WAKEUP" /> + <option name="run-command" value="cmd window dismiss-keyguard" /> + <option name="run-command" value="cmd package compile -m speed com.android.perftests.wm" /> + </target_preparer> + + <!-- Needed for pushing the trace config file --> + <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/> + <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"> + <option name="push-file" key="trace_config_detailed.textproto" value="/data/misc/perfetto-traces/trace_config.textproto" /> + </target_preparer> + + <!-- Needed for storing the perfetto trace files in the sdcard/test_results--> + <option name="isolated-storage" value="false" /> + + <test class="com.android.tradefed.testtype.AndroidJUnitTest" > + <option name="package" value="com.android.perftests.protolog" /> + <option name="hidden-api-checks" value="false"/> + + <!-- Listener related args for collecting the traces and waiting for the device to stabilize. --> + <option name="device-listeners" value="android.device.collectors.ProcLoadListener,android.device.collectors.PerfettoListener" /> + + <!-- Guarantee that user defined RunListeners will be running before any of the default listeners defined in this runner. --> + <option name="instrumentation-arg" key="newRunListenerMode" value="true" /> + + <!-- ProcLoadListener related arguments --> + <!-- Wait for device last minute threshold to reach 3 with 2 minute timeout before starting the test run --> + <option name="instrumentation-arg" key="procload-collector:per_run" value="true" /> + <option name="instrumentation-arg" key="proc-loadavg-threshold" value="3" /> + <option name="instrumentation-arg" key="proc-loadavg-timeout" value="120000" /> + <option name="instrumentation-arg" key="proc-loadavg-interval" value="10000" /> + + <!-- PerfettoListener related arguments --> + <option name="instrumentation-arg" key="perfetto_config_text_proto" value="true" /> + <option name="instrumentation-arg" key="perfetto_config_file" value="trace_config.textproto" /> + </test> + + <!-- <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector"> + <option name="directory-keys" value="/data/local/tmp/ProtologPerfTests" /> --> + <!-- Needed for pulling the collected trace config on to the host --> + <!-- <option name="pull-pattern-keys" value="perfetto_file_path" /> + </metrics_collector> --> +</configuration> diff --git a/apct-tests/perftests/protolog/OWNERS b/apct-tests/perftests/protolog/OWNERS new file mode 100644 index 000000000000..3f3308cfc75a --- /dev/null +++ b/apct-tests/perftests/protolog/OWNERS @@ -0,0 +1 @@ +include platform/development:/tools/winscope/OWNERS diff --git a/apct-tests/perftests/protolog/src/com/android/internal/protolog/ProtologPerfTest.java b/apct-tests/perftests/protolog/src/com/android/internal/protolog/ProtologPerfTest.java new file mode 100644 index 000000000000..e1edb3712ff0 --- /dev/null +++ b/apct-tests/perftests/protolog/src/com/android/internal/protolog/ProtologPerfTest.java @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2024 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.internal.protolog; + +import android.perftests.utils.BenchmarkState; +import android.perftests.utils.PerfStatusReporter; + +import com.android.internal.protolog.common.IProtoLogGroup; +import com.android.internal.protolog.common.LogLevel; + +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +import java.util.Arrays; +import java.util.Collection; + +@RunWith(Parameterized.class) +public class ProtologPerfTest { + @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); + + @Parameters(name="logToProto_{0}_logToLogcat_{1}") + public static Collection<Object[]> params() { + return Arrays.asList(new Object[][] { + { true, true }, + { true, false }, + { false, true }, + { false, false } + }); + } + + private final boolean mLogToProto; + private final boolean mLogToLogcat; + + public ProtologPerfTest(boolean logToProto, boolean logToLogcat) { + mLogToProto = logToProto; + mLogToLogcat = logToLogcat; + } + + @BeforeClass + public static void init() { + ProtoLog.init(TestProtoLogGroup.values()); + } + + @Before + public void setUp() { + TestProtoLogGroup.TEST_GROUP.setLogToProto(mLogToProto); + TestProtoLogGroup.TEST_GROUP.setLogToLogcat(mLogToLogcat); + } + + @Test + public void logProcessedProtoLogMessageWithoutArgs() { + final var protoLog = ProtoLog.getSingleInstance(); + + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + protoLog.log( + LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 123, + 0, (Object[]) null); + } + } + + @Test + public void logProcessedProtoLogMessageWithArgs() { + final var protoLog = ProtoLog.getSingleInstance(); + + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + protoLog.log( + LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 123, + 0b1110101001010100, + new Object[]{"test", 1, 2, 3, 0.4, 0.5, 0.6, true}); + } + } + + @Test + public void logNonProcessedProtoLogMessageWithNoArgs() { + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + ProtoLog.d(TestProtoLogGroup.TEST_GROUP, "Test message"); + } + } + + @Test + public void logNonProcessedProtoLogMessageWithArgs() { + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + ProtoLog.d(TestProtoLogGroup.TEST_GROUP, "Test messag %s, %d, %b", "arg1", 2, true); + } + } + + private enum TestProtoLogGroup implements IProtoLogGroup { + TEST_GROUP(true, true, false, "WindowManagetProtoLogTest"); + + private final boolean mEnabled; + private volatile boolean mLogToProto; + private volatile boolean mLogToLogcat; + private final String mTag; + + /** + * @param enabled set to false to exclude all log statements for this group from + * compilation, they will not be available in runtime. + * @param logToProto enable binary logging for the group + * @param logToLogcat enable text logging for the group + * @param tag name of the source of the logged message + */ + TestProtoLogGroup(boolean enabled, boolean logToProto, boolean logToLogcat, String tag) { + this.mEnabled = enabled; + this.mLogToProto = logToProto; + this.mLogToLogcat = logToLogcat; + this.mTag = tag; + } + + @Override + public boolean isEnabled() { + return mEnabled; + } + + @Override + public boolean isLogToProto() { + return mLogToProto; + } + + @Override + public boolean isLogToLogcat() { + return mLogToLogcat; + } + + @Override + public boolean isLogToAny() { + return mLogToLogcat || mLogToProto; + } + + @Override + public String getTag() { + return mTag; + } + + @Override + public void setLogToProto(boolean logToProto) { + this.mLogToProto = logToProto; + } + + @Override + public void setLogToLogcat(boolean logToLogcat) { + this.mLogToLogcat = logToLogcat; + } + + @Override + public int getId() { + return ordinal(); + } + } +} diff --git a/core/java/com/android/internal/protolog/LogcatOnlyProtoLogImpl.java b/core/java/com/android/internal/protolog/LogcatOnlyProtoLogImpl.java index b82c660fcf57..34e04181388d 100644 --- a/core/java/com/android/internal/protolog/LogcatOnlyProtoLogImpl.java +++ b/core/java/com/android/internal/protolog/LogcatOnlyProtoLogImpl.java @@ -40,6 +40,8 @@ import java.util.List; */ @Deprecated public class LogcatOnlyProtoLogImpl implements IProtoLog { + private static final String LOG_TAG = LogcatOnlyProtoLogImpl.class.getName(); + @Override public void log(LogLevel logLevel, IProtoLogGroup group, long messageHash, int paramsMask, Object[] args) { @@ -48,19 +50,21 @@ public class LogcatOnlyProtoLogImpl implements IProtoLog { @Override public void log(LogLevel logLevel, IProtoLogGroup group, String messageString, Object[] args) { - if (REQUIRE_PROTOLOGTOOL) { - throw new RuntimeException( - "REQUIRE_PROTOLOGTOOL not set to false before the first log call."); + if (REQUIRE_PROTOLOGTOOL && group.isLogToProto()) { + Log.w(LOG_TAG, "ProtoLog message not processed. Failed to log it to proto. " + + "Logging it below to logcat instead."); } - String formattedString = TextUtils.formatSimple(messageString, args); - switch (logLevel) { - case VERBOSE -> Log.v(group.getTag(), formattedString); - case INFO -> Log.i(group.getTag(), formattedString); - case DEBUG -> Log.d(group.getTag(), formattedString); - case WARN -> Log.w(group.getTag(), formattedString); - case ERROR -> Log.e(group.getTag(), formattedString); - case WTF -> Log.wtf(group.getTag(), formattedString); + if (group.isLogToLogcat() || group.isLogToProto()) { + String formattedString = TextUtils.formatSimple(messageString, args); + switch (logLevel) { + case VERBOSE -> Log.v(group.getTag(), formattedString); + case INFO -> Log.i(group.getTag(), formattedString); + case DEBUG -> Log.d(group.getTag(), formattedString); + case WARN -> Log.w(group.getTag(), formattedString); + case ERROR -> Log.e(group.getTag(), formattedString); + case WTF -> Log.wtf(group.getTag(), formattedString); + } } } diff --git a/core/java/com/android/internal/protolog/ProtoLog.java b/core/java/com/android/internal/protolog/ProtoLog.java index 660d3c99f538..bf77db7b6a33 100644 --- a/core/java/com/android/internal/protolog/ProtoLog.java +++ b/core/java/com/android/internal/protolog/ProtoLog.java @@ -63,6 +63,9 @@ public class ProtoLog { * @param groups The ProtoLog groups that will be used in the process. */ public static void init(IProtoLogGroup... groups) { + // These tracing instances are only used when we cannot or do not preprocess the source + // files to extract out the log strings. Otherwise, the trace calls are replaced with calls + // directly to the generated tracing implementations. if (android.tracing.Flags.perfettoProtologTracing()) { synchronized (sInitLock) { if (sProtoLogInstance != null) { @@ -76,8 +79,6 @@ public class ProtoLog { sProtoLogInstance = new PerfettoProtoLogImpl(groups); } } else { - // The first call to ProtoLog is likely to flip REQUIRE_PROTOLOGTOOL, which is when this - // static block will be executed before REQUIRE_PROTOLOGTOOL is actually set. sProtoLogInstance = new LogcatOnlyProtoLogImpl(); } } diff --git a/core/jni/android_graphics_SurfaceTexture.cpp b/core/jni/android_graphics_SurfaceTexture.cpp index 50832a5c256a..8dd63cc07b8a 100644 --- a/core/jni/android_graphics_SurfaceTexture.cpp +++ b/core/jni/android_graphics_SurfaceTexture.cpp @@ -256,9 +256,21 @@ static void SurfaceTexture_classInit(JNIEnv* env, jclass clazz) } } -static void SurfaceTexture_init(JNIEnv* env, jobject thiz, jboolean isDetached, - jint texName, jboolean singleBufferMode, jobject weakThiz) -{ +static void SurfaceTexture_init(JNIEnv* env, jobject thiz, jboolean isDetached, jint texName, + jboolean singleBufferMode, jobject weakThiz) { +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) + sp<SurfaceTexture> surfaceTexture; + if (isDetached) { + surfaceTexture = new SurfaceTexture(GL_TEXTURE_EXTERNAL_OES, true, !singleBufferMode); + } else { + surfaceTexture = + new SurfaceTexture(texName, GL_TEXTURE_EXTERNAL_OES, true, !singleBufferMode); + } + + if (singleBufferMode) { + surfaceTexture->setMaxBufferCount(1); + } +#else sp<IGraphicBufferProducer> producer; sp<IGraphicBufferConsumer> consumer; BufferQueue::createBufferQueue(&producer, &consumer); @@ -275,6 +287,7 @@ static void SurfaceTexture_init(JNIEnv* env, jobject thiz, jboolean isDetached, surfaceTexture = new SurfaceTexture(consumer, texName, GL_TEXTURE_EXTERNAL_OES, true, !singleBufferMode); } +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) if (surfaceTexture == 0) { jniThrowException(env, OutOfResourcesException, @@ -287,11 +300,27 @@ static void SurfaceTexture_init(JNIEnv* env, jobject thiz, jboolean isDetached, createProcessUniqueId())); // If the current context is protected, inform the producer. +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) + surfaceTexture->setConsumerIsProtected(isProtectedContext()); + + SurfaceTexture_setSurfaceTexture(env, thiz, surfaceTexture); + sp<Surface> surface = surfaceTexture->getSurface(); + if (nullptr == surface) { + jniThrowException(env, IllegalStateException, "Unable to get surface from SurfaceTexture"); + return; + } + sp<IGraphicBufferProducer> igbp = surface->getIGraphicBufferProducer(); + if (nullptr == igbp) { + jniThrowException(env, IllegalStateException, "Unable to get IGBP from Surface"); + return; + } + SurfaceTexture_setProducer(env, thiz, igbp); +#else consumer->setConsumerIsProtected(isProtectedContext()); SurfaceTexture_setSurfaceTexture(env, thiz, surfaceTexture); SurfaceTexture_setProducer(env, thiz, producer); - +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) jclass clazz = env->GetObjectClass(thiz); if (clazz == NULL) { jniThrowRuntimeException(env, diff --git a/libs/hwui/tests/common/TestContext.cpp b/libs/hwui/tests/common/TestContext.cpp index fd596d998dfd..e427c97e41fa 100644 --- a/libs/hwui/tests/common/TestContext.cpp +++ b/libs/hwui/tests/common/TestContext.cpp @@ -16,6 +16,7 @@ #include "tests/common/TestContext.h" +#include <com_android_graphics_libgui_flags.h> #include <cutils/trace.h> namespace android { @@ -101,6 +102,14 @@ void TestContext::createWindowSurface() { } void TestContext::createOffscreenSurface() { +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) + mConsumer = new BufferItemConsumer(GRALLOC_USAGE_HW_COMPOSER, 4); + const ui::Size& resolution = getActiveDisplayResolution(); + mConsumer->setDefaultBufferSize(resolution.getWidth(), resolution.getHeight()); + mSurface = mConsumer->getSurface(); + mSurface->setMaxDequeuedBufferCount(3); + mSurface->setAsyncMode(true); +#else sp<IGraphicBufferProducer> producer; sp<IGraphicBufferConsumer> consumer; BufferQueue::createBufferQueue(&producer, &consumer); @@ -110,6 +119,7 @@ void TestContext::createOffscreenSurface() { const ui::Size& resolution = getActiveDisplayResolution(); mConsumer->setDefaultBufferSize(resolution.getWidth(), resolution.getHeight()); mSurface = new Surface(producer); +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) } void TestContext::waitForVsync() { @@ -144,4 +154,4 @@ void TestContext::waitForVsync() { } // namespace test } // namespace uirenderer -} // namespace android +} // namespace android
\ No newline at end of file diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp index 371e3d2deda5..019b1e0de4d6 100644 --- a/media/jni/android_media_ImageReader.cpp +++ b/media/jni/android_media_ImageReader.cpp @@ -17,35 +17,31 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "ImageReader_JNI" #define ATRACE_TAG ATRACE_TAG_CAMERA -#include "android_media_Utils.h" -#include <cutils/atomic.h> -#include <utils/Log.h> -#include <utils/misc.h> -#include <utils/List.h> -#include <utils/Trace.h> -#include <utils/String8.h> - -#include <cstdio> - -#include <gui/BufferItemConsumer.h> -#include <gui/Surface.h> - +#include <android/hardware_buffer_jni.h> #include <android_runtime/AndroidRuntime.h> -#include <android_runtime/android_view_Surface.h> #include <android_runtime/android_graphics_GraphicBuffer.h> #include <android_runtime/android_hardware_HardwareBuffer.h> +#include <android_runtime/android_view_Surface.h> +#include <com_android_graphics_libgui_flags.h> +#include <cutils/atomic.h> #include <grallocusage/GrallocUsageConversion.h> - -#include <private/android/AHardwareBufferHelpers.h> - +#include <gui/BufferItemConsumer.h> +#include <gui/Surface.h> +#include <inttypes.h> #include <jni.h> #include <nativehelper/JNIHelp.h> - +#include <private/android/AHardwareBufferHelpers.h> #include <stdint.h> -#include <inttypes.h> -#include <android/hardware_buffer_jni.h> - #include <ui/Rect.h> +#include <utils/List.h> +#include <utils/Log.h> +#include <utils/String8.h> +#include <utils/Trace.h> +#include <utils/misc.h> + +#include <cstdio> + +#include "android_media_Utils.h" #define ANDROID_MEDIA_IMAGEREADER_CTX_JNI_ID "mNativeContext" #define ANDROID_MEDIA_SURFACEIMAGE_BUFFER_JNI_ID "mNativeBuffer" @@ -393,18 +389,25 @@ static void ImageReader_init(JNIEnv* env, jobject thiz, jobject weakThiz, jint w } sp<JNIImageReaderContext> ctx(new JNIImageReaderContext(env, weakThiz, clazz, maxImages)); - sp<IGraphicBufferProducer> gbProducer; - sp<IGraphicBufferConsumer> gbConsumer; - BufferQueue::createBufferQueue(&gbProducer, &gbConsumer); - sp<BufferItemConsumer> bufferConsumer; String8 consumerName = String8::format("ImageReader-%dx%df%xm%d-%d-%d", width, height, nativeHalFormat, maxImages, getpid(), createProcessUniqueId()); uint64_t consumerUsage = android_hardware_HardwareBuffer_convertToGrallocUsageBits(ndkUsage); +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) + sp<BufferItemConsumer> bufferConsumer = new BufferItemConsumer(consumerUsage, maxImages, + /*controlledByApp*/ true); + sp<IGraphicBufferProducer> gbProducer = + bufferConsumer->getSurface()->getIGraphicBufferProducer(); +#else + sp<IGraphicBufferProducer> gbProducer; + sp<IGraphicBufferConsumer> gbConsumer; + BufferQueue::createBufferQueue(&gbProducer, &gbConsumer); + sp<BufferItemConsumer> bufferConsumer; bufferConsumer = new BufferItemConsumer(gbConsumer, consumerUsage, maxImages, /*controlledByApp*/true); +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) if (bufferConsumer == nullptr) { jniThrowExceptionFmt(env, "java/lang/RuntimeException", "Failed to allocate native buffer consumer for hal format 0x%x and usage 0x%x", @@ -413,7 +416,11 @@ static void ImageReader_init(JNIEnv* env, jobject thiz, jobject weakThiz, jint w } if (consumerUsage & GRALLOC_USAGE_PROTECTED) { +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) + bufferConsumer->setConsumerIsProtected(true); +#else gbConsumer->setConsumerIsProtected(true); +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) } ctx->setBufferConsumer(bufferConsumer); diff --git a/media/mca/filterfw/native/core/gl_env.cpp b/media/mca/filterfw/native/core/gl_env.cpp index 1bb82f88ba48..4637ccdfad15 100644 --- a/media/mca/filterfw/native/core/gl_env.cpp +++ b/media/mca/filterfw/native/core/gl_env.cpp @@ -15,21 +15,23 @@ */ // #define LOG_NDEBUG 0 -#include "base/logging.h" -#include "base/utilities.h" #include "core/gl_env.h" -#include "core/shader_program.h" -#include "core/vertex_frame.h" -#include "system/window.h" -#include <map> -#include <string> #include <EGL/eglext.h> - +#include <com_android_graphics_libgui_flags.h> #include <gui/BufferQueue.h> -#include <gui/Surface.h> #include <gui/GLConsumer.h> #include <gui/IGraphicBufferProducer.h> +#include <gui/Surface.h> + +#include <map> +#include <string> + +#include "base/logging.h" +#include "base/utilities.h" +#include "core/shader_program.h" +#include "core/vertex_frame.h" +#include "system/window.h" namespace android { namespace filterfw { @@ -165,12 +167,18 @@ bool GLEnv::InitWithNewContext() { } // Create dummy surface using a GLConsumer +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) + surfaceTexture_ = new GLConsumer(0, GLConsumer::TEXTURE_EXTERNAL, /*useFenceSync=*/true, + /*isControlledByApp=*/false); + window_ = surfaceTexture_->getSurface(); +#else sp<IGraphicBufferProducer> producer; sp<IGraphicBufferConsumer> consumer; BufferQueue::createBufferQueue(&producer, &consumer); surfaceTexture_ = new GLConsumer(consumer, 0, GLConsumer::TEXTURE_EXTERNAL, true, false); window_ = new Surface(producer); +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) surfaces_[0] = SurfaceWindowPair(eglCreateWindowSurface(display(), config, window_.get(), NULL), NULL); if (CheckEGLError("eglCreateWindowSurface")) return false; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinator.kt index f74c9a6a209f..e9292f8c3cb8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinator.kt @@ -79,6 +79,7 @@ internal constructor( // NOTE: NotificationEntry.isClearable will internally check group children to ensure // the group itself definitively clearable. val isClearable = !isSensitiveContentProtectionActive && entry.isClearable + && !entry.isSensitive.value when { isSilent && isClearable -> hasClearableSilentNotifs = true isSilent && !isClearable -> hasNonClearableSilentNotifs = true diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/lifecycle/ActivatableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/lifecycle/ActivatableTest.kt index 67517a25ec87..67517a25ec87 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/lifecycle/ActivatableTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/lifecycle/ActivatableTest.kt diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/lifecycle/SysUiViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/lifecycle/SysUiViewModelTest.kt index 7d5722035a14..7d5722035a14 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/lifecycle/SysUiViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/lifecycle/SysUiViewModelTest.kt diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/DragAndDropTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/DragAndDropTest.kt index d9faa30cb072..d9faa30cb072 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/DragAndDropTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/DragAndDropTest.kt diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImplTest.kt index fadb1d7c91a1..fadb1d7c91a1 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImplTest.kt diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinatorTest.kt index ad6aca1dcd4f..3c583f26b0df 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinatorTest.kt @@ -34,6 +34,7 @@ import com.android.systemui.statusbar.notification.collection.render.NotifStats import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor import com.android.systemui.statusbar.notification.domain.interactor.RenderNotificationListInteractor import com.android.systemui.statusbar.notification.footer.shared.FooterViewRefactor +import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow import com.android.systemui.statusbar.notification.stack.BUCKET_ALERTING import com.android.systemui.statusbar.notification.stack.BUCKET_SILENT import com.android.systemui.statusbar.policy.SensitiveNotificationProtectionController @@ -45,8 +46,8 @@ import org.junit.runner.RunWith import org.mockito.Mock import org.mockito.Mockito.verify import org.mockito.Mockito.verifyZeroInteractions -import org.mockito.Mockito.`when` as whenever import org.mockito.MockitoAnnotations.initMocks +import org.mockito.Mockito.`when` as whenever @SmallTest @RunWith(AndroidJUnit4::class) @@ -66,6 +67,7 @@ class StackCoordinatorTest : SysuiTestCase() { SensitiveNotificationProtectionController @Mock private lateinit var stackController: NotifStackController @Mock private lateinit var section: NotifSection + @Mock private lateinit var row: ExpandableNotificationRow @Before fun setUp() { @@ -74,6 +76,8 @@ class StackCoordinatorTest : SysuiTestCase() { whenever(sensitiveNotificationProtectionController.isSensitiveStateActive).thenReturn(false) entry = NotificationEntryBuilder().setSection(section).build() + entry.row = row + entry.setSensitive(false, false) coordinator = StackCoordinator( groupExpansionManagerImpl, @@ -189,4 +193,17 @@ class StackCoordinatorTest : SysuiTestCase() { .setNotifStats(NotifStats(1, false, false, true, false)) verifyZeroInteractions(stackController) } + + @Test + @EnableFlags( + FooterViewRefactor.FLAG_NAME + ) + fun testSetNotificationStats_footerFlagOn_nonClearableRedacted() { + entry.setSensitive(true, true) + whenever(section.bucket).thenReturn(BUCKET_ALERTING) + afterRenderListListener.onAfterRenderList(listOf(entry), stackController) + verify(activeNotificationsInteractor) + .setNotifStats(NotifStats(1, hasNonClearableAlertingNotifs = true, false, false, false)) + verifyZeroInteractions(stackController) + } } diff --git a/ravenwood/Android.bp b/ravenwood/Android.bp index 58cd2e4cee6c..c71b99fbdb77 100644 --- a/ravenwood/Android.bp +++ b/ravenwood/Android.bp @@ -331,6 +331,7 @@ android_ravenwood_libgroup { name: "ravenwood-runtime", data: [ "framework-res", + "ravenwood-empty-res", ], libs: [ "100-framework-minus-apex.ravenwood", diff --git a/ravenwood/TEST_MAPPING b/ravenwood/TEST_MAPPING index 691d06e0b2bf..7e2ee3e2a052 100644 --- a/ravenwood/TEST_MAPPING +++ b/ravenwood/TEST_MAPPING @@ -52,10 +52,6 @@ "host": true }, { - "name": "RavenwoodCoreTest", - "host": true - }, - { "name": "RavenwoodResApkTest", "host": true }, diff --git a/ravenwood/coretest/Android.bp b/ravenwood/coretest/Android.bp deleted file mode 100644 index a78c5c1e8227..000000000000 --- a/ravenwood/coretest/Android.bp +++ /dev/null @@ -1,23 +0,0 @@ -package { - // See: http://go/android-license-faq - // A large-scale-change added 'default_applicable_licenses' to import - // all of the 'license_kinds' from "frameworks_base_license" - // to get the below license kinds: - // SPDX-license-identifier-Apache-2.0 - default_applicable_licenses: ["frameworks_base_license"], -} - -android_ravenwood_test { - name: "RavenwoodCoreTest", - - static_libs: [ - "androidx.annotation_annotation", - "androidx.test.ext.junit", - "androidx.test.rules", - ], - srcs: [ - "test/**/*.java", - ], - sdk_version: "test_current", - auto_gen_config: true, -} diff --git a/ravenwood/coretest/README.md b/ravenwood/coretest/README.md deleted file mode 100644 index b60bfbfcb6f4..000000000000 --- a/ravenwood/coretest/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Ravenwood core test - -This test contains (non-bivalent) tests for Ravenwood itself -- e.g. tests for the ravenwood rules.
\ No newline at end of file diff --git a/ravenwood/coretest/test/com/android/ravenwoodtest/coretest/RavenwoodTestRunnerValidationTest.java b/ravenwood/coretest/test/com/android/ravenwoodtest/coretest/RavenwoodTestRunnerValidationTest.java deleted file mode 100644 index f1e33cb686f1..000000000000 --- a/ravenwood/coretest/test/com/android/ravenwoodtest/coretest/RavenwoodTestRunnerValidationTest.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2024 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.ravenwoodtest.coretest; - -import android.platform.test.ravenwood.RavenwoodRule; - -import androidx.test.runner.AndroidJUnit4; // Intentionally use the deprecated one. - -import org.junit.Assume; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.junit.rules.RuleChain; -import org.junit.runner.RunWith; - -/** - * Test for the test runner validator in RavenwoodRule. - */ -@RunWith(AndroidJUnit4.class) -public class RavenwoodTestRunnerValidationTest { - // Note the following rules don't have a @Rule, because they need to be applied in a specific - // order. So we use a RuleChain instead. - private ExpectedException mThrown = ExpectedException.none(); - private final RavenwoodRule mRavenwood = new RavenwoodRule(); - - @Rule - public final RuleChain chain = RuleChain.outerRule(mThrown).around(mRavenwood); - - public RavenwoodTestRunnerValidationTest() { - Assume.assumeTrue(RavenwoodRule._$RavenwoodPrivate.isOptionalValidationEnabled()); - // Because RavenwoodRule will throw this error before executing the test method, - // we can't do it in the test method itself. - // So instead, we initialize it here. - mThrown.expectMessage("Switch to androidx.test.ext.junit.runners.AndroidJUnit4"); - } - - @Test - public void testValidateTestRunner() { - } -} diff --git a/ravenwood/coretest/test/com/android/ravenwoodtest/coretest/methodvalidation/RavenwoodTestMethodValidation_Fail01_Test.java b/ravenwood/coretest/test/com/android/ravenwoodtest/coretest/methodvalidation/RavenwoodTestMethodValidation_Fail01_Test.java deleted file mode 100644 index db95fad2a3ad..000000000000 --- a/ravenwood/coretest/test/com/android/ravenwoodtest/coretest/methodvalidation/RavenwoodTestMethodValidation_Fail01_Test.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2024 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.ravenwoodtest.coretest.methodvalidation; - -import android.platform.test.ravenwood.RavenwoodRule; - -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.junit.rules.RuleChain; -import org.junit.runner.RunWith; - -/** - * RavenwoodRule has a validator to ensure "test-looking" methods have valid JUnit annotations. - * This class contains tests for this validator. - */ -@RunWith(AndroidJUnit4.class) -public class RavenwoodTestMethodValidation_Fail01_Test { - private ExpectedException mThrown = ExpectedException.none(); - private final RavenwoodRule mRavenwood = new RavenwoodRule(); - - @Rule - public final RuleChain chain = RuleChain.outerRule(mThrown).around(mRavenwood); - - public RavenwoodTestMethodValidation_Fail01_Test() { - mThrown.expectMessage("Method setUp() doesn't have @Before"); - } - - @SuppressWarnings("JUnit4SetUpNotRun") - public void setUp() { - } - - @Test - public void testEmpty() { - } -} diff --git a/ravenwood/coretest/test/com/android/ravenwoodtest/coretest/methodvalidation/RavenwoodTestMethodValidation_Fail02_Test.java b/ravenwood/coretest/test/com/android/ravenwoodtest/coretest/methodvalidation/RavenwoodTestMethodValidation_Fail02_Test.java deleted file mode 100644 index ddc66c73a7c0..000000000000 --- a/ravenwood/coretest/test/com/android/ravenwoodtest/coretest/methodvalidation/RavenwoodTestMethodValidation_Fail02_Test.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2024 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.ravenwoodtest.coretest.methodvalidation; - -import android.platform.test.ravenwood.RavenwoodRule; - -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.junit.rules.RuleChain; -import org.junit.runner.RunWith; - -/** - * RavenwoodRule has a validator to ensure "test-looking" methods have valid JUnit annotations. - * This class contains tests for this validator. - */ -@RunWith(AndroidJUnit4.class) -public class RavenwoodTestMethodValidation_Fail02_Test { - private ExpectedException mThrown = ExpectedException.none(); - private final RavenwoodRule mRavenwood = new RavenwoodRule(); - - @Rule - public final RuleChain chain = RuleChain.outerRule(mThrown).around(mRavenwood); - - public RavenwoodTestMethodValidation_Fail02_Test() { - mThrown.expectMessage("Method tearDown() doesn't have @After"); - } - - @SuppressWarnings("JUnit4TearDownNotRun") - public void tearDown() { - } - - @Test - public void testEmpty() { - } -} diff --git a/ravenwood/coretest/test/com/android/ravenwoodtest/coretest/methodvalidation/RavenwoodTestMethodValidation_Fail03_Test.java b/ravenwood/coretest/test/com/android/ravenwoodtest/coretest/methodvalidation/RavenwoodTestMethodValidation_Fail03_Test.java deleted file mode 100644 index ec8e907dcdb3..000000000000 --- a/ravenwood/coretest/test/com/android/ravenwoodtest/coretest/methodvalidation/RavenwoodTestMethodValidation_Fail03_Test.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2024 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.ravenwoodtest.coretest.methodvalidation; - -import android.platform.test.ravenwood.RavenwoodRule; - -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.junit.rules.RuleChain; -import org.junit.runner.RunWith; - -/** - * RavenwoodRule has a validator to ensure "test-looking" methods have valid JUnit annotations. - * This class contains tests for this validator. - */ -@RunWith(AndroidJUnit4.class) -public class RavenwoodTestMethodValidation_Fail03_Test { - private ExpectedException mThrown = ExpectedException.none(); - private final RavenwoodRule mRavenwood = new RavenwoodRule(); - - @Rule - public final RuleChain chain = RuleChain.outerRule(mThrown).around(mRavenwood); - - public RavenwoodTestMethodValidation_Fail03_Test() { - mThrown.expectMessage("Method testFoo() doesn't have @Test"); - } - - @SuppressWarnings("JUnit4TestNotRun") - public void testFoo() { - } - - @Test - public void testEmpty() { - } -} diff --git a/ravenwood/coretest/test/com/android/ravenwoodtest/coretest/methodvalidation/RavenwoodTestMethodValidation_OkTest.java b/ravenwood/coretest/test/com/android/ravenwoodtest/coretest/methodvalidation/RavenwoodTestMethodValidation_OkTest.java deleted file mode 100644 index d952d07b3817..000000000000 --- a/ravenwood/coretest/test/com/android/ravenwoodtest/coretest/methodvalidation/RavenwoodTestMethodValidation_OkTest.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2024 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.ravenwoodtest.coretest.methodvalidation; - -import android.platform.test.ravenwood.RavenwoodRule; - -import androidx.test.runner.AndroidJUnit4; - -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; - -/** - * RavenwoodRule has a validator to ensure "test-looking" methods have valid JUnit annotations. - * This class contains tests for this validator. - */ -@RunWith(AndroidJUnit4.class) -public class RavenwoodTestMethodValidation_OkTest { - @Rule - public final RavenwoodRule mRavenwood = new RavenwoodRule(); - - @Before - public void setUp() { - } - - @Before - public void testSetUp() { - } - - @After - public void tearDown() { - } - - @After - public void testTearDown() { - } - - @Test - public void testEmpty() { - } -} diff --git a/ravenwood/empty-res/Android.bp b/ravenwood/empty-res/Android.bp new file mode 100644 index 000000000000..3af769067d35 --- /dev/null +++ b/ravenwood/empty-res/Android.bp @@ -0,0 +1,4 @@ +android_app { + name: "ravenwood-empty-res", + sdk_version: "current", +} diff --git a/ravenwood/empty-res/AndroidManifest.xml b/ravenwood/empty-res/AndroidManifest.xml new file mode 100644 index 000000000000..f73460b42213 --- /dev/null +++ b/ravenwood/empty-res/AndroidManifest.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2024 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. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.ravenwood.emptyres"> +</manifest> diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java index 3ea4cb7fb69f..7b4c17390942 100644 --- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java +++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java @@ -16,9 +16,9 @@ package android.platform.test.ravenwood; +import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_EMPTY_RESOURCES_APK; import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_RESOURCE_APK; -import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; @@ -39,24 +39,12 @@ import androidx.test.platform.app.InstrumentationRegistry; import com.android.internal.os.RuntimeInit; import com.android.server.LocalServices; -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; import org.junit.runner.Description; -import org.junit.runner.RunWith; import org.junit.runners.model.Statement; import java.io.File; import java.io.IOException; import java.io.PrintStream; -import java.lang.annotation.Annotation; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.List; import java.util.Map; import java.util.Objects; import java.util.concurrent.Executors; @@ -109,10 +97,6 @@ public class RavenwoodRuleImpl { android.os.Process.init$ravenwood(rule.mUid, rule.mPid); android.os.Binder.init$ravenwood(); -// android.os.SystemProperties.init$ravenwood( -// rule.mSystemProperties.getValues(), -// rule.mSystemProperties.getKeyReadablePredicate(), -// rule.mSystemProperties.getKeyWritablePredicate()); setSystemProperties(rule.mSystemProperties); ServiceManager.init$ravenwood(); @@ -131,11 +115,12 @@ public class RavenwoodRuleImpl { // TODO This should be integrated into LoadedApk final Supplier<Resources> resourcesSupplier = () -> { - final var resApkFile = new File(RAVENWOOD_RESOURCE_APK).getAbsoluteFile(); + var resApkFile = new File(RAVENWOOD_RESOURCE_APK); + if (!resApkFile.isFile()) { + resApkFile = new File(RAVENWOOD_EMPTY_RESOURCES_APK); + } assertTrue(resApkFile.isFile()); - - final var res = resApkFile.getAbsolutePath(); - + final String res = resApkFile.getAbsolutePath(); final var emptyPaths = new String[0]; ResourcesManager.getInstance().initializeApplicationPaths(res, emptyPaths); @@ -243,102 +228,7 @@ public class RavenwoodRuleImpl { public static void validate(Statement base, Description description, boolean enableOptionalValidation) { - validateTestRunner(base, description, enableOptionalValidation); - validateTestAnnotations(base, description, enableOptionalValidation); - } - - private static void validateTestRunner(Statement base, Description description, - boolean shouldFail) { - final var testClass = description.getTestClass(); - final var runWith = testClass.getAnnotation(RunWith.class); - if (runWith == null) { - return; - } - - // Due to build dependencies, we can't directly refer to androidx classes here, - // so just check the class name instead. - if (runWith.value().getCanonicalName().equals("androidx.test.runner.AndroidJUnit4")) { - var message = "Test " + testClass.getCanonicalName() + " uses deprecated" - + " test runner androidx.test.runner.AndroidJUnit4." - + " Switch to androidx.test.ext.junit.runners.AndroidJUnit4."; - if (shouldFail) { - Assert.fail(message); - } else { - System.err.println("Warning: " + message); - } - } - } - - /** - * @return if a method has any of annotations. - */ - private static boolean hasAnyAnnotations(Method m, Class<? extends Annotation>... annotations) { - for (var anno : annotations) { - if (m.getAnnotation(anno) != null) { - return true; - } - } - return false; - } - - private static void validateTestAnnotations(Statement base, Description description, - boolean enableOptionalValidation) { - final var testClass = description.getTestClass(); - - final var message = new StringBuilder(); - - boolean hasErrors = false; - for (Method m : collectMethods(testClass)) { - if (Modifier.isPublic(m.getModifiers()) && m.getName().startsWith("test")) { - if (!hasAnyAnnotations(m, Test.class, Before.class, After.class, - BeforeClass.class, AfterClass.class)) { - message.append("\nMethod " + m.getName() + "() doesn't have @Test"); - hasErrors = true; - } - } - if ("setUp".equals(m.getName())) { - if (!hasAnyAnnotations(m, Before.class)) { - message.append("\nMethod " + m.getName() + "() doesn't have @Before"); - hasErrors = true; - } - if (!Modifier.isPublic(m.getModifiers())) { - message.append("\nMethod " + m.getName() + "() must be public"); - hasErrors = true; - } - } - if ("tearDown".equals(m.getName())) { - if (!hasAnyAnnotations(m, After.class)) { - message.append("\nMethod " + m.getName() + "() doesn't have @After"); - hasErrors = true; - } - if (!Modifier.isPublic(m.getModifiers())) { - message.append("\nMethod " + m.getName() + "() must be public"); - hasErrors = true; - } - } - } - assertFalse("Problem(s) detected in class " + testClass.getCanonicalName() + ":" - + message, hasErrors); - } - - /** - * Collect all (public or private or any) methods in a class, including inherited methods. - */ - private static List<Method> collectMethods(Class<?> clazz) { - var ret = new ArrayList<Method>(); - collectMethods(clazz, ret); - return ret; - } - - private static void collectMethods(Class<?> clazz, List<Method> result) { - // Class.getMethods() only return public methods, so we need to use getDeclaredMethods() - // instead, and recurse. - for (var m : clazz.getDeclaredMethods()) { - result.add(m); - } - if (clazz.getSuperclass() != null) { - collectMethods(clazz.getSuperclass(), result); - } + // Nothing to check, for now. } /** diff --git a/ravenwood/runtime-common-src/com/android/ravenwood/common/RavenwoodCommonUtils.java b/ravenwood/runtime-common-src/com/android/ravenwood/common/RavenwoodCommonUtils.java index 129802378cd4..9a11a8a35d70 100644 --- a/ravenwood/runtime-common-src/com/android/ravenwood/common/RavenwoodCommonUtils.java +++ b/ravenwood/runtime-common-src/com/android/ravenwood/common/RavenwoodCommonUtils.java @@ -42,12 +42,15 @@ public class RavenwoodCommonUtils { private static final boolean IS_ON_RAVENWOOD = RavenwoodDivergence.isOnRavenwood(); - private static final String RAVEWOOD_RUNTIME_PATH = getRavenwoodRuntimePathInternal(); + private static final String RAVENWOOD_RUNTIME_PATH = getRavenwoodRuntimePathInternal(); public static final String RAVENWOOD_SYSPROP = "ro.is_on_ravenwood"; public static final String RAVENWOOD_RESOURCE_APK = "ravenwood-res-apks/ravenwood-res.apk"; + public static final String RAVENWOOD_EMPTY_RESOURCES_APK = + RAVENWOOD_RUNTIME_PATH + "ravenwood-data/ravenwood-empty-res.apk"; + // @GuardedBy("sLock") private static boolean sIntegrityChecked = false; @@ -178,7 +181,7 @@ public class RavenwoodCommonUtils { */ public static String getRavenwoodRuntimePath() { ensureOnRavenwood(); - return RAVEWOOD_RUNTIME_PATH; + return RAVENWOOD_RUNTIME_PATH; } private static String getRavenwoodRuntimePathInternal() { diff --git a/ravenwood/services-test/test/com/android/ravenwoodtest/servicestest/RavenwoodServicesTest.java b/ravenwood/services-test/test/com/android/ravenwoodtest/servicestest/RavenwoodServicesTest.java index 044239f06297..b3d3963270ee 100644 --- a/ravenwood/services-test/test/com/android/ravenwoodtest/servicestest/RavenwoodServicesTest.java +++ b/ravenwood/services-test/test/com/android/ravenwoodtest/servicestest/RavenwoodServicesTest.java @@ -16,6 +16,7 @@ package com.android.ravenwoodtest.servicestest; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -62,7 +63,9 @@ public class RavenwoodServicesTest { final SerialManager service = (SerialManager) mRavenwood.getContext().getSystemService(Context.SERIAL_SERVICE); final String[] ports = service.getSerialPorts(); - assertEquals(0, ports.length); + final String[] refPorts = mRavenwood.getContext().getResources().getStringArray( + com.android.internal.R.array.config_serialPorts); + assertArrayEquals(refPorts, ports); } @Test diff --git a/services/core/java/com/android/server/SerialService.java b/services/core/java/com/android/server/SerialService.java index 82c2038d8011..dbf144f0c63e 100644 --- a/services/core/java/com/android/server/SerialService.java +++ b/services/core/java/com/android/server/SerialService.java @@ -56,16 +56,11 @@ public class SerialService extends ISerialManager.Stub { } } - @android.ravenwood.annotation.RavenwoodReplace private static String[] getSerialPorts(Context context) { return context.getResources().getStringArray( com.android.internal.R.array.config_serialPorts); } - private static String[] getSerialPorts$ravenwood(Context context) { - return new String[0]; - } - public static class Lifecycle extends SystemService { private SerialService mService; diff --git a/services/core/java/com/android/server/notification/GroupHelper.java b/services/core/java/com/android/server/notification/GroupHelper.java index 008746c0423c..e5abb448143d 100644 --- a/services/core/java/com/android/server/notification/GroupHelper.java +++ b/services/core/java/com/android/server/notification/GroupHelper.java @@ -830,25 +830,94 @@ public class GroupHelper { } } + // The list of notification operations required after the channel update final ArrayList<NotificationMoveOp> notificationsToMove = new ArrayList<>(); - final Set<FullyQualifiedGroupKey> oldGroups = - new HashSet<>(mAggregatedNotifications.keySet()); - for (FullyQualifiedGroupKey oldFullAggKey : oldGroups) { + // Check any already auto-grouped notifications that may need to be re-grouped + // after the channel update + notificationsToMove.addAll( + getAutogroupedNotificationsMoveOps(userId, pkgName, + notificationsToCheck)); + + // Check any ungrouped notifications that may need to be auto-grouped + // after the channel update + notificationsToMove.addAll( + getUngroupedNotificationsMoveOps(userId, pkgName, notificationsToCheck)); + + // Batch move to new section + if (!notificationsToMove.isEmpty()) { + moveNotificationsToNewSection(userId, pkgName, notificationsToMove); + } + } + } + + @GuardedBy("mAggregatedNotifications") + private List<NotificationMoveOp> getAutogroupedNotificationsMoveOps(int userId, String pkgName, + ArrayMap<String, NotificationRecord> notificationsToCheck) { + final ArrayList<NotificationMoveOp> notificationsToMove = new ArrayList<>(); + final Set<FullyQualifiedGroupKey> oldGroups = + new HashSet<>(mAggregatedNotifications.keySet()); + // Move auto-grouped updated notifications from the old groups to the new groups (section) + for (FullyQualifiedGroupKey oldFullAggKey : oldGroups) { + // Only check aggregate groups that match the same userId & packageName + if (pkgName.equals(oldFullAggKey.pkg) && userId == oldFullAggKey.userId) { + final ArrayMap<String, NotificationAttributes> notificationsInAggGroup = + mAggregatedNotifications.get(oldFullAggKey); + if (notificationsInAggGroup == null) { + continue; + } + + FullyQualifiedGroupKey newFullAggregateGroupKey = null; + for (String key : notificationsInAggGroup.keySet()) { + if (notificationsToCheck.get(key) != null) { + // check if section changes + NotificationSectioner sectioner = getSection(notificationsToCheck.get(key)); + if (sectioner == null) { + continue; + } + newFullAggregateGroupKey = new FullyQualifiedGroupKey(userId, pkgName, + sectioner); + if (!oldFullAggKey.equals(newFullAggregateGroupKey)) { + if (DEBUG) { + Log.i(TAG, "Change section on channel update: " + key); + } + notificationsToMove.add( + new NotificationMoveOp(notificationsToCheck.get(key), + oldFullAggKey, newFullAggregateGroupKey)); + notificationsToCheck.remove(key); + } + } + } + } + } + return notificationsToMove; + } + + @GuardedBy("mAggregatedNotifications") + private List<NotificationMoveOp> getUngroupedNotificationsMoveOps(int userId, String pkgName, + final ArrayMap<String, NotificationRecord> notificationsToCheck) { + final ArrayList<NotificationMoveOp> notificationsToMove = new ArrayList<>(); + // Move any remaining ungrouped updated notifications from the old ungrouped list + // to the new ungrouped section list, if necessary + if (!notificationsToCheck.isEmpty()) { + final Set<FullyQualifiedGroupKey> oldUngroupedSectionKeys = + new HashSet<>(mUngroupedAbuseNotifications.keySet()); + for (FullyQualifiedGroupKey oldFullAggKey : oldUngroupedSectionKeys) { // Only check aggregate groups that match the same userId & packageName if (pkgName.equals(oldFullAggKey.pkg) && userId == oldFullAggKey.userId) { - final ArrayMap<String, NotificationAttributes> notificationsInAggGroup = - mAggregatedNotifications.get(oldFullAggKey); - if (notificationsInAggGroup == null) { + final ArrayMap<String, NotificationAttributes> ungroupedOld = + mUngroupedAbuseNotifications.get(oldFullAggKey); + if (ungroupedOld == null) { continue; } FullyQualifiedGroupKey newFullAggregateGroupKey = null; - for (String key : notificationsInAggGroup.keySet()) { - if (notificationsToCheck.get(key) != null) { + final Set<String> ungroupedKeys = new HashSet<>(ungroupedOld.keySet()); + for (String key : ungroupedKeys) { + NotificationRecord record = notificationsToCheck.get(key); + if (record != null) { // check if section changes - NotificationSectioner sectioner = getSection( - notificationsToCheck.get(key)); + NotificationSectioner sectioner = getSection(record); if (sectioner == null) { continue; } @@ -856,41 +925,22 @@ public class GroupHelper { sectioner); if (!oldFullAggKey.equals(newFullAggregateGroupKey)) { if (DEBUG) { - Log.i(TAG, "Change section on channel update: " + key); + Log.i(TAG, "Change ungrouped section: " + key); } notificationsToMove.add( - new NotificationMoveOp(notificationsToCheck.get(key), - oldFullAggKey, newFullAggregateGroupKey)); - } - } - } - - if (newFullAggregateGroupKey != null) { - // Add any notifications left ungrouped to the new section - ArrayMap<String, NotificationAttributes> ungrouped = - mUngroupedAbuseNotifications.get(newFullAggregateGroupKey); - if (ungrouped != null) { - for (NotificationRecord r : notificationList) { - if (ungrouped.containsKey(r.getKey())) { - if (DEBUG) { - Log.i(TAG, "Add previously ungrouped: " + r); - } - notificationsToMove.add( - new NotificationMoveOp(r, null, newFullAggregateGroupKey)); - } + new NotificationMoveOp(record, oldFullAggKey, + newFullAggregateGroupKey)); + notificationsToCheck.remove(key); + //Remove from previous ungrouped list + ungroupedOld.remove(key); } - //Cleanup mUngroupedAbuseNotifications - mUngroupedAbuseNotifications.remove(newFullAggregateGroupKey); } } + mUngroupedAbuseNotifications.put(oldFullAggKey, ungroupedOld); } } - - // Batch move to new section - if (!notificationsToMove.isEmpty()) { - moveNotificationsToNewSection(userId, pkgName, notificationsToMove); - } } + return notificationsToMove; } @GuardedBy("mAggregatedNotifications") @@ -898,6 +948,7 @@ public class GroupHelper { final List<NotificationMoveOp> notificationsToMove) { record GroupUpdateOp(FullyQualifiedGroupKey groupKey, NotificationRecord record, boolean hasSummary) { } + // Bundled operations to apply to groups affected by the channel update ArrayMap<FullyQualifiedGroupKey, GroupUpdateOp> groupsToUpdate = new ArrayMap<>(); for (NotificationMoveOp moveOp: notificationsToMove) { @@ -923,35 +974,36 @@ public class GroupHelper { // Only add once, for triggering notification if (!groupsToUpdate.containsKey(oldFullAggregateGroupKey)) { groupsToUpdate.put(oldFullAggregateGroupKey, - new GroupUpdateOp(oldFullAggregateGroupKey, record, true)); + new GroupUpdateOp(oldFullAggregateGroupKey, record, true)); } } - // Add/update aggregate summary for new group + // Add moved notifications to the ungrouped list for new group and do grouping + // after all notifications have been handled if (newFullAggregateGroupKey != null) { final ArrayMap<String, NotificationAttributes> newAggregatedNotificationsAttrs = mAggregatedNotifications.getOrDefault(newFullAggregateGroupKey, new ArrayMap<>()); - boolean newGroupExists = !newAggregatedNotificationsAttrs.isEmpty(); - newAggregatedNotificationsAttrs.put(record.getKey(), - new NotificationAttributes(record.getFlags(), - record.getNotification().getSmallIcon(), - record.getNotification().color, - record.getNotification().visibility, - record.getNotification().getGroupAlertBehavior(), - record.getChannel().getId())); - mAggregatedNotifications.put(newFullAggregateGroupKey, - newAggregatedNotificationsAttrs); + boolean hasSummary = !newAggregatedNotificationsAttrs.isEmpty(); + ArrayMap<String, NotificationAttributes> ungrouped = + mUngroupedAbuseNotifications.getOrDefault(newFullAggregateGroupKey, + new ArrayMap<>()); + ungrouped.put(record.getKey(), new NotificationAttributes( + record.getFlags(), + record.getNotification().getSmallIcon(), + record.getNotification().color, + record.getNotification().visibility, + record.getNotification().getGroupAlertBehavior(), + record.getChannel().getId())); + mUngroupedAbuseNotifications.put(newFullAggregateGroupKey, ungrouped); + + record.setOverrideGroupKey(null); // Only add once, for triggering notification if (!groupsToUpdate.containsKey(newFullAggregateGroupKey)) { groupsToUpdate.put(newFullAggregateGroupKey, - new GroupUpdateOp(newFullAggregateGroupKey, record, newGroupExists)); + new GroupUpdateOp(newFullAggregateGroupKey, record, hasSummary)); } - - // Add notification to new group. do not request resort - record.setOverrideGroupKey(null); - mCallback.addAutoGroup(record.getKey(), newFullAggregateGroupKey.toString(), false); } } @@ -959,18 +1011,26 @@ public class GroupHelper { for (FullyQualifiedGroupKey groupKey : groupsToUpdate.keySet()) { final ArrayMap<String, NotificationAttributes> aggregatedNotificationsAttrs = mAggregatedNotifications.getOrDefault(groupKey, new ArrayMap<>()); - if (aggregatedNotificationsAttrs.isEmpty()) { - mCallback.removeAutoGroupSummary(userId, pkgName, groupKey.toString()); - mAggregatedNotifications.remove(groupKey); - } else { - NotificationRecord triggeringNotification = groupsToUpdate.get(groupKey).record; - boolean hasSummary = groupsToUpdate.get(groupKey).hasSummary; + final ArrayMap<String, NotificationAttributes> ungrouped = + mUngroupedAbuseNotifications.getOrDefault(groupKey, new ArrayMap<>()); + + NotificationRecord triggeringNotification = groupsToUpdate.get(groupKey).record; + boolean hasSummary = groupsToUpdate.get(groupKey).hasSummary; + //Group needs to be created/updated + if (ungrouped.size() >= mAutoGroupAtCount + || (hasSummary && !aggregatedNotificationsAttrs.isEmpty())) { NotificationSectioner sectioner = getSection(triggeringNotification); if (sectioner == null) { continue; } - updateAggregateAppGroup(groupKey, triggeringNotification.getKey(), hasSummary, - sectioner.mSummaryId); + aggregateUngroupedNotifications(groupKey, triggeringNotification.getKey(), + ungrouped, hasSummary, sectioner.mSummaryId); + } else { + // Remove empty groups + if (aggregatedNotificationsAttrs.isEmpty() && hasSummary) { + mCallback.removeAutoGroupSummary(userId, pkgName, groupKey.toString()); + mAggregatedNotifications.remove(groupKey); + } } } } diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 2294d6599da1..47d4740eb67f 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -233,7 +233,6 @@ import static com.android.server.wm.StartingData.AFTER_TRANSACTION_COPY_TO_CLIEN import static com.android.server.wm.StartingData.AFTER_TRANSACTION_REMOVE_DIRECTLY; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_PREDICT_BACK; -import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION; import static com.android.server.wm.TaskFragment.TASK_FRAGMENT_VISIBILITY_VISIBLE; import static com.android.server.wm.TaskPersister.DEBUG; @@ -5542,10 +5541,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return false; } if (!mDisplayContent.mAppTransition.isTransitionSet()) { - // Defer committing visibility for non-home app which is animating by recents. - if (isActivityTypeHome() || !isAnimating(PARENTS, ANIMATION_TYPE_RECENTS)) { - return false; - } + return false; } if (mWaitForEnteringPinnedMode && mVisible == visible) { // If the visibility is not changed during enter PIP, we don't want to include it in @@ -5699,8 +5695,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A private void postApplyAnimation(boolean visible, boolean fromTransition) { final boolean usingShellTransitions = mTransitionController.isShellTransitionsEnabled(); final boolean delayed = !usingShellTransitions && isAnimating(PARENTS | CHILDREN, - ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_WINDOW_ANIMATION - | ANIMATION_TYPE_RECENTS); + ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_WINDOW_ANIMATION); if (!delayed && !usingShellTransitions) { // We aren't delayed anything, but exiting windows rely on the animation finished // callback being called in case the ActivityRecord was pretending to be delayed, @@ -5722,7 +5717,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // animation and aren't in RESUMED state. Otherwise, we'll update client visibility in // onAnimationFinished or activityStopped. if (visible || (mState != RESUMED && (usingShellTransitions || !isAnimating( - PARENTS, ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_RECENTS)))) { + PARENTS, ANIMATION_TYPE_APP_TRANSITION)))) { setClientVisible(visible); } @@ -7700,7 +7695,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // Ensure that the activity content is hidden when the decor surface is boosted to // prevent UI redressing attack. && !isDecorSurfaceBoosted) - || isAnimating(PARENTS, ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_RECENTS + || isAnimating(PARENTS, ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_PREDICT_BACK); if (mSurfaceControl != null) { diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java index 06bdc045b5dc..197bd5a308cd 100644 --- a/services/core/java/com/android/server/wm/AppTransitionController.java +++ b/services/core/java/com/android/server/wm/AppTransitionController.java @@ -68,7 +68,6 @@ import static com.android.server.wm.AppTransition.isNormalTransit; import static com.android.server.wm.NonAppWindowAnimationAdapter.shouldAttachNavBarToApp; import static com.android.server.wm.NonAppWindowAnimationAdapter.shouldStartNonAppWindowAnimationsForKeyguardExit; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION; -import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS; import static com.android.server.wm.WallpaperAnimationAdapter.shouldStartWallpaperAnimation; import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; @@ -173,41 +172,6 @@ public class AppTransitionController { || !transitionGoodToGoForTaskFragments()) { return; } - final boolean isRecentsInOpening = mDisplayContent.mOpeningApps.stream().anyMatch( - ConfigurationContainer::isActivityTypeRecents); - // In order to avoid visual clutter caused by a conflict between app transition - // animation and recents animation, app transition is delayed until recents finishes. - // One exceptional case. When 3P launcher is used and a user taps a task screenshot in - // task switcher (isRecentsInOpening=true), app transition must start even though - // recents is running. Otherwise app transition is blocked until timeout (b/232984498). - // When 1P launcher is used, this animation is controlled by the launcher outside of - // the app transition, so delaying app transition doesn't cause visible delay. After - // recents finishes, app transition is handled just to commit visibility on apps. - if (!isRecentsInOpening) { - final ArraySet<WindowContainer> participants = new ArraySet<>(); - participants.addAll(mDisplayContent.mOpeningApps); - participants.addAll(mDisplayContent.mChangingContainers); - boolean deferForRecents = false; - for (int i = 0; i < participants.size(); i++) { - WindowContainer wc = participants.valueAt(i); - final ActivityRecord activity = getAppFromContainer(wc); - if (activity == null) { - continue; - } - // Don't defer recents animation if one of activity isn't running for it, that one - // might be started from quickstep. - if (!activity.isAnimating(PARENTS, ANIMATION_TYPE_RECENTS)) { - deferForRecents = false; - break; - } - deferForRecents = true; - } - if (deferForRecents) { - ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, - "Delaying app transition for recents animation to finish"); - return; - } - } Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "AppTransitionReady"); diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java index 9cfd39688c12..57f9be097ee6 100644 --- a/services/core/java/com/android/server/wm/SurfaceAnimator.java +++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java @@ -32,8 +32,8 @@ import android.view.SurfaceControl; import android.view.SurfaceControl.Transaction; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.protolog.common.LogLevel; import com.android.internal.protolog.ProtoLog; +import com.android.internal.protolog.common.LogLevel; import java.io.PrintWriter; import java.io.StringWriter; @@ -585,7 +585,6 @@ public class SurfaceAnimator { ANIMATION_TYPE_APP_TRANSITION, ANIMATION_TYPE_SCREEN_ROTATION, ANIMATION_TYPE_DIMMER, - ANIMATION_TYPE_RECENTS, ANIMATION_TYPE_WINDOW_ANIMATION, ANIMATION_TYPE_INSETS_CONTROL, ANIMATION_TYPE_TOKEN_TRANSFORM, @@ -604,7 +603,6 @@ public class SurfaceAnimator { case ANIMATION_TYPE_APP_TRANSITION: return "app_transition"; case ANIMATION_TYPE_SCREEN_ROTATION: return "screen_rotation"; case ANIMATION_TYPE_DIMMER: return "dimmer"; - case ANIMATION_TYPE_RECENTS: return "recents_animation"; case ANIMATION_TYPE_WINDOW_ANIMATION: return "window_animation"; case ANIMATION_TYPE_INSETS_CONTROL: return "insets_animation"; case ANIMATION_TYPE_TOKEN_TRANSFORM: return "token_transform"; diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index f000223ccec0..21be0fc2ac68 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -94,7 +94,6 @@ import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_DONT_LOCK; import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_LAUNCHABLE; import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_LAUNCHABLE_PRIV; import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_PINNABLE; -import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS; import static com.android.server.wm.TaskProto.AFFINITY; import static com.android.server.wm.TaskProto.BOUNDS; import static com.android.server.wm.TaskProto.CREATED_BY_ORGANIZER; @@ -2966,8 +2965,7 @@ class Task extends TaskFragment { /** Checking if self or its child tasks are animated by recents animation. */ boolean isAnimatingByRecents() { - return isAnimating(CHILDREN, ANIMATION_TYPE_RECENTS) - || mTransitionController.isTransientHide(this); + return mTransitionController.isTransientHide(this); } WindowState getTopVisibleAppMainWindow() { diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java index 03342d316d1c..13334a5f29b1 100644 --- a/services/core/java/com/android/server/wm/WindowAnimator.java +++ b/services/core/java/com/android/server/wm/WindowAnimator.java @@ -19,7 +19,6 @@ package com.android.server.wm; import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_TRANSACTIONS; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_ALL; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION; -import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_SCREEN_ROTATION; import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN; import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION; @@ -218,8 +217,8 @@ public class WindowAnimator { private void updateRunningExpensiveAnimationsLegacy() { final boolean runningExpensiveAnimations = mService.mRoot.isAnimating(TRANSITION | CHILDREN /* flags */, - ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_SCREEN_ROTATION - | ANIMATION_TYPE_RECENTS /* typesToCheck */); + ANIMATION_TYPE_APP_TRANSITION + | ANIMATION_TYPE_SCREEN_ROTATION /* typesToCheck */); if (runningExpensiveAnimations && !mRunningExpensiveAnimations) { mService.mSnapshotController.setPause(true); mTransaction.setEarlyWakeupStart(); diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index a980b7794547..6995027aac78 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -51,7 +51,6 @@ import static com.android.server.wm.IdentifierProto.TITLE; import static com.android.server.wm.IdentifierProto.USER_ID; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_ALL; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION; -import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS; import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN; import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS; import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION; @@ -1242,8 +1241,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< */ boolean inTransitionSelfOrParent() { if (!mTransitionController.isShellTransitionsEnabled()) { - return isAnimating(PARENTS | TRANSITION, - ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_RECENTS); + return isAnimating(PARENTS | TRANSITION, ANIMATION_TYPE_APP_TRANSITION); } return inTransition(); } diff --git a/services/core/java/com/android/server/wm/WindowContainerThumbnail.java b/services/core/java/com/android/server/wm/WindowContainerThumbnail.java index ad8806293bca..80f3c44267d7 100644 --- a/services/core/java/com/android/server/wm/WindowContainerThumbnail.java +++ b/services/core/java/com/android/server/wm/WindowContainerThumbnail.java @@ -20,7 +20,7 @@ import static android.view.SurfaceControl.METADATA_OWNER_UID; import static android.view.SurfaceControl.METADATA_WINDOW_TYPE; import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_TRANSACTIONS; -import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS; +import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION; import static com.android.server.wm.WindowContainerThumbnailProto.HEIGHT; import static com.android.server.wm.WindowContainerThumbnailProto.SURFACE_ANIMATOR; import static com.android.server.wm.WindowContainerThumbnailProto.WIDTH; @@ -118,7 +118,7 @@ class WindowContainerThumbnail implements Animatable { mWindowContainer.getDisplayContent().mAppTransition.canSkipFirstFrame(), mWindowContainer.getDisplayContent().getWindowCornerRadius()), mWindowContainer.mWmService.mSurfaceAnimationRunner), false /* hidden */, - ANIMATION_TYPE_RECENTS); + ANIMATION_TYPE_APP_TRANSITION); } private void onAnimationFinished(@AnimationType int type, AnimationAdapter anim) { diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index eeda2a734aa4..9b55ed2a0261 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -129,7 +129,6 @@ import static com.android.server.wm.RootWindowContainer.MATCH_ATTACHED_TASK_OR_R import static com.android.server.wm.SensitiveContentPackages.PackageInfo; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_ALL; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION; -import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION; import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN; import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS; @@ -2725,8 +2724,7 @@ public class WindowManagerService extends IWindowManager.Stub win.mTransitionController.mAnimatingExitWindows.add(win); reason = "inTransition"; } - } else if (win.isAnimating(PARENTS | TRANSITION, - ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_RECENTS)) { + } else if (win.isAnimating(PARENTS | TRANSITION, ANIMATION_TYPE_APP_TRANSITION)) { // Already animating as part of a legacy app-transition. reason = "inLegacyTransition"; } diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 81bce186f99e..c8e4b0affa32 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -128,7 +128,6 @@ import static com.android.server.wm.MoveAnimationSpecProto.FROM; import static com.android.server.wm.MoveAnimationSpecProto.TO; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_ALL; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION; -import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_STARTING_REVEAL; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION; import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS; @@ -581,7 +580,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP * is guaranteed to be cleared. */ static final int EXIT_ANIMATING_TYPES = ANIMATION_TYPE_APP_TRANSITION - | ANIMATION_TYPE_WINDOW_ANIMATION | ANIMATION_TYPE_RECENTS; + | ANIMATION_TYPE_WINDOW_ANIMATION; /** Currently running an exit animation? */ boolean mAnimatingExit; diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java index 0787058e3c11..2c785049412a 100644 --- a/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java +++ b/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java @@ -33,11 +33,15 @@ import android.content.Context; import android.content.res.Configuration; import android.graphics.Insets; import android.os.RemoteException; +import android.platform.test.annotations.RequiresFlagsDisabled; +import android.platform.test.flag.junit.CheckFlagsRule; +import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.provider.Settings; import android.util.Log; import android.view.WindowManagerGlobal; import android.view.WindowManagerPolicyConstants; import android.view.inputmethod.EditorInfo; +import android.view.inputmethod.Flags; import android.view.inputmethod.InputMethodManager; import androidx.annotation.NonNull; @@ -56,6 +60,7 @@ import com.android.internal.inputmethod.InputMethodNavButtonFlags; import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -89,6 +94,9 @@ public class InputMethodServiceTest { private String mInputMethodId; private boolean mShowImeWithHardKeyboardEnabled; + @Rule + public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); + @Before public void setUp() throws Exception { mInstrumentation = InstrumentationRegistry.getInstrumentation(); @@ -155,7 +163,13 @@ public class InputMethodServiceTest { () -> assertThat(mUiDevice.pressHome()).isTrue(), true /* expected */, false /* inputViewStarted */); - assertThat(mInputMethodService.isInputViewShown()).isFalse(); + if (Flags.refactorInsetsController()) { + // The IME visibility is only sent at the end of the animation. Therefore, we have to + // wait until the visibility was sent to the server and the IME window hidden. + eventually(() -> assertThat(mInputMethodService.isInputViewShown()).isFalse()); + } else { + assertThat(mInputMethodService.isInputViewShown()).isFalse(); + } } /** @@ -182,8 +196,13 @@ public class InputMethodServiceTest { /** * This checks the result of calling IMS#requestShowSelf and IMS#requestHideSelf. + * + * With the refactor in b/298172246, all calls to IMMS#{show,hide}MySoftInputLocked + * will be just apply the requested visibility (by using the callback). Therefore, we will + * lose flags like HIDE_IMPLICIT_ONLY. */ @Test + @RequiresFlagsDisabled(Flags.FLAG_REFACTOR_INSETS_CONTROLLER) public void testShowHideSelf() throws Exception { setShowImeWithHardKeyboard(true /* enabled */); @@ -375,8 +394,13 @@ public class InputMethodServiceTest { /** * This checks that an implicit show request when the IME is not previously shown, * and it should be shown in fullscreen mode, results in the IME not being shown. + * + * With the refactor in b/298172246, all calls from InputMethodManager#{show,hide}SoftInput + * will be redirected to InsetsController#{show,hide}. Therefore, we will lose flags like + * SHOW_IMPLICIT. */ @Test + @RequiresFlagsDisabled(Flags.FLAG_REFACTOR_INSETS_CONTROLLER) public void testShowSoftInputImplicitly_fullScreenMode() throws Exception { setShowImeWithHardKeyboard(true /* enabled */); @@ -425,8 +449,13 @@ public class InputMethodServiceTest { /** * This checks that an implicit show request when a hard keyboard is connected, * results in the IME not being shown. + * + * With the refactor in b/298172246, all calls from InputMethodManager#{show,hide}SoftInput + * will be redirected to InsetsController#{show,hide}. Therefore, we will lose flags like + * SHOW_IMPLICIT. */ @Test + @RequiresFlagsDisabled(Flags.FLAG_REFACTOR_INSETS_CONTROLLER) public void testShowSoftInputImplicitly_withHardKeyboard() throws Exception { setShowImeWithHardKeyboard(false /* enabled */); @@ -484,8 +513,13 @@ public class InputMethodServiceTest { * This checks that an implicit show request followed by connecting a hard keyboard * and a configuration change, does not trigger IMS#onFinishInputView, * but results in the IME being hidden. + * + * With the refactor in b/298172246, all calls from InputMethodManager#{show,hide}SoftInput + * will be redirected to InsetsController#{show,hide}. Therefore, we will lose flags like + * SHOW_IMPLICIT. */ @Test + @RequiresFlagsDisabled(Flags.FLAG_REFACTOR_INSETS_CONTROLLER) public void testShowSoftInputImplicitly_thenConfigurationChanged() throws Exception { setShowImeWithHardKeyboard(false /* enabled */); @@ -567,8 +601,13 @@ public class InputMethodServiceTest { * This checks that a forced show request directly followed by an explicit show request, * and then a hide not always request, still results in the IME being shown * (i.e. the explicit show request retains the forced state). + * + * With the refactor in b/298172246, all calls from InputMethodManager#{show,hide}SoftInput + * will be redirected to InsetsController#{show,hide}. Therefore, we will lose flags like + * HIDE_NOT_ALWAYS. */ @Test + @RequiresFlagsDisabled(Flags.FLAG_REFACTOR_INSETS_CONTROLLER) public void testShowSoftInputForced_testShowSoftInputExplicitly_thenHideSoftInputNotAlways() throws Exception { setShowImeWithHardKeyboard(true /* enabled */); @@ -734,7 +773,13 @@ public class InputMethodServiceTest { backButtonUiObject.click(); mInstrumentation.waitForIdleSync(); - assertThat(mInputMethodService.isInputViewShown()).isFalse(); + if (Flags.refactorInsetsController()) { + // The IME visibility is only sent at the end of the animation. Therefore, we have to + // wait until the visibility was sent to the server and the IME window hidden. + eventually(() -> assertThat(mInputMethodService.isInputViewShown()).isFalse()); + } else { + assertThat(mInputMethodService.isInputViewShown()).isFalse(); + } } /** @@ -766,7 +811,13 @@ public class InputMethodServiceTest { backButtonUiObject.longClick(); mInstrumentation.waitForIdleSync(); - assertThat(mInputMethodService.isInputViewShown()).isFalse(); + if (Flags.refactorInsetsController()) { + // The IME visibility is only sent at the end of the animation. Therefore, we have to + // wait until the visibility was sent to the server and the IME window hidden. + eventually(() -> assertThat(mInputMethodService.isInputViewShown()).isFalse()); + } else { + assertThat(mInputMethodService.isInputViewShown()).isFalse(); + } } /** @@ -848,7 +899,13 @@ public class InputMethodServiceTest { assertWithMessage("Input Method Switcher Menu is shown") .that(isInputMethodPickerShown(imm)) .isTrue(); - assertThat(mInputMethodService.isInputViewShown()).isTrue(); + if (Flags.refactorInsetsController()) { + // The IME visibility is only sent at the end of the animation. Therefore, we have to + // wait until the visibility was sent to the server and the IME window hidden. + eventually(() -> assertThat(mInputMethodService.isInputViewShown()).isFalse()); + } else { + assertThat(mInputMethodService.isInputViewShown()).isTrue(); + } // Hide the Picker menu before finishing. mUiDevice.pressBack(); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java index 51f64ba2b483..3fc28f838f3e 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java @@ -2204,7 +2204,7 @@ public class GroupHelperTest extends UiServiceTestCase { verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(), eq(expectedGroupKey_silent), anyInt(), eq(getNotificationAttributes(BASE_FLAGS))); verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString(), - eq(expectedGroupKey_silent), eq(false)); + eq(expectedGroupKey_silent), eq(true)); // Check that the alerting section group is removed verify(mCallback, times(1)).removeAutoGroupSummary(anyInt(), eq(pkg), @@ -2264,13 +2264,15 @@ public class GroupHelperTest extends UiServiceTestCase { notificationList); // Check that channel1's notifications are moved to the silent section group - expectedSummaryAttr = new NotificationAttributes(BASE_FLAGS, - mSmallIcon, COLOR_DEFAULT, DEFAULT_VISIBILITY, DEFAULT_GROUP_ALERT, - "TEST_CHANNEL_ID1"); - verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(), - eq(expectedGroupKey_silent), anyInt(), eq(expectedSummaryAttr)); - verify(mCallback, times(AUTOGROUP_AT_COUNT/2 + 1)).addAutoGroup(anyString(), - eq(expectedGroupKey_silent), eq(false)); + // But not enough to auto-group => remove override group key + verify(mCallback, never()).addAutoGroupSummary(anyInt(), eq(pkg), anyString(), + anyString(), anyInt(), any()); + verify(mCallback, never()).addAutoGroup(anyString(), anyString(), anyBoolean()); + for (NotificationRecord record: notificationList) { + if (record.getChannel().getId().equals(channel1.getId())) { + assertThat(record.getSbn().getOverrideGroupKey()).isNull(); + } + } // Check that the alerting section group is not removed, only updated expectedSummaryAttr = new NotificationAttributes(BASE_FLAGS, @@ -2343,7 +2345,7 @@ public class GroupHelperTest extends UiServiceTestCase { verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(), eq(expectedGroupKey_silent), anyInt(), eq(getNotificationAttributes(BASE_FLAGS))); verify(mCallback, times(numSilentGroupNotifications)).addAutoGroup(anyString(), - eq(expectedGroupKey_silent), eq(false)); + eq(expectedGroupKey_silent), eq(true)); // Check that the alerting section group is removed verify(mCallback, times(1)).removeAutoGroupSummary(anyInt(), eq(pkg), @@ -2353,6 +2355,60 @@ public class GroupHelperTest extends UiServiceTestCase { } @Test + @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING) + public void testAutogroup_updateChannel_reachedMinAutogroupCount() { + final String pkg = "package"; + final NotificationChannel channel1 = new NotificationChannel("TEST_CHANNEL_ID1", + "TEST_CHANNEL_ID1", IMPORTANCE_DEFAULT); + final NotificationChannel channel2 = new NotificationChannel("TEST_CHANNEL_ID2", + "TEST_CHANNEL_ID2", IMPORTANCE_LOW); + final List<NotificationRecord> notificationList = new ArrayList<>(); + // Post notifications with different channels that would autogroup in different sections + NotificationRecord r; + // Not enough notifications to autogroup initially + for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) { + if (i % 2 == 0) { + r = getNotificationRecord(pkg, i, String.valueOf(i), + UserHandle.SYSTEM, null, false, channel1); + } else { + r = getNotificationRecord(pkg, i, String.valueOf(i), + UserHandle.SYSTEM, null, false, channel2); + } + notificationList.add(r); + mGroupHelper.onNotificationPosted(r, false); + } + verify(mCallback, never()).addAutoGroupSummary(anyInt(), anyString(), anyString(), + anyString(), anyInt(), any()); + verify(mCallback, never()).addAutoGroup(anyString(), anyString(), anyBoolean()); + verify(mCallback, never()).removeAutoGroup(anyString()); + verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString(), anyString()); + verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), anyString(), + any()); + Mockito.reset(mCallback); + + // Update channel1's importance + final String expectedGroupKey_silent = GroupHelper.getFullAggregateGroupKey(pkg, + AGGREGATE_GROUP_KEY + "SilentSection", UserHandle.SYSTEM.getIdentifier()); + channel1.setImportance(IMPORTANCE_LOW); + for (NotificationRecord record: notificationList) { + if (record.getChannel().getId().equals(channel1.getId())) { + record.updateNotificationChannel(channel1); + } + } + mGroupHelper.onChannelUpdated(UserHandle.SYSTEM.getIdentifier(), pkg, channel1, + notificationList); + + // Check that channel1's notifications are moved to the silent section & autogroup all + NotificationAttributes expectedSummaryAttr = new NotificationAttributes(BASE_FLAGS, + mSmallIcon, COLOR_DEFAULT, DEFAULT_VISIBILITY, DEFAULT_GROUP_ALERT, + "TEST_CHANNEL_ID1"); + verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString(), + eq(expectedGroupKey_silent), eq(true)); + verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(), + eq(expectedGroupKey_silent), anyInt(), eq(expectedSummaryAttr)); + } + + @Test @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING, Flags.FLAG_NOTIFICATION_FORCE_GROUP_SINGLETONS}) public void testNoGroup_singletonGroup_underLimit() { diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java index 99505414b934..b6e393d7be0c 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java @@ -39,10 +39,8 @@ import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentat import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; -import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; -import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS; import static com.android.server.wm.WindowContainer.POSITION_TOP; import static org.junit.Assert.assertEquals; @@ -51,9 +49,7 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeFalse; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; import android.graphics.Rect; import android.os.Binder; @@ -377,41 +373,6 @@ public class AppTransitionTests extends WindowTestsBase { } @Test - public void testDelayWhileRecents() { - final DisplayContent dc = createNewDisplay(Display.STATE_ON); - doReturn(false).when(dc).onDescendantOrientationChanged(any()); - final Task task = createTask(dc); - - // Simulate activity1 launches activity2. - final ActivityRecord activity1 = createActivityRecord(task); - activity1.setVisible(true); - activity1.setVisibleRequested(false); - activity1.allDrawn = true; - final ActivityRecord activity2 = createActivityRecord(task); - activity2.setVisible(false); - activity2.setVisibleRequested(true); - activity2.allDrawn = true; - - dc.mClosingApps.add(activity1); - dc.mOpeningApps.add(activity2); - dc.prepareAppTransition(TRANSIT_OPEN); - assertTrue(dc.mAppTransition.containsTransitRequest(TRANSIT_OPEN)); - - // Wait until everything in animation handler get executed to prevent the exiting window - // from being removed during WindowSurfacePlacer Traversal. - waitUntilHandlersIdle(); - - // Start recents - doReturn(true).when(task) - .isSelfAnimating(anyInt(), eq(ANIMATION_TYPE_RECENTS)); - - dc.mAppTransitionController.handleAppTransitionReady(); - - verify(activity1, never()).commitVisibility(anyBoolean(), anyBoolean(), anyBoolean()); - verify(activity2, never()).commitVisibility(anyBoolean(), anyBoolean(), anyBoolean()); - } - - @Test public void testGetAnimationStyleResId() { // Verify getAnimationStyleResId will return as LayoutParams.windowAnimations when without // specifying window type. diff --git a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java index 6c8a7ac0c613..9981a4dd9fce 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java @@ -23,7 +23,6 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verifyZeroInteractions; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION; -import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -96,18 +95,18 @@ public class SurfaceAnimatorTest extends WindowTestsBase { @Test public void testRunAnimation() { mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */, - ANIMATION_TYPE_RECENTS); + ANIMATION_TYPE_APP_TRANSITION); final ArgumentCaptor<OnAnimationFinishedCallback> callbackCaptor = ArgumentCaptor.forClass( OnAnimationFinishedCallback.class); assertAnimating(mAnimatable); verify(mTransaction).reparent(eq(mAnimatable.mSurface), eq(mAnimatable.mLeash)); - verify(mSpec).startAnimation(any(), any(), eq(ANIMATION_TYPE_RECENTS), + verify(mSpec).startAnimation(any(), any(), eq(ANIMATION_TYPE_APP_TRANSITION), callbackCaptor.capture()); - callbackCaptor.getValue().onAnimationFinished(ANIMATION_TYPE_RECENTS, mSpec); + callbackCaptor.getValue().onAnimationFinished(ANIMATION_TYPE_APP_TRANSITION, mSpec); assertNotAnimating(mAnimatable); assertTrue(mAnimatable.mFinishedCallbackCalled); - assertEquals(ANIMATION_TYPE_RECENTS, mAnimatable.mFinishedAnimationType); + assertEquals(ANIMATION_TYPE_APP_TRANSITION, mAnimatable.mFinishedAnimationType); verify(mTransaction).remove(eq(mAnimatable.mLeash)); // TODO: Verify reparenting once we use mPendingTransaction to reparent it back } diff --git a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java index d537bd764905..88ce3a6f5bf8 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java @@ -40,14 +40,12 @@ import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; -import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS; import static com.android.server.wm.WindowStateAnimator.PRESERVED_SURFACE_LAYER; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; import android.graphics.PixelFormat; import android.graphics.Rect; @@ -405,30 +403,6 @@ public class ZOrderingTests extends WindowTestsBase { } @Test - public void testAssignWindowLayers_ForImeOnAppWithRecentsAnimating() { - final WindowState imeAppTarget = createWindow(null, TYPE_APPLICATION, - mAppWindow.mActivityRecord, "imeAppTarget"); - mDisplayContent.setImeInputTarget(imeAppTarget); - mDisplayContent.setImeLayeringTarget(imeAppTarget); - mDisplayContent.setImeControlTarget(imeAppTarget); - mDisplayContent.updateImeParent(); - - // Simulate the ime layering target task is animating with recents animation. - final Task imeAppTargetTask = imeAppTarget.getTask(); - final SurfaceAnimator imeTargetTaskAnimator = imeAppTargetTask.mSurfaceAnimator; - spyOn(imeTargetTaskAnimator); - doReturn(ANIMATION_TYPE_RECENTS).when(imeTargetTaskAnimator).getAnimationType(); - doReturn(true).when(imeTargetTaskAnimator).isAnimating(); - - mDisplayContent.assignChildLayers(mTransaction); - - // Ime should on top of the application window when in recents animation and keep - // attached on app. - assertTrue(mDisplayContent.shouldImeAttachedToApp()); - assertWindowHigher(mImeWindow, imeAppTarget); - } - - @Test public void testAssignWindowLayers_ForImeOnPopupImeLayeringTarget() { final WindowState imeAppTarget = createWindow(null, TYPE_APPLICATION, mAppWindow.mActivityRecord, "imeAppTarget"); |