diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index b53d9af5d4e45..f9e7bacd9b02b 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -12837,6 +12837,23 @@ public final class Settings { public static final String MAX_SOUND_TRIGGER_DETECTION_SERVICE_OPS_PER_DAY = "max_sound_trigger_detection_service_ops_per_day"; + /** + * Property used by {@code com.android.server.SystemServer} on start to decide whether + * the Smart Suggestions service should be created or not + * + *

By default it should *NOT* be set (in which case the decision is based on whether + * the OEM provides an implementation for the service), but it can be overridden to: + * + *

+ * + * @hide + */ + public static final String SMART_SUGGESTIONS_SERVICE_EXPLICITLY_ENABLED = + "smart_suggestions_service_explicitly_enabled"; + /** * Settings to backup. This is here so that it's in the same place as the settings * keys and easy to update. diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto index d917536b17150..e3184c18659c0 100644 --- a/core/proto/android/providers/settings/global.proto +++ b/core/proto/android/providers/settings/global.proto @@ -761,6 +761,13 @@ message GlobalSettingsProto { } optional SmartSelection smart_selection = 108; + message SmartSuggestions { + option (android.msg_privacy).dest = DEST_EXPLICIT; + + optional SettingProto service_explicitly_enabled = 1 [ (android.privacy).dest = DEST_AUTOMATIC ]; + } + optional SmartSuggestions smart_suggestions = 145; + message Sms { option (android.msg_privacy).dest = DEST_EXPLICIT; @@ -991,5 +998,5 @@ message GlobalSettingsProto { // Please insert fields in alphabetical order and group them into messages // if possible (to avoid reaching the method limit). - // Next tag = 145; + // Next tag = 146; } diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 0cd6bc5cd7001..c62071bdf5527 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -3350,6 +3350,14 @@ --> + + + true diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 01422c8ffd970..6854a84e950ac 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3265,6 +3265,7 @@ + diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java index a8f9e8a5891b3..750505e76a61e 100644 --- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java +++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java @@ -415,6 +415,7 @@ public class SettingsBackupTest { Settings.Global.SHOW_TEMPERATURE_WARNING, Settings.Global.SMART_SELECTION_UPDATE_CONTENT_URL, Settings.Global.SMART_SELECTION_UPDATE_METADATA_URL, + Settings.Global.SMART_SUGGESTIONS_SERVICE_EXPLICITLY_ENABLED, Settings.Global.SMS_ACCESS_RESTRICTION_ENABLED, Settings.Global.SMS_OUTGOING_CHECK_INTERVAL_MS, Settings.Global.SMS_OUTGOING_CHECK_MAX_COUNT, diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java index 56b768feee234..83b1e89af902c 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java @@ -1165,6 +1165,12 @@ class SettingsProtoDumpUtil { GlobalSettingsProto.SmartSelection.UPDATE_METADATA_URL); p.end(smartSelectToken); + final long smartSuggestionsToken = p.start(GlobalSettingsProto.SMART_SUGGESTIONS); + dumpSetting(s, p, + Settings.Global.SMART_SUGGESTIONS_SERVICE_EXPLICITLY_ENABLED, + GlobalSettingsProto.SmartSuggestions.SERVICE_EXPLICITLY_ENABLED); + p.end(smartSuggestionsToken); + final long smsToken = p.start(GlobalSettingsProto.SMS); dumpSetting(s, p, Settings.Global.SMS_OUTGOING_CHECK_INTERVAL_MS, diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java index 0df99d4b6642b..18bc856700f7a 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java @@ -190,6 +190,11 @@ final class AutofillManagerServiceImpl return mInfo.getServiceInfo(); } + @Override // from PerUserSystemService + protected String getDefaultComponentName() { + return getComponentNameFromSettings(); + } + @Nullable String[] getUrlBarResourceIdsForCompatMode(@NonNull String packageName) { return mAutofillCompatState.getUrlBarResourceIds(packageName, mUserId); @@ -369,7 +374,7 @@ final class AutofillManagerServiceImpl final long identity = Binder.clearCallingIdentity(); try { - final String autoFillService = getComponentNameFromSettings(); + final String autoFillService = getComponentNameLocked(); final ComponentName componentName = serviceInfo.getComponentName(); if (componentName.equals(ComponentName.unflattenFromString(autoFillService))) { mMetricsLogger.action(MetricsEvent.AUTOFILL_SERVICE_DISABLED_SELF, diff --git a/services/core/java/com/android/server/AbstractMasterSystemService.java b/services/core/java/com/android/server/AbstractMasterSystemService.java index 1759ce195485b..76010b346a3b3 100644 --- a/services/core/java/com/android/server/AbstractMasterSystemService.java +++ b/services/core/java/com/android/server/AbstractMasterSystemService.java @@ -39,6 +39,7 @@ import android.util.SparseBooleanArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.content.PackageMonitor; import com.android.internal.os.BackgroundThread; +import com.android.internal.util.Preconditions; import java.io.PrintWriter; import java.util.List; @@ -210,6 +211,66 @@ public abstract class AbstractMasterSystemServiceTypically used by Shell command and/or CTS tests. + * + * @param componentName name of the new component + * @param durationMs how long the change will be valid (the service will be automatically reset + * to the default component after this timeout expires). + * @throws SecurityException if caller is not allowed to manage this service's settings. + * @throws IllegalArgumentException if value of {@code durationMs} is higher than + * {@link #getMaximumTemporaryServiceDurationMs()}. + */ + public final void setTemporaryService(@UserIdInt int userId, @NonNull String componentName, + int durationMs) { + Slog.i(mTag, "setTemporaryService(" + userId + ") to " + componentName + " for " + + durationMs + "ms"); + enforceCallingPermissionForManagement(); + + Preconditions.checkNotNull(componentName); + final int maxDurationMs = getMaximumTemporaryServiceDurationMs(); + if (durationMs > maxDurationMs) { + throw new IllegalArgumentException( + "Max duration is " + maxDurationMs + " (called with " + durationMs + ")"); + } + + synchronized (mLock) { + final S service = getServiceForUserLocked(userId); + if (service != null) { + service.setTemporaryServiceLocked(componentName, durationMs); + } + } + } + + /** + * Gets the maximum time the service implementation can be changed. + * + * @throws UnsupportedOperationException if subclass doesn't override it. + */ + protected int getMaximumTemporaryServiceDurationMs() { + throw new UnsupportedOperationException("Not implemented by " + getClass()); + } + + /** + * Resets the temporary service implementation to the default component. + * + *

Typically used by Shell command and/or CTS tests. + * + * @throws SecurityException if caller is not allowed to manage this service's settings. + */ + public final void resetTemporaryService(@UserIdInt int userId) { + Slog.i(mTag, "resetTemporaryService(): " + userId); + enforceCallingPermissionForManagement(); + synchronized (mLock) { + final S service = getServiceForUserLocked(userId); + if (service != null) { + service.resetTemporaryServiceLocked(); + } + } + } + /** * Asserts that the caller has permissions to manage this service. * diff --git a/services/core/java/com/android/server/AbstractPerUserSystemService.java b/services/core/java/com/android/server/AbstractPerUserSystemService.java index 001d85f1b7982..a26102d57297c 100644 --- a/services/core/java/com/android/server/AbstractPerUserSystemService.java +++ b/services/core/java/com/android/server/AbstractPerUserSystemService.java @@ -26,12 +26,17 @@ import android.content.pm.PackageItemInfo; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ServiceInfo; import android.graphics.drawable.Drawable; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; import android.os.Process; import android.os.RemoteException; +import android.os.SystemClock; import android.os.UserManager; import android.provider.Settings; import android.text.TextUtils; import android.util.Slog; +import android.util.TimeUtils; import com.android.internal.annotations.GuardedBy; @@ -49,6 +54,9 @@ import java.io.PrintWriter; public abstract class AbstractPerUserSystemService, M extends AbstractMasterSystemService> { + /** Handler message to {@link #resetTemporaryServiceLocked()} */ + private static final int MSG_RESET_TEMPORARY_SERVICE = 0; + protected final @UserIdInt int mUserId; protected final Object mLock; protected final String mTag = getClass().getSimpleName(); @@ -70,6 +78,26 @@ public abstract class AbstractPerUserSystemServiceTypically used by Shell command and/or CTS tests. + */ + @GuardedBy("mLock") + private String mTemporaryServiceName; + + /** + * When the temporary service will expire (and reset back to the default). + */ + @GuardedBy("mLock") + private long mTemporaryServiceExpiration; + + /** + * Handler used to reset the temporary service name. + */ + @GuardedBy("mLock") + private Handler mTemporaryHandler; + protected AbstractPerUserSystemService(@NonNull M master, @NonNull Object lock, @UserIdInt int userId) { mMaster = master; @@ -130,7 +158,7 @@ public abstract class AbstractPerUserSystemServiceTypically implemented by returning {@link #getComponentNameFromSettings()} or by using + * a string from the system resources. + */ + @Nullable + protected abstract String getDefaultComponentName(); + /** * Gets this name of the remote service this service binds to as defined by {@link Settings}. */ @@ -200,6 +251,66 @@ public abstract class AbstractPerUserSystemService