diff options
26 files changed, 490 insertions, 103 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index c1366a155aed..66a1d308eb7b 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -8741,6 +8741,31 @@ package android.app.appfunctions { method @NonNull public android.app.appfunctions.ExecuteAppFunctionRequest.Builder setParameters(@NonNull android.app.appsearch.GenericDocument); } + @FlaggedApi("android.app.appfunctions.flags.enable_app_function_manager") public final class ExecuteAppFunctionResponse implements android.os.Parcelable { + method public int describeContents(); + method @Nullable public String getErrorMessage(); + method @NonNull public android.os.Bundle getExtras(); + method public int getResultCode(); + method @NonNull public android.app.appsearch.GenericDocument getResultDocument(); + method public boolean isSuccess(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.app.appfunctions.ExecuteAppFunctionResponse> CREATOR; + field public static final String PROPERTY_RETURN_VALUE = "returnValue"; + field public static final int RESULT_APP_UNKNOWN_ERROR = 2; // 0x2 + field public static final int RESULT_DENIED = 1; // 0x1 + field public static final int RESULT_INTERNAL_ERROR = 3; // 0x3 + field public static final int RESULT_INVALID_ARGUMENT = 4; // 0x4 + field public static final int RESULT_OK = 0; // 0x0 + field public static final int RESULT_TIMED_OUT = 5; // 0x5 + } + + @FlaggedApi("android.app.appfunctions.flags.enable_app_function_manager") public static final class ExecuteAppFunctionResponse.Builder { + ctor public ExecuteAppFunctionResponse.Builder(@NonNull android.app.appsearch.GenericDocument); + ctor public ExecuteAppFunctionResponse.Builder(int, @NonNull String); + method @NonNull public android.app.appfunctions.ExecuteAppFunctionResponse build(); + method @NonNull public android.app.appfunctions.ExecuteAppFunctionResponse.Builder setExtras(@NonNull android.os.Bundle); + } + } package android.app.assist { diff --git a/core/java/android/app/appfunctions/ExecuteAppFunctionResponse.aidl b/core/java/android/app/appfunctions/ExecuteAppFunctionResponse.aidl new file mode 100644 index 000000000000..5194e7a4c73f --- /dev/null +++ b/core/java/android/app/appfunctions/ExecuteAppFunctionResponse.aidl @@ -0,0 +1,21 @@ +/* + * 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 android.app.appfunctions; + +import android.app.appfunctions.ExecuteAppFunctionResponse; + +parcelable ExecuteAppFunctionResponse;
\ No newline at end of file diff --git a/core/java/android/app/appfunctions/ExecuteAppFunctionResponse.java b/core/java/android/app/appfunctions/ExecuteAppFunctionResponse.java new file mode 100644 index 000000000000..72205d9cf6c6 --- /dev/null +++ b/core/java/android/app/appfunctions/ExecuteAppFunctionResponse.java @@ -0,0 +1,294 @@ +/* + * 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 android.app.appfunctions; + +import static android.app.appfunctions.flags.Flags.FLAG_ENABLE_APP_FUNCTION_MANAGER; + +import android.annotation.FlaggedApi; +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.appsearch.GenericDocument; +import android.os.Bundle; +import android.os.Parcel; +import android.os.Parcelable; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Objects; + +/** + * The response to an app function execution. + */ +@FlaggedApi(FLAG_ENABLE_APP_FUNCTION_MANAGER) +public final class ExecuteAppFunctionResponse implements Parcelable { + @NonNull + public static final Creator<ExecuteAppFunctionResponse> CREATOR = + new Creator<ExecuteAppFunctionResponse>() { + @Override + public ExecuteAppFunctionResponse createFromParcel(Parcel parcel) { + GenericDocument result = + Objects.requireNonNull(GenericDocument.createFromParcel(parcel)); + Bundle extras = Objects.requireNonNull( + parcel.readBundle(Bundle.class.getClassLoader())); + int resultCode = parcel.readInt(); + String errorMessage = parcel.readString8(); + return new ExecuteAppFunctionResponse(result, extras, resultCode, errorMessage); + } + + @Override + public ExecuteAppFunctionResponse[] newArray(int size) { + return new ExecuteAppFunctionResponse[size]; + } + }; + /** + * The name of the property that stores the function return value within the + * {@code resultDocument}. + * + * <p>See {@link GenericDocument#getProperty(String)} for more information. + * + * <p>If the function returns {@code void} or throws an error, the {@code resultDocument} + * will be empty {@link GenericDocument}. + * + * <p>If the {@code resultDocument} is empty, {@link GenericDocument#getProperty(String)} will + * return {@code null}. + * + * <p>See {@link #getResultDocument} for more information on extracting the return value. + */ + public static final String PROPERTY_RETURN_VALUE = "returnValue"; + + /** + * The call was successful. + */ + public static final int RESULT_OK = 0; + + /** + * The caller does not have the permission to execute an app function. + */ + public static final int RESULT_DENIED = 1; + + /** + * An unknown error occurred while processing the call in the AppFunctionService. + */ + public static final int RESULT_APP_UNKNOWN_ERROR = 2; + + /** + * An internal error occurred within AppFunctionManagerService. + * + * <p>This error may be considered similar to {@link IllegalStateException} + */ + public static final int RESULT_INTERNAL_ERROR = 3; + + /** + * The caller supplied invalid arguments to the call. + * + * <p>This error may be considered similar to {@link IllegalArgumentException}. + */ + public static final int RESULT_INVALID_ARGUMENT = 4; + + /** + * The operation was timed out. + */ + public static final int RESULT_TIMED_OUT = 5; + + /** + * The result code of the app function execution. + */ + @ResultCode + private final int mResultCode; + + /** + * The error message associated with the result, if any. This is {@code null} if the result code + * is {@link #RESULT_OK}. + */ + @Nullable + private final String mErrorMessage; + + /** + * Returns the return value of the executed function. + * + * <p>The return value is stored in a {@link GenericDocument} with the key + * {@link #PROPERTY_RETURN_VALUE}. + * + * <p>See {@link #getResultDocument} for more information on extracting the return value. + */ + @NonNull + private final GenericDocument mResultDocument; + + /** + * Returns the additional metadata data relevant to this function execution response. + */ + @NonNull + private final Bundle mExtras; + + private ExecuteAppFunctionResponse(@NonNull GenericDocument resultDocument, + @NonNull Bundle extras, + @ResultCode int resultCode, + @Nullable String errorMessage) { + mResultDocument = Objects.requireNonNull(resultDocument); + mExtras = Objects.requireNonNull(extras); + mResultCode = resultCode; + mErrorMessage = errorMessage; + } + + /** + * Returns a generic document containing the return value of the executed function. + * + * <p>The {@link #PROPERTY_RETURN_VALUE} key can be used to obtain the return value.</p> + * + * <p>An empty document is returned if {@link #isSuccess} is {@code false} or if the executed + * function does not produce a return value. + * + * <p>Sample code for extracting the return value: + * <pre> + * GenericDocument resultDocument = response.getResultDocument(); + * Object returnValue = resultDocument.getProperty(PROPERTY_RETURN_VALUE); + * if (returnValue != null) { + * // Cast returnValue to expected type, or use {@link GenericDocument#getPropertyString}, + * // {@link GenericDocument#getPropertyLong} etc. + * // Do something with the returnValue + * } + * </pre> + */ + @NonNull + public GenericDocument getResultDocument() { + return mResultDocument; + } + + /** + * Returns the extras of the app function execution. + */ + @NonNull + public Bundle getExtras() { + return mExtras; + } + + /** + * Returns {@code true} if {@link #getResultCode} equals + * {@link ExecuteAppFunctionResponse#RESULT_OK}. + */ + public boolean isSuccess() { + return getResultCode() == RESULT_OK; + } + + /** + * Returns one of the {@code RESULT} constants defined in {@link ExecuteAppFunctionResponse}. + */ + @ResultCode + public int getResultCode() { + return mResultCode; + } + + /** + * Returns the error message associated with this result. + * + * <p>If {@link #isSuccess} is {@code true}, the error message is always {@code null}. + */ + @Nullable + public String getErrorMessage() { + return mErrorMessage; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + mResultDocument.writeToParcel(dest, flags); + dest.writeBundle(mExtras); + dest.writeInt(mResultCode); + dest.writeString8(mErrorMessage); + } + + /** + * Result codes. + * + * @hide + */ + @IntDef( + prefix = {"RESULT_"}, + value = { + RESULT_OK, + RESULT_DENIED, + RESULT_APP_UNKNOWN_ERROR, + RESULT_INTERNAL_ERROR, + RESULT_INVALID_ARGUMENT, + RESULT_TIMED_OUT, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface ResultCode { + } + + /** + * The builder for creating {@link ExecuteAppFunctionResponse} instances. + */ + @FlaggedApi(FLAG_ENABLE_APP_FUNCTION_MANAGER) + public static final class Builder { + @NonNull + private GenericDocument mResultDocument = new GenericDocument.Builder<>("", "", "").build(); + @NonNull + private Bundle mExtras = Bundle.EMPTY; + private int mResultCode; + @Nullable + private String mErrorMessage; + + /** + * Creates a new builder for {@link ExecuteAppFunctionResponse}. + */ + private Builder() { + } + + /** + * Creates a new builder for {@link ExecuteAppFunctionResponse} to build a success response + * with a result code of {@link #RESULT_OK} and a resultDocument. + */ + public Builder(@NonNull GenericDocument resultDocument) { + mResultDocument = Objects.requireNonNull(resultDocument); + mResultCode = RESULT_OK; + } + + /** + * Creates a new builder for {@link ExecuteAppFunctionResponse} to build an error response + * with a result code and an error message. + */ + public Builder(@ResultCode int resultCode, + @NonNull String errorMessage) { + mResultCode = resultCode; + mErrorMessage = Objects.requireNonNull(errorMessage); + } + + /** + * Sets the extras of the app function execution. + */ + @NonNull + public Builder setExtras(@NonNull Bundle extras) { + mExtras = Objects.requireNonNull(extras); + return this; + } + + /** + * Builds the {@link ExecuteAppFunctionResponse} instance. + */ + @NonNull + public ExecuteAppFunctionResponse build() { + return new ExecuteAppFunctionResponse( + mResultDocument, mExtras, mResultCode, mErrorMessage); + } + } +} diff --git a/core/java/android/hardware/input/input_framework.aconfig b/core/java/android/hardware/input/input_framework.aconfig index 6f1d63d856b4..83c4de31824d 100644 --- a/core/java/android/hardware/input/input_framework.aconfig +++ b/core/java/android/hardware/input/input_framework.aconfig @@ -92,3 +92,10 @@ flag { description: "Dump keyboard shortcuts in dumpsys window" bug: "351963350" } + +flag { + name: "modifier_shortcut_manager_refactor" + namespace: "input" + description: "Refactor ModifierShortcutManager internal representation of shortcuts." + bug: "358603902" +} diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 28f2c2530ae9..536eca6f9a0f 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -969,9 +969,7 @@ public class UserManager { /** * Specifies if a user is disallowed from adding new users. This can only be set by device - * owners or profile owners on the primary user. The default value is <code>false</code>. - * <p>This restriction has no effect on secondary users and managed profiles since only the - * primary user can add other users. + * owners or profile owners on the main user. The default value is <code>false</code>. * <p> When the device is an organization-owned device provisioned with a managed profile, * this restriction will be set as a base restriction which cannot be removed by any admin. * diff --git a/core/java/com/android/internal/pm/pkg/component/ParsedProviderImpl.java b/core/java/com/android/internal/pm/pkg/component/ParsedProviderImpl.java index 987fd4158418..ec5ff4c6946a 100644 --- a/core/java/com/android/internal/pm/pkg/component/ParsedProviderImpl.java +++ b/core/java/com/android/internal/pm/pkg/component/ParsedProviderImpl.java @@ -174,7 +174,7 @@ public class ParsedProviderImpl extends ParsedMainComponentImpl implements Parse // CHECKSTYLE:OFF Generated code // // To regenerate run: - // $ codegen $ANDROID_BUILD_TOP/frameworks/base/services/core/java/com/android/server/pm/pkg/component/ParsedProviderImpl.java + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedProviderImpl.java // // To exclude the generated code from IntelliJ auto-formatting enable (one-time): // Settings > Editor > Code Style > Formatter Control @@ -298,9 +298,9 @@ public class ParsedProviderImpl extends ParsedMainComponentImpl implements Parse } @DataClass.Generated( - time = 1642560323360L, + time = 1723882842941L, codegenVersion = "1.0.23", - sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/component/ParsedProviderImpl.java", + sourceFile = "frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedProviderImpl.java", inputSignatures = "private @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String authority\nprivate boolean syncable\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String readPermission\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String writePermission\nprivate boolean grantUriPermissions\nprivate boolean forceUriPermissions\nprivate boolean multiProcess\nprivate int initOrder\nprivate @android.annotation.NonNull java.util.List<android.os.PatternMatcher> uriPermissionPatterns\nprivate @android.annotation.NonNull java.util.List<android.content.pm.PathPermission> pathPermissions\npublic static final @android.annotation.NonNull android.os.Parcelable.Creator<com.android.internal.pm.pkg.component.ParsedProviderImpl> CREATOR\npublic com.android.internal.pm.pkg.component.ParsedProviderImpl setReadPermission(java.lang.String)\npublic com.android.internal.pm.pkg.component.ParsedProviderImpl setWritePermission(java.lang.String)\npublic @android.annotation.NonNull com.android.internal.pm.pkg.component.ParsedProviderImpl addUriPermissionPattern(android.os.PatternMatcher)\npublic @android.annotation.NonNull com.android.internal.pm.pkg.component.ParsedProviderImpl addPathPermission(android.content.pm.PathPermission)\npublic java.lang.String toString()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedProviderImpl extends com.android.internal.pm.pkg.component.ParsedMainComponentImpl implements [com.android.internal.pm.pkg.component.ParsedProvider, android.os.Parcelable]\n@com.android.internal.util.DataClass(genSetters=true, genGetters=true, genParcelable=false, genBuilder=false)") @Deprecated private void __metadata() {} diff --git a/core/java/com/android/internal/protolog/LegacyProtoLogImpl.java b/core/java/com/android/internal/protolog/LegacyProtoLogImpl.java index fcc302331dae..2feb3d50cf64 100644 --- a/core/java/com/android/internal/protolog/LegacyProtoLogImpl.java +++ b/core/java/com/android/internal/protolog/LegacyProtoLogImpl.java @@ -419,7 +419,6 @@ public class LegacyProtoLogImpl implements IProtoLog { return group.isLogToLogcat() || (group.isLogToProto() && isProtoEnabled()); } - @Override public void registerGroups(IProtoLogGroup... protoLogGroups) { for (IProtoLogGroup group : protoLogGroups) { mLogGroups.put(group.name(), group); diff --git a/core/java/com/android/internal/protolog/LogcatOnlyProtoLogImpl.java b/core/java/com/android/internal/protolog/LogcatOnlyProtoLogImpl.java index ebdad6d52933..e8d5195d121d 100644 --- a/core/java/com/android/internal/protolog/LogcatOnlyProtoLogImpl.java +++ b/core/java/com/android/internal/protolog/LogcatOnlyProtoLogImpl.java @@ -79,9 +79,4 @@ public class LogcatOnlyProtoLogImpl implements IProtoLog { public boolean isEnabled(IProtoLogGroup group, LogLevel level) { return true; } - - @Override - public void registerGroups(IProtoLogGroup... protoLogGroups) { - // Does nothing - } } diff --git a/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java b/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java index 79a5469956df..7d12d49325d8 100644 --- a/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java +++ b/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java @@ -89,6 +89,7 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; +import java.util.stream.Stream; /** * A service for the ProtoLog logging system. @@ -125,17 +126,18 @@ public class PerfettoProtoLogImpl extends IProtoLogClient.Stub implements IProto private final Lock mBackgroundServiceLock = new ReentrantLock(); private ExecutorService mBackgroundLoggingService = Executors.newSingleThreadExecutor(); - public PerfettoProtoLogImpl() { - this(null, null, null, () -> {}); + public PerfettoProtoLogImpl(@NonNull IProtoLogGroup[] groups) { + this(null, null, null, () -> {}, groups); } - public PerfettoProtoLogImpl(@NonNull Runnable cacheUpdater) { - this(null, null, null, cacheUpdater); + public PerfettoProtoLogImpl(@NonNull Runnable cacheUpdater, @NonNull IProtoLogGroup[] groups) { + this(null, null, null, cacheUpdater, groups); } public PerfettoProtoLogImpl( @NonNull String viewerConfigFilePath, - @NonNull Runnable cacheUpdater) { + @NonNull Runnable cacheUpdater, + @NonNull IProtoLogGroup[] groups) { this(viewerConfigFilePath, null, new ProtoLogViewerConfigReader(() -> { @@ -146,22 +148,24 @@ public class PerfettoProtoLogImpl extends IProtoLogClient.Stub implements IProto "Failed to load viewer config file " + viewerConfigFilePath, e); } }), - cacheUpdater); + cacheUpdater, groups); } @VisibleForTesting public PerfettoProtoLogImpl( @Nullable ViewerConfigInputStreamProvider viewerConfigInputStreamProvider, @Nullable ProtoLogViewerConfigReader viewerConfigReader, - @NonNull Runnable cacheUpdater) { - this(null, viewerConfigInputStreamProvider, viewerConfigReader, cacheUpdater); + @NonNull Runnable cacheUpdater, + @NonNull IProtoLogGroup[] groups) { + this(null, viewerConfigInputStreamProvider, viewerConfigReader, cacheUpdater, groups); } private PerfettoProtoLogImpl( @Nullable String viewerConfigFilePath, @Nullable ViewerConfigInputStreamProvider viewerConfigInputStreamProvider, @Nullable ProtoLogViewerConfigReader viewerConfigReader, - @NonNull Runnable cacheUpdater) { + @NonNull Runnable cacheUpdater, + @NonNull IProtoLogGroup[] groups) { if (viewerConfigFilePath != null && viewerConfigInputStreamProvider != null) { throw new RuntimeException("Only one of viewerConfigFilePath and " + "viewerConfigInputStreamProvider can be set"); @@ -179,6 +183,8 @@ public class PerfettoProtoLogImpl extends IProtoLogClient.Stub implements IProto this.mViewerConfigReader = viewerConfigReader; this.mCacheUpdater = cacheUpdater; + registerGroupsLocally(groups); + if (android.tracing.Flags.clientSideProtoLogging()) { mProtoLogService = IProtoLogService.Stub.asInterface(ServiceManager.getService(PROTOLOG_SERVICE)); @@ -192,6 +198,12 @@ public class PerfettoProtoLogImpl extends IProtoLogClient.Stub implements IProto args.setViewerConfigFile(viewerConfigFilePath); } + final var groupArgs = Stream.of(groups) + .map(group -> new ProtoLogService.RegisterClientArgs.GroupConfig( + group.name(), group.isLogToLogcat())) + .toArray(ProtoLogService.RegisterClientArgs.GroupConfig[]::new); + args.setGroups(groupArgs); + mProtoLogService.registerClient(this, args); } catch (RemoteException e) { throw new RuntimeException("Failed to register ProtoLog client"); @@ -294,19 +306,18 @@ public class PerfettoProtoLogImpl extends IProtoLogClient.Stub implements IProto || group.isLogToLogcat(); } - @Override - public void registerGroups(IProtoLogGroup... protoLogGroups) { + private void registerGroupsLocally(@NonNull IProtoLogGroup[] protoLogGroups) { + final var groupsLoggingToLogcat = new ArrayList<String>(); for (IProtoLogGroup protoLogGroup : protoLogGroups) { mLogGroups.put(protoLogGroup.name(), protoLogGroup); - } - final String[] groupsLoggingToLogcat = Arrays.stream(protoLogGroups) - .filter(IProtoLogGroup::isLogToLogcat) - .map(IProtoLogGroup::name) - .toArray(String[]::new); + if (protoLogGroup.isLogToLogcat()) { + groupsLoggingToLogcat.add(protoLogGroup.name()); + } + } if (mViewerConfigReader != null) { - mViewerConfigReader.loadViewerConfig(groupsLoggingToLogcat); + mViewerConfigReader.loadViewerConfig(groupsLoggingToLogcat.toArray(new String[0])); } } diff --git a/core/java/com/android/internal/protolog/ProtoLog.java b/core/java/com/android/internal/protolog/ProtoLog.java index 87678e5922f9..f9b989477907 100644 --- a/core/java/com/android/internal/protolog/ProtoLog.java +++ b/core/java/com/android/internal/protolog/ProtoLog.java @@ -50,6 +50,24 @@ public class ProtoLog { private static IProtoLog sProtoLogInstance; /** + * Initialize ProtoLog in this process. + * <p> + * This method MUST be called before any protologging is performed in this process. + * Ensure that all groups that will be used for protologging are registered. + * + * @param groups The ProtoLog groups that will be used in the process. + */ + public static void init(IProtoLogGroup... groups) { + if (android.tracing.Flags.perfettoProtologTracing()) { + 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(); + } + } + + /** * DEBUG level log. * * @param group {@code IProtoLogGroup} controlling this log call. @@ -150,14 +168,6 @@ public class ProtoLog { return sProtoLogInstance; } - /** - * Registers available protolog groups. A group must be registered before it can be used. - * @param protoLogGroups The groups to register for use in protolog. - */ - public static void registerGroups(IProtoLogGroup... protoLogGroups) { - sProtoLogInstance.registerGroups(protoLogGroups); - } - private static void logStringMessage(LogLevel logLevel, IProtoLogGroup group, String stringMessage, Object... args) { if (sProtoLogInstance == null) { @@ -169,14 +179,4 @@ public class ProtoLog { sProtoLogInstance.log(logLevel, group, stringMessage, args); } } - - static { - if (android.tracing.Flags.perfettoProtologTracing()) { - sProtoLogInstance = new PerfettoProtoLogImpl(); - } 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/java/com/android/internal/protolog/ProtoLogImpl.java b/core/java/com/android/internal/protolog/ProtoLogImpl.java index 8659a8ffeb97..da6d8cff6890 100644 --- a/core/java/com/android/internal/protolog/ProtoLogImpl.java +++ b/core/java/com/android/internal/protolog/ProtoLogImpl.java @@ -93,35 +93,30 @@ public class ProtoLogImpl { } /** - * Registers available protolog groups. A group must be registered before it can be used. - * @param protoLogGroups The groups to register for use in protolog. - */ - public static void registerGroups(IProtoLogGroup... protoLogGroups) { - getSingleInstance().registerGroups(protoLogGroups); - } - - /** * Returns the single instance of the ProtoLogImpl singleton class. */ public static synchronized IProtoLog getSingleInstance() { if (sServiceInstance == null) { + final var groups = sLogGroups.values().toArray(new IProtoLogGroup[0]); + if (android.tracing.Flags.perfettoProtologTracing()) { File f = new File(sViewerConfigPath); if (!ProtoLog.REQUIRE_PROTOLOGTOOL && !f.exists()) { // TODO(b/353530422): Remove - temporary fix to unblock b/352290057 - // In so tests the viewer config file might not exist in which we don't + // In some tests the viewer config file might not exist in which we don't // want to provide config path to the user - sServiceInstance = new PerfettoProtoLogImpl(sCacheUpdater); + sServiceInstance = new PerfettoProtoLogImpl(sCacheUpdater, groups); } else { - sServiceInstance = new PerfettoProtoLogImpl(sViewerConfigPath, sCacheUpdater); + sServiceInstance = + new PerfettoProtoLogImpl(sViewerConfigPath, sCacheUpdater, groups); } } else { - sServiceInstance = new LegacyProtoLogImpl( + var protologImpl = new LegacyProtoLogImpl( sLegacyOutputFilePath, sLegacyViewerConfigPath, sCacheUpdater); + protologImpl.registerGroups(groups); + sServiceInstance = protologImpl; } - IProtoLogGroup[] groups = sLogGroups.values().toArray(new IProtoLogGroup[0]); - sServiceInstance.registerGroups(groups); sCacheUpdater.run(); } return sServiceInstance; diff --git a/core/java/com/android/internal/protolog/common/IProtoLog.java b/core/java/com/android/internal/protolog/common/IProtoLog.java index f5695acd0614..d5c2ac10852f 100644 --- a/core/java/com/android/internal/protolog/common/IProtoLog.java +++ b/core/java/com/android/internal/protolog/common/IProtoLog.java @@ -68,10 +68,4 @@ public interface IProtoLog { * @return If we need to log this group and level to either ProtoLog or Logcat. */ boolean isEnabled(IProtoLogGroup group, LogLevel level); - - /** - * Registers available protolog groups. A group must be registered before it can be used. - * @param protoLogGroups The groups to register for use in protolog. - */ - void registerGroups(IProtoLogGroup... protoLogGroups); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellInit.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellInit.java index 287e779d8e24..1140c82a7a08 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellInit.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellInit.java @@ -48,7 +48,7 @@ public class ShellInit { public ShellInit(ShellExecutor mainExecutor) { mMainExecutor = mainExecutor; - ProtoLog.registerGroups(ShellProtoLogGroup.values()); + ProtoLog.init(ShellProtoLogGroup.values()); } /** diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PatternBouncer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PatternBouncer.kt index 069113b378da..163b35596c1b 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PatternBouncer.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PatternBouncer.kt @@ -511,7 +511,7 @@ private const val DOT_DIAMETER_DP = 14 private const val SELECTED_DOT_DIAMETER_DP = (DOT_DIAMETER_DP * 1.5).toInt() private const val SELECTED_DOT_REACTION_ANIMATION_DURATION_MS = 83 private const val SELECTED_DOT_RETRACT_ANIMATION_DURATION_MS = 750 -private const val LINE_STROKE_WIDTH_DP = DOT_DIAMETER_DP +private const val LINE_STROKE_WIDTH_DP = 22 private const val FAILURE_ANIMATION_DOT_DIAMETER_DP = (DOT_DIAMETER_DP * 0.81f).toInt() private const val FAILURE_ANIMATION_DOT_SHRINK_ANIMATION_DURATION_MS = 50 private const val FAILURE_ANIMATION_DOT_SHRINK_STAGGER_DELAY_MS = 33 diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerMessageViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerMessageViewModelTest.kt index b83ab7ef0c1b..c1615253804c 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerMessageViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerMessageViewModelTest.kt @@ -430,6 +430,22 @@ class BouncerMessageViewModelTest : SysuiTestCase() { .isEqualTo("Can’t unlock with face. Too many attempts.") } + @Test + fun startLockdownCountdown_onActivated() = + testScope.runTest { + val bouncerMessage by collectLastValue(underTest.message) + val lockoutSeconds = 200 * 1000 // 200 second lockout + kosmos.fakeAuthenticationRepository.setAuthenticationMethod(Pin) + kosmos.fakeAuthenticationRepository.reportLockoutStarted(lockoutSeconds) + runCurrent() + + assertThat(bouncerMessage?.text).isEqualTo("Try again in 200 seconds.") + advanceTimeBy(100.seconds) + assertThat(bouncerMessage?.text).isEqualTo("Try again in 100 seconds.") + advanceTimeBy(101.seconds) + assertThat(bouncerMessage?.text).isEqualTo("Enter PIN") + } + private fun TestScope.verifyMessagesForAuthFlags( vararg authFlagToMessagePair: Pair<Int, Pair<String, String?>> ) { diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/DragAndDropTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/DragAndDropTest.kt index 4d1dd1cce766..d9faa30cb072 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/DragAndDropTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/DragAndDropTest.kt @@ -32,6 +32,7 @@ import androidx.compose.ui.test.onNodeWithContentDescription import androidx.compose.ui.test.onNodeWithTag import androidx.compose.ui.test.onNodeWithText import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.FlakyTest import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.common.shared.model.ContentDescription @@ -45,6 +46,7 @@ import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith +@FlakyTest(bugId = 360351805) @SmallTest @RunWith(AndroidJUnit4::class) class DragAndDropTest : SysuiTestCase() { diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerMessageViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerMessageViewModel.kt index d746220dd7ce..cfd4f506f169 100644 --- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerMessageViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerMessageViewModel.kt @@ -264,6 +264,9 @@ constructor( // Keeps the lockout message up-to-date. launch { bouncerInteractor.onLockoutStarted.collect { startLockoutCountdown() } } + // Start already active lockdown if it exists + launch { startLockoutCountdown() } + // Listens to relevant bouncer events launch { bouncerInteractor.onIncorrectBouncerInput diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/OWNERS b/packages/SystemUI/src/com/android/systemui/statusbar/OWNERS index c4f539a4acdf..408fc6d06461 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/OWNERS +++ b/packages/SystemUI/src/com/android/systemui/statusbar/OWNERS @@ -13,4 +13,12 @@ per-file *Doze* = file:../keyguard/OWNERS per-file *Keyboard* = set noparent per-file *Keyboard* = file:../keyguard/OWNERS per-file *Keyguard* = set noparent -per-file *Keyguard* = file:../keyguard/OWNERS
\ No newline at end of file +per-file *Keyguard* = file:../keyguard/OWNERS +per-file *Notification* = set noparent +per-file *Notification* = file:notification/OWNERS +per-file *Mode* = set noparent +per-file *Mode* = file:notification/OWNERS +per-file *RemoteInput* = set noparent +per-file *RemoteInput* = file:notification/OWNERS +per-file *EmptyShadeView* = set noparent +per-file *EmptyShadeView* = file:notification/OWNERS
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index 20b1fffc2c02..e8020764bce4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -258,7 +258,7 @@ public class NotificationStackScrollLayout private float mOverScrolledBottomPixels; private final ListenerSet<Runnable> mStackHeightChangedListeners = new ListenerSet<>(); private final ListenerSet<Runnable> mHeadsUpHeightChangedListeners = new ListenerSet<>(); - private NotificationLogger.OnChildLocationsChangedListener mListener; + private NotificationLogger.OnChildLocationsChangedListener mLegacyLocationsChangedListener; private OnNotificationLocationsChangedListener mLocationsChangedListener; private OnOverscrollTopChangedListener mOverscrollTopChangedListener; private ExpandableView.OnHeightChangedListener mOnHeightChangedListener; @@ -1281,7 +1281,7 @@ public class NotificationStackScrollLayout public void setChildLocationsChangedListener( NotificationLogger.OnChildLocationsChangedListener listener) { NotificationsLiveDataStoreRefactor.assertInLegacyMode(); - mListener = listener; + mLegacyLocationsChangedListener = listener; } private void setMaxLayoutHeight(int maxLayoutHeight) { @@ -4433,8 +4433,8 @@ public class NotificationStackScrollLayout mLocationsChangedListener.onChildLocationsChanged(collectVisibleLocationsCallable); } } else { - if (mListener != null) { - mListener.onChildLocationsChanged(); + if (mLegacyLocationsChangedListener != null) { + mLegacyLocationsChangedListener.onChildLocationsChanged(); } } diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java index 08153847df88..e84250dff028 100644 --- a/services/core/java/com/android/server/PackageWatchdog.java +++ b/services/core/java/com/android/server/PackageWatchdog.java @@ -309,13 +309,14 @@ public class PackageWatchdog { */ public void registerHealthObserver(PackageHealthObserver observer) { synchronized (mLock) { - ObserverInternal internalObserver = mAllObservers.get(observer.getName()); + ObserverInternal internalObserver = mAllObservers.get(observer.getUniqueIdentifier()); if (internalObserver != null) { internalObserver.registeredObserver = observer; } else { - internalObserver = new ObserverInternal(observer.getName(), new ArrayList<>()); + internalObserver = new ObserverInternal(observer.getUniqueIdentifier(), + new ArrayList<>()); internalObserver.registeredObserver = observer; - mAllObservers.put(observer.getName(), internalObserver); + mAllObservers.put(observer.getUniqueIdentifier(), internalObserver); syncState("added new observer"); } } @@ -342,12 +343,12 @@ public class PackageWatchdog { public void startObservingHealth(PackageHealthObserver observer, List<String> packageNames, long durationMs) { if (packageNames.isEmpty()) { - Slog.wtf(TAG, "No packages to observe, " + observer.getName()); + Slog.wtf(TAG, "No packages to observe, " + observer.getUniqueIdentifier()); return; } if (durationMs < 1) { Slog.wtf(TAG, "Invalid duration " + durationMs + "ms for observer " - + observer.getName() + ". Not observing packages " + packageNames); + + observer.getUniqueIdentifier() + ". Not observing packages " + packageNames); durationMs = DEFAULT_OBSERVING_DURATION_MS; } @@ -374,14 +375,14 @@ public class PackageWatchdog { syncState("observing new packages"); synchronized (mLock) { - ObserverInternal oldObserver = mAllObservers.get(observer.getName()); + ObserverInternal oldObserver = mAllObservers.get(observer.getUniqueIdentifier()); if (oldObserver == null) { - Slog.d(TAG, observer.getName() + " started monitoring health " + Slog.d(TAG, observer.getUniqueIdentifier() + " started monitoring health " + "of packages " + packageNames); - mAllObservers.put(observer.getName(), - new ObserverInternal(observer.getName(), packages)); + mAllObservers.put(observer.getUniqueIdentifier(), + new ObserverInternal(observer.getUniqueIdentifier(), packages)); } else { - Slog.d(TAG, observer.getName() + " added the following " + Slog.d(TAG, observer.getUniqueIdentifier() + " added the following " + "packages to monitor " + packageNames); oldObserver.updatePackagesLocked(packages); } @@ -405,9 +406,9 @@ public class PackageWatchdog { public void unregisterHealthObserver(PackageHealthObserver observer) { mLongTaskHandler.post(() -> { synchronized (mLock) { - mAllObservers.remove(observer.getName()); + mAllObservers.remove(observer.getUniqueIdentifier()); } - syncState("unregistering observer: " + observer.getName()); + syncState("unregistering observer: " + observer.getUniqueIdentifier()); }); } @@ -781,7 +782,7 @@ public class PackageWatchdog { * Identifier for the observer, should not change across device updates otherwise the * watchdog may drop observing packages with the old name. */ - String getName(); + String getUniqueIdentifier(); /** * An observer will not be pruned if this is set, even if the observer is not explicitly diff --git a/services/core/java/com/android/server/RescueParty.java b/services/core/java/com/android/server/RescueParty.java index c2cb5e90ca58..bba97fad0fc9 100644 --- a/services/core/java/com/android/server/RescueParty.java +++ b/services/core/java/com/android/server/RescueParty.java @@ -917,7 +917,7 @@ public class RescueParty { } @Override - public String getName() { + public String getUniqueIdentifier() { return NAME; } diff --git a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java index e9f662dbd974..e91097cbd8f8 100644 --- a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java +++ b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java @@ -233,7 +233,7 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve @Override - public String getName() { + public String getUniqueIdentifier() { return NAME; } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index bdb1d43faf79..87c0084083be 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -32,6 +32,7 @@ import static android.app.ActivityManagerInternal.ALLOW_NON_FULL; import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW; import static android.app.StatusBarManager.DISABLE_MASK; import static android.app.WindowConfiguration.ROTATION_UNDEFINED; +import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED; import static android.content.pm.PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT; import static android.content.pm.PackageManager.FEATURE_PC; @@ -9024,14 +9025,7 @@ public class WindowManagerService extends IWindowManager.Stub } clearPointerDownOutsideFocusRunnable(); - // For embedded activity that is showing side-by-side with another activity, delay - // handling the touch-outside event to prevent focus rapid changes back-n-forth. - // Otherwise, handle the touch-outside event directly. - final WindowState w = t.getWindowState(); - final ActivityRecord activity = w != null ? w.getActivityRecord() : null; - if (mFocusedInputTarget != t && mFocusedInputTarget != null - && activity != null && activity.isEmbedded() - && activity.getTaskFragment().getAdjacentTaskFragment() != null) { + if (shouldDelayTouchOutside(t)) { mPointerDownOutsideFocusRunnable = () -> handlePointerDownOutsideFocus(t); mH.postDelayed(mPointerDownOutsideFocusRunnable, POINTER_DOWN_OUTSIDE_FOCUS_TIMEOUT_MS); } else if (!fromHandler) { @@ -9044,6 +9038,33 @@ public class WindowManagerService extends IWindowManager.Stub } } + private boolean shouldDelayTouchOutside(InputTarget t) { + final WindowState w = t.getWindowState(); + final ActivityRecord activity = w != null ? w.getActivityRecord() : null; + final Task task = w != null ? w.getRootTask() : null; + + final boolean isInputTargetNotFocused = + mFocusedInputTarget != t && mFocusedInputTarget != null; + if (!isInputTargetNotFocused) { + return false; + } + + // For embedded activity that is showing side-by-side with another activity, delay + // handling the touch-outside event to prevent focus rapid changes back-n-forth. + final boolean shouldDelayTouchForEmbeddedActivity = activity != null + && activity.isEmbedded() + && activity.getTaskFragment().getAdjacentTaskFragment() != null; + + // For cases when there are multiple freeform windows where non-top windows are blocking + // the gesture zones, delay handling the touch-outside event to prevent refocusing the + // the non-top windows during the gesture. + final boolean shouldDelayTouchForFreeform = + task != null && task.getWindowingMode() == WINDOWING_MODE_FREEFORM; + + // If non of the above cases are true, handle the touch-outside event directly. + return shouldDelayTouchForEmbeddedActivity || shouldDelayTouchForFreeform; + } + private void handlePointerDownOutsideFocus(InputTarget t) { synchronized (mGlobalLock) { if (mPointerDownOutsideFocusRunnable != null diff --git a/tests/Internal/src/com/android/internal/protolog/PerfettoProtoLogImplTest.java b/tests/Internal/src/com/android/internal/protolog/PerfettoProtoLogImplTest.java index 4b745b289d33..4826f4241e2b 100644 --- a/tests/Internal/src/com/android/internal/protolog/PerfettoProtoLogImplTest.java +++ b/tests/Internal/src/com/android/internal/protolog/PerfettoProtoLogImplTest.java @@ -43,7 +43,6 @@ import android.tools.traces.protolog.ProtoLogTrace; import android.tracing.perfetto.DataSource; import android.util.proto.ProtoInputStream; -import androidx.test.filters.SmallTest; import androidx.test.platform.app.InstrumentationRegistry; import com.android.internal.protolog.common.IProtoLogGroup; @@ -73,7 +72,6 @@ import java.util.concurrent.atomic.AtomicInteger; * Test class for {@link ProtoLogImpl}. */ @SuppressWarnings("ConstantConditions") -@SmallTest @Presubmit @RunWith(JUnit4.class) public class PerfettoProtoLogImplTest { @@ -166,8 +164,7 @@ public class PerfettoProtoLogImplTest { mReader = Mockito.spy(new ProtoLogViewerConfigReader(viewerConfigInputStreamProvider)); mProtoLog = new PerfettoProtoLogImpl( viewerConfigInputStreamProvider, mReader, - () -> mCacheUpdater.run()); - mProtoLog.registerGroups(TestProtoLogGroup.values()); + () -> mCacheUpdater.run(), TestProtoLogGroup.values()); } @After diff --git a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java index ab406ef4632e..5b178250a4c9 100644 --- a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java +++ b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java @@ -1867,7 +1867,7 @@ public class PackageWatchdogTest { return true; } - public String getName() { + public String getUniqueIdentifier() { return mName; } diff --git a/tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessorImpl.kt b/tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessorImpl.kt index 3c99e68cd6a0..c3595b7ac288 100644 --- a/tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessorImpl.kt +++ b/tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessorImpl.kt @@ -120,7 +120,7 @@ class ProtoLogCallProcessorImpl( logCallVisitor?.processCall(call, messageString, getLevelForMethodName( call.name.toString(), call, context), groupMap.getValue(groupName)) - } else if (call.name.id == "initialize") { + } else if (call.name.id == "init") { // No processing } else { // Process non-log message calls |