Merge "Add satellite provision APIs"
diff --git a/apex/jobscheduler/framework/java/com/android/server/job/JobSchedulerInternal.java b/apex/jobscheduler/framework/java/com/android/server/job/JobSchedulerInternal.java
index 217b8b6..c956bf5 100644
--- a/apex/jobscheduler/framework/java/com/android/server/job/JobSchedulerInternal.java
+++ b/apex/jobscheduler/framework/java/com/android/server/job/JobSchedulerInternal.java
@@ -17,9 +17,12 @@
package com.android.server.job;
import android.annotation.Nullable;
+import android.app.job.JobInfo;
import android.app.job.JobParameters;
import android.util.proto.ProtoOutputStream;
+import java.util.List;
+
/**
* JobScheduler local system service interface.
* {@hide} Only for use within the system server.
@@ -27,6 +30,11 @@
public interface JobSchedulerInternal {
/**
+ * Returns a list of jobs scheduled by the system service for itself.
+ */
+ List<JobInfo> getSystemScheduledOwnJobs(@Nullable String namespace);
+
+ /**
* Cancel the jobs for a given uid (e.g. when app data is cleared)
*
* @param includeProxiedJobs Include jobs scheduled for this UID by other apps
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index fce75a2..e786342 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -3536,6 +3536,21 @@
final class LocalService implements JobSchedulerInternal {
@Override
+ public List<JobInfo> getSystemScheduledOwnJobs(@Nullable String namespace) {
+ synchronized (mLock) {
+ final List<JobInfo> ownJobs = new ArrayList<>();
+ mJobs.forEachJob(Process.SYSTEM_UID, (job) -> {
+ if (job.getSourceUid() == Process.SYSTEM_UID
+ && Objects.equals(job.getNamespace(), namespace)
+ && "android".equals(job.getSourcePackageName())) {
+ ownJobs.add(job.getJob());
+ }
+ });
+ return ownJobs;
+ }
+ }
+
+ @Override
public void cancelJobsForUid(int uid, boolean includeProxiedJobs,
@JobParameters.StopReason int reason, int internalReasonCode, String debugReason) {
JobSchedulerService.this.cancelJobsForUid(uid,
diff --git a/boot/preloaded-classes b/boot/preloaded-classes
index 39b7385..b43421d 100644
--- a/boot/preloaded-classes
+++ b/boot/preloaded-classes
@@ -5525,6 +5525,8 @@
android.nfc.NfcAdapter
android.nfc.NfcControllerAlwaysOnListener
android.nfc.NfcManager
+android.nfc.NfcServiceManager$ServiceRegisterer
+android.nfc.NfcServiceManager
android.nfc.Tag$1
android.nfc.Tag
android.nfc.TechListParcel$1
diff --git a/core/api/current.txt b/core/api/current.txt
index ed81918..75f5727 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -13465,7 +13465,7 @@
ctor public CreateCredentialException(@NonNull String);
method @NonNull public String getType();
field @NonNull public static final String TYPE_INTERRUPTED = "android.credentials.CreateCredentialException.TYPE_INTERRUPTED";
- field @NonNull public static final String TYPE_NO_CREDENTIAL = "android.credentials.CreateCredentialException.TYPE_NO_CREDENTIAL";
+ field @NonNull public static final String TYPE_NO_CREATE_OPTIONS = "android.credentials.CreateCredentialException.TYPE_NO_CREATE_OPTIONS";
field @NonNull public static final String TYPE_UNKNOWN = "android.credentials.CreateCredentialException.TYPE_UNKNOWN";
field @NonNull public static final String TYPE_USER_CANCELED = "android.credentials.CreateCredentialException.TYPE_USER_CANCELED";
}
@@ -39475,6 +39475,7 @@
method @NonNull public android.service.autofill.Dataset build();
method @NonNull public android.service.autofill.Dataset.Builder setAuthentication(@Nullable android.content.IntentSender);
method @NonNull public android.service.autofill.Dataset.Builder setField(@NonNull android.view.autofill.AutofillId, @Nullable android.service.autofill.Field);
+ method @NonNull public android.service.autofill.Dataset.Builder setField(@NonNull String, @NonNull android.service.autofill.Field);
method @NonNull public android.service.autofill.Dataset.Builder setId(@Nullable String);
method @Deprecated @NonNull public android.service.autofill.Dataset.Builder setInlinePresentation(@NonNull android.service.autofill.InlinePresentation);
method @Deprecated @NonNull public android.service.autofill.Dataset.Builder setInlinePresentation(@NonNull android.service.autofill.InlinePresentation, @NonNull android.service.autofill.InlinePresentation);
@@ -39583,6 +39584,7 @@
method @Nullable public android.content.IntentSender getDelayedFillIntentSender();
method @NonNull public java.util.List<android.service.autofill.FillContext> getFillContexts();
method public int getFlags();
+ method @NonNull public java.util.List<java.lang.String> getHints();
method public int getId();
method @Nullable public android.view.inputmethod.InlineSuggestionsRequest getInlineSuggestionsRequest();
method public void writeToParcel(@NonNull android.os.Parcel, int);
@@ -39611,6 +39613,7 @@
method @Deprecated @NonNull public android.service.autofill.FillResponse.Builder setAuthentication(@NonNull android.view.autofill.AutofillId[], @Nullable android.content.IntentSender, @Nullable android.widget.RemoteViews, @Nullable android.service.autofill.InlinePresentation, @Nullable android.service.autofill.InlinePresentation);
method @NonNull public android.service.autofill.FillResponse.Builder setAuthentication(@NonNull android.view.autofill.AutofillId[], @Nullable android.content.IntentSender, @Nullable android.service.autofill.Presentations);
method @NonNull public android.service.autofill.FillResponse.Builder setClientState(@Nullable android.os.Bundle);
+ method @NonNull public android.service.autofill.FillResponse.Builder setDetectedFieldClassifications(@NonNull java.util.Set<android.service.assist.classification.FieldClassification>);
method @NonNull public android.service.autofill.FillResponse.Builder setDialogHeader(@NonNull android.widget.RemoteViews);
method @NonNull public android.service.autofill.FillResponse.Builder setFieldClassificationIds(@NonNull android.view.autofill.AutofillId...);
method @NonNull public android.service.autofill.FillResponse.Builder setFillDialogTriggerIds(@NonNull android.view.autofill.AutofillId...);
@@ -40242,6 +40245,7 @@
}
public final class BeginCreateCredentialResponse implements android.os.Parcelable {
+ ctor public BeginCreateCredentialResponse();
method public int describeContents();
method @NonNull public java.util.List<android.service.credentials.CreateEntry> getCreateEntries();
method @Nullable public android.service.credentials.CreateEntry getRemoteCreateEntry();
@@ -40283,6 +40287,7 @@
}
public final class BeginGetCredentialResponse implements android.os.Parcelable {
+ ctor public BeginGetCredentialResponse();
method public int describeContents();
method @NonNull public java.util.List<android.service.credentials.Action> getActions();
method @NonNull public java.util.List<android.service.credentials.Action> getAuthenticationActions();
@@ -40976,7 +40981,7 @@
method public void onRequestCompleteVoice(android.service.voice.VoiceInteractionSession.CompleteVoiceRequest);
method public void onRequestConfirmation(android.service.voice.VoiceInteractionSession.ConfirmationRequest);
method public void onRequestPickOption(android.service.voice.VoiceInteractionSession.PickOptionRequest);
- method public void onShow(android.os.Bundle, int);
+ method public void onShow(@Nullable android.os.Bundle, int);
method public void onTaskFinished(android.content.Intent, int);
method public void onTaskStarted(android.content.Intent, int);
method public void onTrimMemory(int);
@@ -44008,6 +44013,7 @@
field public static final int IWLAN_SEMANTIC_ERROR_IN_THE_TFT_OPERATION = 8241; // 0x2031
field public static final int IWLAN_SYNTACTICAL_ERRORS_IN_PACKET_FILTERS = 8245; // 0x2035
field public static final int IWLAN_SYNTACTICAL_ERROR_IN_THE_TFT_OPERATION = 8242; // 0x2032
+ field public static final int IWLAN_TUNNEL_NOT_FOUND = 16390; // 0x4006
field public static final int IWLAN_UNAUTHENTICATED_EMERGENCY_NOT_SUPPORTED = 11055; // 0x2b2f
field public static final int IWLAN_USER_UNKNOWN = 9001; // 0x2329
field public static final int LIMITED_TO_IPV4 = 2234; // 0x8ba
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index af35d96..5171027 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -316,6 +316,30 @@
}
+package android.nfc {
+
+ public class NfcFrameworkInitializer {
+ method public static void registerServiceWrappers();
+ method public static void setNfcServiceManager(@NonNull android.nfc.NfcServiceManager);
+ }
+
+ public class NfcServiceManager {
+ method @NonNull public android.nfc.NfcServiceManager.ServiceRegisterer getNfcManagerServiceRegisterer();
+ }
+
+ public static class NfcServiceManager.ServiceNotFoundException extends java.lang.Exception {
+ ctor public NfcServiceManager.ServiceNotFoundException(@NonNull String);
+ }
+
+ public static final class NfcServiceManager.ServiceRegisterer {
+ method @Nullable public android.os.IBinder get();
+ method @NonNull public android.os.IBinder getOrThrow() throws android.nfc.NfcServiceManager.ServiceNotFoundException;
+ method public void register(@NonNull android.os.IBinder);
+ method @Nullable public android.os.IBinder tryGet();
+ }
+
+}
+
package android.os {
public class ArtModuleServiceManager {
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 85861c3..51e90d2 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -2529,6 +2529,7 @@
public final class Dataset implements android.os.Parcelable {
method @Nullable public android.content.IntentSender getAuthentication();
+ method @Nullable public java.util.ArrayList<java.lang.String> getAutofillDatatypes();
method @Nullable public android.content.ClipData getFieldContent();
method @Nullable public java.util.ArrayList<android.view.autofill.AutofillId> getFieldIds();
method @Nullable public java.util.ArrayList<android.view.autofill.AutofillValue> getFieldValues();
@@ -2549,6 +2550,7 @@
}
public final class FillResponse implements android.os.Parcelable {
+ method @NonNull public java.util.Set<android.service.assist.classification.FieldClassification> getDetectedFieldClassifications();
method public int getFlags();
}
@@ -3278,6 +3280,7 @@
field public static final String DEVICE_CONFIG_AUTOFILL_CREDENTIAL_MANAGER_IGNORE_VIEWS = "autofill_credential_manager_ignore_views";
field public static final String DEVICE_CONFIG_AUTOFILL_DIALOG_ENABLED = "autofill_dialog_enabled";
field public static final String DEVICE_CONFIG_AUTOFILL_PCC_CLASSIFICATION_ENABLED = "pcc_classification_enabled";
+ field public static final String DEVICE_CONFIG_AUTOFILL_PCC_FEATURE_PROVIDER_HINTS = "pcc_classification_hints";
field public static final String DEVICE_CONFIG_AUTOFILL_SMART_SUGGESTION_SUPPORTED_MODES = "smart_suggestion_supported_modes";
field public static final String DEVICE_CONFIG_NON_AUTOFILLABLE_IME_ACTION_IDS = "non_autofillable_ime_action_ids";
field public static final String DEVICE_CONFIG_PACKAGE_DENYLIST_FOR_UNIMPORTANT_VIEW = "package_deny_list_for_unimportant_view";
diff --git a/core/java/android/accessibilityservice/MagnificationConfig.java b/core/java/android/accessibilityservice/MagnificationConfig.java
index 486dc50..5019aee 100644
--- a/core/java/android/accessibilityservice/MagnificationConfig.java
+++ b/core/java/android/accessibilityservice/MagnificationConfig.java
@@ -107,7 +107,7 @@
* Returns the activated state of the controlling magnifier. The controlling magnifier can be
* activated even if the scale returned by {@link MagnificationConfig#getScale()} equals to 1.0.
*
- * @return {@code true} if the magnifier is showing on screen,
+ * @return {@code true} if the magnifier is activated and showing on screen,
* {@code false} otherwise.
*/
public boolean isActivated() {
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 8395ec6..5496191 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -109,6 +109,8 @@
import android.net.Proxy;
import android.net.TrafficStats;
import android.net.Uri;
+import android.nfc.NfcFrameworkInitializer;
+import android.nfc.NfcServiceManager;
import android.os.AsyncTask;
import android.os.Binder;
import android.os.BluetoothServiceManager;
@@ -8135,6 +8137,7 @@
BluetoothFrameworkInitializer.setBluetoothServiceManager(new BluetoothServiceManager());
BluetoothFrameworkInitializer.setBinderCallsStatsInitializer(context -> {
BinderCallsStats.startForBluetooth(context); });
+ NfcFrameworkInitializer.setNfcServiceManager(new NfcServiceManager());
}
private void purgePendingResources() {
diff --git a/core/java/android/app/ForegroundServiceTypePolicy.java b/core/java/android/app/ForegroundServiceTypePolicy.java
index 5ef29e4..a7824a8 100644
--- a/core/java/android/app/ForegroundServiceTypePolicy.java
+++ b/core/java/android/app/ForegroundServiceTypePolicy.java
@@ -107,9 +107,8 @@
*
* @hide
*/
- // TODO (b/254661666): Change to @EnabledAfter(T)
@ChangeId
- @Disabled
+ @EnabledAfter(targetSdkVersion = android.os.Build.VERSION_CODES.TIRAMISU)
@Overridable
public static final long FGS_TYPE_NONE_DISABLED_CHANGE_ID = 255038118L;
@@ -142,9 +141,8 @@
*
* @hide
*/
- // TODO (b/254661666): Change to @EnabledAfter(T)
@ChangeId
- @Disabled
+ @EnabledAfter(targetSdkVersion = android.os.Build.VERSION_CODES.TIRAMISU)
@Overridable
public static final long FGS_TYPE_PERMISSION_CHANGE_ID = 254662522L;
@@ -286,10 +284,7 @@
new ForegroundServiceTypePermissions(new ForegroundServiceTypePermission[] {
new RegularPermission(Manifest.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION)
}, true),
- new ForegroundServiceTypePermissions(new ForegroundServiceTypePermission[] {
- new RegularPermission(Manifest.permission.CAPTURE_VIDEO_OUTPUT),
- new AppOpPermission(AppOpsManager.OP_PROJECT_MEDIA)
- }, false)
+ null
);
/**
@@ -1058,7 +1053,7 @@
if (policy.isTypeDisabled(callerUid)) {
return FGS_TYPE_POLICY_CHECK_DISABLED;
}
- int permissionResult = PERMISSION_DENIED;
+ int permissionResult = PERMISSION_GRANTED;
// Do we have the permission to start FGS with this type.
if (policy.mAllOfPermissions != null) {
permissionResult = policy.mAllOfPermissions.checkPermissions(context,
diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index 9e31011..f74be22 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -940,7 +940,7 @@
* @param tileLabel label of the tile to show to the user.
* @param icon icon to use in the tile shown to the user.
* @param resultExecutor an executor to run the callback on
- * @param resultCallback callback to indicate the {@link RequestResult}.
+ * @param resultCallback callback to indicate the result of the request.
*
* @see android.service.quicksettings.TileService
*/
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 0365f8c..64538ec 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -157,7 +157,7 @@
import android.net.wifi.WifiFrameworkInitializer;
import android.net.wifi.nl80211.WifiNl80211Manager;
import android.net.wifi.sharedconnectivity.app.SharedConnectivityManager;
-import android.nfc.NfcManager;
+import android.nfc.NfcFrameworkInitializer;
import android.ondevicepersonalization.OnDevicePersonalizationFrameworkInitializer;
import android.os.BatteryManager;
import android.os.BatteryStats;
@@ -484,13 +484,6 @@
return new BatteryManager(ctx, stats, registrar);
}});
- registerService(Context.NFC_SERVICE, NfcManager.class,
- new CachedServiceFetcher<NfcManager>() {
- @Override
- public NfcManager createService(ContextImpl ctx) {
- return new NfcManager(ctx);
- }});
-
registerService(Context.DROPBOX_SERVICE, DropBoxManager.class,
new CachedServiceFetcher<DropBoxManager>() {
@Override
@@ -1589,6 +1582,7 @@
JobSchedulerFrameworkInitializer.registerServiceWrappers();
BlobStoreManagerFrameworkInitializer.initialize();
BluetoothFrameworkInitializer.registerServiceWrappers();
+ NfcFrameworkInitializer.registerServiceWrappers();
TelephonyFrameworkInitializer.registerServiceWrappers();
AppSearchManagerFrameworkInitializer.initialize();
HealthServicesInitializer.registerServiceWrappers();
diff --git a/core/java/android/credentials/CreateCredentialException.java b/core/java/android/credentials/CreateCredentialException.java
index 84cc9a8..c344004 100644
--- a/core/java/android/credentials/CreateCredentialException.java
+++ b/core/java/android/credentials/CreateCredentialException.java
@@ -40,13 +40,13 @@
"android.credentials.CreateCredentialException.TYPE_UNKNOWN";
/**
- * The error type value for when no credential is available for the given {@link
- * CredentialManager#createCredential(CreateCredentialRequest, Activity,
+ * The error type value for when no create options are available from any provider(s),
+ * for the given {@link CredentialManager#createCredential(CreateCredentialRequest, Activity,
* CancellationSignal, Executor, OutcomeReceiver)} request.
*/
@NonNull
- public static final String TYPE_NO_CREDENTIAL =
- "android.credentials.CreateCredentialException.TYPE_NO_CREDENTIAL";
+ public static final String TYPE_NO_CREATE_OPTIONS =
+ "android.credentials.CreateCredentialException.TYPE_NO_CREATE_OPTIONS";
/**
* The error type value for when the user intentionally cancelled the request.
*
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index 6dc80cf..1bb44af 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -43,7 +43,6 @@
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.util.Log;
import java.io.IOException;
@@ -426,6 +425,7 @@
// recovery
@UnsupportedAppUsage
static INfcAdapter sService;
+ static NfcServiceManager.ServiceRegisterer sServiceRegisterer;
static INfcTag sTagService;
static INfcCardEmulation sCardEmulationService;
static INfcFCardEmulation sNfcFCardEmulationService;
@@ -624,6 +624,12 @@
Log.v(TAG, "this device does not have NFC support");
throw new UnsupportedOperationException();
}
+ NfcServiceManager manager = NfcFrameworkInitializer.getNfcServiceManager();
+ if (manager == null) {
+ Log.e(TAG, "NfcServiceManager is null");
+ throw new UnsupportedOperationException();
+ }
+ sServiceRegisterer = manager.getNfcManagerServiceRegisterer();
sService = getServiceInterface();
if (sService == null) {
Log.e(TAG, "could not retrieve NFC service");
@@ -665,7 +671,7 @@
/** get handle to NFC service interface */
private static INfcAdapter getServiceInterface() {
/* get a handle to NFC service */
- IBinder b = ServiceManager.getService("nfc");
+ IBinder b = sServiceRegisterer.get();
if (b == null) {
return null;
}
@@ -695,12 +701,13 @@
"context not associated with any application (using a mock context?)");
}
- if (getServiceInterface() == null) {
- // NFC is not available
- return null;
+ if (sIsInitialized && sServiceRegisterer.tryGet() == null) {
+ synchronized (NfcAdapter.class) {
+ /* Stale sService pointer */
+ if (sIsInitialized) sIsInitialized = false;
+ }
}
-
- /* use getSystemService() for consistency */
+ /* Try to initialize the service */
NfcManager manager = (NfcManager) context.getSystemService(Context.NFC_SERVICE);
if (manager == null) {
// NFC not available
diff --git a/core/java/android/nfc/NfcFrameworkInitializer.java b/core/java/android/nfc/NfcFrameworkInitializer.java
new file mode 100644
index 0000000..1ab8a1e
--- /dev/null
+++ b/core/java/android/nfc/NfcFrameworkInitializer.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2023 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.nfc;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.app.SystemServiceRegistry;
+import android.content.Context;
+
+/**
+ * Class for performing registration for Nfc service.
+ *
+ * @hide
+ */
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+public class NfcFrameworkInitializer {
+ private NfcFrameworkInitializer() {}
+
+ private static volatile NfcServiceManager sNfcServiceManager;
+
+ /**
+ * Sets an instance of {@link NfcServiceManager} that allows
+ * the nfc mainline module to register/obtain nfc binder services. This is called
+ * by the platform during the system initialization.
+ *
+ * @param nfcServiceManager instance of {@link NfcServiceManager} that allows
+ * the nfc mainline module to register/obtain nfcd binder services.
+ */
+ public static void setNfcServiceManager(
+ @NonNull NfcServiceManager nfcServiceManager) {
+ if (sNfcServiceManager != null) {
+ throw new IllegalStateException("setNfcServiceManager called twice!");
+ }
+
+ if (nfcServiceManager == null) {
+ throw new IllegalArgumentException("nfcServiceManager must not be null");
+ }
+
+ sNfcServiceManager = nfcServiceManager;
+ }
+
+ /** @hide */
+ public static NfcServiceManager getNfcServiceManager() {
+ return sNfcServiceManager;
+ }
+
+ /**
+ * Called by {@link SystemServiceRegistry}'s static initializer and registers NFC service
+ * to {@link Context}, so that {@link Context#getSystemService} can return them.
+ *
+ * @throws IllegalStateException if this is called from anywhere besides
+ * {@link SystemServiceRegistry}
+ */
+ public static void registerServiceWrappers() {
+ SystemServiceRegistry.registerContextAwareService(Context.NFC_SERVICE,
+ NfcManager.class, context -> new NfcManager(context));
+ }
+}
diff --git a/core/java/android/nfc/NfcServiceManager.java b/core/java/android/nfc/NfcServiceManager.java
new file mode 100644
index 0000000..5582f11
--- /dev/null
+++ b/core/java/android/nfc/NfcServiceManager.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+
+/**********************************************************************
+ * This file is not a part of the NFC mainline modure *
+ * *******************************************************************/
+
+package android.nfc;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.annotation.SystemApi.Client;
+import android.content.Context;
+import android.os.IBinder;
+import android.os.ServiceManager;
+
+/**
+ * Provides a way to register and obtain the system service binder objects managed by the nfc
+ * service.
+ *
+ * @hide
+ */
+@SystemApi(client = Client.MODULE_LIBRARIES)
+public class NfcServiceManager {
+
+ /**
+ * @hide
+ */
+ public NfcServiceManager() {
+ }
+
+ /**
+ * A class that exposes the methods to register and obtain each system service.
+ */
+ public static final class ServiceRegisterer {
+ private final String mServiceName;
+
+ /**
+ * @hide
+ */
+ public ServiceRegisterer(String serviceName) {
+ mServiceName = serviceName;
+ }
+
+ /**
+ * Register a system server binding object for a service.
+ */
+ public void register(@NonNull IBinder service) {
+ ServiceManager.addService(mServiceName, service);
+ }
+
+ /**
+ * Get the system server binding object for a service.
+ *
+ * <p>This blocks until the service instance is ready,
+ * or a timeout happens, in which case it returns null.
+ */
+ @Nullable
+ public IBinder get() {
+ return ServiceManager.getService(mServiceName);
+ }
+
+ /**
+ * Get the system server binding object for a service.
+ *
+ * <p>This blocks until the service instance is ready,
+ * or a timeout happens, in which case it throws {@link ServiceNotFoundException}.
+ */
+ @NonNull
+ public IBinder getOrThrow() throws ServiceNotFoundException {
+ try {
+ return ServiceManager.getServiceOrThrow(mServiceName);
+ } catch (ServiceManager.ServiceNotFoundException e) {
+ throw new ServiceNotFoundException(mServiceName);
+ }
+ }
+
+ /**
+ * Get the system server binding object for a service. If the specified service is
+ * not available, it returns null.
+ */
+ @Nullable
+ public IBinder tryGet() {
+ return ServiceManager.checkService(mServiceName);
+ }
+ }
+
+ /**
+ * See {@link ServiceRegisterer#getOrThrow}.
+ *
+ */
+ public static class ServiceNotFoundException extends ServiceManager.ServiceNotFoundException {
+ /**
+ * Constructor.
+ *
+ * @param name the name of the binder service that cannot be found.
+ *
+ */
+ public ServiceNotFoundException(@NonNull String name) {
+ super(name);
+ }
+ }
+
+ /**
+ * Returns {@link ServiceRegisterer} for the "nfc" service.
+ */
+ @NonNull
+ public ServiceRegisterer getNfcManagerServiceRegisterer() {
+ return new ServiceRegisterer(Context.NFC_SERVICE);
+ }
+}
diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java
index 7ad1735..810bd63 100644
--- a/core/java/android/os/ParcelFileDescriptor.java
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -34,7 +34,6 @@
import android.annotation.NonNull;
import android.annotation.SuppressLint;
import android.annotation.TestApi;
-import android.app.ActivityThread;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.BroadcastReceiver;
import android.content.ContentProvider;
@@ -46,7 +45,6 @@
import android.system.OsConstants;
import android.system.StructStat;
import android.util.Log;
-import android.util.Slog;
import dalvik.system.CloseGuard;
import dalvik.system.VMRuntime;
@@ -331,17 +329,6 @@
}
private static FileDescriptor openInternal(File file, int mode) throws FileNotFoundException {
- if ((mode & MODE_WRITE_ONLY) != 0 && (mode & MODE_APPEND) == 0
- && (mode & MODE_TRUNCATE) == 0 && ((mode & MODE_READ_ONLY) == 0)
- && file.exists()) {
- String packageName = ActivityThread.currentApplication().getApplicationContext()
- .getPackageName();
- Slog.wtfQuiet(TAG, "ParcelFileDescriptor.open is called with w without t or a or r, "
- + "which will have a different behavior beginning in Android Q."
- + "\nPackage Name: " + packageName + "\nMode: " + mode
- + "\nFilename: " + file.getPath());
- }
-
final int flags = FileUtils.translateModePfdToPosix(mode) | ifAtLeastQ(O_CLOEXEC);
int realMode = S_IRWXU | S_IRWXG;
diff --git a/core/java/android/service/autofill/Dataset.java b/core/java/android/service/autofill/Dataset.java
index e9f099a..0fa5e3e 100644
--- a/core/java/android/service/autofill/Dataset.java
+++ b/core/java/android/service/autofill/Dataset.java
@@ -120,6 +120,8 @@
private final ArrayList<InlinePresentation> mFieldInlinePresentations;
private final ArrayList<InlinePresentation> mFieldInlineTooltipPresentations;
private final ArrayList<DatasetFieldFilter> mFieldFilters;
+ private final ArrayList<String> mAutofillDatatypes;
+
@Nullable private final ClipData mFieldContent;
private final RemoteViews mPresentation;
private final RemoteViews mDialogPresentation;
@@ -143,6 +145,14 @@
mInlineTooltipPresentation = builder.mInlineTooltipPresentation;
mAuthentication = builder.mAuthentication;
mId = builder.mId;
+ mAutofillDatatypes = builder.mAutofillDatatypes;
+ }
+
+ /** @hide */
+ @TestApi
+ @SuppressLint({"ConcreteCollection", "NullableCollection"})
+ public @Nullable ArrayList<String> getAutofillDatatypes() {
+ return mAutofillDatatypes;
}
/** @hide */
@@ -293,6 +303,7 @@
private ArrayList<InlinePresentation> mFieldInlinePresentations;
private ArrayList<InlinePresentation> mFieldInlineTooltipPresentations;
private ArrayList<DatasetFieldFilter> mFieldFilters;
+ private ArrayList<String> mAutofillDatatypes;
@Nullable private ClipData mFieldContent;
private RemoteViews mPresentation;
private RemoteViews mDialogPresentation;
@@ -922,6 +933,55 @@
}
/**
+ * Adds a field to this Dataset with a specific type and no
+ * AutofillId. This is used to send back Field information
+ * when Autofilling with platform detections is on.
+ * Platform detections are on when receiving a populated list from
+ * FillRequest#getHints().
+ *
+ * Populate every field/type known for this user for this app.
+ *
+ * For example, if getHints() contains "username" and "password",
+ * a new Dataset should be created that calls this method twice,
+ * one for the username, then another for the password (assuming
+ * the only one credential pair is found for the user). If a user
+ * has two credential pairs, then two Datasets should be created,
+ * and so on.
+ *
+ * Using this will remove any data populated with
+ * setField(@NonNull AutofillId id, @Nullable Field field).
+ *
+ * @param hint An autofill hint returned from {@link
+ * FillRequest#getHints()}.
+ *
+ * @param field the fill information about the field.
+ *
+ * @throws IllegalStateException if {@link #build()} was already called
+ * or this builder also contains AutofillId information
+ *
+ * @return this builder.
+ */
+ public @NonNull Dataset.Builder setField(
+ @NonNull String hint, @NonNull Field field) {
+ throwIfDestroyed();
+
+ final DatasetFieldFilter filter = field.getDatasetFieldFilter();
+ final Presentations presentations = field.getPresentations();
+ if (presentations == null) {
+ setLifeTheUniverseAndEverything(hint, field.getValue(), null, null, null,
+ filter, null);
+ } else {
+ setLifeTheUniverseAndEverything(hint, field.getValue(),
+ presentations.getMenuPresentation(),
+ presentations.getInlinePresentation(),
+ presentations.getInlineTooltipPresentation(), filter,
+ presentations.getDialogPresentation());
+ }
+
+ return this;
+ }
+
+ /**
* Sets the value of a field with an <a href="#Filtering">explicit filter</a>, and using an
* {@link InlinePresentation} to visualize it as an inline suggestion.
*
@@ -958,6 +1018,32 @@
return this;
}
+ private void setLifeTheUniverseAndEverything(String datatype,
+ @Nullable AutofillValue value,
+ @Nullable RemoteViews presentation,
+ @Nullable InlinePresentation inlinePresentation,
+ @Nullable InlinePresentation tooltip,
+ @Nullable DatasetFieldFilter filter,
+ @Nullable RemoteViews dialogPresentation) {
+ if (mAutofillDatatypes == null) {
+ mFieldValues = new ArrayList<>();
+ mFieldPresentations = new ArrayList<>();
+ mFieldDialogPresentations = new ArrayList<>();
+ mFieldInlinePresentations = new ArrayList<>();
+ mFieldInlineTooltipPresentations = new ArrayList<>();
+ mFieldFilters = new ArrayList<>();
+ mAutofillDatatypes = new ArrayList<>();
+ mFieldIds = null;
+ }
+ mFieldValues.add(value);
+ mFieldPresentations.add(presentation);
+ mFieldDialogPresentations.add(dialogPresentation);
+ mFieldInlinePresentations.add(inlinePresentation);
+ mFieldInlineTooltipPresentations.add(tooltip);
+ mFieldFilters.add(filter);
+ mAutofillDatatypes.add(datatype);
+ }
+
private void setLifeTheUniverseAndEverything(@NonNull AutofillId id,
@Nullable AutofillValue value, @Nullable RemoteViews presentation,
@Nullable InlinePresentation inlinePresentation,
@@ -984,6 +1070,7 @@
mFieldInlinePresentations = new ArrayList<>();
mFieldInlineTooltipPresentations = new ArrayList<>();
mFieldFilters = new ArrayList<>();
+ mAutofillDatatypes = null;
}
mFieldIds.add(id);
mFieldValues.add(value);
@@ -1007,9 +1094,14 @@
public @NonNull Dataset build() {
throwIfDestroyed();
mDestroyed = true;
- if (mFieldIds == null) {
+ if (mFieldIds == null && mAutofillDatatypes == null) {
throw new IllegalStateException("at least one value must be set");
}
+ if (mFieldIds != null && mAutofillDatatypes != null) {
+ if (mFieldIds.size() > 0 && mAutofillDatatypes.size() > 0) {
+ throw new IllegalStateException("both field and datatype were populated");
+ }
+ }
if (mFieldContent != null) {
if (mFieldIds.size() > 1) {
throw new IllegalStateException(
@@ -1051,6 +1143,7 @@
parcel.writeTypedList(mFieldInlinePresentations, flags);
parcel.writeTypedList(mFieldInlineTooltipPresentations, flags);
parcel.writeTypedList(mFieldFilters, flags);
+ parcel.writeStringList(mAutofillDatatypes);
parcel.writeParcelable(mFieldContent, flags);
parcel.writeParcelable(mAuthentication, flags);
parcel.writeString(mId);
@@ -1081,6 +1174,8 @@
parcel.createTypedArrayList(InlinePresentation.CREATOR);
final ArrayList<DatasetFieldFilter> filters =
parcel.createTypedArrayList(DatasetFieldFilter.CREATOR);
+ final ArrayList<String> datatypes =
+ parcel.createStringArrayList();
final ClipData fieldContent = parcel.readParcelable(null,
android.content.ClipData.class);
final IntentSender authentication = parcel.readParcelable(null,
@@ -1114,19 +1209,37 @@
builder.setContent(ids.get(0), fieldContent);
}
final int inlinePresentationsSize = inlinePresentations.size();
- for (int i = 0; i < ids.size(); i++) {
- final AutofillId id = ids.get(i);
- final AutofillValue value = values.get(i);
- final RemoteViews fieldPresentation = presentations.get(i);
- final RemoteViews fieldDialogPresentation = dialogPresentations.get(i);
- final InlinePresentation fieldInlinePresentation =
- i < inlinePresentationsSize ? inlinePresentations.get(i) : null;
- final InlinePresentation fieldInlineTooltipPresentation =
- i < inlinePresentationsSize ? inlineTooltipPresentations.get(i) : null;
- final DatasetFieldFilter filter = filters.get(i);
- builder.setLifeTheUniverseAndEverything(id, value, fieldPresentation,
- fieldInlinePresentation, fieldInlineTooltipPresentation, filter,
- fieldDialogPresentation);
+
+ if (ids.size() == 0 && datatypes.size() > 0) {
+ for (int i = 0; i < ids.size(); i++) {
+ final String datatype = datatypes.get(i);
+ final AutofillValue value = values.get(i);
+ final RemoteViews fieldPresentation = presentations.get(i);
+ final RemoteViews fieldDialogPresentation = dialogPresentations.get(i);
+ final InlinePresentation fieldInlinePresentation =
+ i < inlinePresentationsSize ? inlinePresentations.get(i) : null;
+ final InlinePresentation fieldInlineTooltipPresentation =
+ i < inlinePresentationsSize ? inlineTooltipPresentations.get(i) : null;
+ final DatasetFieldFilter filter = filters.get(i);
+ builder.setLifeTheUniverseAndEverything(
+ datatype, value, fieldPresentation, fieldInlinePresentation,
+ fieldInlineTooltipPresentation, filter, fieldDialogPresentation);
+ }
+ } else {
+ for (int i = 0; i < ids.size(); i++) {
+ final AutofillId id = ids.get(i);
+ final AutofillValue value = values.get(i);
+ final RemoteViews fieldPresentation = presentations.get(i);
+ final RemoteViews fieldDialogPresentation = dialogPresentations.get(i);
+ final InlinePresentation fieldInlinePresentation =
+ i < inlinePresentationsSize ? inlinePresentations.get(i) : null;
+ final InlinePresentation fieldInlineTooltipPresentation =
+ i < inlinePresentationsSize ? inlineTooltipPresentations.get(i) : null;
+ final DatasetFieldFilter filter = filters.get(i);
+ builder.setLifeTheUniverseAndEverything(id, value, fieldPresentation,
+ fieldInlinePresentation, fieldInlineTooltipPresentation, filter,
+ fieldDialogPresentation);
+ }
}
builder.setAuthentication(authentication);
builder.setId(datasetId);
diff --git a/core/java/android/service/autofill/FillRequest.java b/core/java/android/service/autofill/FillRequest.java
index eb5e893..4a848dd 100644
--- a/core/java/android/service/autofill/FillRequest.java
+++ b/core/java/android/service/autofill/FillRequest.java
@@ -141,6 +141,19 @@
private final @NonNull List<FillContext> mFillContexts;
/**
+ * Sends a list of datatypes for the Autofill Provider.
+ *
+ * If this is populated, Autofill Provider should return data
+ * for the autofill hints requested here,
+ * even though the Autofill Provider may not have detected these types.
+ * The hints would be part of HintConstants:
+ * https://developer.android.com/reference/androidx/autofill/HintConstants
+ *
+ * This is populated if the platform's field detection is enabled.
+ */
+ private final @NonNull List<String> mHints;
+
+ /**
* Gets the latest client state bundle set by the service in a
* {@link FillResponse.Builder#setClientState(Bundle) fill response}.
*
@@ -196,6 +209,7 @@
private void onConstructed() {
Preconditions.checkCollectionElementsNotNull(mFillContexts, "contexts");
+ Preconditions.checkCollectionElementsNotNull(mHints, "hints");
}
@@ -269,6 +283,11 @@
* <p><b>Note:</b> Starting on Android {@link android.os.Build.VERSION_CODES#Q}, it could also
* include contexts from requests whose {@link SaveInfo} had the
* {@link SaveInfo#FLAG_DELAY_SAVE} flag.
+ * @param hints
+ * Autofill Provider should return data for the autofill hints requested here,
+ * even though the Autofill Provider may not have detected these types.
+ * The hints would be part of HintConstants:
+ * https://developer.android.com/reference/androidx/autofill/HintConstants
* @param clientState
* Gets the latest client state bundle set by the service in a
* {@link FillResponse.Builder#setClientState(Bundle) fill response}.
@@ -312,6 +331,7 @@
public FillRequest(
int id,
@NonNull List<FillContext> fillContexts,
+ @NonNull List<String> hints,
@Nullable Bundle clientState,
@RequestFlags int flags,
@Nullable InlineSuggestionsRequest inlineSuggestionsRequest,
@@ -320,6 +340,9 @@
this.mFillContexts = fillContexts;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mFillContexts);
+ this.mHints = hints;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mHints);
this.mClientState = clientState;
this.mFlags = flags;
@@ -360,6 +383,17 @@
}
/**
+ * Autofill Provider should return data for the autofill hints requested here,
+ * even though the Autofill Provider may not have detected these types.
+ * The hints would be part of HintConstants:
+ * https://developer.android.com/reference/androidx/autofill/HintConstants
+ */
+ @DataClass.Generated.Member
+ public @NonNull List<String> getHints() {
+ return mHints;
+ }
+
+ /**
* Gets the latest client state bundle set by the service in a
* {@link FillResponse.Builder#setClientState(Bundle) fill response}.
*
@@ -433,6 +467,7 @@
return "FillRequest { " +
"id = " + mId + ", " +
"fillContexts = " + mFillContexts + ", " +
+ "hints = " + mHints + ", " +
"clientState = " + mClientState + ", " +
"flags = " + requestFlagsToString(mFlags) + ", " +
"inlineSuggestionsRequest = " + mInlineSuggestionsRequest + ", " +
@@ -447,12 +482,13 @@
// void parcelFieldName(Parcel dest, int flags) { ... }
byte flg = 0;
- if (mClientState != null) flg |= 0x4;
- if (mInlineSuggestionsRequest != null) flg |= 0x10;
- if (mDelayedFillIntentSender != null) flg |= 0x20;
+ if (mClientState != null) flg |= 0x8;
+ if (mInlineSuggestionsRequest != null) flg |= 0x20;
+ if (mDelayedFillIntentSender != null) flg |= 0x40;
dest.writeByte(flg);
dest.writeInt(mId);
dest.writeParcelableList(mFillContexts, flags);
+ dest.writeStringList(mHints);
if (mClientState != null) dest.writeBundle(mClientState);
dest.writeInt(mFlags);
if (mInlineSuggestionsRequest != null) dest.writeTypedObject(mInlineSuggestionsRequest, flags);
@@ -474,15 +510,20 @@
int id = in.readInt();
List<FillContext> fillContexts = new ArrayList<>();
in.readParcelableList(fillContexts, FillContext.class.getClassLoader());
- Bundle clientState = (flg & 0x4) == 0 ? null : in.readBundle();
+ List<String> hints = new ArrayList<>();
+ in.readStringList(hints);
+ Bundle clientState = (flg & 0x8) == 0 ? null : in.readBundle();
int flags = in.readInt();
- InlineSuggestionsRequest inlineSuggestionsRequest = (flg & 0x10) == 0 ? null : (InlineSuggestionsRequest) in.readTypedObject(InlineSuggestionsRequest.CREATOR);
- IntentSender delayedFillIntentSender = (flg & 0x20) == 0 ? null : (IntentSender) in.readTypedObject(IntentSender.CREATOR);
+ InlineSuggestionsRequest inlineSuggestionsRequest = (flg & 0x20) == 0 ? null : (InlineSuggestionsRequest) in.readTypedObject(InlineSuggestionsRequest.CREATOR);
+ IntentSender delayedFillIntentSender = (flg & 0x40) == 0 ? null : (IntentSender) in.readTypedObject(IntentSender.CREATOR);
this.mId = id;
this.mFillContexts = fillContexts;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mFillContexts);
+ this.mHints = hints;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mHints);
this.mClientState = clientState;
this.mFlags = flags;
@@ -517,10 +558,10 @@
};
@DataClass.Generated(
- time = 1675460688829L,
+ time = 1675711417112L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/service/autofill/FillRequest.java",
- inputSignatures = "public static final @android.service.autofill.FillRequest.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_PASSWORD_INPUT_TYPE\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_VIEW_NOT_FOCUSED\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_SUPPORTS_FILL_DIALOG\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_IME_SHOWING\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_RESET_FILL_DIALOG_STATE\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_PCC_DETECTION\npublic static final int INVALID_REQUEST_ID\nprivate final int mId\nprivate final @android.annotation.NonNull java.util.List<android.service.autofill.FillContext> mFillContexts\nprivate final @android.annotation.Nullable android.os.Bundle mClientState\nprivate final @android.service.autofill.FillRequest.RequestFlags int mFlags\nprivate final @android.annotation.Nullable android.view.inputmethod.InlineSuggestionsRequest mInlineSuggestionsRequest\nprivate final @android.annotation.Nullable android.content.IntentSender mDelayedFillIntentSender\nprivate void onConstructed()\nclass FillRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstructor=true, genHiddenConstDefs=true)")
+ inputSignatures = "public static final @android.service.autofill.FillRequest.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_PASSWORD_INPUT_TYPE\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_VIEW_NOT_FOCUSED\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_SUPPORTS_FILL_DIALOG\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_IME_SHOWING\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_RESET_FILL_DIALOG_STATE\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_PCC_DETECTION\npublic static final int INVALID_REQUEST_ID\nprivate final int mId\nprivate final @android.annotation.NonNull java.util.List<android.service.autofill.FillContext> mFillContexts\nprivate final @android.annotation.NonNull java.util.List<java.lang.String> mHints\nprivate final @android.annotation.Nullable android.os.Bundle mClientState\nprivate final @android.service.autofill.FillRequest.RequestFlags int mFlags\nprivate final @android.annotation.Nullable android.view.inputmethod.InlineSuggestionsRequest mInlineSuggestionsRequest\nprivate final @android.annotation.Nullable android.content.IntentSender mDelayedFillIntentSender\nprivate void onConstructed()\nclass FillRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstructor=true, genHiddenConstDefs=true)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/service/autofill/FillResponse.java b/core/java/android/service/autofill/FillResponse.java
index 385b0aa..fa7ace3 100644
--- a/core/java/android/service/autofill/FillResponse.java
+++ b/core/java/android/service/autofill/FillResponse.java
@@ -34,6 +34,7 @@
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
+import android.service.assist.classification.FieldClassification;
import android.view.autofill.AutofillId;
import android.widget.RemoteViews;
@@ -45,6 +46,7 @@
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
+import java.util.Set;
/**
* Response for an {@link
@@ -113,6 +115,7 @@
private final @StringRes int mServiceDisplayNameResourceId;
private final boolean mShowFillDialogIcon;
private final boolean mShowSaveDialogIcon;
+ private final @Nullable FieldClassification[] mDetectedFieldTypes;
private FillResponse(@NonNull Builder builder) {
mDatasets = (builder.mDatasets != null) ? new ParceledListSlice<>(builder.mDatasets) : null;
@@ -140,6 +143,14 @@
mServiceDisplayNameResourceId = builder.mServiceDisplayNameResourceId;
mShowFillDialogIcon = builder.mShowFillDialogIcon;
mShowSaveDialogIcon = builder.mShowSaveDialogIcon;
+ mDetectedFieldTypes = builder.mDetectedFieldTypes;
+ }
+
+ /** @hide */
+ @TestApi
+ @NonNull
+ public Set<FieldClassification> getDetectedFieldClassifications() {
+ return Set.of(mDetectedFieldTypes);
}
/** @hide */
@@ -312,6 +323,28 @@
private int mServiceDisplayNameResourceId;
private boolean mShowFillDialogIcon = true;
private boolean mShowSaveDialogIcon = true;
+ private FieldClassification[] mDetectedFieldTypes;
+
+ /**
+ * Adds a new {@link FieldClassification} to this response, to
+ * help the platform provide more accurate detection results.
+ *
+ * Call this when a field has been detected with a type.
+ *
+ * Altough similiarly named with {@link setFieldClassificationIds},
+ * it provides a different functionality - setFieldClassificationIds should
+ * be used when a field is only suspected to be Autofillable.
+ * This method should be used when a field is certainly Autofillable
+ * with a certain type.
+ */
+ @NonNull
+ public Builder setDetectedFieldClassifications(
+ @NonNull Set<FieldClassification> fieldInfos) {
+ throwIfDestroyed();
+ throwIfDisableAutofillCalled();
+ mDetectedFieldTypes = fieldInfos.toArray(new FieldClassification[0]);
+ return this;
+ }
/**
* Triggers a custom UI before autofilling the screen with any data set in this
@@ -1122,6 +1155,7 @@
parcel.writeParcelableArray(mIgnoredIds, flags);
parcel.writeLong(mDisableDuration);
parcel.writeParcelableArray(mFieldClassificationIds, flags);
+ parcel.writeParcelableArray(mDetectedFieldTypes, flags);
parcel.writeInt(mIconResourceId);
parcel.writeInt(mServiceDisplayNameResourceId);
parcel.writeBoolean(mShowFillDialogIcon);
@@ -1192,6 +1226,12 @@
builder.setFieldClassificationIds(fieldClassifactionIds);
}
+ final FieldClassification[] detectedFields =
+ parcel.readParcelableArray(null, FieldClassification.class);
+ if (detectedFields != null) {
+ builder.setDetectedFieldClassifications(Set.of(detectedFields));
+ }
+
builder.setIconResourceId(parcel.readInt());
builder.setServiceDisplayNameResourceId(parcel.readInt());
builder.setShowFillDialogIcon(parcel.readBoolean());
diff --git a/core/java/android/service/autofill/SaveInfo.java b/core/java/android/service/autofill/SaveInfo.java
index 5fe1d4f..828e466 100644
--- a/core/java/android/service/autofill/SaveInfo.java
+++ b/core/java/android/service/autofill/SaveInfo.java
@@ -308,7 +308,7 @@
* username field, another for password).
*/
// TODO(b/113281366): improve documentation: add example, document relationship with other
- // flagss, etc...
+ // flags, etc...
public static final int FLAG_DELAY_SAVE = 0x4;
/** @hide */
@@ -777,17 +777,13 @@
/**
* Builds a new {@link SaveInfo} instance.
*
- * @throws IllegalStateException if no
- * {@link #Builder(int, AutofillId[]) required ids},
+ * If no {@link #Builder(int, AutofillId[]) required ids},
* or {@link #setOptionalIds(AutofillId[]) optional ids}, or {@link #FLAG_DELAY_SAVE}
- * were set
+ * were set, Save Dialog will only be triggered if platform detection is enabled, which
+ * is indicated when {@link FillRequest.getHints()} is not empty.
*/
public SaveInfo build() {
throwIfDestroyed();
- Preconditions.checkState(
- !ArrayUtils.isEmpty(mRequiredIds) || !ArrayUtils.isEmpty(mOptionalIds)
- || (mFlags & FLAG_DELAY_SAVE) != 0,
- "must have at least one required or optional id or FLAG_DELAYED_SAVE");
mDestroyed = true;
return new SaveInfo(this);
}
diff --git a/core/java/android/service/credentials/BeginCreateCredentialResponse.java b/core/java/android/service/credentials/BeginCreateCredentialResponse.java
index 8ca3a1a..f0f954d 100644
--- a/core/java/android/service/credentials/BeginCreateCredentialResponse.java
+++ b/core/java/android/service/credentials/BeginCreateCredentialResponse.java
@@ -34,6 +34,14 @@
private final @NonNull List<CreateEntry> mCreateEntries;
private final @Nullable CreateEntry mRemoteCreateEntry;
+ /**
+ * Creates an empty response instance, to be used when there are no {@link CreateEntry}
+ * to return.
+ */
+ public BeginCreateCredentialResponse() {
+ this(/*createEntries=*/new ArrayList<>(), /*remoteCreateEntry=*/null);
+ }
+
private BeginCreateCredentialResponse(@NonNull Parcel in) {
List<CreateEntry> createEntries = new ArrayList<>();
in.readTypedList(createEntries, CreateEntry.CREATOR);
@@ -137,13 +145,8 @@
/**
* Builds a new instance of {@link BeginCreateCredentialResponse}.
- *
- * @throws NullPointerException If {@code createEntries} is null.
- * @throws IllegalArgumentException If {@code createEntries} is empty.
*/
public @NonNull BeginCreateCredentialResponse build() {
- Preconditions.checkCollectionNotEmpty(mCreateEntries, "createEntries must "
- + "not be null, or empty");
return new BeginCreateCredentialResponse(mCreateEntries, mRemoteCreateEntry);
}
}
diff --git a/core/java/android/service/credentials/BeginGetCredentialOption.java b/core/java/android/service/credentials/BeginGetCredentialOption.java
index 1df908a..3d39f65 100644
--- a/core/java/android/service/credentials/BeginGetCredentialOption.java
+++ b/core/java/android/service/credentials/BeginGetCredentialOption.java
@@ -39,6 +39,8 @@
*/
@SuppressLint("ParcelNotFinal")
public class BeginGetCredentialOption implements Parcelable {
+ private static final String BUNDLE_ID_KEY =
+ "android.service.credentials.BeginGetCredentialOption.BUNDLE_ID_KEY";
/**
* A unique id associated with this request option.
*/
@@ -129,6 +131,11 @@
mType = Preconditions.checkStringNotEmpty(type, "type must not be empty");
mCandidateQueryData = requireNonNull(
candidateQueryData, "candidateQueryData must not be null");
+ addIdToBundle();
+ }
+
+ private void addIdToBundle() {
+ mCandidateQueryData.putString(BUNDLE_ID_KEY, mId);
}
private BeginGetCredentialOption(@NonNull Parcel in) {
diff --git a/core/java/android/service/credentials/BeginGetCredentialResponse.java b/core/java/android/service/credentials/BeginGetCredentialResponse.java
index 0f64c63..3652742 100644
--- a/core/java/android/service/credentials/BeginGetCredentialResponse.java
+++ b/core/java/android/service/credentials/BeginGetCredentialResponse.java
@@ -44,6 +44,17 @@
/** Remote credential entry to get the response from a different device. */
private final @Nullable CredentialEntry mRemoteCredentialEntry;
+ /**
+ * Creates an empty response instance, to be used when there are no {@link CredentialEntry},
+ * or {@link Action} to return.
+ */
+ public BeginGetCredentialResponse() {
+ this(/*credentialEntries=*/new ArrayList<>(),
+ /*authenticationActions=*/new ArrayList<>(),
+ /*actions=*/new ArrayList<>(),
+ /*remoteCredentialEntry=*/null);
+ }
+
private BeginGetCredentialResponse(@NonNull List<CredentialEntry> credentialEntries,
@NonNull List<Action> authenticationEntries, @NonNull List<Action> actions,
@Nullable CredentialEntry remoteCredentialEntry) {
@@ -243,16 +254,8 @@
/**
* Builds a {@link BeginGetCredentialResponse} instance.
- *
- * @throws IllegalStateException if {@code credentialEntries}, {@code actions}
- * and {@code remoteCredentialEntry} are all null or empty.
*/
public @NonNull BeginGetCredentialResponse build() {
- if (mCredentialEntries.isEmpty() && mActions.isEmpty()
- && mRemoteCredentialEntry == null && mAuthenticationEntries.isEmpty()) {
- throw new IllegalStateException("must set either an authentication, "
- + "credential, action or remote entry");
- }
return new BeginGetCredentialResponse(mCredentialEntries, mAuthenticationEntries,
mActions, mRemoteCredentialEntry);
}
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index 0d51395..5778518 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -1781,11 +1781,13 @@
* Intent.EXTRA_TIME ("android.intent.extra.TIME") indicating timing
* in milliseconds of the KeyEvent that triggered Assistant and
* Intent.EXTRA_ASSIST_INPUT_DEVICE_ID (android.intent.extra.ASSIST_INPUT_DEVICE_ID)
- * referring to the device that sent the request.
+ * referring to the device that sent the request. Starting from Android 14, the system will
+ * add {@link VoiceInteractionService#KEY_SHOW_SESSION_ID}, the Bundle is not null. But the
+ * application should handle null case before Android 14.
* @param showFlags The show flags originally provided to
* {@link VoiceInteractionService#showSession VoiceInteractionService.showSession}.
*/
- public void onShow(Bundle args, int showFlags) {
+ public void onShow(@Nullable Bundle args, int showFlags) {
}
/**
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 8663013..7da141b 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -479,6 +479,14 @@
private WeakReference<View> mLocalOwnerView;
+ // A throwable with the stack filled when this SurfaceControl is released (only if
+ // sDebugUsageAfterRelease) is enabled
+ private Throwable mReleaseStack = null;
+
+ // Triggers the stack to be saved when any SurfaceControl in this process is released, which can
+ // be dumped as additional context
+ private static volatile boolean sDebugUsageAfterRelease = false;
+
static GlobalTransactionWrapper sGlobalTransaction;
static long sTransactionNestCount = 0;
@@ -751,6 +759,11 @@
}
mNativeObject = nativeObject;
mNativeHandle = mNativeObject != 0 ? nativeGetHandle(nativeObject) : 0;
+ if (sDebugUsageAfterRelease && mNativeObject == 0) {
+ mReleaseStack = new Throwable("Assigned invalid nativeObject");
+ } else {
+ mReleaseStack = null;
+ }
}
/**
@@ -1246,6 +1259,9 @@
@Override
public void writeToParcel(Parcel dest, int flags) {
+ if (sDebugUsageAfterRelease) {
+ checkNotReleased();
+ }
dest.writeString8(mName);
dest.writeInt(mWidth);
dest.writeInt(mHeight);
@@ -1262,6 +1278,18 @@
}
/**
+ * Enables additional debug logs to track usage-after-release of all SurfaceControls in this
+ * process.
+ * @hide
+ */
+ public static void setDebugUsageAfterRelease(boolean debug) {
+ if (!Build.isDebuggable()) {
+ return;
+ }
+ sDebugUsageAfterRelease = debug;
+ }
+
+ /**
* Checks whether two {@link SurfaceControl} objects represent the same surface.
*
* @param other The other object to check
@@ -1382,6 +1410,9 @@
mFreeNativeResources.run();
mNativeObject = 0;
mNativeHandle = 0;
+ if (sDebugUsageAfterRelease) {
+ mReleaseStack = new Throwable("Released");
+ }
mCloseGuard.close();
synchronized (mChoreographerLock) {
if (mChoreographer != null) {
@@ -1403,8 +1434,15 @@
}
private void checkNotReleased() {
- if (mNativeObject == 0) throw new NullPointerException(
- "Invalid " + this + ", mNativeObject is null. Have you called release() already?");
+ if (mNativeObject == 0) {
+ if (mReleaseStack != null) {
+ throw new IllegalStateException("Invalid usage after release of " + this,
+ mReleaseStack);
+ } else {
+ throw new NullPointerException("mNativeObject of " + this
+ + " is null. Have you called release() already?");
+ }
+ }
}
/**
@@ -2738,7 +2776,7 @@
*/
@NonNull
public Transaction setFrameRateSelectionPriority(@NonNull SurfaceControl sc, int priority) {
- sc.checkNotReleased();
+ checkPreconditions(sc);
nativeSetFrameRateSelectionPriority(mNativeObject, sc.mNativeObject, priority);
return this;
}
diff --git a/core/java/android/view/autofill/AutofillFeatureFlags.java b/core/java/android/view/autofill/AutofillFeatureFlags.java
index e7c610b..864ba92 100644
--- a/core/java/android/view/autofill/AutofillFeatureFlags.java
+++ b/core/java/android/view/autofill/AutofillFeatureFlags.java
@@ -82,6 +82,12 @@
"autofill_dialog_enabled";
/**
+ * Indicates that PCC Autofill detection feature is enabled or not.
+ */
+ public static final String DEVICE_CONFIG_AUTOFILL_PCC_FEATURE_PROVIDER_HINTS =
+ "pcc_classification_hints";
+
+ /**
* Sets the autofill hints allowed list for the fields that can trigger the fill dialog
* feature at Activity starting.
*
@@ -178,6 +184,22 @@
public static final String DEVICE_CONFIG_AUTOFILL_PCC_CLASSIFICATION_ENABLED =
"pcc_classification_enabled";
+ /**
+ * Give preference to autofill provider's detection.
+ * @hide
+ */
+ public static final String DEVICE_CONFIG_PREFER_PROVIDER_OVER_PCC = "prefer_provider_over_pcc";
+
+
+ /**
+ * Use data from secondary source if primary not present .
+ * For eg: if we prefer PCC over provider, and PCC detection didn't classify a field, however,
+ * autofill provider did, this flag would decide whether we use that result, and show some
+ * presentation for that particular field.
+ * @hide
+ */
+ public static final String DEVICE_CONFIG_PCC_USE_FALLBACK = "pcc_use_fallback";
+
// END AUTOFILL PCC CLASSIFICATION FLAGS
@@ -190,9 +212,11 @@
"autofill_inline_tooltip_first_show_delay";
private static final String DIALOG_HINTS_DELIMITER = ":";
+ private static final String PCC_HINTS_DELIMITER = ",";
private static final boolean DEFAULT_HAS_FILL_DIALOG_UI_FEATURE = false;
private static final String DEFAULT_FILL_DIALOG_ENABLED_HINTS = "";
+ private static final String DEFAULT_PCC_FEATURE_PROVIDER_HINTS = "";
// CREDENTIAL MANAGER DEFAULTS
@@ -206,7 +230,8 @@
// AUTOFILL PCC CLASSIFICATION FLAGS DEFAULTS
// Default for whether the pcc classification is enabled for autofill.
- private static final boolean DEFAULT_AUTOFILL_PCC_CLASSIFICATION_ENABLED = false;
+ /** @hide */
+ public static final boolean DEFAULT_AUTOFILL_PCC_CLASSIFICATION_ENABLED = false;
// END AUTOFILL PCC CLASSIFICATION FLAGS DEFAULTS
@@ -225,6 +250,25 @@
}
/**
+ * The list of datatypes that is supported by framework
+ * detection.
+ *
+ * @hide
+ */
+ public static String[] getTypeHintsForProvider() {
+ final String typeHints = DeviceConfig.getString(
+ DeviceConfig.NAMESPACE_AUTOFILL,
+ DEVICE_CONFIG_AUTOFILL_PCC_FEATURE_PROVIDER_HINTS,
+ DEFAULT_PCC_FEATURE_PROVIDER_HINTS);
+ if (TextUtils.isEmpty(typeHints)) {
+ return new String[0];
+ }
+
+ return ArrayUtils.filter(typeHints.split(PCC_HINTS_DELIMITER), String[]::new,
+ (str) -> !TextUtils.isEmpty(str));
+ }
+
+ /**
* Gets fill dialog enabled hints.
*
* @hide
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 136846a..3f452f8 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -124,13 +124,11 @@
import android.view.animation.LinearInterpolator;
import android.view.inputmethod.CorrectionInfo;
import android.view.inputmethod.CursorAnchorInfo;
-import android.view.inputmethod.EditorBoundsInfo;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.ExtractedText;
import android.view.inputmethod.ExtractedTextRequest;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
-import android.view.inputmethod.TextAppearanceInfo;
import android.view.textclassifier.TextClassification;
import android.view.textclassifier.TextClassificationManager;
import android.widget.AdapterView.OnItemClickListener;
@@ -4667,7 +4665,7 @@
* {@link InputMethodManager#isWatchingCursor(View)} returns false.
*/
private final class CursorAnchorInfoNotifier implements TextViewPositionListener {
- final CursorAnchorInfo.Builder mSelectionInfoBuilder = new CursorAnchorInfo.Builder();
+ final CursorAnchorInfo.Builder mCursorAnchorInfoBuilder = new CursorAnchorInfo.Builder();
final Matrix mViewToScreenMatrix = new Matrix();
@Override
@@ -4687,165 +4685,21 @@
// Skip if the IME has not requested the cursor/anchor position.
final int knownCursorAnchorInfoModes =
InputConnection.CURSOR_UPDATE_IMMEDIATE | InputConnection.CURSOR_UPDATE_MONITOR;
- if ((mInputMethodState.mUpdateCursorAnchorInfoMode & knownCursorAnchorInfoModes) == 0) {
+ if ((ims.mUpdateCursorAnchorInfoMode & knownCursorAnchorInfoModes) == 0) {
return;
}
- Layout layout = mTextView.getLayout();
- if (layout == null) {
- return;
+
+ final CursorAnchorInfo cursorAnchorInfo =
+ mTextView.getCursorAnchorInfo(ims.mUpdateCursorAnchorInfoFilter,
+ mCursorAnchorInfoBuilder, mViewToScreenMatrix);
+
+ if (cursorAnchorInfo != null) {
+ imm.updateCursorAnchorInfo(mTextView, cursorAnchorInfo);
+
+ // Drop the immediate flag if any.
+ mInputMethodState.mUpdateCursorAnchorInfoMode &=
+ ~InputConnection.CURSOR_UPDATE_IMMEDIATE;
}
- final int filter = mInputMethodState.mUpdateCursorAnchorInfoFilter;
- boolean includeEditorBounds =
- (filter & InputConnection.CURSOR_UPDATE_FILTER_EDITOR_BOUNDS) != 0;
- boolean includeCharacterBounds =
- (filter & InputConnection.CURSOR_UPDATE_FILTER_CHARACTER_BOUNDS) != 0;
- boolean includeInsertionMarker =
- (filter & InputConnection.CURSOR_UPDATE_FILTER_INSERTION_MARKER) != 0;
- boolean includeVisibleLineBounds =
- (filter & InputConnection.CURSOR_UPDATE_FILTER_VISIBLE_LINE_BOUNDS) != 0;
- boolean includeTextAppearance =
- (filter & InputConnection.CURSOR_UPDATE_FILTER_TEXT_APPEARANCE) != 0;
- boolean includeAll =
- (!includeEditorBounds && !includeCharacterBounds && !includeInsertionMarker
- && !includeVisibleLineBounds && !includeTextAppearance);
-
- includeEditorBounds |= includeAll;
- includeCharacterBounds |= includeAll;
- includeInsertionMarker |= includeAll;
- includeVisibleLineBounds |= includeAll;
- includeTextAppearance |= includeAll;
-
- final CursorAnchorInfo.Builder builder = mSelectionInfoBuilder;
- builder.reset();
-
- final int selectionStart = mTextView.getSelectionStart();
- builder.setSelectionRange(selectionStart, mTextView.getSelectionEnd());
-
- // Construct transformation matrix from view local coordinates to screen coordinates.
- mViewToScreenMatrix.reset();
- mTextView.transformMatrixToGlobal(mViewToScreenMatrix);
- builder.setMatrix(mViewToScreenMatrix);
-
- if (includeEditorBounds) {
- final RectF editorBounds = new RectF();
- editorBounds.set(0 /* left */, 0 /* top */,
- mTextView.getWidth(), mTextView.getHeight());
- final RectF handwritingBounds = new RectF(
- -mTextView.getHandwritingBoundsOffsetLeft(),
- -mTextView.getHandwritingBoundsOffsetTop(),
- mTextView.getWidth() + mTextView.getHandwritingBoundsOffsetRight(),
- mTextView.getHeight() + mTextView.getHandwritingBoundsOffsetBottom());
- EditorBoundsInfo.Builder boundsBuilder = new EditorBoundsInfo.Builder();
- EditorBoundsInfo editorBoundsInfo = boundsBuilder.setEditorBounds(editorBounds)
- .setHandwritingBounds(handwritingBounds).build();
- builder.setEditorBoundsInfo(editorBoundsInfo);
- }
-
- if (includeCharacterBounds || includeInsertionMarker || includeVisibleLineBounds) {
- final float viewportToContentHorizontalOffset =
- mTextView.viewportToContentHorizontalOffset();
- final float viewportToContentVerticalOffset =
- mTextView.viewportToContentVerticalOffset();
- final boolean isTextTransformed = (mTextView.getTransformationMethod() != null
- && mTextView.getTransformed() instanceof OffsetMapping);
- if (includeCharacterBounds && !isTextTransformed) {
- final CharSequence text = mTextView.getText();
- if (text instanceof Spannable) {
- final Spannable sp = (Spannable) text;
- int composingTextStart = EditableInputConnection.getComposingSpanStart(sp);
- int composingTextEnd = EditableInputConnection.getComposingSpanEnd(sp);
- if (composingTextEnd < composingTextStart) {
- final int temp = composingTextEnd;
- composingTextEnd = composingTextStart;
- composingTextStart = temp;
- }
- final boolean hasComposingText =
- (0 <= composingTextStart) && (composingTextStart
- < composingTextEnd);
- if (hasComposingText) {
- final CharSequence composingText = text.subSequence(composingTextStart,
- composingTextEnd);
- builder.setComposingText(composingTextStart, composingText);
- mTextView.populateCharacterBounds(builder, composingTextStart,
- composingTextEnd, viewportToContentHorizontalOffset,
- viewportToContentVerticalOffset);
- }
- }
- }
-
- if (includeInsertionMarker) {
- // Treat selectionStart as the insertion point.
- if (0 <= selectionStart) {
- final int offsetTransformed = mTextView.originalToTransformed(
- selectionStart, OffsetMapping.MAP_STRATEGY_CURSOR);
- final int line = layout.getLineForOffset(offsetTransformed);
- final float insertionMarkerX =
- layout.getPrimaryHorizontal(offsetTransformed)
- + viewportToContentHorizontalOffset;
- final float insertionMarkerTop = layout.getLineTop(line)
- + viewportToContentVerticalOffset;
- final float insertionMarkerBaseline = layout.getLineBaseline(line)
- + viewportToContentVerticalOffset;
- final float insertionMarkerBottom =
- layout.getLineBottom(line, /* includeLineSpacing= */ false)
- + viewportToContentVerticalOffset;
- final boolean isTopVisible = mTextView
- .isPositionVisible(insertionMarkerX, insertionMarkerTop);
- final boolean isBottomVisible = mTextView
- .isPositionVisible(insertionMarkerX, insertionMarkerBottom);
- int insertionMarkerFlags = 0;
- if (isTopVisible || isBottomVisible) {
- insertionMarkerFlags |= CursorAnchorInfo.FLAG_HAS_VISIBLE_REGION;
- }
- if (!isTopVisible || !isBottomVisible) {
- insertionMarkerFlags |= CursorAnchorInfo.FLAG_HAS_INVISIBLE_REGION;
- }
- if (layout.isRtlCharAt(offsetTransformed)) {
- insertionMarkerFlags |= CursorAnchorInfo.FLAG_IS_RTL;
- }
- builder.setInsertionMarkerLocation(insertionMarkerX, insertionMarkerTop,
- insertionMarkerBaseline, insertionMarkerBottom,
- insertionMarkerFlags);
- }
- }
-
- if (includeVisibleLineBounds) {
- final Rect visibleRect = new Rect();
- if (mTextView.getContentVisibleRect(visibleRect)) {
- // Subtract the viewportToContentVerticalOffset to convert the view
- // coordinates to layout coordinates.
- final float visibleTop =
- visibleRect.top - viewportToContentVerticalOffset;
- final float visibleBottom =
- visibleRect.bottom - viewportToContentVerticalOffset;
- final int firstLine =
- layout.getLineForVertical((int) Math.floor(visibleTop));
- final int lastLine =
- layout.getLineForVertical((int) Math.ceil(visibleBottom));
-
- for (int line = firstLine; line <= lastLine; ++line) {
- final float left = layout.getLineLeft(line)
- + viewportToContentHorizontalOffset;
- final float top = layout.getLineTop(line)
- + viewportToContentVerticalOffset;
- final float right = layout.getLineRight(line)
- + viewportToContentHorizontalOffset;
- final float bottom = layout.getLineBottom(line, false)
- + viewportToContentVerticalOffset;
- builder.addVisibleLineBounds(left, top, right, bottom);
- }
- }
- }
- }
-
- if (includeTextAppearance) {
- builder.setTextAppearanceInfo(TextAppearanceInfo.createFromTextView(mTextView));
- }
- imm.updateCursorAnchorInfo(mTextView, builder.build());
-
- // Drop the immediate flag if any.
- mInputMethodState.mUpdateCursorAnchorInfoMode &=
- ~InputConnection.CURSOR_UPDATE_IMMEDIATE;
}
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 77df1f1..626df48 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -196,6 +196,7 @@
import android.view.inputmethod.CursorAnchorInfo;
import android.view.inputmethod.DeleteGesture;
import android.view.inputmethod.DeleteRangeGesture;
+import android.view.inputmethod.EditorBoundsInfo;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.ExtractedText;
import android.view.inputmethod.ExtractedTextRequest;
@@ -209,6 +210,7 @@
import android.view.inputmethod.RemoveSpaceGesture;
import android.view.inputmethod.SelectGesture;
import android.view.inputmethod.SelectRangeGesture;
+import android.view.inputmethod.TextAppearanceInfo;
import android.view.inputmethod.TextBoundsInfo;
import android.view.inspector.InspectableProperty;
import android.view.inspector.InspectableProperty.EnumEntry;
@@ -13658,7 +13660,7 @@
* @return true if at least part of the text content is visible; false if the text content is
* completely clipped or translated out of the visible area.
*/
- boolean getContentVisibleRect(Rect rect) {
+ private boolean getContentVisibleRect(Rect rect) {
if (!getLocalVisibleRect(rect)) {
return false;
}
@@ -13744,6 +13746,176 @@
}
/**
+ * Compute {@link CursorAnchorInfo} from this {@link TextView}.
+ *
+ * @param filter the {@link CursorAnchorInfo} update filter which specified the needed
+ * information from IME.
+ * @param cursorAnchorInfoBuilder a cached {@link CursorAnchorInfo.Builder} object used to build
+ * the result {@link CursorAnchorInfo}.
+ * @param viewToScreenMatrix a cached {@link Matrix} object used to compute the view to screen
+ * matrix.
+ * @return the result {@link CursorAnchorInfo} to be passed to IME.
+ * @hide
+ */
+ @VisibleForTesting
+ @Nullable
+ public CursorAnchorInfo getCursorAnchorInfo(@InputConnection.CursorUpdateFilter int filter,
+ @NonNull CursorAnchorInfo.Builder cursorAnchorInfoBuilder,
+ @NonNull Matrix viewToScreenMatrix) {
+ Layout layout = getLayout();
+ if (layout == null) {
+ return null;
+ }
+ boolean includeEditorBounds =
+ (filter & InputConnection.CURSOR_UPDATE_FILTER_EDITOR_BOUNDS) != 0;
+ boolean includeCharacterBounds =
+ (filter & InputConnection.CURSOR_UPDATE_FILTER_CHARACTER_BOUNDS) != 0;
+ boolean includeInsertionMarker =
+ (filter & InputConnection.CURSOR_UPDATE_FILTER_INSERTION_MARKER) != 0;
+ boolean includeVisibleLineBounds =
+ (filter & InputConnection.CURSOR_UPDATE_FILTER_VISIBLE_LINE_BOUNDS) != 0;
+ boolean includeTextAppearance =
+ (filter & InputConnection.CURSOR_UPDATE_FILTER_TEXT_APPEARANCE) != 0;
+ boolean includeAll =
+ (!includeEditorBounds && !includeCharacterBounds && !includeInsertionMarker
+ && !includeVisibleLineBounds && !includeTextAppearance);
+
+ includeEditorBounds |= includeAll;
+ includeCharacterBounds |= includeAll;
+ includeInsertionMarker |= includeAll;
+ includeVisibleLineBounds |= includeAll;
+ includeTextAppearance |= includeAll;
+
+ final CursorAnchorInfo.Builder builder = cursorAnchorInfoBuilder;
+ builder.reset();
+
+ final int selectionStart = getSelectionStart();
+ builder.setSelectionRange(selectionStart, getSelectionEnd());
+
+ // Construct transformation matrix from view local coordinates to screen coordinates.
+ viewToScreenMatrix.reset();
+ transformMatrixToGlobal(viewToScreenMatrix);
+ builder.setMatrix(viewToScreenMatrix);
+
+ if (includeEditorBounds) {
+ final RectF editorBounds = new RectF();
+ editorBounds.set(0 /* left */, 0 /* top */,
+ getWidth(), getHeight());
+ final RectF handwritingBounds = new RectF(
+ -getHandwritingBoundsOffsetLeft(),
+ -getHandwritingBoundsOffsetTop(),
+ getWidth() + getHandwritingBoundsOffsetRight(),
+ getHeight() + getHandwritingBoundsOffsetBottom());
+ EditorBoundsInfo.Builder boundsBuilder = new EditorBoundsInfo.Builder();
+ EditorBoundsInfo editorBoundsInfo = boundsBuilder.setEditorBounds(editorBounds)
+ .setHandwritingBounds(handwritingBounds).build();
+ builder.setEditorBoundsInfo(editorBoundsInfo);
+ }
+
+ if (includeCharacterBounds || includeInsertionMarker || includeVisibleLineBounds) {
+ final float viewportToContentHorizontalOffset =
+ viewportToContentHorizontalOffset();
+ final float viewportToContentVerticalOffset =
+ viewportToContentVerticalOffset();
+ final boolean isTextTransformed = (getTransformationMethod() != null
+ && getTransformed() instanceof OffsetMapping);
+ if (includeCharacterBounds && !isTextTransformed) {
+ final CharSequence text = getText();
+ if (text instanceof Spannable) {
+ final Spannable sp = (Spannable) text;
+ int composingTextStart = EditableInputConnection.getComposingSpanStart(sp);
+ int composingTextEnd = EditableInputConnection.getComposingSpanEnd(sp);
+ if (composingTextEnd < composingTextStart) {
+ final int temp = composingTextEnd;
+ composingTextEnd = composingTextStart;
+ composingTextStart = temp;
+ }
+ final boolean hasComposingText =
+ (0 <= composingTextStart) && (composingTextStart
+ < composingTextEnd);
+ if (hasComposingText) {
+ final CharSequence composingText = text.subSequence(composingTextStart,
+ composingTextEnd);
+ builder.setComposingText(composingTextStart, composingText);
+ populateCharacterBounds(builder, composingTextStart,
+ composingTextEnd, viewportToContentHorizontalOffset,
+ viewportToContentVerticalOffset);
+ }
+ }
+ }
+
+ if (includeInsertionMarker) {
+ // Treat selectionStart as the insertion point.
+ if (0 <= selectionStart) {
+ final int offsetTransformed = originalToTransformed(
+ selectionStart, OffsetMapping.MAP_STRATEGY_CURSOR);
+ final int line = layout.getLineForOffset(offsetTransformed);
+ final float insertionMarkerX =
+ layout.getPrimaryHorizontal(offsetTransformed)
+ + viewportToContentHorizontalOffset;
+ final float insertionMarkerTop = layout.getLineTop(line)
+ + viewportToContentVerticalOffset;
+ final float insertionMarkerBaseline = layout.getLineBaseline(line)
+ + viewportToContentVerticalOffset;
+ final float insertionMarkerBottom =
+ layout.getLineBottom(line, /* includeLineSpacing= */ false)
+ + viewportToContentVerticalOffset;
+ final boolean isTopVisible =
+ isPositionVisible(insertionMarkerX, insertionMarkerTop);
+ final boolean isBottomVisible =
+ isPositionVisible(insertionMarkerX, insertionMarkerBottom);
+ int insertionMarkerFlags = 0;
+ if (isTopVisible || isBottomVisible) {
+ insertionMarkerFlags |= CursorAnchorInfo.FLAG_HAS_VISIBLE_REGION;
+ }
+ if (!isTopVisible || !isBottomVisible) {
+ insertionMarkerFlags |= CursorAnchorInfo.FLAG_HAS_INVISIBLE_REGION;
+ }
+ if (layout.isRtlCharAt(offsetTransformed)) {
+ insertionMarkerFlags |= CursorAnchorInfo.FLAG_IS_RTL;
+ }
+ builder.setInsertionMarkerLocation(insertionMarkerX, insertionMarkerTop,
+ insertionMarkerBaseline, insertionMarkerBottom,
+ insertionMarkerFlags);
+ }
+ }
+
+ if (includeVisibleLineBounds) {
+ final Rect visibleRect = new Rect();
+ if (getContentVisibleRect(visibleRect)) {
+ // Subtract the viewportToContentVerticalOffset to convert the view
+ // coordinates to layout coordinates.
+ final float visibleTop =
+ visibleRect.top - viewportToContentVerticalOffset;
+ final float visibleBottom =
+ visibleRect.bottom - viewportToContentVerticalOffset;
+ final int firstLine =
+ layout.getLineForVertical((int) Math.floor(visibleTop));
+ final int lastLine =
+ layout.getLineForVertical((int) Math.ceil(visibleBottom));
+
+ for (int line = firstLine; line <= lastLine; ++line) {
+ final float left = layout.getLineLeft(line)
+ + viewportToContentHorizontalOffset;
+ final float top = layout.getLineTop(line)
+ + viewportToContentVerticalOffset;
+ final float right = layout.getLineRight(line)
+ + viewportToContentHorizontalOffset;
+ final float bottom = layout.getLineBottom(line, false)
+ + viewportToContentVerticalOffset;
+ builder.addVisibleLineBounds(left, top, right, bottom);
+ }
+ }
+ }
+ }
+
+ if (includeTextAppearance) {
+ builder.setTextAppearanceInfo(TextAppearanceInfo.createFromTextView(this));
+ }
+ return builder.build();
+ }
+
+ /**
* Creates the {@link TextBoundsInfo} for the text lines that intersects with the {@code rectF}.
* @hide
*/
diff --git a/core/proto/android/server/syncstorageengine.proto b/core/proto/android/server/syncstorageengine.proto
index 2f35a07..7fa01d8 100644
--- a/core/proto/android/server/syncstorageengine.proto
+++ b/core/proto/android/server/syncstorageengine.proto
@@ -85,4 +85,5 @@
repeated StatusInfo status = 1;
optional bool is_job_namespace_migrated = 2;
+ optional bool is_job_attribution_fixed = 3;
}
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index a1de6bb..a1e18a7 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4375,6 +4375,18 @@
-->
<string name="config_defaultCredentialManagerHybridService" translatable="false"></string>
+ <!-- The component name, flattened to a string, for the system's credential manager
+ provider service. This service allows credential retrieval and storage od credentials.
+
+ This service must be trusted, as it can be activated without explicit consent of the user.
+ If no service with the specified name exists on the device, there will be no user configurable
+ provider to service credential manager requests. However, credential manager system
+ services that do not require user consent, will still work.
+
+ See android.credentials.CredentialManager
+ -->
+ <string name="config_defaultCredentialProviderService" translatable="false"></string>
+
<!-- The package name for the system's smartspace service.
This service returns smartspace results.
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index f237ece..5ccc248 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3729,6 +3729,7 @@
<java-symbol type="string" name="config_defaultAppPredictionService" />
<java-symbol type="string" name="config_defaultContentSuggestionsService" />
<java-symbol type="string" name="config_defaultCredentialManagerHybridService" />
+ <java-symbol type="string" name="config_defaultCredentialProviderService" />
<java-symbol type="string" name="config_defaultSearchUiService" />
<java-symbol type="string" name="config_defaultSmartspaceService" />
<java-symbol type="string" name="config_defaultWallpaperEffectsGenerationService" />
diff --git a/core/tests/coretests/src/android/widget/EditTextCursorAnchorInfoTest.java b/core/tests/coretests/src/android/widget/EditTextCursorAnchorInfoTest.java
new file mode 100644
index 0000000..1a01987
--- /dev/null
+++ b/core/tests/coretests/src/android/widget/EditTextCursorAnchorInfoTest.java
@@ -0,0 +1,576 @@
+/*
+ * Copyright (C) 2023 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.widget;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.graphics.Matrix;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.Typeface;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.ShapeDrawable;
+import android.util.TypedValue;
+import android.view.Gravity;
+import android.view.View;
+import android.view.inputmethod.CursorAnchorInfo;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.rule.ActivityTestRule;
+
+import com.google.common.collect.ImmutableList;
+
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+public class EditTextCursorAnchorInfoTest {
+ private static final CursorAnchorInfo.Builder sCursorAnchorInfoBuilder =
+ new CursorAnchorInfo.Builder();
+ private static final Matrix sMatrix = new Matrix();
+ private static final int[] sLocationOnScreen = new int[2];
+ private static Typeface sTypeface;
+ private static final float TEXT_SIZE = 1f;
+ // The line height of the test font font is 1.2 * textSize.
+ private static final int LINE_HEIGHT = 12;
+ private static final CharSequence DEFAULT_TEXT = "X\nXX\nXXX\nXXXX\nXXXXX";
+ private static final ImmutableList<RectF> DEFAULT_LINE_BOUNDS = ImmutableList.of(
+ new RectF(0f, 0f, 10f, LINE_HEIGHT),
+ new RectF(0f, LINE_HEIGHT, 20f, 2 * LINE_HEIGHT),
+ new RectF(0f, 2 * LINE_HEIGHT, 30f, 3 * LINE_HEIGHT),
+ new RectF(0f, 3 * LINE_HEIGHT, 40f, 4 * LINE_HEIGHT),
+ new RectF(0f, 4 * LINE_HEIGHT, 50f, 5 * LINE_HEIGHT));
+
+ @Rule
+ public ActivityTestRule<TextViewActivity> mActivityRule = new ActivityTestRule<>(
+ TextViewActivity.class);
+ private Activity mActivity;
+ private TextView mEditText;
+
+ @BeforeClass
+ public static void setupClass() {
+ Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+
+ // The test font has following coverage and width.
+ // U+0020: 10em
+ // U+002E (.): 10em
+ // U+0043 (C): 100em
+ // U+0049 (I): 1em
+ // U+004C (L): 50em
+ // U+0056 (V): 5em
+ // U+0058 (X): 10em
+ // U+005F (_): 0em
+ // U+05D0 : 1em // HEBREW LETTER ALEF
+ // U+05D1 : 5em // HEBREW LETTER BET
+ // U+FFFD (invalid surrogate will be replaced to this): 7em
+ // U+10331 (\uD800\uDF31): 10em
+ // Undefined : 0.5em
+ sTypeface = Typeface.createFromAsset(instrumentation.getTargetContext().getAssets(),
+ "fonts/StaticLayoutLineBreakingTestFont.ttf");
+ }
+
+ @Before
+ public void setup() {
+ mActivity = mActivityRule.getActivity();
+ }
+
+ @Test
+ public void testMatrix() {
+ setupEditText("", /* height= */ 100);
+ CursorAnchorInfo cursorAnchorInfo =
+ mEditText.getCursorAnchorInfo(0, sCursorAnchorInfoBuilder, sMatrix);
+
+ Matrix actualMatrix = cursorAnchorInfo.getMatrix();
+ Matrix expectedMatrix = new Matrix();
+ expectedMatrix.setTranslate(sLocationOnScreen[0], sLocationOnScreen[1]);
+
+ assertThat(actualMatrix).isEqualTo(expectedMatrix);
+ }
+
+ @Test
+ public void testMatrix_withTranslation() {
+ float translationX = 10f;
+ float translationY = 20f;
+ createEditText("");
+ mEditText.setTranslationX(translationX);
+ mEditText.setTranslationY(translationY);
+ measureEditText(100);
+
+ CursorAnchorInfo cursorAnchorInfo =
+ mEditText.getCursorAnchorInfo(0, sCursorAnchorInfoBuilder, sMatrix);
+
+ Matrix actualMatrix = cursorAnchorInfo.getMatrix();
+ Matrix expectedMatrix = new Matrix();
+ expectedMatrix.setTranslate(sLocationOnScreen[0] + translationX,
+ sLocationOnScreen[1] + translationY);
+
+ assertThat(actualMatrix).isEqualTo(expectedMatrix);
+ }
+
+ @Test
+ public void testVisibleLineBounds_allVisible() {
+ setupEditText(DEFAULT_TEXT, /* height= */ 100);
+ CursorAnchorInfo cursorAnchorInfo =
+ mEditText.getCursorAnchorInfo(0, sCursorAnchorInfoBuilder, sMatrix);
+
+ List<RectF> lineBounds = cursorAnchorInfo.getVisibleLineBounds();
+
+ assertThat(lineBounds).isEqualTo(DEFAULT_LINE_BOUNDS);
+ }
+
+ @Test
+ public void testVisibleLineBounds_allVisible_withLineSpacing() {
+ float lineSpacing = 10f;
+ setupEditText("X\nXX\nXXX", /* height= */ 100, lineSpacing,
+ /* lineMultiplier=*/ 1f);
+ CursorAnchorInfo cursorAnchorInfo =
+ mEditText.getCursorAnchorInfo(0, sCursorAnchorInfoBuilder, sMatrix);
+
+ List<RectF> lineBounds = cursorAnchorInfo.getVisibleLineBounds();
+
+ assertThat(lineBounds.size()).isEqualTo(3);
+ assertThat(lineBounds.get(0)).isEqualTo(new RectF(0f, 0f, 10f, LINE_HEIGHT));
+
+ float line1Top = LINE_HEIGHT + lineSpacing;
+ float line1Bottom = line1Top + LINE_HEIGHT;
+ assertThat(lineBounds.get(1)).isEqualTo(new RectF(0f, line1Top, 20f, line1Bottom));
+
+ float line2Top = 2 * (LINE_HEIGHT + lineSpacing);
+ float line2Bottom = line2Top + LINE_HEIGHT;
+ assertThat(lineBounds.get(2)).isEqualTo(new RectF(0f, line2Top, 30f, line2Bottom));
+ }
+
+ @Test
+ public void testVisibleLineBounds_allVisible_withLineMultiplier() {
+ float lineMultiplier = 2f;
+ setupEditText("X\nXX\nXXX", /* height= */ 100, /* lineSpacing= */ 0f,
+ /* lineMultiplier=*/ lineMultiplier);
+ CursorAnchorInfo cursorAnchorInfo =
+ mEditText.getCursorAnchorInfo(0, sCursorAnchorInfoBuilder, sMatrix);
+
+ List<RectF> lineBounds = cursorAnchorInfo.getVisibleLineBounds();
+
+ assertThat(lineBounds.size()).isEqualTo(3);
+ assertThat(lineBounds.get(0)).isEqualTo(new RectF(0f, 0f, 10f, LINE_HEIGHT));
+
+ float line1Top = LINE_HEIGHT * lineMultiplier;
+ float line1Bottom = line1Top + LINE_HEIGHT;
+ assertThat(lineBounds.get(1)).isEqualTo(new RectF(0f, line1Top, 20f, line1Bottom));
+
+ float line2Top = 2 * LINE_HEIGHT * lineMultiplier;
+ float line2Bottom = line2Top + LINE_HEIGHT;
+ assertThat(lineBounds.get(2)).isEqualTo(new RectF(0f, line2Top, 30f, line2Bottom));
+ }
+
+ @Test
+ public void testVisibleLineBounds_cutBottomLines() {
+ // Line top is inclusive and line bottom is exclusive. And if the visible area's
+ // bottom equals to the line top, this line is still visible. So the line height is
+ // 3 * LINE_HEIGHT - 1 to avoid including the line 3.
+ setupEditText(DEFAULT_TEXT, /* height= */ 3 * LINE_HEIGHT - 1);
+ CursorAnchorInfo cursorAnchorInfo =
+ mEditText.getCursorAnchorInfo(0, sCursorAnchorInfoBuilder, sMatrix);
+
+ List<RectF> lineBounds = cursorAnchorInfo.getVisibleLineBounds();
+
+ assertThat(lineBounds).isEqualTo(DEFAULT_LINE_BOUNDS.subList(0, 3));
+ }
+
+ @Test
+ public void testVisibleLineBounds_scrolled_cutTopLines() {
+ // First 2 lines are cut.
+ int scrollY = 2 * LINE_HEIGHT;
+ setupEditText(/* height= */ 3 * LINE_HEIGHT,
+ /* scrollY= */ scrollY);
+ CursorAnchorInfo cursorAnchorInfo =
+ mEditText.getCursorAnchorInfo(0, sCursorAnchorInfoBuilder, sMatrix);
+
+ List<RectF> lineBounds = cursorAnchorInfo.getVisibleLineBounds();
+
+ List<RectF> expectedLineBounds = subList(DEFAULT_LINE_BOUNDS, 2, 5);
+ expectedLineBounds.forEach(rectF -> rectF.offset(0, -scrollY));
+
+ assertThat(lineBounds).isEqualTo(expectedLineBounds);
+ }
+
+ @Test
+ public void testVisibleLineBounds_scrolled_cutTopAndBottomLines() {
+ // Line top is inclusive and line bottom is exclusive. And if the visible area's
+ // bottom equals to the line top, this line is still visible. So the line height is
+ // 2 * LINE_HEIGHT - 1 which only shows 2 lines.
+ int scrollY = 2 * LINE_HEIGHT;
+ setupEditText(/* height= */ 2 * LINE_HEIGHT - 1,
+ /* scrollY= */ scrollY);
+ CursorAnchorInfo cursorAnchorInfo =
+ mEditText.getCursorAnchorInfo(0, sCursorAnchorInfoBuilder, sMatrix);
+
+ List<RectF> lineBounds = cursorAnchorInfo.getVisibleLineBounds();
+
+ List<RectF> expectedLineBounds = subList(DEFAULT_LINE_BOUNDS, 2, 4);
+ expectedLineBounds.forEach(rectF -> rectF.offset(0, -scrollY));
+
+ assertThat(lineBounds).isEqualTo(expectedLineBounds);
+ }
+
+ @Test
+ public void testVisibleLineBounds_scrolled_partiallyVisibleLines() {
+ // The first 2 lines are completely cut, line 2 and 3 are partially visible.
+ int scrollY = 2 * LINE_HEIGHT + LINE_HEIGHT / 2;
+ setupEditText(/* height= */ LINE_HEIGHT,
+ /* scrollY= */ scrollY);
+ CursorAnchorInfo cursorAnchorInfo =
+ mEditText.getCursorAnchorInfo(0, sCursorAnchorInfoBuilder, sMatrix);
+
+ List<RectF> lineBounds = cursorAnchorInfo.getVisibleLineBounds();
+
+ List<RectF> expectedLineBounds = subList(DEFAULT_LINE_BOUNDS, 2, 4);
+ expectedLineBounds.forEach(rectF -> rectF.offset(0f, -scrollY));
+
+ assertThat(lineBounds).isEqualTo(expectedLineBounds);
+ }
+
+ @Test
+ public void testVisibleLineBounds_withCompoundDrawable_allVisible() {
+ int topDrawableHeight = LINE_HEIGHT;
+ Drawable topDrawable = createDrawable(topDrawableHeight);
+ Drawable bottomDrawable = createDrawable(2 * LINE_HEIGHT);
+ setupEditText(/* height= */ 100,
+ /* scrollY= */ 0, topDrawable, bottomDrawable);
+ CursorAnchorInfo cursorAnchorInfo =
+ mEditText.getCursorAnchorInfo(0, sCursorAnchorInfoBuilder, sMatrix);
+
+ List<RectF> lineBounds = cursorAnchorInfo.getVisibleLineBounds();
+
+ List<RectF> expectedLineBounds = copy(DEFAULT_LINE_BOUNDS);
+ expectedLineBounds.forEach(rectF -> rectF.offset(0f, topDrawableHeight));
+
+ assertThat(lineBounds).isEqualTo(expectedLineBounds);
+ }
+
+ @Test
+ public void testVisibleLineBounds_withCompoundDrawable_cutBottomLines() {
+ // The view's totally height is 5 * LINE_HEIGHT, and drawables take 3 * LINE_HEIGHT.
+ // Only first 2 lines are visible.
+ int topDrawableHeight = LINE_HEIGHT;
+ Drawable topDrawable = createDrawable(topDrawableHeight);
+ Drawable bottomDrawable = createDrawable(2 * LINE_HEIGHT + 1);
+ setupEditText(/* height= */ 5 * LINE_HEIGHT,
+ /* scrollY= */ 0, topDrawable, bottomDrawable);
+ CursorAnchorInfo cursorAnchorInfo =
+ mEditText.getCursorAnchorInfo(0, sCursorAnchorInfoBuilder, sMatrix);
+
+ List<RectF> lineBounds = cursorAnchorInfo.getVisibleLineBounds();
+
+ List<RectF> expectedLineBounds = subList(DEFAULT_LINE_BOUNDS, 0, 2);
+ expectedLineBounds.forEach(rectF -> rectF.offset(0f, topDrawableHeight));
+
+ assertThat(lineBounds).isEqualTo(expectedLineBounds);
+ }
+
+ @Test
+ public void testVisibleLineBounds_withCompoundDrawable_scrolled() {
+ // The view's totally height is 5 * LINE_HEIGHT, and drawables take 3 * LINE_HEIGHT.
+ // So 2 lines are visible. Because the view is scrolled vertically by LINE_HEIGHT,
+ // the line 1 and 2 are visible.
+ int topDrawableHeight = LINE_HEIGHT;
+ Drawable topDrawable = createDrawable(topDrawableHeight);
+ Drawable bottomDrawable = createDrawable(2 * LINE_HEIGHT + 1);
+ int scrollY = LINE_HEIGHT;
+ setupEditText(/* height= */ 5 * LINE_HEIGHT, scrollY,
+ topDrawable, bottomDrawable);
+ CursorAnchorInfo cursorAnchorInfo =
+ mEditText.getCursorAnchorInfo(0, sCursorAnchorInfoBuilder, sMatrix);
+
+ List<RectF> lineBounds = cursorAnchorInfo.getVisibleLineBounds();
+
+ List<RectF> expectedLineBounds = subList(DEFAULT_LINE_BOUNDS, 1, 3);
+ expectedLineBounds.forEach(rectF -> rectF.offset(0f, topDrawableHeight - scrollY));
+
+ assertThat(lineBounds).isEqualTo(expectedLineBounds);
+ }
+
+ @Test
+ public void testVisibleLineBounds_withCompoundDrawable_partiallyVisible() {
+ // The view's totally height is 5 * LINE_HEIGHT, and drawables take 3 * LINE_HEIGHT.
+ // And because the view is scrolled vertically by 0.5 * LINE_HEIGHT,
+ // the line 0, 1 and 2 are visible.
+ int topDrawableHeight = LINE_HEIGHT;
+ Drawable topDrawable = createDrawable(topDrawableHeight);
+ Drawable bottomDrawable = createDrawable(2 * LINE_HEIGHT + 1);
+ int scrollY = LINE_HEIGHT / 2;
+ setupEditText(/* height= */ 5 * LINE_HEIGHT, scrollY,
+ topDrawable, bottomDrawable);
+ CursorAnchorInfo cursorAnchorInfo =
+ mEditText.getCursorAnchorInfo(0, sCursorAnchorInfoBuilder, sMatrix);
+
+ List<RectF> lineBounds = cursorAnchorInfo.getVisibleLineBounds();
+
+ List<RectF> expectedLineBounds = subList(DEFAULT_LINE_BOUNDS, 0, 3);
+ expectedLineBounds.forEach(rectF -> rectF.offset(0f, topDrawableHeight - scrollY));
+
+ assertThat(lineBounds).isEqualTo(expectedLineBounds);
+ }
+
+ @Test
+ public void testVisibleLineBounds_withPaddings_allVisible() {
+ int topPadding = LINE_HEIGHT;
+ int bottomPadding = LINE_HEIGHT;
+ setupEditText(/* height= */ 100, /* scrollY= */ 0, topPadding, bottomPadding);
+ CursorAnchorInfo cursorAnchorInfo =
+ mEditText.getCursorAnchorInfo(0, sCursorAnchorInfoBuilder, sMatrix);
+
+ List<RectF> lineBounds = cursorAnchorInfo.getVisibleLineBounds();
+
+ List<RectF> expectedLineBounds = copy(DEFAULT_LINE_BOUNDS);
+ expectedLineBounds.forEach(rectF -> rectF.offset(0f, topPadding));
+
+ assertThat(lineBounds).isEqualTo(expectedLineBounds);
+ }
+
+ @Test
+ public void testVisibleLineBounds_withPaddings_cutBottomLines() {
+ // The view's totally height is 5 * LINE_HEIGHT, and paddings take 3 * LINE_HEIGHT.
+ // So 2 lines are visible.
+ int topPadding = LINE_HEIGHT;
+ int bottomPadding = 2 * LINE_HEIGHT + 1;
+ setupEditText(/* height= */ 5 * LINE_HEIGHT, /* scrollY= */ 0, topPadding, bottomPadding);
+ CursorAnchorInfo cursorAnchorInfo =
+ mEditText.getCursorAnchorInfo(0, sCursorAnchorInfoBuilder, sMatrix);
+
+ List<RectF> lineBounds = cursorAnchorInfo.getVisibleLineBounds();
+
+ List<RectF> expectedLineBounds = subList(DEFAULT_LINE_BOUNDS, 0, 2);
+ expectedLineBounds.forEach(rectF -> rectF.offset(0f, topPadding));
+
+ assertThat(lineBounds).isEqualTo(expectedLineBounds);
+ }
+
+ @Test
+ public void testVisibleLineBounds_withPaddings_scrolled() {
+ // The view's totally height is 5 * LINE_HEIGHT, and paddings take 3 * LINE_HEIGHT.
+ // So 2 lines are visible. Because the view is scrolled vertically by LINE_HEIGHT,
+ // the line 1 and 2 are visible.
+ int topPadding = LINE_HEIGHT;
+ int bottomPadding = 2 * LINE_HEIGHT + 1;
+ int scrollY = LINE_HEIGHT;
+ setupEditText(/* height= */ 5 * LINE_HEIGHT, scrollY,
+ topPadding, bottomPadding);
+ CursorAnchorInfo cursorAnchorInfo =
+ mEditText.getCursorAnchorInfo(0, sCursorAnchorInfoBuilder, sMatrix);
+
+ List<RectF> lineBounds = cursorAnchorInfo.getVisibleLineBounds();
+
+ List<RectF> expectedLineBounds = subList(DEFAULT_LINE_BOUNDS, 1, 3);
+ expectedLineBounds.forEach(rectF -> rectF.offset(0f, topPadding - scrollY));
+
+ assertThat(lineBounds).isEqualTo(expectedLineBounds);
+ }
+
+ @Test
+ public void testVisibleLineBounds_withPadding_partiallyVisible() {
+ // The view's totally height is 5 * LINE_HEIGHT, and paddings take 3 * LINE_HEIGHT.
+ // And because the view is scrolled vertically by 0.5 * LINE_HEIGHT, the line 0, 1 and 2
+ // are visible.
+ int topPadding = LINE_HEIGHT;
+ int bottomPadding = 2 * LINE_HEIGHT + 1;
+ int scrollY = LINE_HEIGHT / 2;
+ setupEditText(/* height= */ 5 * LINE_HEIGHT, scrollY,
+ topPadding, bottomPadding);
+ CursorAnchorInfo cursorAnchorInfo =
+ mEditText.getCursorAnchorInfo(0, sCursorAnchorInfoBuilder, sMatrix);
+
+ List<RectF> lineBounds = cursorAnchorInfo.getVisibleLineBounds();
+
+ List<RectF> expectedLineBounds = subList(DEFAULT_LINE_BOUNDS, 0, 3);
+ expectedLineBounds.forEach(rectF -> rectF.offset(0f, topPadding - scrollY));
+
+ assertThat(lineBounds).isEqualTo(expectedLineBounds);
+ }
+
+ @Test
+ public void testVisibleLineBounds_clippedTop() {
+ // The first line is clipped off.
+ setupVerticalClippedEditText(LINE_HEIGHT, 5 * LINE_HEIGHT);
+ CursorAnchorInfo cursorAnchorInfo =
+ mEditText.getCursorAnchorInfo(0, sCursorAnchorInfoBuilder, sMatrix);
+
+ List<RectF> lineBounds = cursorAnchorInfo.getVisibleLineBounds();
+
+ List<RectF> expectedLineBounds = subList(DEFAULT_LINE_BOUNDS, 1, 5);
+ assertThat(lineBounds).isEqualTo(expectedLineBounds);
+ }
+
+ @Test
+ public void testVisibleLineBounds_clippedBottom() {
+ // The last line is clipped off.
+ setupVerticalClippedEditText(0, 4 * LINE_HEIGHT - 1);
+ CursorAnchorInfo cursorAnchorInfo =
+ mEditText.getCursorAnchorInfo(0, sCursorAnchorInfoBuilder, sMatrix);
+
+ List<RectF> lineBounds = cursorAnchorInfo.getVisibleLineBounds();
+
+ List<RectF> expectedLineBounds = subList(DEFAULT_LINE_BOUNDS, 0, 4);
+ assertThat(lineBounds).isEqualTo(expectedLineBounds);
+ }
+
+ @Test
+ public void testVisibleLineBounds_clippedTopAndBottom() {
+ // The first and last line are clipped off.
+ setupVerticalClippedEditText(LINE_HEIGHT, 4 * LINE_HEIGHT - 1);
+ CursorAnchorInfo cursorAnchorInfo =
+ mEditText.getCursorAnchorInfo(0, sCursorAnchorInfoBuilder, sMatrix);
+
+ List<RectF> lineBounds = cursorAnchorInfo.getVisibleLineBounds();
+
+ List<RectF> expectedLineBounds = subList(DEFAULT_LINE_BOUNDS, 1, 4);
+ assertThat(lineBounds).isEqualTo(expectedLineBounds);
+ }
+
+ private List<RectF> copy(List<RectF> rectFList) {
+ List<RectF> result = new ArrayList<>();
+ for (RectF rectF : rectFList) {
+ result.add(new RectF(rectF));
+ }
+ return result;
+ }
+ private List<RectF> subList(List<RectF> rectFList, int start, int end) {
+ List<RectF> result = new ArrayList<>();
+ for (int index = start; index < end; ++index) {
+ result.add(new RectF(rectFList.get(index)));
+ }
+ return result;
+ }
+
+ private void setupVerticalClippedEditText(int visibleTop, int visibleBottom) {
+ ScrollView scrollView = new ScrollView(mActivity);
+ mEditText = new EditText(mActivity);
+ mEditText.setTypeface(sTypeface);
+ mEditText.setText(DEFAULT_TEXT);
+ mEditText.setTextSize(TypedValue.COMPLEX_UNIT_PX, TEXT_SIZE);
+
+ mEditText.setPadding(0, 0, 0, 0);
+ mEditText.setCompoundDrawables(null, null, null, null);
+ mEditText.setCompoundDrawablePadding(0);
+
+ mEditText.scrollTo(0, 0);
+ mEditText.setLineSpacing(0f, 1f);
+
+ // Place the text layout top to the view's top.
+ mEditText.setGravity(Gravity.TOP);
+ int width = 1000;
+ int height = visibleBottom - visibleTop;
+
+ scrollView.addView(mEditText, new FrameLayout.LayoutParams(
+ View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
+ View.MeasureSpec.makeMeasureSpec(5 * LINE_HEIGHT, View.MeasureSpec.EXACTLY)));
+ scrollView.measure(
+ View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
+ View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY));
+ scrollView.layout(0, 0, width, height);
+
+ scrollView.scrollTo(0, visibleTop);
+ }
+
+ private void setupEditText(CharSequence text, int height) {
+ createEditText(text);
+ measureEditText(height);
+ }
+
+ private void setupEditText(CharSequence text, int height, float lineSpacing,
+ float lineMultiplier) {
+ createEditText(text);
+ mEditText.setLineSpacing(lineSpacing, lineMultiplier);
+ measureEditText(height);
+ }
+
+ private void setupEditText(int height, int scrollY) {
+ createEditText();
+ mEditText.scrollTo(0, scrollY);
+ measureEditText(height);
+ }
+
+ private void setupEditText(int height, int scrollY, Drawable drawableTop,
+ Drawable drawableBottom) {
+ createEditText();
+ mEditText.scrollTo(0, scrollY);
+ mEditText.setCompoundDrawables(null, drawableTop, null, drawableBottom);
+ measureEditText(height);
+ }
+
+ private void setupEditText(int height, int scrollY, int paddingTop,
+ int paddingBottom) {
+ createEditText();
+ mEditText.scrollTo(0, scrollY);
+ mEditText.setPadding(0, paddingTop, 0, paddingBottom);
+ measureEditText(height);
+ }
+
+ private void createEditText() {
+ createEditText(DEFAULT_TEXT);
+ }
+
+ private void createEditText(CharSequence text) {
+ mEditText = new EditText(mActivity);
+ mEditText.setTypeface(sTypeface);
+ mEditText.setText(text);
+ mEditText.setTextSize(TypedValue.COMPLEX_UNIT_PX, TEXT_SIZE);
+
+ mEditText.setPadding(0, 0, 0, 0);
+ mEditText.setCompoundDrawables(null, null, null, null);
+ mEditText.setCompoundDrawablePadding(0);
+
+ mEditText.scrollTo(0, 0);
+ mEditText.setLineSpacing(0f, 1f);
+
+ // Place the text layout top to the view's top.
+ mEditText.setGravity(Gravity.TOP);
+ }
+
+ private void measureEditText(int height) {
+ // width equals to 1000 is enough to avoid line break for all test cases.
+ measureEditText(1000, height);
+ }
+
+ private void measureEditText(int width, int height) {
+ mEditText.measure(
+ View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
+ View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY));
+ mEditText.layout(0, 0, width, height);
+
+ mEditText.getLocationOnScreen(sLocationOnScreen);
+ }
+
+ private Drawable createDrawable(int height) {
+ // width is not important for this drawable, make it 1 pixel.
+ return createDrawable(1, height);
+ }
+
+ private Drawable createDrawable(int width, int height) {
+ ShapeDrawable drawable = new ShapeDrawable();
+ drawable.setBounds(new Rect(0, 0, width, height));
+ return drawable;
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ProtoLogController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ProtoLogController.java
index d276002..88525aa 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ProtoLogController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ProtoLogController.java
@@ -84,6 +84,15 @@
String[] groups = Arrays.copyOfRange(args, 1, args.length);
return mShellProtoLog.stopTextLogging(groups, pw) == 0;
}
+ case "save-for-bugreport": {
+ if (!mShellProtoLog.isProtoEnabled()) {
+ pw.println("Logging to proto is not enabled for WMShell.");
+ return false;
+ }
+ mShellProtoLog.stopProtoLog(pw, true /* writeToFile */);
+ mShellProtoLog.startProtoLog(pw);
+ return true;
+ }
default: {
pw.println("Invalid command: " + args[0]);
printShellCommandHelp(pw, "");
@@ -108,5 +117,7 @@
pw.println(prefix + " Enable logcat logging for given groups.");
pw.println(prefix + "disable-text [group...]");
pw.println(prefix + " Disable logcat logging for given groups.");
+ pw.println(prefix + "save-for-bugreport");
+ pw.println(prefix + " Flush proto logging to file, only if it's enabled.");
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index b2f61c2..5275e90 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -829,7 +829,15 @@
}
mOrganizer.startTransition(transitionToken, wct != null && wct.isEmpty() ? null : wct);
active.mToken = transitionToken;
- mActiveTransitions.add(active);
+ int insertIdx = 0;
+ for (; insertIdx < mActiveTransitions.size(); ++insertIdx) {
+ if (mActiveTransitions.get(insertIdx).mInfo == null) {
+ // A `startNewTransition` was sent to WMCore, but wasn't acknowledged before WMCore
+ // made this request, so insert this request beforehand to keep order in sync.
+ break;
+ }
+ }
+ mActiveTransitions.add(insertIdx, active);
}
/** Start a new transition directly. */
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
index 595c3b4..a9061ae 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
@@ -45,6 +45,7 @@
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.clearInvocations;
@@ -119,8 +120,8 @@
@Before
public void setUp() {
- doAnswer(invocation -> invocation.getArguments()[1])
- .when(mOrganizer).startTransition(any(), any());
+ doAnswer(invocation -> new Binder())
+ .when(mOrganizer).startNewTransition(anyInt(), any());
}
@Test
@@ -562,6 +563,32 @@
}
@Test
+ public void testTransitionOrderMatchesCore() {
+ Transitions transitions = createTestTransitions();
+ transitions.replaceDefaultHandlerForTest(mDefaultHandler);
+
+ IBinder transitToken = new Binder();
+ IBinder shellInit = transitions.startTransition(TRANSIT_CLOSE,
+ new WindowContainerTransaction(), null /* handler */);
+ // make sure we are testing the "New" API.
+ verify(mOrganizer, times(1)).startNewTransition(eq(TRANSIT_CLOSE), any());
+ // WMCore may not receive the new transition before requesting its own.
+ transitions.requestStartTransition(transitToken,
+ new TransitionRequestInfo(TRANSIT_OPEN, null /* trigger */, null /* remote */));
+ verify(mOrganizer, times(1)).startTransition(eq(transitToken), any());
+
+ // At this point, WM is working on its transition (the shell-initialized one is still
+ // queued), so continue the transition lifecycle for that.
+ TransitionInfo info = new TransitionInfoBuilder(TRANSIT_OPEN)
+ .addChange(TRANSIT_OPEN).addChange(TRANSIT_CLOSE).build();
+ transitions.onTransitionReady(transitToken, info, mock(SurfaceControl.Transaction.class),
+ mock(SurfaceControl.Transaction.class));
+ // At this point, if things are not working, we'd get an NPE due to attempting to merge
+ // into the shellInit transition which hasn't started yet.
+ assertEquals(1, mDefaultHandler.activeCount());
+ }
+
+ @Test
public void testShouldRotateSeamlessly() throws Exception {
final RunningTaskInfo taskInfo =
createTaskInfo(1, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
diff --git a/packages/CredentialManager/res/drawable/ic_passkeys_onboarding.png b/packages/CredentialManager/res/drawable/ic_passkeys_onboarding.png
deleted file mode 100644
index 388d098..0000000
--- a/packages/CredentialManager/res/drawable/ic_passkeys_onboarding.png
+++ /dev/null
Binary files differ
diff --git a/packages/CredentialManager/res/drawable/ic_passkeys_onboarding.xml b/packages/CredentialManager/res/drawable/ic_passkeys_onboarding.xml
new file mode 100644
index 0000000..91b23cc
--- /dev/null
+++ b/packages/CredentialManager/res/drawable/ic_passkeys_onboarding.xml
@@ -0,0 +1,158 @@
+<!--
+ ~ Copyright (C) 2023 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.
+ -->
+
+<vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:name="vector"
+ android:width="316dp"
+ android:height="168dp"
+ android:viewportWidth="316"
+ android:viewportHeight="168">
+ <path
+ android:name="path"
+ android:pathData="M 238 56 C 238 42.75 227.26 32 214 32 C 200.75 32 190 42.75 190 56 L 190 74 C 190 77.31 192.69 80 196 80 L 214 80 C 227.26 80 238 69.26 238 56 Z"
+ android:fillColor="#ffba29"
+ android:strokeWidth="1"/>
+ <path
+ android:name="path_1"
+ android:pathData="M 199.42 51.71 C 199.34 51.65 199.29 51.56 199.27 51.44 C 199.26 51.31 199.27 51.21 199.33 51.13 C 201.08 48.8 203.23 46.98 205.79 45.67 C 208.35 44.36 211.07 43.71 213.96 43.71 C 216.85 43.71 219.64 44.34 222.25 45.61 C 224.86 46.88 227.03 48.69 228.75 51.05 C 228.86 51.19 228.9 51.32 228.85 51.45 C 228.81 51.57 228.72 51.68 228.58 51.76 C 228.5 51.82 228.38 51.84 228.23 51.84 C 228.08 51.84 227.96 51.76 227.88 51.59 C 226.27 49.34 224.23 47.63 221.78 46.47 C 219.32 45.3 216.72 44.72 213.97 44.72 C 211.22 44.72 208.68 45.32 206.26 46.51 C 203.84 47.7 201.83 49.4 200.22 51.59 C 200.08 51.76 199.94 51.84 199.8 51.84 C 199.66 51.84 199.54 51.8 199.42 51.72 Z M 218.75 72.42 C 216 71.7 213.72 70.28 211.9 68.17 C 210.08 66.06 209.17 63.49 209.17 60.46 C 209.17 59.13 209.65 58.02 210.61 57.15 C 211.57 56.27 212.71 55.84 214.05 55.84 C 215.39 55.84 216.48 56.28 217.43 57.15 C 218.37 58.02 218.85 59.13 218.85 60.46 C 218.85 61.49 219.23 62.34 220 63.02 C 220.76 63.7 221.66 64.04 222.69 64.04 C 223.72 64.04 224.64 63.69 225.38 63 C 226.12 62.31 226.48 61.46 226.48 60.46 C 226.48 57.13 225.25 54.32 222.79 52.04 C 220.33 49.76 217.39 48.62 213.98 48.62 C 210.57 48.62 207.63 49.76 205.19 52.04 C 202.75 54.32 201.52 57.12 201.52 60.46 C 201.52 61.13 201.61 61.97 201.79 63 C 201.97 64.03 202.28 65.22 202.73 66.58 C 202.79 66.72 202.79 66.84 202.75 66.93 C 202.71 67.03 202.6 67.12 202.44 67.2 C 202.3 67.28 202.17 67.3 202.04 67.24 C 201.91 67.18 201.82 67.09 201.77 66.95 C 201.35 65.78 201.04 64.68 200.83 63.64 C 200.62 62.6 200.52 61.54 200.52 60.45 C 200.52 56.81 201.85 53.76 204.5 51.3 C 207.15 48.84 210.31 47.61 213.98 47.61 C 217.65 47.61 220.86 48.84 223.52 51.3 C 226.19 53.76 227.52 56.81 227.52 60.45 C 227.52 61.73 227.05 62.81 226.1 63.7 C 225.16 64.59 224.02 65.03 222.68 65.03 C 221.34 65.03 220.24 64.59 219.28 63.7 C 218.32 62.81 217.84 61.73 217.84 60.45 C 217.84 59.42 217.46 58.56 216.72 57.87 C 215.98 57.18 215.08 56.83 214.05 56.83 C 213.02 56.83 212.08 57.18 211.32 57.87 C 210.56 58.56 210.17 59.43 210.17 60.45 C 210.17 63.26 211.01 65.6 212.69 67.47 C 214.37 69.35 216.49 70.66 219.04 71.41 C 219.21 71.47 219.32 71.55 219.39 71.66 C 219.46 71.77 219.47 71.9 219.41 72.04 C 219.35 72.15 219.28 72.25 219.18 72.35 C 219.08 72.45 218.94 72.47 218.74 72.41 Z M 204.42 43.04 C 204.36 43.04 204.27 43.03 204.15 43 C 204.02 42.97 203.95 42.9 203.92 42.79 C 203.86 42.71 203.84 42.6 203.86 42.46 C 203.87 42.32 203.92 42.22 204.01 42.17 C 205.54 41.31 207.16 40.66 208.86 40.23 C 210.57 39.8 212.3 39.58 214.05 39.58 C 215.8 39.58 217.51 39.79 219.17 40.2 C 220.84 40.62 222.45 41.24 224 42.08 C 224.17 42.16 224.27 42.27 224.31 42.41 C 224.35 42.55 224.35 42.67 224.29 42.79 C 224.23 42.9 224.14 42.98 224.02 43.04 C 223.89 43.1 223.78 43.1 223.67 43.04 C 222.2 42.18 220.65 41.55 219.02 41.16 C 217.39 40.77 215.74 40.58 214.04 40.58 C 212.34 40.58 210.7 40.8 209.1 41.23 C 207.5 41.66 205.94 42.26 204.41 43.04 Z M 209.92 71.96 C 208.36 70.29 207.14 68.55 206.25 66.73 C 205.36 64.91 204.92 62.82 204.92 60.46 C 204.92 58.1 205.82 55.91 207.61 54.23 C 209.4 52.55 211.55 51.71 214.05 51.71 C 216.55 51.71 218.7 52.55 220.49 54.23 C 222.28 55.91 223.18 57.99 223.18 60.46 C 223.18 60.6 223.14 60.72 223.06 60.81 C 222.98 60.91 222.85 60.96 222.68 60.96 C 222.6 60.96 222.49 60.91 222.37 60.81 C 222.25 60.71 222.18 60.6 222.18 60.46 C 222.18 58.27 221.38 56.43 219.78 54.94 C 218.18 53.45 216.27 52.71 214.05 52.71 C 211.83 52.71 209.92 53.45 208.32 54.94 C 206.72 56.43 205.92 58.27 205.92 60.46 C 205.92 62.77 206.32 64.72 207.13 66.34 C 207.94 67.95 209.1 69.58 210.63 71.22 C 210.77 71.39 210.82 71.53 210.78 71.66 C 210.74 71.78 210.69 71.89 210.63 71.97 C 210.55 72.05 210.44 72.1 210.3 72.12 C 210.16 72.13 210.04 72.09 209.92 71.97 Z M 222.34 68.96 C 219.95 68.96 217.88 68.15 216.11 66.54 C 214.35 64.93 213.46 62.9 213.46 60.46 C 213.46 60.32 213.5 60.2 213.58 60.11 C 213.66 60.01 213.79 59.96 213.96 59.96 C 214.1 59.96 214.22 60.01 214.31 60.11 C 214.41 60.21 214.46 60.33 214.46 60.46 C 214.46 62.65 215.24 64.45 216.81 65.86 C 218.38 67.26 220.22 67.96 222.33 67.96 C 222.64 67.96 222.95 67.95 223.27 67.92 C 223.59 67.89 223.9 67.85 224.21 67.8 C 224.32 67.8 224.42 67.83 224.5 67.88 C 224.58 67.93 224.64 68.03 224.67 68.17 C 224.73 68.31 224.71 68.43 224.63 68.52 C 224.55 68.62 224.42 68.68 224.25 68.71 C 224 68.79 223.7 68.86 223.35 68.9 C 223 68.94 222.66 68.96 222.33 68.96 Z"
+ android:fillColor="#1f1f1f"
+ android:strokeWidth="1"/>
+ <path
+ android:name="path_2"
+ android:pathData="M 134 72 L 134 60 C 134 46.75 144.75 36 158 36 C 171.25 36 182 46.75 182 60 L 182 72 M 124 72 L 192 72 C 195.712 72 199.275 73.476 201.899 76.101 C 204.524 78.725 206 82.288 206 86 L 206 146 C 206 149.712 204.524 153.275 201.899 155.899 C 199.275 158.524 195.712 160 192 160 L 124 160 C 120.288 160 116.725 158.524 114.101 155.899 C 111.476 153.275 110 149.712 110 146 L 110 86 C 110 82.288 111.476 78.725 114.101 76.101 C 116.725 73.476 120.288 72 124 72"
+ android:strokeColor="#1f1f1f"
+ android:strokeWidth="1"
+ android:strokeLineCap="round"/>
+ <path
+ android:name="path_3"
+ android:pathData="M 155.67 114.83 C 153.22 114.83 151.15 113.98 149.46 112.29 C 147.77 110.6 146.92 108.53 146.92 106.08 C 146.92 103.63 147.77 101.56 149.46 99.87 C 151.15 98.18 153.22 97.33 155.67 97.33 C 158.12 97.33 160.19 98.18 161.88 99.87 C 163.57 101.56 164.42 103.63 164.42 106.08 C 164.42 108.53 163.57 110.6 161.88 112.29 C 160.19 113.98 158.12 114.83 155.67 114.83 Z M 172.59 137 L 169.67 133.5 L 169.67 124.92 C 168.27 124.38 167.14 123.51 166.29 122.32 C 165.44 121.13 165.01 119.8 165.01 118.32 C 165.01 116.38 165.69 114.72 167.05 113.36 C 168.41 112 170.06 111.32 172.01 111.32 C 173.96 111.32 175.61 112 176.97 113.36 C 178.33 114.72 179.01 116.37 179.01 118.32 C 179.01 119.8 178.58 121.13 177.73 122.32 C 176.88 123.51 175.75 124.37 174.35 124.92 L 174.35 125.33 L 176.68 127.66 L 174.35 129.99 L 176.68 132.32 L 172.6 136.99 Z M 172.01 121.83 C 172.98 121.83 173.81 121.49 174.49 120.81 C 175.17 120.13 175.51 119.3 175.51 118.33 C 175.51 117.36 175.17 116.53 174.49 115.85 C 173.81 115.17 172.98 114.83 172.01 114.83 C 171.04 114.83 170.21 115.17 169.53 115.85 C 168.85 116.53 168.51 117.36 168.51 118.33 C 168.51 119.3 168.85 120.13 169.53 120.81 C 170.21 121.49 171.04 121.83 172.01 121.83 Z M 160.46 119.85 C 160.65 121.44 161.15 122.9 161.95 124.23 C 162.75 125.55 163.77 126.7 165.01 127.67 L 165.01 134.67 L 137.01 134.67 L 137.01 129.13 C 137.01 127.81 137.38 126.6 138.12 125.51 C 138.86 124.42 139.81 123.59 140.98 123 C 143.27 121.83 145.66 120.96 148.13 120.38 C 150.6 119.8 153.12 119.5 155.68 119.5 C 156.46 119.5 157.26 119.53 158.07 119.59 C 158.89 119.65 159.68 119.74 160.46 119.85 Z"
+ android:fillColor="#1f1f1f"
+ android:strokeWidth="1"/>
+ <path
+ android:name="path_4"
+ android:pathData="M 63.481 27.427 L 102.118 17.075 C 102.457 16.984 102.815 16.984 103.154 17.075 C 103.493 17.166 103.802 17.344 104.05 17.592 C 104.298 17.841 104.477 18.15 104.568 18.489 L 110.779 41.671 C 110.87 42.01 110.87 42.367 110.779 42.706 C 110.689 43.045 110.51 43.355 110.262 43.603 C 110.014 43.851 109.704 44.03 109.365 44.121 L 70.728 54.473 C 70.216 54.611 69.67 54.539 69.211 54.274 C 68.751 54.008 68.416 53.571 68.279 53.059 L 62.067 29.877 C 61.976 29.538 61.976 29.181 62.067 28.842 C 62.158 28.503 62.336 28.193 62.585 27.945 C 62.833 27.697 63.142 27.518 63.481 27.427"
+ android:strokeColor="#e1e3e1"
+ android:strokeWidth="1"
+ android:strokeLineCap="round"
+ android:strokeMiterLimit="10"/>
+ <path
+ android:name="path_5"
+ android:pathData="M 86.189 50.327 L 93.917 48.256 L 94.952 52.12 L 87.225 54.191 Z"
+ android:fillColor="#e1e3e1"
+ android:strokeWidth="1"/>
+ <path
+ android:name="path_6"
+ android:pathData="M 83.36 55.23 L 98.81 51.08"
+ android:strokeColor="#e1e3e1"
+ android:strokeWidth="1"
+ android:strokeLineCap="round"
+ android:strokeMiterLimit="10"/>
+ <path
+ android:name="path_7"
+ android:pathData="M 90.9 37.2 L 88.3 35.7 L 89.4 33.8 C 89.59 33.48 89.37 33.07 89 33.05 L 81.88 32.62 C 81.47 32.6 81.21 33.05 81.43 33.39 L 85.36 39.34 C 85.56 39.65 86.02 39.64 86.21 39.31 L 87.31 37.41 L 89.91 38.91 C 90.39 39.19 91 39.02 91.28 38.54 C 91.56 38.06 91.39 37.45 90.91 37.17 Z"
+ android:fillColor="#e1e3e1"
+ android:strokeWidth="1"/>
+ <path
+ android:name="path_8"
+ android:pathData="M 86 160 L 222 160"
+ android:strokeColor="#1f1f1f"
+ android:strokeWidth="1"
+ android:strokeLineCap="round"/>
+ <group android:name="group">
+ <path
+ android:name="path_9"
+ android:pathData="M 98 80 C 92.088 80 86.325 81.872 81.542 85.348 C 76.759 88.823 73.197 93.725 71.37 99.348 C 69.543 104.97 69.543 111.03 71.37 116.652 C 73.197 122.275 76.759 127.177 81.542 130.652 C 86.325 134.128 92.088 136 98 136 C 103.912 136 109.675 134.128 114.458 130.652 C 119.241 127.177 122.803 122.275 124.63 116.652 C 126.457 111.03 126.457 104.97 124.63 99.348 C 122.803 93.725 119.241 88.823 114.458 85.348 C 109.675 81.872 103.912 80 98 80 Z"
+ android:fillColor="#6dd48b"
+ android:strokeWidth="1"/>
+ <path
+ android:name="path_10"
+ android:pathData="M 98 90.5 C 93.36 90.5 88.906 92.345 85.626 95.626 C 82.345 98.906 80.5 103.36 80.5 108 C 80.5 112.64 82.345 117.094 85.626 120.374 C 88.906 123.655 93.36 125.5 98 125.5 C 102.64 125.5 107.094 123.655 110.374 120.374 C 113.655 117.094 115.5 112.64 115.5 108 C 115.5 103.36 113.655 98.906 110.374 95.626 C 107.094 92.345 102.64 90.5 98 90.5 Z"
+ android:strokeColor="#1f1f1f"
+ android:strokeWidth="1"
+ android:strokeMiterLimit="10"/>
+ <path
+ android:name="path_11"
+ android:pathData="M 92.31 104.5 C 92.31 105.22 91.72 105.81 91 105.81 C 90.28 105.81 89.69 105.22 89.69 104.5 C 89.69 103.78 90.28 103.19 91 103.19 C 91.72 103.19 92.31 103.78 92.31 104.5 Z M 106.31 104.5 C 106.31 105.22 105.72 105.81 105 105.81 C 104.28 105.81 103.69 105.22 103.69 104.5 C 103.69 103.78 104.28 103.19 105 103.19 C 105.72 103.19 106.31 103.78 106.31 104.5 Z"
+ android:fillColor="#1f1f1f"
+ android:strokeWidth="1"/>
+ <path
+ android:name="path_12"
+ android:pathData="M 98.88 107.12 L 98.88 110.62 L 96.61 110.62 M 100.11 116.16 C 98.94 117.33 97.06 117.33 95.89 116.16 C 95.29 115.56 95 114.76 95.02 113.97"
+ android:strokeColor="#1f1f1f"
+ android:strokeWidth="1"
+ android:strokeMiterLimit="10"/>
+ </group>
+ <group android:name="group_2">
+ <path
+ android:name="path_13"
+ android:pathData="M 264.23 104 L 296.23 104"
+ android:strokeColor="#e1e3e1"
+ android:strokeWidth="1"
+ android:strokeLineCap="round"
+ android:strokeMiterLimit="10"/>
+ <path
+ android:name="path_14"
+ android:pathData="M 273.16 81.21 C 272.82 80.19 271.87 79.5 270.79 79.5 L 243.01 79.5 C 242.2 79.5 241.46 79.88 240.98 80.54 C 240.5 81.2 240.38 82.02 240.64 82.79 L 247.31 102.79 C 247.65 103.81 248.6 104.5 249.68 104.5 L 280.93 104.5 L 273.17 81.21 Z M 248.25 87.93 C 247.45 88.14 246.57 87.45 246.28 86.39 C 245.99 85.33 246.41 84.28 247.21 84.07 C 248.01 83.86 248.89 84.55 249.18 85.61 C 249.47 86.68 249.05 87.72 248.25 87.93 Z"
+ android:fillColor="#e1e3e1"
+ android:strokeWidth="1"/>
+ <group android:name="group_1">
+ <path
+ android:name="path_15"
+ android:pathData="M 279 83 L 285 83 M 277 77 L 285 69 M 271 75 L 271 69"
+ android:strokeColor="#e1e3e1"
+ android:strokeWidth="1"
+ android:strokeLineCap="round"/>
+ </group>
+ </group>
+ <path
+ android:name="path_16"
+ android:pathData="M 58.16 105.86 C 57.83 105.28 57.29 104.87 56.64 104.69 L 45.05 101.58 C 43.72 101.22 42.34 102.02 41.99 103.35 L 35.78 126.53 C 35.61 127.17 35.7 127.85 36.03 128.43 C 36.36 129.01 36.9 129.42 37.55 129.6 L 49.14 132.71 C 49.36 132.77 49.57 132.79 49.79 132.79 C 50.89 132.79 51.91 132.05 52.21 130.94 L 58.42 107.76 C 58.59 107.11 58.5 106.44 58.17 105.86 Z M 50.65 107.75 C 50.51 108.28 49.96 108.6 49.43 108.46 C 48.9 108.32 48.58 107.77 48.72 107.24 C 48.86 106.71 49.41 106.39 49.94 106.53 C 50.47 106.67 50.79 107.22 50.65 107.75 Z"
+ android:fillColor="#e1e3e1"
+ android:strokeWidth="1"/>
+ <path
+ android:name="path_17"
+ android:pathData="M 230 160 L 246 160"
+ android:strokeColor="#1f1f1f"
+ android:strokeWidth="1"
+ android:strokeLineCap="round"/>
+ <path
+ android:name="path_18"
+ android:pathData="M 204.63 80 C 202.38 75.27 197.58 72 192 72 L 190 72 L 190 74 C 190 77.31 192.69 80 196 80 L 204.63 80 Z"
+ android:fillColor="#1f1f1f"
+ android:strokeWidth="1"/>
+ <group android:name="group_4">
+ <path
+ android:name="path_19"
+ android:pathData="M 211.37 102.29 C 210.53 102.82 209.46 102.82 208.63 102.29 C 202.93 98.67 195.29 99.35 190.31 104.32 C 185.34 109.29 184.67 116.93 188.28 122.63 C 188.81 123.46 188.81 124.54 188.28 125.38 C 184.66 131.08 185.34 138.72 190.31 143.69 C 195.29 148.66 202.93 149.34 208.63 145.72 C 209.46 145.19 210.54 145.19 211.37 145.72 C 217.07 149.34 224.71 148.66 229.68 143.69 C 234.66 138.72 235.33 131.08 231.71 125.38 C 231.18 124.55 231.18 123.47 231.71 122.63 C 235.33 116.93 234.65 109.29 229.68 104.32 C 224.71 99.35 217.07 98.67 211.37 102.29 Z"
+ android:fillColor="#0b57cf"
+ android:strokeWidth="1"
+ android:fillType="evenOdd"/>
+ <group android:name="group_3">
+ <path
+ android:name="path_20"
+ android:pathData="M 198 110 C 197.47 110 196.961 110.211 196.586 110.586 C 196.211 110.961 196 111.47 196 112 C 196 112.53 196.211 113.039 196.586 113.414 C 196.961 113.789 197.47 114 198 114 C 198.53 114 199.039 113.789 199.414 113.414 C 199.789 113.039 200 112.53 200 112 C 200 111.47 199.789 110.961 199.414 110.586 C 199.039 110.211 198.53 110 198 110 Z M 210 110 C 209.47 110 208.961 110.211 208.586 110.586 C 208.211 110.961 208 111.47 208 112 C 208 112.53 208.211 113.039 208.586 113.414 C 208.961 113.789 209.47 114 210 114 C 210.53 114 211.039 113.789 211.414 113.414 C 211.789 113.039 212 112.53 212 112 C 212 111.47 211.789 110.961 211.414 110.586 C 211.039 110.211 210.53 110 210 110 Z M 222 110 C 221.47 110 220.961 110.211 220.586 110.586 C 220.211 110.961 220 111.47 220 112 C 220 112.53 220.211 113.039 220.586 113.414 C 220.961 113.789 221.47 114 222 114 C 222.53 114 223.039 113.789 223.414 113.414 C 223.789 113.039 224 112.53 224 112 C 224 111.47 223.789 110.961 223.414 110.586 C 223.039 110.211 222.53 110 222 110 Z M 198 122 C 197.47 122 196.961 122.211 196.586 122.586 C 196.211 122.961 196 123.47 196 124 C 196 124.53 196.211 125.039 196.586 125.414 C 196.961 125.789 197.47 126 198 126 C 198.53 126 199.039 125.789 199.414 125.414 C 199.789 125.039 200 124.53 200 124 C 200 123.47 199.789 122.961 199.414 122.586 C 199.039 122.211 198.53 122 198 122 Z M 210 122 C 209.47 122 208.961 122.211 208.586 122.586 C 208.211 122.961 208 123.47 208 124 C 208 124.53 208.211 125.039 208.586 125.414 C 208.961 125.789 209.47 126 210 126 C 210.53 126 211.039 125.789 211.414 125.414 C 211.789 125.039 212 124.53 212 124 C 212 123.47 211.789 122.961 211.414 122.586 C 211.039 122.211 210.53 122 210 122 Z M 222 122 C 221.47 122 220.961 122.211 220.586 122.586 C 220.211 122.961 220 123.47 220 124 C 220 124.53 220.211 125.039 220.586 125.414 C 220.961 125.789 221.47 126 222 126 C 222.53 126 223.039 125.789 223.414 125.414 C 223.789 125.039 224 124.53 224 124 C 224 123.47 223.789 122.961 223.414 122.586 C 223.039 122.211 222.53 122 222 122 Z M 198 134 C 197.47 134 196.961 134.211 196.586 134.586 C 196.211 134.961 196 135.47 196 136 C 196 136.53 196.211 137.039 196.586 137.414 C 196.961 137.789 197.47 138 198 138 C 198.53 138 199.039 137.789 199.414 137.414 C 199.789 137.039 200 136.53 200 136 C 200 135.47 199.789 134.961 199.414 134.586 C 199.039 134.211 198.53 134 198 134 Z M 210 134 C 209.47 134 208.961 134.211 208.586 134.586 C 208.211 134.961 208 135.47 208 136 C 208 136.53 208.211 137.039 208.586 137.414 C 208.961 137.789 209.47 138 210 138 C 210.53 138 211.039 137.789 211.414 137.414 C 211.789 137.039 212 136.53 212 136 C 212 135.47 211.789 134.961 211.414 134.586 C 211.039 134.211 210.53 134 210 134 Z M 222 134 C 221.47 134 220.961 134.211 220.586 134.586 C 220.211 134.961 220 135.47 220 136 C 220 136.53 220.211 137.039 220.586 137.414 C 220.961 137.789 221.47 138 222 138 C 222.53 138 223.039 137.789 223.414 137.414 C 223.789 137.039 224 136.53 224 136 C 224 135.47 223.789 134.961 223.414 134.586 C 223.039 134.211 222.53 134 222 134 Z"
+ android:fillColor="#ffffff"
+ android:strokeWidth="1"/>
+ </group>
+ <path
+ android:name="path_21"
+ android:pathData="M 222 112 L 198 136 L 222 136"
+ android:strokeColor="#ffffff"
+ android:strokeWidth="1"
+ android:strokeLineCap="round"/>
+ </group>
+</vector>
diff --git a/packages/CredentialManager/res/drawable/ic_passkeys_onboarding_dark.xml b/packages/CredentialManager/res/drawable/ic_passkeys_onboarding_dark.xml
new file mode 100644
index 0000000..53933cb
--- /dev/null
+++ b/packages/CredentialManager/res/drawable/ic_passkeys_onboarding_dark.xml
@@ -0,0 +1,158 @@
+<!--
+ ~ Copyright (C) 2023 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.
+ -->
+
+<vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:name="vector"
+ android:width="316dp"
+ android:height="168dp"
+ android:viewportWidth="316"
+ android:viewportHeight="168">
+ <path
+ android:name="path"
+ android:pathData="M 238 56 C 238 42.75 227.26 32 214 32 C 200.75 32 190 42.75 190 56 L 190 74 C 190 77.31 192.69 80 196 80 L 214 80 C 227.26 80 238 69.26 238 56 Z"
+ android:fillColor="#f09d00"
+ android:strokeWidth="1"/>
+ <path
+ android:name="path_1"
+ android:pathData="M 199.42 51.71 C 199.34 51.65 199.29 51.56 199.27 51.44 C 199.26 51.31 199.27 51.21 199.33 51.13 C 201.08 48.8 203.23 46.98 205.79 45.67 C 208.35 44.36 211.07 43.71 213.96 43.71 C 216.85 43.71 219.64 44.34 222.25 45.61 C 224.86 46.88 227.03 48.69 228.75 51.05 C 228.86 51.19 228.9 51.32 228.85 51.45 C 228.81 51.57 228.72 51.68 228.58 51.76 C 228.5 51.82 228.38 51.84 228.23 51.84 C 228.08 51.84 227.96 51.76 227.88 51.59 C 226.27 49.34 224.23 47.63 221.78 46.47 C 219.32 45.3 216.72 44.72 213.97 44.72 C 211.22 44.72 208.68 45.32 206.26 46.51 C 203.84 47.7 201.83 49.4 200.22 51.59 C 200.08 51.76 199.94 51.84 199.8 51.84 C 199.66 51.84 199.54 51.8 199.42 51.72 Z M 218.75 72.42 C 216 71.7 213.72 70.28 211.9 68.17 C 210.08 66.06 209.17 63.49 209.17 60.46 C 209.17 59.13 209.65 58.02 210.61 57.15 C 211.57 56.27 212.71 55.84 214.05 55.84 C 215.39 55.84 216.48 56.28 217.43 57.15 C 218.37 58.02 218.85 59.13 218.85 60.46 C 218.85 61.49 219.23 62.34 220 63.02 C 220.76 63.7 221.66 64.04 222.69 64.04 C 223.72 64.04 224.64 63.69 225.38 63 C 226.12 62.31 226.48 61.46 226.48 60.46 C 226.48 57.13 225.25 54.32 222.79 52.04 C 220.33 49.76 217.39 48.62 213.98 48.62 C 210.57 48.62 207.63 49.76 205.19 52.04 C 202.75 54.32 201.52 57.12 201.52 60.46 C 201.52 61.13 201.61 61.97 201.79 63 C 201.97 64.03 202.28 65.22 202.73 66.58 C 202.79 66.72 202.79 66.84 202.75 66.93 C 202.71 67.03 202.6 67.12 202.44 67.2 C 202.3 67.28 202.17 67.3 202.04 67.24 C 201.91 67.18 201.82 67.09 201.77 66.95 C 201.35 65.78 201.04 64.68 200.83 63.64 C 200.62 62.6 200.52 61.54 200.52 60.45 C 200.52 56.81 201.85 53.76 204.5 51.3 C 207.15 48.84 210.31 47.61 213.98 47.61 C 217.65 47.61 220.86 48.84 223.52 51.3 C 226.19 53.76 227.52 56.81 227.52 60.45 C 227.52 61.73 227.05 62.81 226.1 63.7 C 225.16 64.59 224.02 65.03 222.68 65.03 C 221.34 65.03 220.24 64.59 219.28 63.7 C 218.32 62.81 217.84 61.73 217.84 60.45 C 217.84 59.42 217.46 58.56 216.72 57.87 C 215.98 57.18 215.08 56.83 214.05 56.83 C 213.02 56.83 212.08 57.18 211.32 57.87 C 210.56 58.56 210.17 59.43 210.17 60.45 C 210.17 63.26 211.01 65.6 212.69 67.47 C 214.37 69.35 216.49 70.66 219.04 71.41 C 219.21 71.47 219.32 71.55 219.39 71.66 C 219.46 71.77 219.47 71.9 219.41 72.04 C 219.35 72.15 219.28 72.25 219.18 72.35 C 219.08 72.45 218.94 72.47 218.74 72.41 Z M 204.42 43.04 C 204.36 43.04 204.27 43.03 204.15 43 C 204.02 42.97 203.95 42.9 203.92 42.79 C 203.86 42.71 203.84 42.6 203.86 42.46 C 203.87 42.32 203.92 42.22 204.01 42.17 C 205.54 41.31 207.16 40.66 208.86 40.23 C 210.57 39.8 212.3 39.58 214.05 39.58 C 215.8 39.58 217.51 39.79 219.17 40.2 C 220.84 40.62 222.45 41.24 224 42.08 C 224.17 42.16 224.27 42.27 224.31 42.41 C 224.35 42.55 224.35 42.67 224.29 42.79 C 224.23 42.9 224.14 42.98 224.02 43.04 C 223.89 43.1 223.78 43.1 223.67 43.04 C 222.2 42.18 220.65 41.55 219.02 41.16 C 217.39 40.77 215.74 40.58 214.04 40.58 C 212.34 40.58 210.7 40.8 209.1 41.23 C 207.5 41.66 205.94 42.26 204.41 43.04 Z M 209.92 71.96 C 208.36 70.29 207.14 68.55 206.25 66.73 C 205.36 64.91 204.92 62.82 204.92 60.46 C 204.92 58.1 205.82 55.91 207.61 54.23 C 209.4 52.55 211.55 51.71 214.05 51.71 C 216.55 51.71 218.7 52.55 220.49 54.23 C 222.28 55.91 223.18 57.99 223.18 60.46 C 223.18 60.6 223.14 60.72 223.06 60.81 C 222.98 60.91 222.85 60.96 222.68 60.96 C 222.6 60.96 222.49 60.91 222.37 60.81 C 222.25 60.71 222.18 60.6 222.18 60.46 C 222.18 58.27 221.38 56.43 219.78 54.94 C 218.18 53.45 216.27 52.71 214.05 52.71 C 211.83 52.71 209.92 53.45 208.32 54.94 C 206.72 56.43 205.92 58.27 205.92 60.46 C 205.92 62.77 206.32 64.72 207.13 66.34 C 207.94 67.95 209.1 69.58 210.63 71.22 C 210.77 71.39 210.82 71.53 210.78 71.66 C 210.74 71.78 210.69 71.89 210.63 71.97 C 210.55 72.05 210.44 72.1 210.3 72.12 C 210.16 72.13 210.04 72.09 209.92 71.97 Z M 222.34 68.96 C 219.95 68.96 217.88 68.15 216.11 66.54 C 214.35 64.93 213.46 62.9 213.46 60.46 C 213.46 60.32 213.5 60.2 213.58 60.11 C 213.66 60.01 213.79 59.96 213.96 59.96 C 214.1 59.96 214.22 60.01 214.31 60.11 C 214.41 60.21 214.46 60.33 214.46 60.46 C 214.46 62.65 215.24 64.45 216.81 65.86 C 218.38 67.26 220.22 67.96 222.33 67.96 C 222.64 67.96 222.95 67.95 223.27 67.92 C 223.59 67.89 223.9 67.85 224.21 67.8 C 224.32 67.8 224.42 67.83 224.5 67.88 C 224.58 67.93 224.64 68.03 224.67 68.17 C 224.73 68.31 224.71 68.43 224.63 68.52 C 224.55 68.62 224.42 68.68 224.25 68.71 C 224 68.79 223.7 68.86 223.35 68.9 C 223 68.94 222.66 68.96 222.33 68.96 Z"
+ android:fillColor="#1f1f1f"
+ android:strokeWidth="1"/>
+ <path
+ android:name="path_2"
+ android:pathData="M 134 72 L 134 60 C 134 46.75 144.75 36 158 36 C 171.25 36 182 46.75 182 60 L 182 72 M 124 72 L 192 72 C 195.712 72 199.275 73.476 201.899 76.101 C 204.524 78.725 206 82.288 206 86 L 206 146 C 206 149.712 204.524 153.275 201.899 155.899 C 199.275 158.524 195.712 160 192 160 L 124 160 C 120.288 160 116.725 158.524 114.101 155.899 C 111.476 153.275 110 149.712 110 146 L 110 86 C 110 82.288 111.476 78.725 114.101 76.101 C 116.725 73.476 120.288 72 124 72"
+ android:strokeColor="#e1e3e1"
+ android:strokeWidth="1"
+ android:strokeLineCap="round"/>
+ <path
+ android:name="path_3"
+ android:pathData="M 155.67 114.83 C 153.22 114.83 151.15 113.98 149.46 112.29 C 147.77 110.6 146.92 108.53 146.92 106.08 C 146.92 103.63 147.77 101.56 149.46 99.87 C 151.15 98.18 153.22 97.33 155.67 97.33 C 158.12 97.33 160.19 98.18 161.88 99.87 C 163.57 101.56 164.42 103.63 164.42 106.08 C 164.42 108.53 163.57 110.6 161.88 112.29 C 160.19 113.98 158.12 114.83 155.67 114.83 Z M 172.59 137 L 169.67 133.5 L 169.67 124.92 C 168.27 124.38 167.14 123.51 166.29 122.32 C 165.44 121.13 165.01 119.8 165.01 118.32 C 165.01 116.38 165.69 114.72 167.05 113.36 C 168.41 112 170.06 111.32 172.01 111.32 C 173.96 111.32 175.61 112 176.97 113.36 C 178.33 114.72 179.01 116.37 179.01 118.32 C 179.01 119.8 178.58 121.13 177.73 122.32 C 176.88 123.51 175.75 124.37 174.35 124.92 L 174.35 125.33 L 176.68 127.66 L 174.35 129.99 L 176.68 132.32 L 172.6 136.99 Z M 172.01 121.83 C 172.98 121.83 173.81 121.49 174.49 120.81 C 175.17 120.13 175.51 119.3 175.51 118.33 C 175.51 117.36 175.17 116.53 174.49 115.85 C 173.81 115.17 172.98 114.83 172.01 114.83 C 171.04 114.83 170.21 115.17 169.53 115.85 C 168.85 116.53 168.51 117.36 168.51 118.33 C 168.51 119.3 168.85 120.13 169.53 120.81 C 170.21 121.49 171.04 121.83 172.01 121.83 Z M 160.46 119.85 C 160.65 121.44 161.15 122.9 161.95 124.23 C 162.75 125.55 163.77 126.7 165.01 127.67 L 165.01 134.67 L 137.01 134.67 L 137.01 129.13 C 137.01 127.81 137.38 126.6 138.12 125.51 C 138.86 124.42 139.81 123.59 140.98 123 C 143.27 121.83 145.66 120.96 148.13 120.38 C 150.6 119.8 153.12 119.5 155.68 119.5 C 156.46 119.5 157.26 119.53 158.07 119.59 C 158.89 119.65 159.68 119.74 160.46 119.85 Z"
+ android:fillColor="#e1e3e1"
+ android:strokeWidth="1"/>
+ <path
+ android:name="path_4"
+ android:pathData="M 63.481 27.427 L 102.118 17.075 C 102.457 16.984 102.815 16.984 103.154 17.075 C 103.493 17.166 103.802 17.344 104.05 17.592 C 104.298 17.841 104.477 18.15 104.568 18.489 L 110.779 41.671 C 110.87 42.01 110.87 42.367 110.779 42.706 C 110.689 43.045 110.51 43.355 110.262 43.603 C 110.014 43.851 109.704 44.03 109.365 44.121 L 70.728 54.473 C 70.216 54.611 69.67 54.539 69.211 54.274 C 68.751 54.008 68.416 53.571 68.279 53.059 L 62.067 29.877 C 61.976 29.538 61.976 29.181 62.067 28.842 C 62.158 28.503 62.336 28.193 62.585 27.945 C 62.833 27.697 63.142 27.518 63.481 27.427"
+ android:strokeColor="#444746"
+ android:strokeWidth="1"
+ android:strokeLineCap="round"
+ android:strokeMiterLimit="10"/>
+ <path
+ android:name="path_5"
+ android:pathData="M 86.189 50.327 L 93.917 48.256 L 94.952 52.12 L 87.225 54.191 Z"
+ android:fillColor="#444746"
+ android:strokeWidth="1"/>
+ <path
+ android:name="path_6"
+ android:pathData="M 83.36 55.23 L 98.81 51.08"
+ android:strokeColor="#444746"
+ android:strokeWidth="1"
+ android:strokeLineCap="round"
+ android:strokeMiterLimit="10"/>
+ <path
+ android:name="path_7"
+ android:pathData="M 90.9 37.2 L 88.3 35.7 L 89.4 33.8 C 89.59 33.48 89.37 33.07 89 33.05 L 81.88 32.62 C 81.47 32.6 81.21 33.05 81.43 33.39 L 85.36 39.34 C 85.56 39.65 86.02 39.64 86.21 39.31 L 87.31 37.41 L 89.91 38.91 C 90.39 39.19 91 39.02 91.28 38.54 C 91.56 38.06 91.39 37.45 90.91 37.17 Z"
+ android:fillColor="#444746"
+ android:strokeWidth="1"/>
+ <path
+ android:name="path_8"
+ android:pathData="M 86 160 L 222 160"
+ android:strokeColor="#e1e3e1"
+ android:strokeWidth="1"
+ android:strokeLineCap="round"/>
+ <group android:name="group">
+ <path
+ android:name="path_9"
+ android:pathData="M 98 80 C 92.088 80 86.325 81.872 81.542 85.348 C 76.759 88.823 73.197 93.725 71.37 99.348 C 69.543 104.97 69.543 111.03 71.37 116.652 C 73.197 122.275 76.759 127.177 81.542 130.652 C 86.325 134.128 92.088 136 98 136 C 103.912 136 109.675 134.128 114.458 130.652 C 119.241 127.177 122.803 122.275 124.63 116.652 C 126.457 111.03 126.457 104.97 124.63 99.348 C 122.803 93.725 119.241 88.823 114.458 85.348 C 109.675 81.872 103.912 80 98 80 Z"
+ android:fillColor="#37be5f"
+ android:strokeWidth="1"/>
+ <path
+ android:name="path_10"
+ android:pathData="M 98 90.5 C 93.36 90.5 88.906 92.345 85.626 95.626 C 82.345 98.906 80.5 103.36 80.5 108 C 80.5 112.64 82.345 117.094 85.626 120.374 C 88.906 123.655 93.36 125.5 98 125.5 C 102.64 125.5 107.094 123.655 110.374 120.374 C 113.655 117.094 115.5 112.64 115.5 108 C 115.5 103.36 113.655 98.906 110.374 95.626 C 107.094 92.345 102.64 90.5 98 90.5 Z"
+ android:strokeColor="#1f1f1f"
+ android:strokeWidth="1"
+ android:strokeMiterLimit="10"/>
+ <path
+ android:name="path_11"
+ android:pathData="M 92.31 104.5 C 92.31 105.22 91.72 105.81 91 105.81 C 90.28 105.81 89.69 105.22 89.69 104.5 C 89.69 103.78 90.28 103.19 91 103.19 C 91.72 103.19 92.31 103.78 92.31 104.5 Z M 106.31 104.5 C 106.31 105.22 105.72 105.81 105 105.81 C 104.28 105.81 103.69 105.22 103.69 104.5 C 103.69 103.78 104.28 103.19 105 103.19 C 105.72 103.19 106.31 103.78 106.31 104.5 Z"
+ android:fillColor="#1f1f1f"
+ android:strokeWidth="1"/>
+ <path
+ android:name="path_12"
+ android:pathData="M 98.88 107.12 L 98.88 110.62 L 96.61 110.62 M 100.11 116.16 C 98.94 117.33 97.06 117.33 95.89 116.16 C 95.29 115.56 95 114.76 95.02 113.97"
+ android:strokeColor="#1f1f1f"
+ android:strokeWidth="1"
+ android:strokeMiterLimit="10"/>
+ </group>
+ <group android:name="group_2">
+ <path
+ android:name="path_13"
+ android:pathData="M 264.23 104 L 296.23 104"
+ android:strokeColor="#444746"
+ android:strokeWidth="1"
+ android:strokeLineCap="round"
+ android:strokeMiterLimit="10"/>
+ <path
+ android:name="path_14"
+ android:pathData="M 273.16 81.21 C 272.82 80.19 271.87 79.5 270.79 79.5 L 243.01 79.5 C 242.2 79.5 241.46 79.88 240.98 80.54 C 240.5 81.2 240.38 82.02 240.64 82.79 L 247.31 102.79 C 247.65 103.81 248.6 104.5 249.68 104.5 L 280.93 104.5 L 273.17 81.21 Z M 248.25 87.93 C 247.45 88.14 246.57 87.45 246.28 86.39 C 245.99 85.33 246.41 84.28 247.21 84.07 C 248.01 83.86 248.89 84.55 249.18 85.61 C 249.47 86.68 249.05 87.72 248.25 87.93 Z"
+ android:fillColor="#444746"
+ android:strokeWidth="1"/>
+ <group android:name="group_1">
+ <path
+ android:name="path_15"
+ android:pathData="M 279 83 L 285 83 M 277 77 L 285 69 M 271 75 L 271 69"
+ android:strokeColor="#444746"
+ android:strokeWidth="1"
+ android:strokeLineCap="round"/>
+ </group>
+ </group>
+ <path
+ android:name="path_16"
+ android:pathData="M 58.16 105.86 C 57.83 105.28 57.29 104.87 56.64 104.69 L 45.05 101.58 C 43.72 101.22 42.34 102.02 41.99 103.35 L 35.78 126.53 C 35.61 127.17 35.7 127.85 36.03 128.43 C 36.36 129.01 36.9 129.42 37.55 129.6 L 49.14 132.71 C 49.36 132.77 49.57 132.79 49.79 132.79 C 50.89 132.79 51.91 132.05 52.21 130.94 L 58.42 107.76 C 58.59 107.11 58.5 106.44 58.17 105.86 Z M 50.65 107.75 C 50.51 108.28 49.96 108.6 49.43 108.46 C 48.9 108.32 48.58 107.77 48.72 107.24 C 48.86 106.71 49.41 106.39 49.94 106.53 C 50.47 106.67 50.79 107.22 50.65 107.75 Z"
+ android:fillColor="#444746"
+ android:strokeWidth="1"/>
+ <path
+ android:name="path_17"
+ android:pathData="M 230 160 L 246 160"
+ android:strokeColor="#e1e3e1"
+ android:strokeWidth="1"
+ android:strokeLineCap="round"/>
+ <path
+ android:name="path_18"
+ android:pathData="M 204.63 80 C 202.38 75.27 197.58 72 192 72 L 190 72 L 190 74 C 190 77.31 192.69 80 196 80 L 204.63 80 Z"
+ android:fillColor="#e1e3e1"
+ android:strokeWidth="1"/>
+ <group android:name="group_4">
+ <path
+ android:name="path_19"
+ android:pathData="M 211.37 102.29 C 210.53 102.82 209.46 102.82 208.63 102.29 C 202.93 98.67 195.29 99.35 190.31 104.32 C 185.34 109.29 184.67 116.93 188.28 122.63 C 188.81 123.46 188.81 124.54 188.28 125.38 C 184.66 131.08 185.34 138.72 190.31 143.69 C 195.29 148.66 202.93 149.34 208.63 145.72 C 209.46 145.19 210.54 145.19 211.37 145.72 C 217.07 149.34 224.71 148.66 229.68 143.69 C 234.66 138.72 235.33 131.08 231.71 125.38 C 231.18 124.55 231.18 123.47 231.71 122.63 C 235.33 116.93 234.65 109.29 229.68 104.32 C 224.71 99.35 217.07 98.67 211.37 102.29 Z"
+ android:fillColor="#7cacf8"
+ android:strokeWidth="1"
+ android:fillType="evenOdd"/>
+ <group android:name="group_3">
+ <path
+ android:name="path_20"
+ android:pathData="M 198 110 C 197.47 110 196.961 110.211 196.586 110.586 C 196.211 110.961 196 111.47 196 112 C 196 112.53 196.211 113.039 196.586 113.414 C 196.961 113.789 197.47 114 198 114 C 198.53 114 199.039 113.789 199.414 113.414 C 199.789 113.039 200 112.53 200 112 C 200 111.47 199.789 110.961 199.414 110.586 C 199.039 110.211 198.53 110 198 110 Z M 210 110 C 209.47 110 208.961 110.211 208.586 110.586 C 208.211 110.961 208 111.47 208 112 C 208 112.53 208.211 113.039 208.586 113.414 C 208.961 113.789 209.47 114 210 114 C 210.53 114 211.039 113.789 211.414 113.414 C 211.789 113.039 212 112.53 212 112 C 212 111.47 211.789 110.961 211.414 110.586 C 211.039 110.211 210.53 110 210 110 Z M 222 110 C 221.47 110 220.961 110.211 220.586 110.586 C 220.211 110.961 220 111.47 220 112 C 220 112.53 220.211 113.039 220.586 113.414 C 220.961 113.789 221.47 114 222 114 C 222.53 114 223.039 113.789 223.414 113.414 C 223.789 113.039 224 112.53 224 112 C 224 111.47 223.789 110.961 223.414 110.586 C 223.039 110.211 222.53 110 222 110 Z M 198 122 C 197.47 122 196.961 122.211 196.586 122.586 C 196.211 122.961 196 123.47 196 124 C 196 124.53 196.211 125.039 196.586 125.414 C 196.961 125.789 197.47 126 198 126 C 198.53 126 199.039 125.789 199.414 125.414 C 199.789 125.039 200 124.53 200 124 C 200 123.47 199.789 122.961 199.414 122.586 C 199.039 122.211 198.53 122 198 122 Z M 210 122 C 209.47 122 208.961 122.211 208.586 122.586 C 208.211 122.961 208 123.47 208 124 C 208 124.53 208.211 125.039 208.586 125.414 C 208.961 125.789 209.47 126 210 126 C 210.53 126 211.039 125.789 211.414 125.414 C 211.789 125.039 212 124.53 212 124 C 212 123.47 211.789 122.961 211.414 122.586 C 211.039 122.211 210.53 122 210 122 Z M 222 122 C 221.47 122 220.961 122.211 220.586 122.586 C 220.211 122.961 220 123.47 220 124 C 220 124.53 220.211 125.039 220.586 125.414 C 220.961 125.789 221.47 126 222 126 C 222.53 126 223.039 125.789 223.414 125.414 C 223.789 125.039 224 124.53 224 124 C 224 123.47 223.789 122.961 223.414 122.586 C 223.039 122.211 222.53 122 222 122 Z M 198 134 C 197.47 134 196.961 134.211 196.586 134.586 C 196.211 134.961 196 135.47 196 136 C 196 136.53 196.211 137.039 196.586 137.414 C 196.961 137.789 197.47 138 198 138 C 198.53 138 199.039 137.789 199.414 137.414 C 199.789 137.039 200 136.53 200 136 C 200 135.47 199.789 134.961 199.414 134.586 C 199.039 134.211 198.53 134 198 134 Z M 210 134 C 209.47 134 208.961 134.211 208.586 134.586 C 208.211 134.961 208 135.47 208 136 C 208 136.53 208.211 137.039 208.586 137.414 C 208.961 137.789 209.47 138 210 138 C 210.53 138 211.039 137.789 211.414 137.414 C 211.789 137.039 212 136.53 212 136 C 212 135.47 211.789 134.961 211.414 134.586 C 211.039 134.211 210.53 134 210 134 Z M 222 134 C 221.47 134 220.961 134.211 220.586 134.586 C 220.211 134.961 220 135.47 220 136 C 220 136.53 220.211 137.039 220.586 137.414 C 220.961 137.789 221.47 138 222 138 C 222.53 138 223.039 137.789 223.414 137.414 C 223.789 137.039 224 136.53 224 136 C 224 135.47 223.789 134.961 223.414 134.586 C 223.039 134.211 222.53 134 222 134 Z"
+ android:fillColor="#1f1f1f"
+ android:strokeWidth="1"/>
+ </group>
+ <path
+ android:name="path_21"
+ android:pathData="M 222 112 L 198 136 L 222 136"
+ android:strokeColor="#1f1f1f"
+ android:strokeWidth="1"
+ android:strokeLineCap="round"/>
+ </group>
+</vector>
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
index 558c229..823ee5b 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
@@ -5,6 +5,7 @@
import androidx.activity.compose.ManagedActivityResultLauncher
import androidx.activity.result.ActivityResult
import androidx.activity.result.IntentSenderRequest
+import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
@@ -165,8 +166,16 @@
) {
ContainerCard() {
Column() {
+ val onboardingImageResource = remember {
+ mutableStateOf(R.drawable.ic_passkeys_onboarding)
+ }
+ if (isSystemInDarkTheme()) {
+ onboardingImageResource.value = R.drawable.ic_passkeys_onboarding_dark
+ } else {
+ onboardingImageResource.value = R.drawable.ic_passkeys_onboarding
+ }
Image(
- painter = painterResource(R.drawable.ic_passkeys_onboarding),
+ painter = painterResource(onboardingImageResource.value),
contentDescription = null,
modifier = Modifier.align(alignment = Alignment.CenterHorizontally)
.padding(top = 24.dp, bottom = 12.dp).size(316.dp, 168.dp)
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt
index e8b5b19..f6bb3cc 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt
@@ -119,7 +119,6 @@
actions = actions,
colors = topAppBarColors(),
windowInsets = TopAppBarDefaults.windowInsets,
- maxHeightWithoutTitle = 120.dp,
pinnedHeight = ContainerHeight,
scrollBehavior = scrollBehavior,
)
@@ -261,7 +260,7 @@
* A two-rows top app bar that is designed to be called by the Large and Medium top app bar
* composables.
*
- * @throws [IllegalArgumentException] if the given [maxHeightWithoutTitle] is equal or smaller than
+ * @throws [IllegalArgumentException] if the given [MaxHeightWithoutTitle] is equal or smaller than
* the [pinnedHeight]
*/
@OptIn(ExperimentalMaterial3Api::class)
@@ -277,11 +276,10 @@
actions: @Composable RowScope.() -> Unit,
windowInsets: WindowInsets,
colors: TopAppBarColors,
- maxHeightWithoutTitle: Dp,
pinnedHeight: Dp,
scrollBehavior: TopAppBarScrollBehavior?
) {
- if (maxHeightWithoutTitle <= pinnedHeight) {
+ if (MaxHeightWithoutTitle <= pinnedHeight) {
throw IllegalArgumentException(
"A TwoRowsTopAppBar max height should be greater than its pinned height"
)
@@ -289,7 +287,7 @@
val pinnedHeightPx: Float
val density = LocalDensity.current
val maxHeightPx = density.run {
- remember { mutableStateOf((maxHeightWithoutTitle + pinnedHeight).toPx()) }
+ remember { mutableStateOf((MaxHeightWithoutTitle + DefaultTitleHeight).toPx()) }
}
val titleBottomPaddingPx: Int
density.run {
@@ -380,7 +378,7 @@
Box(modifier = Modifier.onGloballyPositioned { coordinates ->
density.run {
maxHeightPx.value =
- maxHeightWithoutTitle.toPx() + coordinates.size.height.toFloat()
+ MaxHeightWithoutTitle.toPx() + coordinates.size.height.toFloat()
}
}) { title() }
},
@@ -610,6 +608,8 @@
// Medium or Large app bar.
private val TopTitleAlphaEasing = CubicBezierEasing(.8f, 0f, .8f, .15f)
+private val MaxHeightWithoutTitle = 124.dp
+private val DefaultTitleHeight = 52.dp
private val ContainerHeight = 56.dp
private val LargeTitleBottomPadding = 28.dp
private val TopAppBarHorizontalPadding = 4.dp
diff --git a/packages/SystemUI/TEST_MAPPING b/packages/SystemUI/TEST_MAPPING
index 333aeba..bdd941d 100644
--- a/packages/SystemUI/TEST_MAPPING
+++ b/packages/SystemUI/TEST_MAPPING
@@ -49,13 +49,16 @@
},
{
// Permission indicators
- "name": "CtsPermission4TestCases",
+ "name": "CtsPermission3TestCases",
"options": [
{
"exclude-annotation": "org.junit.Ignore"
},
{
"exclude-annotation": "androidx.test.filters.FlakyTest"
+ },
+ {
+ "include-filter": "android.permission3.cts.CameraMicIndicatorsPermissionTest"
}
]
},
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamMonitor.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamMonitor.java
index 102f208..055cd52 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamMonitor.java
@@ -16,19 +16,23 @@
package com.android.systemui.dreams;
+import static com.android.systemui.dreams.dagger.DreamModule.DREAM_PRETEXT_MONITOR;
+
import android.util.Log;
import com.android.systemui.CoreStartable;
import com.android.systemui.dreams.callbacks.DreamStatusBarStateCallback;
import com.android.systemui.dreams.conditions.DreamCondition;
import com.android.systemui.shared.condition.Monitor;
+import com.android.systemui.util.condition.ConditionalCoreStartable;
import javax.inject.Inject;
+import javax.inject.Named;
/**
* A {@link CoreStartable} to retain a monitor for tracking dreaming.
*/
-public class DreamMonitor implements CoreStartable {
+public class DreamMonitor extends ConditionalCoreStartable {
private static final String TAG = "DreamMonitor";
// We retain a reference to the monitor so it is not garbage-collected.
@@ -39,14 +43,17 @@
@Inject
public DreamMonitor(Monitor monitor, DreamCondition dreamCondition,
+ @Named(DREAM_PRETEXT_MONITOR) Monitor pretextMonitor,
DreamStatusBarStateCallback callback) {
+ super(pretextMonitor);
mConditionMonitor = monitor;
mDreamCondition = dreamCondition;
mCallback = callback;
}
+
@Override
- public void start() {
+ protected void onStart() {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "started");
}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayRegistrant.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayRegistrant.java
index 87c5f51..a2dcdf5 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayRegistrant.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayRegistrant.java
@@ -17,6 +17,7 @@
package com.android.systemui.dreams;
import static com.android.systemui.dreams.dagger.DreamModule.DREAM_OVERLAY_SERVICE_COMPONENT;
+import static com.android.systemui.dreams.dagger.DreamModule.DREAM_PRETEXT_MONITOR;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -33,8 +34,9 @@
import android.service.dreams.IDreamManager;
import android.util.Log;
-import com.android.systemui.CoreStartable;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.shared.condition.Monitor;
+import com.android.systemui.util.condition.ConditionalCoreStartable;
import javax.inject.Inject;
import javax.inject.Named;
@@ -43,7 +45,7 @@
* {@link DreamOverlayRegistrant} is responsible for telling system server that SystemUI should be
* the designated dream overlay component.
*/
-public class DreamOverlayRegistrant implements CoreStartable {
+public class DreamOverlayRegistrant extends ConditionalCoreStartable {
private static final String TAG = "DreamOverlayRegistrant";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private final IDreamManager mDreamManager;
@@ -102,7 +104,9 @@
@Inject
public DreamOverlayRegistrant(Context context, @Main Resources resources,
- @Named(DREAM_OVERLAY_SERVICE_COMPONENT) ComponentName dreamOverlayServiceComponent) {
+ @Named(DREAM_OVERLAY_SERVICE_COMPONENT) ComponentName dreamOverlayServiceComponent,
+ @Named(DREAM_PRETEXT_MONITOR) Monitor monitor) {
+ super(monitor);
mContext = context;
mResources = resources;
mDreamManager = IDreamManager.Stub.asInterface(
@@ -111,7 +115,7 @@
}
@Override
- public void start() {
+ protected void onStart() {
final IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_CHANGED);
filter.addDataScheme("package");
filter.addDataSchemeSpecificPart(mOverlayServiceComponent.getPackageName(),
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationTypesUpdater.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationTypesUpdater.java
index ee2f1af..244212b 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationTypesUpdater.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationTypesUpdater.java
@@ -16,27 +16,31 @@
package com.android.systemui.dreams.complication;
+import static com.android.systemui.dreams.dagger.DreamModule.DREAM_PRETEXT_MONITOR;
+
import android.database.ContentObserver;
import android.os.UserHandle;
import android.provider.Settings;
import com.android.settingslib.dream.DreamBackend;
-import com.android.systemui.CoreStartable;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dreams.DreamOverlayStateController;
+import com.android.systemui.shared.condition.Monitor;
+import com.android.systemui.util.condition.ConditionalCoreStartable;
import com.android.systemui.util.settings.SecureSettings;
import java.util.concurrent.Executor;
import javax.inject.Inject;
+import javax.inject.Named;
/**
* {@link ComplicationTypesUpdater} observes the state of available complication types set by the
* user, and pushes updates to {@link DreamOverlayStateController}.
*/
@SysUISingleton
-public class ComplicationTypesUpdater implements CoreStartable {
+public class ComplicationTypesUpdater extends ConditionalCoreStartable {
private final DreamBackend mDreamBackend;
private final Executor mExecutor;
private final SecureSettings mSecureSettings;
@@ -48,7 +52,9 @@
DreamBackend dreamBackend,
@Main Executor executor,
SecureSettings secureSettings,
- DreamOverlayStateController dreamOverlayStateController) {
+ DreamOverlayStateController dreamOverlayStateController,
+ @Named(DREAM_PRETEXT_MONITOR) Monitor monitor) {
+ super(monitor);
mDreamBackend = dreamBackend;
mExecutor = executor;
mSecureSettings = secureSettings;
@@ -56,7 +62,7 @@
}
@Override
- public void start() {
+ public void onStart() {
final ContentObserver settingsObserver = new ContentObserver(null /*handler*/) {
@Override
public void onChange(boolean selfChange) {
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamClockTimeComplication.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamClockTimeComplication.java
index 77e1fc9..bb1e6e2 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamClockTimeComplication.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamClockTimeComplication.java
@@ -18,11 +18,14 @@
import static com.android.systemui.dreams.complication.dagger.DreamClockTimeComplicationModule.DREAM_CLOCK_TIME_COMPLICATION_VIEW;
import static com.android.systemui.dreams.complication.dagger.RegisteredComplicationsModule.DREAM_CLOCK_TIME_COMPLICATION_LAYOUT_PARAMS;
+import static com.android.systemui.dreams.dagger.DreamModule.DREAM_PRETEXT_MONITOR;
import android.view.View;
import com.android.systemui.CoreStartable;
import com.android.systemui.dreams.DreamOverlayStateController;
+import com.android.systemui.shared.condition.Monitor;
+import com.android.systemui.util.condition.ConditionalCoreStartable;
import javax.inject.Inject;
import javax.inject.Named;
@@ -60,7 +63,7 @@
* {@link CoreStartable} responsible for registering {@link DreamClockTimeComplication} with
* SystemUI.
*/
- public static class Registrant implements CoreStartable {
+ public static class Registrant extends ConditionalCoreStartable {
private final DreamOverlayStateController mDreamOverlayStateController;
private final DreamClockTimeComplication mComplication;
@@ -70,13 +73,15 @@
@Inject
public Registrant(
DreamOverlayStateController dreamOverlayStateController,
- DreamClockTimeComplication dreamClockTimeComplication) {
+ DreamClockTimeComplication dreamClockTimeComplication,
+ @Named(DREAM_PRETEXT_MONITOR) Monitor monitor) {
+ super(monitor);
mDreamOverlayStateController = dreamOverlayStateController;
mComplication = dreamClockTimeComplication;
}
@Override
- public void start() {
+ public void onStart() {
mDreamOverlayStateController.addComplication(mComplication);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamHomeControlsComplication.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamHomeControlsComplication.java
index 1065b94..7f395d8 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamHomeControlsComplication.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamHomeControlsComplication.java
@@ -21,6 +21,7 @@
import static com.android.systemui.controls.dagger.ControlsComponent.Visibility.UNAVAILABLE;
import static com.android.systemui.dreams.complication.dagger.DreamHomeControlsComplicationComponent.DreamHomeControlsModule.DREAM_HOME_CONTROLS_CHIP_VIEW;
import static com.android.systemui.dreams.complication.dagger.RegisteredComplicationsModule.DREAM_HOME_CONTROLS_CHIP_LAYOUT_PARAMS;
+import static com.android.systemui.dreams.dagger.DreamModule.DREAM_PRETEXT_MONITOR;
import android.content.Context;
import android.content.Intent;
@@ -42,7 +43,9 @@
import com.android.systemui.dreams.DreamOverlayStateController;
import com.android.systemui.dreams.complication.dagger.DreamHomeControlsComplicationComponent;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.shared.condition.Monitor;
import com.android.systemui.util.ViewController;
+import com.android.systemui.util.condition.ConditionalCoreStartable;
import java.util.List;
@@ -75,7 +78,7 @@
/**
* {@link CoreStartable} for registering the complication with SystemUI on startup.
*/
- public static class Registrant implements CoreStartable {
+ public static class Registrant extends ConditionalCoreStartable {
private final DreamHomeControlsComplication mComplication;
private final DreamOverlayStateController mDreamOverlayStateController;
private final ControlsComponent mControlsComponent;
@@ -105,14 +108,16 @@
@Inject
public Registrant(DreamHomeControlsComplication complication,
DreamOverlayStateController dreamOverlayStateController,
- ControlsComponent controlsComponent) {
+ ControlsComponent controlsComponent,
+ @Named(DREAM_PRETEXT_MONITOR) Monitor monitor) {
+ super(monitor);
mComplication = complication;
mControlsComponent = controlsComponent;
mDreamOverlayStateController = dreamOverlayStateController;
}
@Override
- public void start() {
+ public void onStart() {
mControlsComponent.getControlsListingController().ifPresent(
c -> c.addCallback(mControlsCallback));
mDreamOverlayStateController.addCallback(mOverlayStateCallback);
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/SmartSpaceComplication.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/SmartSpaceComplication.java
index c3aaf0c..e39073b 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/SmartSpaceComplication.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/SmartSpaceComplication.java
@@ -17,6 +17,7 @@
package com.android.systemui.dreams.complication;
import static com.android.systemui.dreams.complication.dagger.RegisteredComplicationsModule.DREAM_SMARTSPACE_LAYOUT_PARAMS;
+import static com.android.systemui.dreams.dagger.DreamModule.DREAM_PRETEXT_MONITOR;
import android.content.Context;
import android.os.Parcelable;
@@ -28,6 +29,8 @@
import com.android.systemui.dreams.DreamOverlayStateController;
import com.android.systemui.dreams.smartspace.DreamSmartspaceController;
import com.android.systemui.plugins.BcSmartspaceDataPlugin;
+import com.android.systemui.shared.condition.Monitor;
+import com.android.systemui.util.condition.ConditionalCoreStartable;
import java.util.List;
@@ -61,7 +64,7 @@
* {@link CoreStartable} responsbile for registering {@link SmartSpaceComplication} with
* SystemUI.
*/
- public static class Registrant implements CoreStartable {
+ public static class Registrant extends ConditionalCoreStartable {
private final DreamSmartspaceController mSmartSpaceController;
private final DreamOverlayStateController mDreamOverlayStateController;
private final SmartSpaceComplication mComplication;
@@ -81,14 +84,16 @@
public Registrant(
DreamOverlayStateController dreamOverlayStateController,
SmartSpaceComplication smartSpaceComplication,
- DreamSmartspaceController smartSpaceController) {
+ DreamSmartspaceController smartSpaceController,
+ @Named(DREAM_PRETEXT_MONITOR) Monitor monitor) {
+ super(monitor);
mDreamOverlayStateController = dreamOverlayStateController;
mComplication = smartSpaceComplication;
mSmartSpaceController = smartSpaceController;
}
@Override
- public void start() {
+ public void onStart() {
mDreamOverlayStateController.addCallback(new DreamOverlayStateController.Callback() {
@Override
public void onStateChanged() {
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java
index 7d8389a..3a37c6f 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java
@@ -30,11 +30,18 @@
import com.android.systemui.dreams.complication.dagger.RegisteredComplicationsModule;
import com.android.systemui.dreams.dreamcomplication.dagger.ComplicationComponent;
import com.android.systemui.dreams.touch.scrim.dagger.ScrimModule;
+import com.android.systemui.process.condition.UserProcessCondition;
+import com.android.systemui.shared.condition.Condition;
+import com.android.systemui.shared.condition.Monitor;
+import dagger.Binds;
import dagger.Module;
import dagger.Provides;
+import dagger.multibindings.IntoSet;
import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.Executor;
import javax.inject.Named;
@@ -57,6 +64,8 @@
String DREAM_OVERLAY_ENABLED = "dream_overlay_enabled";
String DREAM_SUPPORTED = "dream_supported";
+ String DREAM_PRETEXT_CONDITIONS = "dream_pretext_conditions";
+ String DREAM_PRETEXT_MONITOR = "dream_prtext_monitor";
/**
* Provides the dream component
@@ -115,4 +124,19 @@
static boolean providesDreamSupported(@Main Resources resources) {
return resources.getBoolean(com.android.internal.R.bool.config_dreamsSupported);
}
+
+ /** */
+ @Binds
+ @IntoSet
+ @Named(DREAM_PRETEXT_CONDITIONS)
+ Condition bindsUserProcessCondition(UserProcessCondition condition);
+
+ /** */
+ @Provides
+ @Named(DREAM_PRETEXT_MONITOR)
+ static Monitor providesDockerPretextMonitor(
+ @Main Executor executor,
+ @Named(DREAM_PRETEXT_CONDITIONS) Set<Condition> pretextConditions) {
+ return new Monitor(executor, pretextConditions);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/process/ProcessWrapper.java b/packages/SystemUI/src/com/android/systemui/process/ProcessWrapper.java
index 7db293d..245cf89 100644
--- a/packages/SystemUI/src/com/android/systemui/process/ProcessWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/process/ProcessWrapper.java
@@ -16,11 +16,16 @@
package com.android.systemui.process;
+import javax.inject.Inject;
+
/**
* A simple wrapper that provides access to process-related details. This facilitates testing by
* providing a mockable target around these details.
*/
public class ProcessWrapper {
+ @Inject
+ public ProcessWrapper() {}
+
public int getUserHandleIdentifier() {
return android.os.Process.myUserHandle().getIdentifier();
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index f53f824..9286d29 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -2144,6 +2144,7 @@
void flingToHeight(float vel, boolean expand, float target,
float collapseSpeedUpFactor, boolean expandBecauseOfFalsing) {
mLastFlingWasExpanding = expand;
+ mShadeLog.logLastFlingWasExpanding(expand);
mHeadsUpTouchHelper.notifyFling(!expand);
mKeyguardStateController.notifyPanelFlingStart(!expand /* flingingToDismiss */);
setClosingWithAlphaFadeout(!expand && !isOnKeyguard() && getFadeoutAlpha() == 1.0f);
@@ -4624,6 +4625,7 @@
ipw.println(mBlockingExpansionForCurrentTouch);
ipw.print("mExpectingSynthesizedDown="); ipw.println(mExpectingSynthesizedDown);
ipw.print("mLastEventSynthesizedDown="); ipw.println(mLastEventSynthesizedDown);
+ ipw.print("mLastFlingWasExpanding="); ipw.println(mLastFlingWasExpanding);
ipw.print("mInterpolatedDarkAmount="); ipw.println(mInterpolatedDarkAmount);
ipw.print("mLinearDarkAmount="); ipw.println(mLinearDarkAmount);
ipw.print("mPulsing="); ipw.println(mPulsing);
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt
index 11617be..26c839de 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt
@@ -20,7 +20,6 @@
import com.android.systemui.log.dagger.ShadeLog
import com.android.systemui.plugins.log.LogBuffer
import com.android.systemui.plugins.log.LogLevel
-import com.android.systemui.plugins.log.LogMessage
import com.google.errorprone.annotations.CompileTimeConstant
import javax.inject.Inject
@@ -234,4 +233,19 @@
}
)
}
+
+ fun logLastFlingWasExpanding(
+ expand: Boolean
+ ) {
+ buffer.log(
+ TAG,
+ LogLevel.VERBOSE,
+ {
+ bool1 = expand
+ },
+ {
+ "NPVC mLastFlingWasExpanding set to: $bool1"
+ }
+ )
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinator.java
index 058042c..0c95eab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinator.java
@@ -71,11 +71,9 @@
* marking them as relevant for setup are allowed to show when device is unprovisioned
*/
private boolean showNotificationEvenIfUnprovisioned(StatusBarNotification sbn) {
- final boolean hasPermission = checkUidPermission(
- Manifest.permission.NOTIFICATION_DURING_SETUP,
- sbn.getUid()) == PackageManager.PERMISSION_GRANTED;
- return hasPermission
- && sbn.getNotification().extras.getBoolean(Notification.EXTRA_ALLOW_DURING_SETUP);
+ // system_server checks the permission so systemui can just check whether the
+ // extra exists
+ return sbn.getNotification().extras.getBoolean(Notification.EXTRA_ALLOW_DURING_SETUP);
}
private int checkUidPermission(String permission, int uid) {
diff --git a/packages/SystemUI/src/com/android/systemui/theme/DynamicColors.kt b/packages/SystemUI/src/com/android/systemui/theme/DynamicColors.kt
new file mode 100644
index 0000000..c1f0c58
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/theme/DynamicColors.kt
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.theme
+
+import android.util.Pair
+import com.android.systemui.monet.dynamiccolor.DynamicColor
+import com.android.systemui.monet.dynamiccolor.MaterialDynamicColors as MDC
+
+class DynamicColors {
+ companion object {
+ @JvmField
+ val ALL_DYNAMIC_COLORS_MAPPED: List<Pair<String, DynamicColor>> =
+ arrayListOf(
+ Pair.create("primary_container", MDC.primaryContainer),
+ Pair.create("on_primary_container", MDC.onPrimaryContainer),
+ Pair.create("primary", MDC.primary),
+ Pair.create("on_primary", MDC.onPrimary),
+ Pair.create("secondary_container", MDC.secondaryContainer),
+ Pair.create("on_secondary_container", MDC.onSecondaryContainer),
+ Pair.create("secondary", MDC.secondary),
+ Pair.create("on_secondary", MDC.onSecondary),
+ Pair.create("tertiary_container", MDC.tertiaryContainer),
+ Pair.create("on_tertiary_container", MDC.onTertiaryContainer),
+ Pair.create("tertiary", MDC.tertiary),
+ Pair.create("on_tertiary", MDC.onTertiary),
+ Pair.create("background", MDC.background),
+ Pair.create("on_background", MDC.onBackground),
+ Pair.create("surface", MDC.surface),
+ Pair.create("on_surface", MDC.onSurface),
+ Pair.create("surface_container_low", MDC.surfaceContainerLow),
+ Pair.create("surface_container_lowest", MDC.surfaceContainerLowest),
+ Pair.create("surface_container", MDC.surfaceContainer),
+ Pair.create("surface_container_high", MDC.surfaceContainerHigh),
+ Pair.create("surface_container_highest", MDC.surfaceContainerHighest),
+ Pair.create("surface_bright", MDC.surfaceBright),
+ Pair.create("surface_dim", MDC.surfaceDim),
+ Pair.create("surface_variant", MDC.surfaceVariant),
+ Pair.create("on_surface_variant", MDC.onSurfaceVariant),
+ Pair.create("outline", MDC.outline),
+ Pair.create("error", MDC.error),
+ Pair.create("on_error", MDC.onError),
+ Pair.create("error_container", MDC.errorContainer),
+ Pair.create("on_error_container", MDC.onErrorContainer),
+ Pair.create("primary_fixed", MDC.primaryFixed),
+ Pair.create("primary_fixed_darker", MDC.primaryFixedDarker),
+ Pair.create("on_primary_fixed", MDC.onPrimaryFixed),
+ Pair.create("on_primary_fixed_variant", MDC.onPrimaryFixedVariant),
+ Pair.create("secondary_fixed", MDC.secondaryFixed),
+ Pair.create("secondary_fixed_darker", MDC.secondaryFixedDarker),
+ Pair.create("on_secondary_fixed", MDC.onSecondaryFixed),
+ Pair.create("on_secondary_fixed_variant", MDC.onSecondaryFixedVariant),
+ Pair.create("tertiary_fixed", MDC.tertiaryFixed),
+ Pair.create("tertiary_fixed_darker", MDC.tertiaryFixedDarker),
+ Pair.create("on_tertiary_fixed", MDC.onTertiaryFixed),
+ Pair.create("on_tertiary_fixed_variant", MDC.onTertiaryFixedVariant),
+ Pair.create("control_activated", MDC.controlActivated),
+ Pair.create("control_normal", MDC.controlNormal),
+ Pair.create("control_highlight", MDC.controlHighlight),
+ Pair.create("text_primary_inverse", MDC.textPrimaryInverse),
+ Pair.create(
+ "text_secondary_and_tertiary_inverse",
+ MDC.textSecondaryAndTertiaryInverse
+ ),
+ Pair.create("text_primary_inverse_disable_only", MDC.textPrimaryInverseDisableOnly),
+ Pair.create(
+ "text_secondary_and_tertiary_inverse_disabled",
+ MDC.textSecondaryAndTertiaryInverseDisabled
+ ),
+ Pair.create("text_hint_inverse", MDC.textHintInverse),
+ Pair.create("palette_key_color_primary", MDC.primaryPaletteKeyColor),
+ Pair.create("palette_key_color_secondary", MDC.secondaryPaletteKeyColor),
+ Pair.create("palette_key_color_tertiary", MDC.tertiaryPaletteKeyColor),
+ Pair.create("palette_key_color_neutral", MDC.neutralPaletteKeyColor),
+ Pair.create("palette_key_color_neutral_variant", MDC.neutralVariantPaletteKeyColor)
+ )
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java
index ba39367..3376e23 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java
@@ -65,6 +65,8 @@
@VisibleForTesting
static final String SYSUI_PACKAGE = "com.android.systemui";
+ static final String OVERLAY_CATEGORY_DYNAMIC_COLOR =
+ "android.theme.customization.dynamic_color";
static final String OVERLAY_CATEGORY_ACCENT_COLOR =
"android.theme.customization.accent_color";
static final String OVERLAY_CATEGORY_SYSTEM_PALETTE =
@@ -117,6 +119,7 @@
OVERLAY_CATEGORY_SHAPE,
OVERLAY_CATEGORY_FONT,
OVERLAY_CATEGORY_ACCENT_COLOR,
+ OVERLAY_CATEGORY_DYNAMIC_COLOR,
OVERLAY_CATEGORY_ICON_ANDROID,
OVERLAY_CATEGORY_ICON_SYSUI,
OVERLAY_CATEGORY_ICON_SETTINGS,
@@ -127,6 +130,7 @@
static final Set<String> SYSTEM_USER_CATEGORIES = Sets.newHashSet(
OVERLAY_CATEGORY_SYSTEM_PALETTE,
OVERLAY_CATEGORY_ACCENT_COLOR,
+ OVERLAY_CATEGORY_DYNAMIC_COLOR,
OVERLAY_CATEGORY_FONT,
OVERLAY_CATEGORY_SHAPE,
OVERLAY_CATEGORY_ICON_ANDROID,
@@ -153,6 +157,7 @@
mThemePickerPackage = themePickerPackage;
mTargetPackageToCategories.put(ANDROID_PACKAGE, Sets.newHashSet(
OVERLAY_CATEGORY_SYSTEM_PALETTE, OVERLAY_CATEGORY_ACCENT_COLOR,
+ OVERLAY_CATEGORY_DYNAMIC_COLOR,
OVERLAY_CATEGORY_FONT, OVERLAY_CATEGORY_SHAPE,
OVERLAY_CATEGORY_ICON_ANDROID));
mTargetPackageToCategories.put(SYSUI_PACKAGE,
@@ -164,6 +169,7 @@
mTargetPackageToCategories.put(mThemePickerPackage,
Sets.newHashSet(OVERLAY_CATEGORY_ICON_THEME_PICKER));
mCategoryToTargetPackage.put(OVERLAY_CATEGORY_ACCENT_COLOR, ANDROID_PACKAGE);
+ mCategoryToTargetPackage.put(OVERLAY_CATEGORY_DYNAMIC_COLOR, ANDROID_PACKAGE);
mCategoryToTargetPackage.put(OVERLAY_CATEGORY_FONT, ANDROID_PACKAGE);
mCategoryToTargetPackage.put(OVERLAY_CATEGORY_SHAPE, ANDROID_PACKAGE);
mCategoryToTargetPackage.put(OVERLAY_CATEGORY_ICON_ANDROID, ANDROID_PACKAGE);
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index 6b507ba..2ad3558 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -15,11 +15,14 @@
*/
package com.android.systemui.theme;
+import static android.util.TypedValue.TYPE_INT_COLOR_ARGB8;
+
import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASLEEP;
import static com.android.systemui.theme.ThemeOverlayApplier.COLOR_SOURCE_HOME;
import static com.android.systemui.theme.ThemeOverlayApplier.COLOR_SOURCE_LOCK;
import static com.android.systemui.theme.ThemeOverlayApplier.COLOR_SOURCE_PRESET;
import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_ACCENT_COLOR;
+import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_DYNAMIC_COLOR;
import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_SYSTEM_PALETTE;
import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_COLOR_BOTH;
import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_COLOR_INDEX;
@@ -51,7 +54,7 @@
import android.util.Log;
import android.util.SparseArray;
import android.util.SparseIntArray;
-import android.util.TypedValue;
+import android.view.accessibility.AccessibilityManager;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
@@ -70,6 +73,16 @@
import com.android.systemui.monet.ColorScheme;
import com.android.systemui.monet.Style;
import com.android.systemui.monet.TonalPalette;
+import com.android.systemui.monet.dynamiccolor.MaterialDynamicColors;
+import com.android.systemui.monet.hct.Hct;
+import com.android.systemui.monet.scheme.DynamicScheme;
+import com.android.systemui.monet.scheme.SchemeExpressive;
+import com.android.systemui.monet.scheme.SchemeFruitSalad;
+import com.android.systemui.monet.scheme.SchemeMonochrome;
+import com.android.systemui.monet.scheme.SchemeNeutral;
+import com.android.systemui.monet.scheme.SchemeRainbow;
+import com.android.systemui.monet.scheme.SchemeTonalSpot;
+import com.android.systemui.monet.scheme.SchemeVibrant;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
@@ -105,9 +118,6 @@
protected static final String TAG = "ThemeOverlayController";
private static final boolean DEBUG = true;
- protected static final int NEUTRAL = 0;
- protected static final int ACCENT = 1;
-
private final ThemeOverlayApplier mThemeManager;
private final UserManager mUserManager;
private final BroadcastDispatcher mBroadcastDispatcher;
@@ -130,12 +140,17 @@
private boolean mNeedsOverlayCreation;
// Dominant color extracted from wallpaper, NOT the color used on the overlay
protected int mMainWallpaperColor = Color.TRANSPARENT;
+ // UI contrast as reported by AccessibilityManager
+ private float mUiContrast = 0;
// Theme variant: Vibrant, Tonal, Expressive, etc
- private Style mThemeStyle = Style.TONAL_SPOT;
+ @VisibleForTesting
+ protected Style mThemeStyle = Style.TONAL_SPOT;
// Accent colors overlay
private FabricatedOverlay mSecondaryOverlay;
// Neutral system colors overlay
private FabricatedOverlay mNeutralOverlay;
+ // Dynamic colors overlay
+ private FabricatedOverlay mDynamicOverlay;
// If wallpaper color event will be accepted and change the UI colors.
private boolean mAcceptColorEvents = true;
// If non-null (per user), colors that were sent to the framework, and processing was deferred
@@ -143,6 +158,9 @@
private final SparseArray<WallpaperColors> mDeferredWallpaperColors = new SparseArray<>();
private final SparseIntArray mDeferredWallpaperColorsFlags = new SparseIntArray();
private final WakefulnessLifecycle mWakefulnessLifecycle;
+ private final AccessibilityManager mAccessibilityManager;
+ private DynamicScheme mDynamicSchemeDark;
+ private DynamicScheme mDynamicSchemeLight;
// Defers changing themes until Setup Wizard is done.
private boolean mDeferredThemeEvaluation;
@@ -304,6 +322,7 @@
mSkipSettingChange = true;
if (jsonObject.has(OVERLAY_CATEGORY_ACCENT_COLOR) || jsonObject.has(
OVERLAY_CATEGORY_SYSTEM_PALETTE)) {
+ jsonObject.remove(OVERLAY_CATEGORY_DYNAMIC_COLOR);
jsonObject.remove(OVERLAY_CATEGORY_ACCENT_COLOR);
jsonObject.remove(OVERLAY_CATEGORY_SYSTEM_PALETTE);
jsonObject.remove(OVERLAY_COLOR_INDEX);
@@ -372,7 +391,8 @@
DumpManager dumpManager,
FeatureFlags featureFlags,
@Main Resources resources,
- WakefulnessLifecycle wakefulnessLifecycle) {
+ WakefulnessLifecycle wakefulnessLifecycle,
+ AccessibilityManager accessibilityManager) {
mContext = context;
mIsMonochromaticEnabled = featureFlags.isEnabled(Flags.MONOCHROMATIC_THEME);
mIsMonetEnabled = featureFlags.isEnabled(Flags.MONET);
@@ -388,6 +408,7 @@
mUserTracker = userTracker;
mResources = resources;
mWakefulnessLifecycle = wakefulnessLifecycle;
+ mAccessibilityManager = accessibilityManager;
dumpManager.registerDumpable(TAG, this);
}
@@ -424,6 +445,12 @@
}
},
UserHandle.USER_ALL);
+ mUiContrast = mAccessibilityManager.getUiContrast();
+ mAccessibilityManager.addUiContrastChangeListener(mMainExecutor, uiContrast -> {
+ mUiContrast = uiContrast;
+ // Force reload so that we update even when the main color has not changed
+ reevaluateSystemTheme(true /* forceReload */);
+ });
if (!mIsMonetEnabled) {
return;
@@ -496,12 +523,11 @@
if (mIsMonetEnabled) {
mThemeStyle = fetchThemeStyleFromSetting();
- mSecondaryOverlay = getOverlay(mMainWallpaperColor, ACCENT, mThemeStyle);
- mNeutralOverlay = getOverlay(mMainWallpaperColor, NEUTRAL, mThemeStyle);
+ createOverlays(mMainWallpaperColor);
mNeedsOverlayCreation = true;
if (DEBUG) {
Log.d(TAG, "fetched overlays. accent: " + mSecondaryOverlay
- + " neutral: " + mNeutralOverlay);
+ + " neutral: " + mNeutralOverlay + " dynamic: " + mDynamicOverlay);
}
}
@@ -519,42 +545,95 @@
return ColorScheme.getSeedColor(wallpaperColors);
}
- /**
- * Given a color candidate, return an overlay definition.
- */
- protected FabricatedOverlay getOverlay(int color, int type, Style style) {
- boolean nightMode = (mResources.getConfiguration().uiMode
- & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES;
-
- mColorScheme = new ColorScheme(color, nightMode, style);
- String name = type == ACCENT ? "accent" : "neutral";
-
- FabricatedOverlay.Builder overlay =
- new FabricatedOverlay.Builder("com.android.systemui", name, "android");
-
- if (type == ACCENT) {
- assignTonalPaletteToOverlay("accent1", overlay, mColorScheme.getAccent1());
- assignTonalPaletteToOverlay("accent2", overlay, mColorScheme.getAccent2());
- assignTonalPaletteToOverlay("accent3", overlay, mColorScheme.getAccent3());
- } else {
- assignTonalPaletteToOverlay("neutral1", overlay, mColorScheme.getNeutral1());
- assignTonalPaletteToOverlay("neutral2", overlay, mColorScheme.getNeutral2());
+ private static DynamicScheme dynamicSchemeFromStyle(Style style, int color,
+ boolean isDark, double contrastLevel) {
+ Hct sourceColorHct = Hct.fromInt(color);
+ switch (style) {
+ case EXPRESSIVE:
+ return new SchemeExpressive(sourceColorHct, isDark, contrastLevel);
+ case SPRITZ:
+ return new SchemeNeutral(sourceColorHct, isDark, contrastLevel);
+ case TONAL_SPOT:
+ return new SchemeTonalSpot(sourceColorHct, isDark, contrastLevel);
+ case FRUIT_SALAD:
+ return new SchemeFruitSalad(sourceColorHct, isDark, contrastLevel);
+ case RAINBOW:
+ return new SchemeRainbow(sourceColorHct, isDark, contrastLevel);
+ case VIBRANT:
+ return new SchemeVibrant(sourceColorHct, isDark, contrastLevel);
+ case MONOCHROMATIC:
+ return new SchemeMonochrome(sourceColorHct, isDark, contrastLevel);
+ default:
+ return null;
}
-
- return overlay.build();
}
- private void assignTonalPaletteToOverlay(String name,
- FabricatedOverlay.Builder overlay, TonalPalette tonalPalette) {
+ @VisibleForTesting
+ protected boolean isNightMode() {
+ return (mResources.getConfiguration().uiMode
+ & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES;
+ }
+ @VisibleForTesting
+ protected FabricatedOverlay newFabricatedOverlay(String name) {
+ return new FabricatedOverlay.Builder("com.android.systemui", name, "android").build();
+ }
+
+ private void createOverlays(int color) {
+ boolean nightMode = isNightMode();
+ mColorScheme = new ColorScheme(color, nightMode, mThemeStyle);
+ mNeutralOverlay = createNeutralOverlay();
+ mSecondaryOverlay = createAccentOverlay();
+
+ mDynamicSchemeDark = dynamicSchemeFromStyle(
+ mThemeStyle, color, true /* isDark */, mUiContrast);
+ mDynamicSchemeLight = dynamicSchemeFromStyle(
+ mThemeStyle, color, false /* isDark */, mUiContrast);
+ mDynamicOverlay = createDynamicOverlay();
+ }
+
+ protected FabricatedOverlay createNeutralOverlay() {
+ FabricatedOverlay overlay = newFabricatedOverlay("neutral");
+ assignTonalPaletteToOverlay("neutral1", overlay, mColorScheme.getNeutral1());
+ assignTonalPaletteToOverlay("neutral2", overlay, mColorScheme.getNeutral2());
+ return overlay;
+ }
+
+ protected FabricatedOverlay createAccentOverlay() {
+ FabricatedOverlay overlay = newFabricatedOverlay("accent");
+ assignTonalPaletteToOverlay("accent1", overlay, mColorScheme.getAccent1());
+ assignTonalPaletteToOverlay("accent2", overlay, mColorScheme.getAccent2());
+ assignTonalPaletteToOverlay("accent3", overlay, mColorScheme.getAccent3());
+ return overlay;
+ }
+
+ private void assignTonalPaletteToOverlay(String name, FabricatedOverlay overlay,
+ TonalPalette tonalPalette) {
String resourcePrefix = "android:color/system_" + name;
- int colorDataType = TypedValue.TYPE_INT_COLOR_ARGB8;
tonalPalette.getAllShadesMapped().forEach((key, value) -> {
String resourceName = resourcePrefix + "_" + key;
int colorValue = ColorUtils.setAlphaComponent(value, 0xFF);
- overlay.setResourceValue(resourceName, colorDataType,
- colorValue);
+ overlay.setResourceValue(resourceName, TYPE_INT_COLOR_ARGB8, colorValue,
+ null /* configuration */);
+ });
+ }
+
+ protected FabricatedOverlay createDynamicOverlay() {
+ FabricatedOverlay overlay = newFabricatedOverlay("dynamic");
+ assignDynamicPaletteToOverlay(overlay, true /* isDark */);
+ assignDynamicPaletteToOverlay(overlay, false /* isDark */);
+ return overlay;
+ }
+
+ private void assignDynamicPaletteToOverlay(FabricatedOverlay overlay, boolean isDark) {
+ String suffix = isDark ? "dark" : "light";
+ DynamicScheme scheme = isDark ? mDynamicSchemeDark : mDynamicSchemeLight;
+ DynamicColors.ALL_DYNAMIC_COLORS_MAPPED.forEach(p -> {
+ String resourceName = "android:color/system_" + p.first + "_" + suffix;
+ int colorValue = p.second.getArgb(scheme);
+ overlay.setResourceValue(resourceName, TYPE_INT_COLOR_ARGB8, colorValue,
+ null /* configuration */);
});
}
@@ -568,16 +647,21 @@
for (UserHandle userHandle : allProfiles) {
Resources res = userHandle.isSystem()
? mResources : mContext.createContextAsUser(userHandle, 0).getResources();
- if (!(res.getColor(android.R.color.system_accent1_500, mContext.getTheme())
+ Resources.Theme theme = mContext.getTheme();
+ if (!(res.getColor(android.R.color.system_accent1_500, theme)
== mColorScheme.getAccent1().getS500()
- && res.getColor(android.R.color.system_accent2_500, mContext.getTheme())
+ && res.getColor(android.R.color.system_accent2_500, theme)
== mColorScheme.getAccent2().getS500()
- && res.getColor(android.R.color.system_accent3_500, mContext.getTheme())
+ && res.getColor(android.R.color.system_accent3_500, theme)
== mColorScheme.getAccent3().getS500()
- && res.getColor(android.R.color.system_neutral1_500, mContext.getTheme())
+ && res.getColor(android.R.color.system_neutral1_500, theme)
== mColorScheme.getNeutral1().getS500()
- && res.getColor(android.R.color.system_neutral2_500, mContext.getTheme())
- == mColorScheme.getNeutral2().getS500())) {
+ && res.getColor(android.R.color.system_neutral2_500, theme)
+ == mColorScheme.getNeutral2().getS500()
+ && res.getColor(android.R.color.system_primary_container_dark, theme)
+ == MaterialDynamicColors.primaryContainer.getArgb(mDynamicSchemeDark)
+ && res.getColor(android.R.color.system_primary_container_light, theme)
+ == MaterialDynamicColors.primaryContainer.getArgb(mDynamicSchemeLight))) {
return false;
}
}
@@ -614,12 +698,11 @@
if (!colorString.startsWith("#")) {
colorString = "#" + colorString;
}
- int color = Color.parseColor(colorString);
- mNeutralOverlay = getOverlay(color, NEUTRAL, mThemeStyle);
- mSecondaryOverlay = getOverlay(color, ACCENT, mThemeStyle);
+ createOverlays(Color.parseColor(colorString));
mNeedsOverlayCreation = true;
categoryToPackage.remove(OVERLAY_CATEGORY_SYSTEM_PALETTE);
categoryToPackage.remove(OVERLAY_CATEGORY_ACCENT_COLOR);
+ categoryToPackage.remove(OVERLAY_CATEGORY_DYNAMIC_COLOR);
} catch (Exception e) {
// Color.parseColor doesn't catch any exceptions from the calls it makes
Log.w(TAG, "Invalid color definition: " + systemPalette.getPackageName(), e);
@@ -631,6 +714,7 @@
// fail.
categoryToPackage.remove(OVERLAY_CATEGORY_SYSTEM_PALETTE);
categoryToPackage.remove(OVERLAY_CATEGORY_ACCENT_COLOR);
+ categoryToPackage.remove(OVERLAY_CATEGORY_DYNAMIC_COLOR);
} catch (NumberFormatException e) {
// This is a package name. All good, let's continue
}
@@ -647,6 +731,10 @@
&& mSecondaryOverlay != null) {
categoryToPackage.put(OVERLAY_CATEGORY_ACCENT_COLOR, mSecondaryOverlay.getIdentifier());
}
+ if (!categoryToPackage.containsKey(OVERLAY_CATEGORY_DYNAMIC_COLOR)
+ && mDynamicOverlay != null) {
+ categoryToPackage.put(OVERLAY_CATEGORY_DYNAMIC_COLOR, mDynamicOverlay.getIdentifier());
+ }
Set<UserHandle> managedProfiles = new HashSet<>();
for (UserInfo userInfo : mUserManager.getEnabledProfiles(currentUser)) {
@@ -668,7 +756,7 @@
if (mNeedsOverlayCreation) {
mNeedsOverlayCreation = false;
mThemeManager.applyCurrentUserOverlays(categoryToPackage, new FabricatedOverlay[]{
- mSecondaryOverlay, mNeutralOverlay
+ mSecondaryOverlay, mNeutralOverlay, mDynamicOverlay
}, currentUser, managedProfiles);
} else {
mThemeManager.applyCurrentUserOverlays(categoryToPackage, null, currentUser,
@@ -710,6 +798,7 @@
pw.println("mMainWallpaperColor=" + Integer.toHexString(mMainWallpaperColor));
pw.println("mSecondaryOverlay=" + mSecondaryOverlay);
pw.println("mNeutralOverlay=" + mNeutralOverlay);
+ pw.println("mDynamicOverlay=" + mDynamicOverlay);
pw.println("mIsMonetEnabled=" + mIsMonetEnabled);
pw.println("mColorScheme=" + mColorScheme);
pw.println("mNeedsOverlayCreation=" + mNeedsOverlayCreation);
diff --git a/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt b/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt
index 5cf01af..70523bb 100644
--- a/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt
@@ -47,12 +47,14 @@
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
@@ -123,9 +125,25 @@
featureFlags: FeatureFlags,
) : UserRepository {
- private val _userSwitcherSettings = MutableStateFlow(runBlocking { getSettings() })
- override val userSwitcherSettings: Flow<UserSwitcherSettingsModel> =
- _userSwitcherSettings.asStateFlow().filterNotNull()
+ private val _userSwitcherSettings: StateFlow<UserSwitcherSettingsModel> =
+ globalSettings
+ .observerFlow(
+ names =
+ arrayOf(
+ SETTING_SIMPLE_USER_SWITCHER,
+ Settings.Global.ADD_USERS_WHEN_LOCKED,
+ Settings.Global.USER_SWITCHER_ENABLED,
+ ),
+ userId = UserHandle.USER_SYSTEM,
+ )
+ .onStart { emit(Unit) } // Forces an initial update.
+ .map { getSettings() }
+ .stateIn(
+ scope = applicationScope,
+ started = SharingStarted.Eagerly,
+ initialValue = runBlocking { getSettings() },
+ )
+ override val userSwitcherSettings: Flow<UserSwitcherSettingsModel> = _userSwitcherSettings
private val _userInfos = MutableStateFlow<List<UserInfo>?>(null)
override val userInfos: Flow<List<UserInfo>> = _userInfos.filterNotNull()
@@ -159,7 +177,6 @@
init {
observeSelectedUser()
- observeUserSettings()
if (featureFlags.isEnabled(FACE_AUTH_REFACTOR)) {
observeUserSwitching()
}
@@ -247,23 +264,6 @@
.launchIn(applicationScope)
}
- private fun observeUserSettings() {
- globalSettings
- .observerFlow(
- names =
- arrayOf(
- SETTING_SIMPLE_USER_SWITCHER,
- Settings.Global.ADD_USERS_WHEN_LOCKED,
- Settings.Global.USER_SWITCHER_ENABLED,
- ),
- userId = UserHandle.USER_SYSTEM,
- )
- .onStart { emit(Unit) } // Forces an initial update.
- .map { getSettings() }
- .onEach { _userSwitcherSettings.value = it }
- .launchIn(applicationScope)
- }
-
private suspend fun getSettings(): UserSwitcherSettingsModel {
return withContext(backgroundDispatcher) {
val isSimpleUserSwitcher =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationTypesUpdaterTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationTypesUpdaterTest.java
index 9f4a7c8..b9db9c4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationTypesUpdaterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationTypesUpdaterTest.java
@@ -33,6 +33,7 @@
import com.android.settingslib.dream.DreamBackend;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dreams.DreamOverlayStateController;
+import com.android.systemui.shared.condition.Monitor;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.settings.SecureSettings;
import com.android.systemui.util.time.FakeSystemClock;
@@ -66,13 +67,16 @@
private ComplicationTypesUpdater mController;
+ @Mock
+ private Monitor mMonitor;
+
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
when(mDreamBackend.getEnabledComplications()).thenReturn(new HashSet<>());
mController = new ComplicationTypesUpdater(mDreamBackend, mExecutor,
- mSecureSettings, mDreamOverlayStateController);
+ mSecureSettings, mDreamOverlayStateController, mMonitor);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockTimeComplicationTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockTimeComplicationTest.java
index ec448f9..52aaea1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockTimeComplicationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockTimeComplicationTest.java
@@ -30,6 +30,7 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dreams.DreamOverlayStateController;
+import com.android.systemui.shared.condition.Monitor;
import org.junit.Before;
import org.junit.Test;
@@ -69,6 +70,9 @@
@Mock
private ComplicationLayoutParams mLayoutParams;
+ @Mock
+ private Monitor mMonitor;
+
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
@@ -83,7 +87,8 @@
final DreamClockTimeComplication.Registrant registrant =
new DreamClockTimeComplication.Registrant(
mDreamOverlayStateController,
- mComplication);
+ mComplication,
+ mMonitor);
registrant.start();
verify(mDreamOverlayStateController).addComplication(eq(mComplication));
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamHomeControlsComplicationTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamHomeControlsComplicationTest.java
index a4cf15c..fc1d38b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamHomeControlsComplicationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamHomeControlsComplicationTest.java
@@ -46,6 +46,7 @@
import com.android.systemui.dreams.DreamOverlayStateController;
import com.android.systemui.dreams.complication.dagger.DreamHomeControlsComplicationComponent;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.shared.condition.Monitor;
import org.junit.Before;
import org.junit.Test;
@@ -101,6 +102,9 @@
@Captor
private ArgumentCaptor<DreamOverlayStateController.Callback> mStateCallbackCaptor;
+ @Mock
+ private Monitor mMonitor;
+
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
@@ -126,7 +130,7 @@
public void complicationAvailability_serviceNotAvailable_noFavorites_doNotAddComplication() {
final DreamHomeControlsComplication.Registrant registrant =
new DreamHomeControlsComplication.Registrant(mComplication,
- mDreamOverlayStateController, mControlsComponent);
+ mDreamOverlayStateController, mControlsComponent, mMonitor);
registrant.start();
setHaveFavorites(false);
@@ -139,7 +143,7 @@
public void complicationAvailability_serviceAvailable_noFavorites_doNotAddComplication() {
final DreamHomeControlsComplication.Registrant registrant =
new DreamHomeControlsComplication.Registrant(mComplication,
- mDreamOverlayStateController, mControlsComponent);
+ mDreamOverlayStateController, mControlsComponent, mMonitor);
registrant.start();
setHaveFavorites(false);
@@ -152,7 +156,7 @@
public void complicationAvailability_serviceAvailable_noFavorites_panel_addComplication() {
final DreamHomeControlsComplication.Registrant registrant =
new DreamHomeControlsComplication.Registrant(mComplication,
- mDreamOverlayStateController, mControlsComponent);
+ mDreamOverlayStateController, mControlsComponent, mMonitor);
registrant.start();
setHaveFavorites(false);
@@ -165,7 +169,7 @@
public void complicationAvailability_serviceNotAvailable_haveFavorites_doNotAddComplication() {
final DreamHomeControlsComplication.Registrant registrant =
new DreamHomeControlsComplication.Registrant(mComplication,
- mDreamOverlayStateController, mControlsComponent);
+ mDreamOverlayStateController, mControlsComponent, mMonitor);
registrant.start();
setHaveFavorites(true);
@@ -178,7 +182,7 @@
public void complicationAvailability_serviceAvailable_haveFavorites_addComplication() {
final DreamHomeControlsComplication.Registrant registrant =
new DreamHomeControlsComplication.Registrant(mComplication,
- mDreamOverlayStateController, mControlsComponent);
+ mDreamOverlayStateController, mControlsComponent, mMonitor);
registrant.start();
setHaveFavorites(true);
@@ -191,7 +195,7 @@
public void complicationAvailability_checkAvailabilityWhenDreamOverlayBecomesActive() {
final DreamHomeControlsComplication.Registrant registrant =
new DreamHomeControlsComplication.Registrant(mComplication,
- mDreamOverlayStateController, mControlsComponent);
+ mDreamOverlayStateController, mControlsComponent, mMonitor);
registrant.start();
setServiceAvailable(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/SmartSpaceComplicationTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/SmartSpaceComplicationTest.java
index c8b2b25..77ca958 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/SmartSpaceComplicationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/SmartSpaceComplicationTest.java
@@ -33,6 +33,8 @@
import com.android.systemui.dreams.DreamOverlayStateController;
import com.android.systemui.dreams.smartspace.DreamSmartspaceController;
import com.android.systemui.plugins.BcSmartspaceDataPlugin;
+import com.android.systemui.shared.condition.Condition;
+import com.android.systemui.shared.condition.Monitor;
import org.junit.Before;
import org.junit.Test;
@@ -43,6 +45,8 @@
import org.mockito.MockitoAnnotations;
import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@@ -60,6 +64,11 @@
@Mock
private View mBcSmartspaceView;
+ @Mock
+ private Monitor mMonitor;
+
+ private final Set<Condition> mPreconditions = new HashSet<>();
+
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
@@ -79,7 +88,8 @@
return new SmartSpaceComplication.Registrant(
mDreamOverlayStateController,
mComplication,
- mSmartspaceController);
+ mSmartspaceController,
+ mMonitor);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinatorTest.java
index 701cf95..af52459 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinatorTest.java
@@ -117,10 +117,6 @@
extras.putBoolean(SHOW_WHEN_UNPROVISIONED_FLAG, true);
mNotification.extras = extras;
- // GIVEN notification has the permission to display during setup
- when(mIPackageManager.checkUidPermission(SETUP_NOTIF_PERMISSION, NOTIF_UID))
- .thenReturn(PackageManager.PERMISSION_GRANTED);
-
// THEN don't filter out the notification
assertFalse(mDeviceProvisionedFilter.shouldFilterOut(mEntry, 0));
}
@@ -130,15 +126,10 @@
// GIVEN device is unprovisioned
when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(false);
- // GIVEN notification has a flag to allow the notification during setup
+ // GIVEN notification does not have the flag to allow the notification during setup
Bundle extras = new Bundle();
- extras.putBoolean(SHOW_WHEN_UNPROVISIONED_FLAG, true);
mNotification.extras = extras;
- // GIVEN notification does NOT have permission to display during setup
- when(mIPackageManager.checkUidPermission(SETUP_NOTIF_PERMISSION, NOTIF_UID))
- .thenReturn(PackageManager.PERMISSION_DENIED);
-
// THEN filter out the notification
assertTrue(mDeviceProvisionedFilter.shouldFilterOut(mEntry, 0));
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayApplierTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayApplierTest.java
index 3032ff1f..83439f0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayApplierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayApplierTest.java
@@ -17,6 +17,7 @@
import static com.android.systemui.theme.ThemeOverlayApplier.ANDROID_PACKAGE;
import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_ACCENT_COLOR;
+import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_DYNAMIC_COLOR;
import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_FONT;
import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_ICON_ANDROID;
import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_ICON_LAUNCHER;
@@ -113,6 +114,8 @@
};
when(mOverlayManager.getOverlayInfosForTarget(ANDROID_PACKAGE, UserHandle.SYSTEM))
.thenReturn(Lists.newArrayList(
+ createOverlayInfo(TEST_DISABLED_PREFIX + OVERLAY_CATEGORY_DYNAMIC_COLOR,
+ ANDROID_PACKAGE, OVERLAY_CATEGORY_DYNAMIC_COLOR, false),
createOverlayInfo(TEST_DISABLED_PREFIX + OVERLAY_CATEGORY_ACCENT_COLOR,
ANDROID_PACKAGE, OVERLAY_CATEGORY_ACCENT_COLOR, false),
createOverlayInfo(TEST_DISABLED_PREFIX + OVERLAY_CATEGORY_SYSTEM_PALETTE,
@@ -123,6 +126,8 @@
ANDROID_PACKAGE, OVERLAY_CATEGORY_SHAPE, false),
createOverlayInfo(TEST_DISABLED_PREFIX + OVERLAY_CATEGORY_ICON_ANDROID,
ANDROID_PACKAGE, OVERLAY_CATEGORY_ICON_ANDROID, false),
+ createOverlayInfo(TEST_ENABLED_PREFIX + OVERLAY_CATEGORY_DYNAMIC_COLOR,
+ ANDROID_PACKAGE, OVERLAY_CATEGORY_DYNAMIC_COLOR, true),
createOverlayInfo(TEST_ENABLED_PREFIX + OVERLAY_CATEGORY_ACCENT_COLOR,
ANDROID_PACKAGE, OVERLAY_CATEGORY_ACCENT_COLOR, true),
createOverlayInfo(TEST_ENABLED_PREFIX + OVERLAY_CATEGORY_SYSTEM_PALETTE,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
index 1710709..f9b5767 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
@@ -47,8 +47,9 @@
import android.os.UserManager;
import android.provider.Settings;
import android.testing.AndroidTestingRunner;
+import android.view.accessibility.AccessibilityManager;
-import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -57,7 +58,6 @@
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.WakefulnessLifecycle;
-import com.android.systemui.monet.ColorScheme;
import com.android.systemui.monet.Style;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
@@ -115,6 +115,8 @@
private Resources mResources;
@Mock
private WakefulnessLifecycle mWakefulnessLifecycle;
+ @Mock
+ private AccessibilityManager mAccessibilityManager;
@Captor
private ArgumentCaptor<BroadcastReceiver> mBroadcastReceiver;
@Captor
@@ -127,13 +129,13 @@
private ArgumentCaptor<UserTracker.Callback> mUserTrackerCallback;
@Captor
private ArgumentCaptor<ContentObserver> mSettingsObserver;
- private Style mCurrentStyle;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
when(mFeatureFlags.isEnabled(Flags.MONET)).thenReturn(true);
when(mWakefulnessLifecycle.getWakefulness()).thenReturn(WAKEFULNESS_AWAKE);
+ when(mAccessibilityManager.getUiContrast()).thenReturn(0.5f);
when(mDeviceProvisionedController.isCurrentUserSetup()).thenReturn(true);
when(mResources.getColor(eq(android.R.color.system_accent1_500), any()))
.thenReturn(Color.RED);
@@ -148,15 +150,19 @@
mThemeOverlayController = new ThemeOverlayController(mContext,
mBroadcastDispatcher, mBgHandler, mMainExecutor, mBgExecutor, mThemeOverlayApplier,
mSecureSettings, mWallpaperManager, mUserManager, mDeviceProvisionedController,
- mUserTracker, mDumpManager, mFeatureFlags, mResources, mWakefulnessLifecycle) {
- @Nullable
- @Override
- protected FabricatedOverlay getOverlay(int color, int type, Style style) {
+ mUserTracker, mDumpManager, mFeatureFlags, mResources, mWakefulnessLifecycle,
+ mAccessibilityManager) {
+ @VisibleForTesting
+ protected boolean isNightMode() {
+ return false;
+ }
+
+ @VisibleForTesting
+ protected FabricatedOverlay newFabricatedOverlay(String name) {
FabricatedOverlay overlay = mock(FabricatedOverlay.class);
when(overlay.getIdentifier())
- .thenReturn(new OverlayIdentifier(Integer.toHexString(color | 0xff000000)));
- mCurrentStyle = style;
- mColorScheme = new ColorScheme(color, false /* nightMode */, style);
+ .thenReturn(new OverlayIdentifier(
+ Integer.toHexString(mColorScheme.getSeed() | 0xff000000)));
return overlay;
}
};
@@ -416,7 +422,7 @@
mSettingsObserver.getValue().onChange(true, null, 0, mUserTracker.getUserId());
- assertThat(mCurrentStyle).isEqualTo(style);
+ assertThat(mThemeOverlayController.mThemeStyle).isEqualTo(style);
}
}
@@ -432,7 +438,7 @@
mSettingsObserver.getValue().onChange(true, null, 0, mUserTracker.getUserId());
- assertThat(mCurrentStyle).isEqualTo(Style.TONAL_SPOT);
+ assertThat(mThemeOverlayController.mThemeStyle).isEqualTo(Style.TONAL_SPOT);
}
@Test
@@ -726,17 +732,20 @@
mThemeOverlayController = new ThemeOverlayController(mContext,
mBroadcastDispatcher, mBgHandler, executor, executor, mThemeOverlayApplier,
mSecureSettings, mWallpaperManager, mUserManager, mDeviceProvisionedController,
- mUserTracker, mDumpManager, mFeatureFlags, mResources, mWakefulnessLifecycle) {
- @Nullable
- @Override
- protected FabricatedOverlay getOverlay(int color, int type, Style style) {
+ mUserTracker, mDumpManager, mFeatureFlags, mResources, mWakefulnessLifecycle,
+ mAccessibilityManager) {
+ @VisibleForTesting
+ protected boolean isNightMode() {
+ return false;
+ }
+
+ @VisibleForTesting
+ protected FabricatedOverlay newFabricatedOverlay(String name) {
FabricatedOverlay overlay = mock(FabricatedOverlay.class);
when(overlay.getIdentifier())
.thenReturn(new OverlayIdentifier("com.thebest.livewallpaperapp.ever"));
- mColorScheme = new ColorScheme(color, false /* nightMode */, style);
return overlay;
}
-
};
mThemeOverlayController.start();
@@ -763,14 +772,19 @@
mThemeOverlayController = new ThemeOverlayController(mContext,
mBroadcastDispatcher, mBgHandler, executor, executor, mThemeOverlayApplier,
mSecureSettings, mWallpaperManager, mUserManager, mDeviceProvisionedController,
- mUserTracker, mDumpManager, mFeatureFlags, mResources, mWakefulnessLifecycle) {
- @Nullable
- @Override
- protected FabricatedOverlay getOverlay(int color, int type, Style style) {
+ mUserTracker, mDumpManager, mFeatureFlags, mResources, mWakefulnessLifecycle,
+ mAccessibilityManager) {
+ @VisibleForTesting
+ protected boolean isNightMode() {
+ return false;
+ }
+
+ @VisibleForTesting
+ protected FabricatedOverlay newFabricatedOverlay(String name) {
FabricatedOverlay overlay = mock(FabricatedOverlay.class);
when(overlay.getIdentifier())
- .thenReturn(new OverlayIdentifier(Integer.toHexString(color | 0xff000000)));
- mColorScheme = new ColorScheme(color, false /* nightMode */, style);
+ .thenReturn(new OverlayIdentifier(
+ Integer.toHexString(mColorScheme.getSeed() | 0xff000000)));
return overlay;
}
};
diff --git a/services/Android.bp b/services/Android.bp
index 3f3ba06..f8097ec 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -191,6 +191,10 @@
"service-sdksandbox.stubs.system_server",
],
+ vintf_fragments: [
+ "manifest_services.xml",
+ ],
+
// Uncomment to enable output of certain warnings (deprecated, unchecked)
//javacflags: ["-Xlint"],
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index d3593f0..03cf9b4 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -4384,9 +4384,8 @@
private final Uri mMagnificationFollowTypingUri = Settings.Secure.getUriFor(
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_FOLLOW_TYPING_ENABLED);
- // TODO: replace name with Settings Secure Key
private final Uri mAlwaysOnMagnificationUri = Settings.Secure.getUriFor(
- "accessibility_magnification_always_on_enabled");
+ Settings.Secure.ACCESSIBILITY_MAGNIFICATION_ALWAYS_ON_ENABLED);
private final Uri mUiContrastUri = Settings.Secure.getUriFor(
CONTRAST_LEVEL);
@@ -4620,10 +4619,9 @@
}
boolean readAlwaysOnMagnificationLocked(AccessibilityUserState userState) {
- // TODO: replace name const with Settings Secure Key
final boolean isSettingsAlwaysOnEnabled = Settings.Secure.getIntForUser(
mContext.getContentResolver(),
- "accessibility_magnification_always_on_enabled",
+ Settings.Secure.ACCESSIBILITY_MAGNIFICATION_ALWAYS_ON_ENABLED,
0, userState.mUserId) == 1;
final boolean isAlwaysOnFeatureFlagEnabled = mMagnificationController
.isAlwaysOnMagnificationFeatureFlagEnabled();
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 6b61e97..b991a02 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -193,6 +193,32 @@
final AugmentedAutofillState mAugmentedAutofillState = new AugmentedAutofillState();
+ /**
+ * Lock used to synchronize access to flags.
+ */
+ private final Object mFlagLock = new Object();
+
+ // Flag holders for Autofill PCC classification
+
+ @GuardedBy("mFlagLock")
+ private boolean mPccClassificationEnabled;
+
+ @GuardedBy("mFlagLock")
+ private boolean mPccPreferProviderOverPcc;
+
+ @GuardedBy("mFlagLock")
+ private boolean mPccUseFallbackDetection;
+
+ @GuardedBy("mFlagLock")
+ private String mPccProviderHints;
+
+ // Default flag values for Autofill PCC
+
+ private static final String DEFAULT_PCC_FEATURE_PROVIDER_HINTS = "";
+ private static final boolean DEFAULT_PREFER_PROVIDER_OVER_PCC = true;
+
+ private static final boolean DEFAULT_PCC_USE_FALLBACK = true;
+
public AutofillManagerService(Context context) {
super(context,
new SecureSettingsServiceNameResolver(context, Settings.Secure.AUTOFILL_SERVICE),
@@ -302,6 +328,10 @@
case AutofillFeatureFlags.DEVICE_CONFIG_AUTOFILL_SMART_SUGGESTION_SUPPORTED_MODES:
case AutofillFeatureFlags.DEVICE_CONFIG_AUGMENTED_SERVICE_IDLE_UNBIND_TIMEOUT:
case AutofillFeatureFlags.DEVICE_CONFIG_AUGMENTED_SERVICE_REQUEST_TIMEOUT:
+ case AutofillFeatureFlags.DEVICE_CONFIG_AUTOFILL_PCC_CLASSIFICATION_ENABLED:
+ case AutofillFeatureFlags.DEVICE_CONFIG_AUTOFILL_PCC_FEATURE_PROVIDER_HINTS:
+ case AutofillFeatureFlags.DEVICE_CONFIG_PREFER_PROVIDER_OVER_PCC:
+ case AutofillFeatureFlags.DEVICE_CONFIG_PCC_USE_FALLBACK:
setDeviceConfigProperties();
break;
case AutofillFeatureFlags.DEVICE_CONFIG_AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES:
@@ -579,13 +609,38 @@
AutofillFeatureFlags.DEVICE_CONFIG_AUTOFILL_SMART_SUGGESTION_SUPPORTED_MODES,
AutofillManager.FLAG_SMART_SUGGESTION_SYSTEM);
if (verbose) {
- Slog.v(mTag, "setDeviceConfigProperties(): "
+ Slog.v(mTag, "setDeviceConfigProperties() for AugmentedAutofill: "
+ "augmentedIdleTimeout=" + mAugmentedServiceIdleUnbindTimeoutMs
+ ", augmentedRequestTimeout=" + mAugmentedServiceRequestTimeoutMs
+ ", smartSuggestionMode="
+ getSmartSuggestionModeToString(mSupportedSmartSuggestionModes));
}
}
+ synchronized (mFlagLock) {
+ mPccClassificationEnabled = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_AUTOFILL,
+ AutofillFeatureFlags.DEVICE_CONFIG_AUTOFILL_PCC_CLASSIFICATION_ENABLED,
+ AutofillFeatureFlags.DEFAULT_AUTOFILL_PCC_CLASSIFICATION_ENABLED);
+ mPccPreferProviderOverPcc = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_AUTOFILL,
+ AutofillFeatureFlags.DEVICE_CONFIG_PREFER_PROVIDER_OVER_PCC,
+ DEFAULT_PREFER_PROVIDER_OVER_PCC);
+ mPccUseFallbackDetection = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_AUTOFILL,
+ AutofillFeatureFlags.DEVICE_CONFIG_PCC_USE_FALLBACK,
+ DEFAULT_PCC_USE_FALLBACK);
+ mPccProviderHints = DeviceConfig.getString(
+ DeviceConfig.NAMESPACE_AUTOFILL,
+ AutofillFeatureFlags.DEVICE_CONFIG_AUTOFILL_PCC_FEATURE_PROVIDER_HINTS,
+ DEFAULT_PCC_FEATURE_PROVIDER_HINTS);
+ if (verbose) {
+ Slog.v(mTag, "setDeviceConfigProperties() for PCC: "
+ + "mPccClassificationEnabled=" + mPccClassificationEnabled
+ + ", mPccPreferProviderOverPcc=" + mPccPreferProviderOverPcc
+ + ", mPccUseFallbackDetection=" + mPccUseFallbackDetection
+ + ", mPccProviderHints=" + mPccProviderHints);
+ }
+ }
}
private void updateCachedServices() {
@@ -791,6 +846,46 @@
}
}
+ /**
+ * Whether the Autofill PCC Classification feature is enabled.
+ */
+ public boolean isPccClassificationEnabled() {
+ synchronized (mFlagLock) {
+ return mPccClassificationEnabled;
+ }
+ }
+
+ /**
+ * Whether the Autofill Provider shouldbe preferred over PCC results for selecting datasets.
+ */
+ public boolean preferProviderOverPcc() {
+ synchronized (mFlagLock) {
+ return mPccPreferProviderOverPcc;
+ }
+ }
+
+ /**
+ * Whether to use the fallback for detection.
+ * If true, use data from secondary source if primary not present .
+ * For eg: if we prefer PCC over provider, and PCC detection didn't classify a field, however,
+ * autofill provider did, this flag would decide whether we use that result, and show some
+ * presentation for that particular field.
+ */
+ public boolean shouldUsePccFallback() {
+ synchronized (mFlagLock) {
+ return mPccUseFallbackDetection;
+ }
+ }
+
+ /**
+ * Provides Autofill Hints that would be requested by the service from the Autofill Provider.
+ */
+ public String getPccProviderHints() {
+ synchronized (mFlagLock) {
+ return mPccProviderHints;
+ }
+ }
+
@Nullable
@VisibleForTesting
static Map<String, String[]> getAllowedCompatModePackages(String setting) {
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 2b529bf..c5c9288 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -170,6 +170,8 @@
"android.service.autofill.action.DELAYED_FILL";
private static final String EXTRA_REQUEST_ID = "android.service.autofill.extra.REQUEST_ID";
+ private static final String PCC_HINTS_DELIMITER = ",";
+
final Object mLock;
private final AutofillManagerServiceImpl mService;
@@ -564,6 +566,7 @@
if (mPendingInlineSuggestionsRequest.isServiceSupported()) {
mPendingFillRequest = new FillRequest(mPendingFillRequest.getId(),
mPendingFillRequest.getFillContexts(),
+ mPendingFillRequest.getHints(),
mPendingFillRequest.getClientState(),
mPendingFillRequest.getFlags(),
mPendingInlineSuggestionsRequest,
@@ -672,8 +675,10 @@
final ArrayList<FillContext> contexts =
mergePreviousSessionLocked(/* forSave= */ false);
+ final List<String> hints = getTypeHintsForProvider();
+
mDelayedFillPendingIntent = createPendingIntent(requestId);
- request = new FillRequest(requestId, contexts, mClientState, flags,
+ request = new FillRequest(requestId, contexts, hints, mClientState, flags,
/*inlineSuggestionsRequest=*/ null,
/*delayedFillIntentSender=*/ mDelayedFillPendingIntent == null
? null
@@ -705,6 +710,22 @@
}
/**
+ * Get the list of valid autofill hint types from Device flags
+ * Returns empty list if PCC is off or no types available
+ */
+ private List<String> getTypeHintsForProvider() {
+ if (!mService.getMaster().isPccClassificationEnabled()) {
+ return Collections.EMPTY_LIST;
+ }
+ final String typeHints = mService.getMaster().getPccProviderHints();
+ if (TextUtils.isEmpty(typeHints)) {
+ return new ArrayList<>();
+ }
+
+ return List.of(typeHints.split(PCC_HINTS_DELIMITER));
+ }
+
+ /**
* Assist Data Receiver for PCC
*/
private final class PccAssistDataReceiverImpl extends IAssistDataReceiver.Stub {
diff --git a/services/core/Android.bp b/services/core/Android.bp
index bd072f5..c8caab9 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -146,6 +146,7 @@
],
static_libs: [
+ "android.frameworks.location.altitude-V1-java", // AIDL
"android.hardware.authsecret-V1.0-java",
"android.hardware.authsecret-V1-java",
"android.hardware.boot-V1.0-java", // HIDL
diff --git a/services/core/java/android/os/BatteryStatsInternal.java b/services/core/java/android/os/BatteryStatsInternal.java
index 9c2de65..17ef9a2 100644
--- a/services/core/java/android/os/BatteryStatsInternal.java
+++ b/services/core/java/android/os/BatteryStatsInternal.java
@@ -104,8 +104,18 @@
/**
* Reports any activity that could potentially have caused the CPU to wake up.
- * Accepts a timestamp to allow the reporter to report it before or after the event.
+ * Accepts a timestamp to allow free ordering between the event and its reporting.
+ * @param subsystem The subsystem this activity should be attributed to.
+ * @param elapsedMillis The time when this activity happened in the elapsed timebase.
+ * @param uids The uid (or uids) that should be blamed for this activity.
*/
public abstract void noteCpuWakingActivity(@CpuWakeupSubsystem int subsystem,
long elapsedMillis, @NonNull int... uids);
+
+ /**
+ * Reports a sound trigger recognition event that may have woken up the CPU.
+ * @param elapsedMillis The time when the event happened in the elapsed timebase.
+ * @param uid The uid that requested this trigger.
+ */
+ public abstract void noteWakingSoundTrigger(long elapsedMillis, int uid);
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index e1d1f6c..2aeaa2f 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -962,7 +962,7 @@
private static final String KEY_ENABLE_WAIT_FOR_FINISH_ATTACH_APPLICATION =
"enable_wait_for_finish_attach_application";
- private static final boolean DEFAULT_ENABLE_WAIT_FOR_FINISH_ATTACH_APPLICATION = true;
+ private static final boolean DEFAULT_ENABLE_WAIT_FOR_FINISH_ATTACH_APPLICATION = false;
/** @see #KEY_ENABLE_WAIT_FOR_FINISH_ATTACH_APPLICATION */
public volatile boolean mEnableWaitForFinishAttachApplication =
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index f73594c..19235c9 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -483,6 +483,12 @@
Objects.requireNonNull(uids);
mCpuWakeupStats.noteWakingActivity(subsystem, elapsedMillis, uids);
}
+
+ @Override
+ public void noteWakingSoundTrigger(long elapsedMillis, int uid) {
+ // TODO(b/267717665): Pipe to noteCpuWakingActivity once SoundTrigger starts using this.
+ Slog.w(TAG, "Sound trigger event dispatched to uid " + uid);
+ }
}
@Override
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index ec2e254..0318b24 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -488,31 +488,65 @@
* migrated already.
*/
private void migrateSyncJobNamespaceIfNeeded() {
- if (mSyncStorageEngine.isJobNamespaceMigrated()) {
+ final boolean namespaceMigrated = mSyncStorageEngine.isJobNamespaceMigrated();
+ final boolean attributionFixed = mSyncStorageEngine.isJobAttributionFixed();
+ if (namespaceMigrated && attributionFixed) {
return;
}
final JobScheduler jobSchedulerDefaultNamespace =
mContext.getSystemService(JobScheduler.class);
- final List<JobInfo> pendingJobs = jobSchedulerDefaultNamespace.getAllPendingJobs();
- // Wait until we've confirmed that all syncs have been migrated to the new namespace
- // before we persist successful migration to our status file. This is done to avoid
+ if (!namespaceMigrated) {
+ final List<JobInfo> pendingJobs = jobSchedulerDefaultNamespace.getAllPendingJobs();
+ // Wait until we've confirmed that all syncs have been migrated to the new namespace
+ // before we persist successful migration to our status file. This is done to avoid
+ // internal consistency issues if the devices reboots right after SyncManager has
+ // done the migration on its side but before JobScheduler has finished persisting
+ // the updated jobs to disk. If JobScheduler hasn't persisted the update to disk,
+ // then nothing that happened afterwards should have been persisted either, so there's
+ // no concern over activity happening after the migration causing issues.
+ boolean allSyncsMigrated = true;
+ for (int i = pendingJobs.size() - 1; i >= 0; --i) {
+ final JobInfo job = pendingJobs.get(i);
+ final SyncOperation op = SyncOperation.maybeCreateFromJobExtras(job.getExtras());
+ if (op != null) {
+ // This is a sync. Move it over to SyncManager's namespace.
+ mJobScheduler.scheduleAsPackage(job,
+ op.owningPackage, op.target.userId, op.wakeLockName());
+ jobSchedulerDefaultNamespace.cancel(job.getId());
+ allSyncsMigrated = false;
+ }
+ }
+ mSyncStorageEngine.setJobNamespaceMigrated(allSyncsMigrated);
+ }
+
+ // Fix attribution for any syncs that were previously scheduled using
+ // JobScheduler.schedule() instead of JobScheduler.scheduleAsPackage().
+ final List<JobInfo> namespacedJobs = LocalServices.getService(JobSchedulerInternal.class)
+ .getSystemScheduledOwnJobs(mJobScheduler.getNamespace());
+ // Wait until we've confirmed that all syncs have been proper attribution
+ // before we persist attribution state to our status file. This is done to avoid
// internal consistency issues if the devices reboots right after SyncManager has
- // done the migration on its side but before JobScheduler has finished persisting
+ // rescheduled the job on its side but before JobScheduler has finished persisting
// the updated jobs to disk. If JobScheduler hasn't persisted the update to disk,
// then nothing that happened afterwards should have been persisted either, so there's
// no concern over activity happening after the migration causing issues.
- boolean allSyncsMigrated = true;
- for (int i = pendingJobs.size() - 1; i >= 0; --i) {
- final JobInfo job = pendingJobs.get(i);
+ // This case is done to fix issues for a subset of test devices.
+ // TODO: remove this attribution check/fix code
+ boolean allSyncsAttributed = true;
+ for (int i = namespacedJobs.size() - 1; i >= 0; --i) {
+ final JobInfo job = namespacedJobs.get(i);
final SyncOperation op = SyncOperation.maybeCreateFromJobExtras(job.getExtras());
if (op != null) {
- // This is a sync. Move it over to SyncManager's namespace.
- mJobScheduler.schedule(job);
- jobSchedulerDefaultNamespace.cancel(job.getId());
- allSyncsMigrated = false;
+ // This is a sync. Make sure it's properly attributed to the app
+ // instead of the system.
+ // Since the job ID stays the same, scheduleAsPackage will replace the scheduled
+ // job, so we don't need to call cancel as well.
+ mJobScheduler.scheduleAsPackage(job,
+ op.owningPackage, op.target.userId, op.wakeLockName());
+ allSyncsAttributed = false;
}
}
- mSyncStorageEngine.setJobNamespaceMigrated(allSyncsMigrated);
+ mSyncStorageEngine.setJobAttributionFixed(allSyncsAttributed);
}
private synchronized void verifyJobScheduler() {
diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java
index 9f3302d..b890bbd 100644
--- a/services/core/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/core/java/com/android/server/content/SyncStorageEngine.java
@@ -173,6 +173,7 @@
private volatile boolean mIsClockValid;
private volatile boolean mIsJobNamespaceMigrated;
+ private volatile boolean mIsJobAttributionFixed;
static {
sAuthorityRenames = new HashMap<String, String>();
@@ -852,6 +853,20 @@
return mIsJobNamespaceMigrated;
}
+ void setJobAttributionFixed(boolean fixed) {
+ if (mIsJobAttributionFixed == fixed) {
+ return;
+ }
+ mIsJobAttributionFixed = fixed;
+ // This isn't urgent enough to write synchronously. Post it to the handler thread so
+ // SyncManager can move on with whatever it was doing.
+ mHandler.sendEmptyMessageDelayed(MSG_WRITE_STATUS, WRITE_STATUS_DELAY);
+ }
+
+ boolean isJobAttributionFixed() {
+ return mIsJobAttributionFixed;
+ }
+
public Pair<Long, Long> getBackoff(EndPoint info) {
synchronized (mAuthorities) {
AuthorityInfo authority = getAuthorityLocked(info, "getBackoff");
@@ -2120,6 +2135,10 @@
mIsJobNamespaceMigrated =
proto.readBoolean(SyncStatusProto.IS_JOB_NAMESPACE_MIGRATED);
break;
+ case (int) SyncStatusProto.IS_JOB_ATTRIBUTION_FIXED:
+ mIsJobAttributionFixed =
+ proto.readBoolean(SyncStatusProto.IS_JOB_ATTRIBUTION_FIXED);
+ break;
case ProtoInputStream.NO_MORE_FIELDS:
return;
}
@@ -2389,6 +2408,7 @@
}
proto.write(SyncStatusProto.IS_JOB_NAMESPACE_MIGRATED, mIsJobNamespaceMigrated);
+ proto.write(SyncStatusProto.IS_JOB_ATTRIBUTION_FIXED, mIsJobAttributionFixed);
proto.flush();
}
diff --git a/services/core/java/com/android/server/location/altitude/AltitudeService.java b/services/core/java/com/android/server/location/altitude/AltitudeService.java
new file mode 100644
index 0000000..b321e4d
--- /dev/null
+++ b/services/core/java/com/android/server/location/altitude/AltitudeService.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2023 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.server.location.altitude;
+
+import android.content.Context;
+import android.frameworks.location.altitude.AddMslAltitudeToLocationRequest;
+import android.frameworks.location.altitude.AddMslAltitudeToLocationResponse;
+import android.frameworks.location.altitude.IAltitudeService;
+import android.location.Location;
+import android.location.altitude.AltitudeConverter;
+import android.os.RemoteException;
+
+import com.android.server.SystemService;
+
+import java.io.IOException;
+
+/**
+ * Manages altitude information exchange through the HAL, e.g., geoid height requests such that
+ * vendors can perform altitude conversions.
+ *
+ * @hide
+ */
+public class AltitudeService extends IAltitudeService.Stub {
+
+ private final AltitudeConverter mAltitudeConverter = new AltitudeConverter();
+ private final Context mContext;
+
+ /** @hide */
+ public AltitudeService(Context context) {
+ mContext = context;
+ }
+
+ @Override
+ public AddMslAltitudeToLocationResponse addMslAltitudeToLocation(
+ AddMslAltitudeToLocationRequest request) throws RemoteException {
+ Location location = new Location("");
+ location.setLatitude(request.latitudeDegrees);
+ location.setLongitude(request.longitudeDegrees);
+ location.setAltitude(request.altitudeMeters);
+ location.setVerticalAccuracyMeters(request.verticalAccuracyMeters);
+ try {
+ mAltitudeConverter.addMslAltitudeToLocation(mContext, location);
+ } catch (IOException e) {
+ throw new RemoteException(e);
+ }
+
+ AddMslAltitudeToLocationResponse response = new AddMslAltitudeToLocationResponse();
+ response.mslAltitudeMeters = location.getMslAltitudeMeters();
+ response.mslAltitudeAccuracyMeters = location.getMslAltitudeAccuracyMeters();
+ return response;
+ }
+
+ @Override
+ public String getInterfaceHash() {
+ return IAltitudeService.HASH;
+ }
+
+ @Override
+ public int getInterfaceVersion() {
+ return IAltitudeService.VERSION;
+ }
+
+ /** @hide */
+ public static class Lifecycle extends SystemService {
+
+ private static final String SERVICE_NAME = IAltitudeService.DESCRIPTOR + "/default";
+
+ private AltitudeService mService;
+
+ public Lifecycle(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void onStart() {
+ mService = new AltitudeService(getContext());
+ publishBinderService(SERVICE_NAME, mService);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 0aa822b..94d5d53 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -114,6 +114,7 @@
import static android.service.notification.NotificationListenerService.TRIM_LIGHT;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
+import static com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags.ALLOW_DISMISS_ONGOING;
import static com.android.internal.util.FrameworkStatsLog.DND_MODE_RULE;
import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES;
import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES;
@@ -271,6 +272,7 @@
import com.android.internal.app.IAppOpsService;
import com.android.internal.compat.IPlatformCompat;
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
+import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags;
import com.android.internal.logging.InstanceId;
import com.android.internal.logging.InstanceIdSequence;
import com.android.internal.logging.MetricsLogger;
@@ -577,11 +579,11 @@
private float mInCallNotificationVolume;
private Binder mCallNotificationToken = null;
- private static final boolean ONGOING_DISMISSAL = SystemProperties.getBoolean(
- "persist.sysui.notification.ongoing_dismissal", true);
@VisibleForTesting
protected boolean mSystemExemptFromDismissal = false;
+ private SystemUiSystemPropertiesFlags.FlagResolver mFlagResolver;
+
// used as a mutex for access to all active notifications & listeners
final Object mNotificationLock = new Object();
@GuardedBy("mNotificationLock")
@@ -1208,7 +1210,8 @@
}
}
- int mustNotHaveFlags = ONGOING_DISMISSAL ? FLAG_NO_DISMISS : FLAG_ONGOING_EVENT;
+ int mustNotHaveFlags = mFlagResolver.isEnabled(ALLOW_DISMISS_ONGOING)
+ ? FLAG_NO_DISMISS : FLAG_ONGOING_EVENT;
cancelNotification(callingUid, callingPid, pkg, tag, id,
/* mustHaveFlags= */ 0,
/* mustNotHaveFlags= */ mustNotHaveFlags,
@@ -2219,7 +2222,8 @@
TelephonyManager telephonyManager, ActivityManagerInternal ami,
MultiRateLimiter toastRateLimiter, PermissionHelper permissionHelper,
UsageStatsManagerInternal usageStatsManagerInternal,
- TelecomManager telecomManager, NotificationChannelLogger channelLogger) {
+ TelecomManager telecomManager, NotificationChannelLogger channelLogger,
+ SystemUiSystemPropertiesFlags.FlagResolver flagResolver) {
mHandler = handler;
Resources resources = getContext().getResources();
mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
@@ -2417,6 +2421,8 @@
mMsgPkgsAllowedAsConvos = Set.of(getStringArrayResource(
com.android.internal.R.array.config_notificationMsgPkgsAllowedAsConvos));
+ mFlagResolver = flagResolver;
+
mStatsManager = statsManager;
mToastRateLimiter = toastRateLimiter;
@@ -2548,7 +2554,7 @@
AppGlobals.getPermissionManager()),
LocalServices.getService(UsageStatsManagerInternal.class),
getContext().getSystemService(TelecomManager.class),
- new NotificationChannelLoggerImpl());
+ new NotificationChannelLoggerImpl(), SystemUiSystemPropertiesFlags.getResolver());
publishBinderService(Context.NOTIFICATION_SERVICE, mService, /* allowIsolated= */ false,
DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL);
@@ -6516,7 +6522,7 @@
// Fix the notification as best we can.
try {
- fixNotification(notification, pkg, tag, id, userId);
+ fixNotification(notification, pkg, tag, id, userId, notificationUid);
} catch (Exception e) {
if (notification.isForegroundService()) {
throw new SecurityException("Invalid FGS notification", e);
@@ -6694,14 +6700,15 @@
@VisibleForTesting
protected void fixNotification(Notification notification, String pkg, String tag, int id,
- int userId) throws NameNotFoundException, RemoteException {
+ @UserIdInt int userId, int notificationUid) throws NameNotFoundException,
+ RemoteException {
final ApplicationInfo ai = mPackageManagerClient.getApplicationInfoAsUser(
pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
(userId == UserHandle.USER_ALL) ? USER_SYSTEM : userId);
Notification.addFieldsFromContext(ai, notification);
// Only notifications that can be non-dismissible can have the flag FLAG_NO_DISMISS
- if (ONGOING_DISMISSAL) {
+ if (mFlagResolver.isEnabled(ALLOW_DISMISS_ONGOING)) {
if (((notification.flags & FLAG_ONGOING_EVENT) > 0)
&& canBeNonDismissible(ai, notification)) {
notification.flags |= FLAG_NO_DISMISS;
@@ -6710,17 +6717,31 @@
}
}
- int canColorize = mPackageManagerClient.checkPermission(
- android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, pkg);
+ int canColorize = getContext().checkPermission(
+ android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, -1, notificationUid);
+
if (canColorize == PERMISSION_GRANTED) {
notification.flags |= Notification.FLAG_CAN_COLORIZE;
} else {
notification.flags &= ~Notification.FLAG_CAN_COLORIZE;
}
+ if (notification.extras.getBoolean(Notification.EXTRA_ALLOW_DURING_SETUP, false)) {
+ int hasShowDuringSetupPerm = getContext().checkPermission(
+ android.Manifest.permission.NOTIFICATION_DURING_SETUP, -1, notificationUid);
+ if (hasShowDuringSetupPerm != PERMISSION_GRANTED) {
+ notification.extras.remove(Notification.EXTRA_ALLOW_DURING_SETUP);
+ if (DBG) {
+ Slog.w(TAG, "warning: pkg " + pkg + " attempting to show during setup"
+ + " without holding perm "
+ + Manifest.permission.NOTIFICATION_DURING_SETUP);
+ }
+ }
+ }
+
if (notification.fullScreenIntent != null && ai.targetSdkVersion >= Build.VERSION_CODES.Q) {
- int fullscreenIntentPermission = mPackageManagerClient.checkPermission(
- android.Manifest.permission.USE_FULL_SCREEN_INTENT, pkg);
+ int fullscreenIntentPermission = getContext().checkPermission(
+ android.Manifest.permission.USE_FULL_SCREEN_INTENT, -1, notificationUid);
if (fullscreenIntentPermission != PERMISSION_GRANTED) {
notification.fullScreenIntent = null;
Slog.w(TAG, "Package " + pkg +
@@ -6765,8 +6786,8 @@
// Ensure MediaStyle has correct permissions for remote device extras
if (notification.isStyle(Notification.MediaStyle.class)) {
- int hasMediaContentControlPermission = mPackageManager.checkPermission(
- android.Manifest.permission.MEDIA_CONTENT_CONTROL, pkg, userId);
+ int hasMediaContentControlPermission = getContext().checkPermission(
+ android.Manifest.permission.MEDIA_CONTENT_CONTROL, -1, notificationUid);
if (hasMediaContentControlPermission != PERMISSION_GRANTED) {
notification.extras.remove(Notification.EXTRA_MEDIA_REMOTE_DEVICE);
notification.extras.remove(Notification.EXTRA_MEDIA_REMOTE_ICON);
@@ -6780,8 +6801,8 @@
// Ensure only allowed packages have a substitute app name
if (notification.extras.containsKey(Notification.EXTRA_SUBSTITUTE_APP_NAME)) {
- int hasSubstituteAppNamePermission = mPackageManager.checkPermission(
- permission.SUBSTITUTE_NOTIFICATION_APP_NAME, pkg, userId);
+ int hasSubstituteAppNamePermission = getContext().checkPermission(
+ permission.SUBSTITUTE_NOTIFICATION_APP_NAME, -1, notificationUid);
if (hasSubstituteAppNamePermission != PERMISSION_GRANTED) {
notification.extras.remove(Notification.EXTRA_SUBSTITUTE_APP_NAME);
if (DBG) {
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index 062f0fc..d471c8a 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -301,7 +301,7 @@
&& shellPkgName.equals(overlayInfo.packageName));
initIfNeeded();
- onSwitchUser(UserHandle.USER_SYSTEM);
+ onStartUser(UserHandle.USER_SYSTEM);
publishBinderService(Context.OVERLAY_SERVICE, mService);
publishLocalService(OverlayManagerService.class, this);
@@ -324,7 +324,7 @@
final UserInfo userInfo = users.get(i);
if (!userInfo.supportsSwitchTo() && userInfo.id != UserHandle.USER_SYSTEM) {
// Initialize any users that can't be switched to, as their state would
- // never be setup in onSwitchUser(). We will switch to the system user right
+ // never be setup in onStartUser(). We will switch to the system user right
// after this, and its state will be setup there.
updatePackageManagerLocked(mImpl.updateOverlaysForUser(users.get(i).id));
}
@@ -333,13 +333,13 @@
}
@Override
- public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
- onSwitchUser(to.getUserIdentifier());
+ public void onUserStarting(TargetUser user) {
+ onStartUser(user.getUserIdentifier());
}
- private void onSwitchUser(@UserIdInt int newUserId) {
+ private void onStartUser(@UserIdInt int newUserId) {
try {
- traceBegin(TRACE_TAG_RRO, "OMS#onSwitchUser " + newUserId);
+ traceBegin(TRACE_TAG_RRO, "OMS#onStartUser " + newUserId);
// ensure overlays in the settings are up-to-date, and propagate
// any asset changes to the rest of the system
synchronized (mLock) {
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 198c339..477a8a6 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -3154,8 +3154,9 @@
}
}
- final ActivityOptions clientOptions = ActivityOptions.makeBasic();
- clientOptions.setIgnorePendingIntentCreatorForegroundState(true);
+ final ActivityOptions clientOptions = ActivityOptions.makeBasic()
+ .setPendingIntentCreatorBackgroundActivityStartMode(
+ ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_DENIED);
PendingIntent clientIntent = PendingIntent.getActivityAsUser(
mContext, 0, Intent.createChooser(
new Intent(Intent.ACTION_SET_WALLPAPER),
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index 4507637..502bfd1 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -781,6 +781,7 @@
// the running transition finish.
final Transition transition = r != null
&& r.mTransitionController.inPlayingTransition(r)
+ && !r.mTransitionController.isCollecting()
? r.mTransitionController.createTransition(TRANSIT_TO_BACK) : null;
if (transition != null) {
r.mTransitionController.requestStartTransition(transition, null /*startTask */,
@@ -820,6 +821,7 @@
// visibility while playing transition, there won't able to commit visibility until
// the running transition finish.
final Transition transition = r.mTransitionController.inPlayingTransition(r)
+ && !r.mTransitionController.isCollecting()
? r.mTransitionController.createTransition(TRANSIT_TO_FRONT) : null;
if (transition != null) {
r.mTransitionController.requestStartTransition(transition, null /*startTask */,
diff --git a/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java b/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java
index e04900c..47bdba3 100644
--- a/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java
@@ -250,10 +250,7 @@
}
ActivityRecord topActivity = mDisplayContent.topRunningActivity(
/* considerKeyguardState= */ true);
- if (topActivity == null
- // Checking windowing mode on activity level because we don't want to
- // show toast in case of activity embedding.
- || topActivity.getWindowingMode() != WINDOWING_MODE_FULLSCREEN) {
+ if (!isTreatmentEnabledForActivity(topActivity)) {
return;
}
showToast(R.string.display_rotation_camera_compat_toast_after_rotation);
@@ -309,21 +306,28 @@
}
boolean isActivityEligibleForOrientationOverride(@NonNull ActivityRecord activity) {
- return isTreatmentEnabledForDisplay() && isCameraActiveInFullscreen(activity);
+ return isTreatmentEnabledForDisplay()
+ && isCameraActive(activity, /* mustBeFullscreen */ true);
}
+
/**
* Whether camera compat treatment is applicable for the given activity.
*
* <p>Conditions that need to be met:
* <ul>
- * <li>{@link #isCameraActiveForPackage} is {@code true} for the activity.
+ * <li>Camera is active for the package.
* <li>The activity is in fullscreen
* <li>The activity has fixed orientation but not "locked" or "nosensor" one.
* </ul>
*/
boolean isTreatmentEnabledForActivity(@Nullable ActivityRecord activity) {
- return activity != null && isCameraActiveInFullscreen(activity)
+ return isTreatmentEnabledForActivity(activity, /* mustBeFullscreen */ true);
+ }
+
+ private boolean isTreatmentEnabledForActivity(@Nullable ActivityRecord activity,
+ boolean mustBeFullscreen) {
+ return activity != null && isCameraActive(activity, mustBeFullscreen)
&& activity.getRequestedConfigurationOrientation() != ORIENTATION_UNDEFINED
// "locked" and "nosensor" values are often used by camera apps that can't
// handle dynamic changes so we shouldn't force rotate them.
@@ -331,8 +335,10 @@
&& activity.getOverrideOrientation() != SCREEN_ORIENTATION_LOCKED;
}
- private boolean isCameraActiveInFullscreen(@NonNull ActivityRecord activity) {
- return !activity.inMultiWindowMode()
+ private boolean isCameraActive(@NonNull ActivityRecord activity, boolean mustBeFullscreen) {
+ // Checking windowing mode on activity level because we don't want to
+ // apply treatment in case of activity embedding.
+ return (!mustBeFullscreen || !activity.inMultiWindowMode())
&& mCameraIdPackageBiMap.containsPackageName(activity.packageName)
&& activity.mLetterboxUiController.shouldForceRotateForCameraCompat();
}
@@ -385,7 +391,8 @@
}
// Checking that the whole app is in multi-window mode as we shouldn't show toast
// for the activity embedding case.
- if (topActivity.getTask().getWindowingMode() == WINDOWING_MODE_MULTI_WINDOW) {
+ if (topActivity.getTask().getWindowingMode() == WINDOWING_MODE_MULTI_WINDOW
+ && isTreatmentEnabledForActivity(topActivity, /* mustBeFullscreen */ false)) {
showToast(R.string.display_rotation_camera_compat_toast_in_split_screen);
}
}
diff --git a/services/credentials/java/com/android/server/credentials/CreateRequestSession.java b/services/credentials/java/com/android/server/credentials/CreateRequestSession.java
index 2345e3f..c8518c5 100644
--- a/services/credentials/java/com/android/server/credentials/CreateRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/CreateRequestSession.java
@@ -97,7 +97,7 @@
if (response != null) {
respondToClientWithResponseAndFinish(response);
} else {
- respondToClientWithErrorAndFinish(CreateCredentialException.TYPE_NO_CREDENTIAL,
+ respondToClientWithErrorAndFinish(CreateCredentialException.TYPE_NO_CREATE_OPTIONS,
"Invalid response");
}
}
@@ -119,6 +119,12 @@
}
}
+ @Override
+ public void onUiSelectorInvocationFailure() {
+ respondToClientWithErrorAndFinish(CreateCredentialException.TYPE_NO_CREATE_OPTIONS,
+ "No create options available.");
+ }
+
private void respondToClientWithResponseAndFinish(CreateCredentialResponse response) {
Log.i(TAG, "respondToClientWithResponseAndFinish");
if (isSessionCancelled()) {
@@ -166,8 +172,8 @@
Log.i(TAG, "in onProviderStatusChanged - isUiInvocationNeeded");
getProviderDataAndInitiateUi();
} else {
- respondToClientWithErrorAndFinish(CreateCredentialException.TYPE_NO_CREDENTIAL,
- "No credentials available");
+ respondToClientWithErrorAndFinish(CreateCredentialException.TYPE_NO_CREATE_OPTIONS,
+ "No create options available.");
}
}
}
diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
index 6857239..edffad2 100644
--- a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
+++ b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
@@ -472,8 +472,8 @@
if (providerSessions.isEmpty()) {
try {
callback.onError(
- CreateCredentialException.TYPE_NO_CREDENTIAL,
- "No credentials available on this device.");
+ CreateCredentialException.TYPE_NO_CREATE_OPTIONS,
+ "No create options available.");
} catch (RemoteException e) {
Log.i(
TAG,
diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java b/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java
index 797601a..a6f6a830 100644
--- a/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java
+++ b/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java
@@ -56,19 +56,29 @@
};
private void handleUiResult(int resultCode, Bundle resultData) {
- if (resultCode == UserSelectionDialogResult.RESULT_CODE_DIALOG_COMPLETE_WITH_SELECTION) {
- UserSelectionDialogResult selection = UserSelectionDialogResult
- .fromResultData(resultData);
- if (selection != null) {
- mCallbacks.onUiSelection(selection);
- } else {
- Slog.i(TAG, "No selection found in UI result");
- }
- } else if (resultCode == UserSelectionDialogResult.RESULT_CODE_DIALOG_USER_CANCELED) {
- mCallbacks.onUiCancellation(/* isUserCancellation= */ true);
- } else if (resultCode
- == UserSelectionDialogResult.RESULT_CODE_CANCELED_AND_LAUNCHED_SETTINGS) {
- mCallbacks.onUiCancellation(/* isUserCancellation= */ false);
+ switch (resultCode) {
+ case UserSelectionDialogResult.RESULT_CODE_DIALOG_COMPLETE_WITH_SELECTION:
+ UserSelectionDialogResult selection = UserSelectionDialogResult
+ .fromResultData(resultData);
+ if (selection != null) {
+ mCallbacks.onUiSelection(selection);
+ } else {
+ Slog.i(TAG, "No selection found in UI result");
+ }
+ break;
+ case UserSelectionDialogResult.RESULT_CODE_DIALOG_USER_CANCELED:
+ mCallbacks.onUiCancellation(/* isUserCancellation= */ true);
+ break;
+ case UserSelectionDialogResult.RESULT_CODE_CANCELED_AND_LAUNCHED_SETTINGS:
+ mCallbacks.onUiCancellation(/* isUserCancellation= */ false);
+ break;
+ case UserSelectionDialogResult.RESULT_CODE_DATA_PARSING_FAILURE:
+ mCallbacks.onUiSelectorInvocationFailure();
+ break;
+ default:
+ Slog.i(TAG, "Unknown error code returned from the UI");
+ mCallbacks.onUiSelectorInvocationFailure();
+ break;
}
}
@@ -80,6 +90,9 @@
void onUiSelection(UserSelectionDialogResult selection);
/** Called when the UI is canceled without a successful provider result. */
void onUiCancellation(boolean isUserCancellation);
+
+ /** Called when the selector UI fails to come up (mostly due to parsing issue today). */
+ void onUiSelectorInvocationFailure();
}
public CredentialManagerUi(Context context, int userId,
CredentialManagerUiCallback callbacks) {
diff --git a/services/credentials/java/com/android/server/credentials/GetRequestSession.java b/services/credentials/java/com/android/server/credentials/GetRequestSession.java
index e732c23..3324999 100644
--- a/services/credentials/java/com/android/server/credentials/GetRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/GetRequestSession.java
@@ -147,6 +147,12 @@
}
@Override
+ public void onUiSelectorInvocationFailure() {
+ respondToClientWithErrorAndFinish(GetCredentialException.TYPE_NO_CREDENTIAL,
+ "No credentials to show on the selector.");
+ }
+
+ @Override
public void onProviderStatusChanged(ProviderSession.Status status,
ComponentName componentName) {
Log.i(TAG, "in onStatusChanged with status: " + status);
diff --git a/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java b/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java
index 20e358c..3f285b7 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java
@@ -96,13 +96,14 @@
if (propagateToProvider) {
return new BeginCreateCredentialRequest(
type,
- candidateQueryData
+ candidateQueryData,
+ callingAppInfo
);
}
return new BeginCreateCredentialRequest(
type,
- candidateQueryData,
- callingAppInfo);
+ candidateQueryData
+ );
}
@Nullable
@@ -168,7 +169,16 @@
private void onUpdateResponse(BeginCreateCredentialResponse response) {
Log.i(TAG, "updateResponse with save entries");
mProviderResponse = response;
- updateStatusAndInvokeCallback(Status.SAVE_ENTRIES_RECEIVED);
+ if (isEmptyResponse(response)) {
+ updateStatusAndInvokeCallback(Status.EMPTY_RESPONSE);
+ } else {
+ updateStatusAndInvokeCallback(Status.SAVE_ENTRIES_RECEIVED);
+ }
+ }
+
+ private boolean isEmptyResponse(BeginCreateCredentialResponse response) {
+ return (response.getCreateEntries() == null || response.getCreateEntries().isEmpty())
+ && response.getRemoteCreateEntry() == null;
}
@Override
@@ -294,7 +304,7 @@
ProviderPendingIntentResponse pendingIntentResponse) {
if (pendingIntentResponse == null) {
Log.i(TAG, "pendingIntentResponse is null");
- return new CreateCredentialException(CreateCredentialException.TYPE_NO_CREDENTIAL);
+ return new CreateCredentialException(CreateCredentialException.TYPE_NO_CREATE_OPTIONS);
}
if (PendingIntentResultHandler.isValidResponse(pendingIntentResponse)) {
CreateCredentialException exception = PendingIntentResultHandler
@@ -306,7 +316,7 @@
} else if (PendingIntentResultHandler.isCancelledResponse(pendingIntentResponse)) {
return new CreateCredentialException(CreateCredentialException.TYPE_USER_CANCELED);
} else {
- return new CreateCredentialException(CreateCredentialException.TYPE_NO_CREDENTIAL);
+ return new CreateCredentialException(CreateCredentialException.TYPE_NO_CREATE_OPTIONS);
}
return null;
}
diff --git a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
index 9fba95b..764aac3 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
@@ -108,7 +108,6 @@
Log.i(TAG, "Unable to create provider session");
return null;
}
-
private static BeginGetCredentialRequest constructQueryPhaseRequest(
android.credentials.GetCredentialRequest filteredRequest,
CallingAppInfo callingAppInfo,
@@ -306,18 +305,20 @@
Log.i(TAG, "in prepareUiProviderData creating ui entry with id " + entryId);
credentialUiEntries.add(new Entry(CREDENTIAL_ENTRY_KEY, entryId,
credentialEntry.getSlice(),
- /*fillInIntent=*/setUpFillInIntent(credentialEntry.getType())));
+ /*fillInIntent=*/setUpFillInIntent(credentialEntry
+ .getBeginGetCredentialOption().getId())));
}
return credentialUiEntries;
}
- private Intent setUpFillInIntent(@Nullable String id) {
+ private Intent setUpFillInIntent(@NonNull String id) {
// TODO: Determine if we should skip this entry if entry id is not set, or is set
// but does not resolve to a valid option. For now, not skipping it because
// it may be possible that the provider adds their own extras and expects to receive
// those and complete the flow.
- if (id == null || mBeginGetOptionToCredentialOptionMap.get(id) == null) {
+ if (mBeginGetOptionToCredentialOptionMap.get(id) == null) {
Log.i(TAG, "Id from Credential Entry does not resolve to a valid option");
+ return new Intent();
}
return new Intent().putExtra(CredentialProviderService.EXTRA_GET_CREDENTIAL_REQUEST,
new GetCredentialRequest(
@@ -445,7 +446,22 @@
/** Updates the response being maintained in state by this provider session. */
private void onUpdateResponse(BeginGetCredentialResponse response) {
mProviderResponse = response;
- updateStatusAndInvokeCallback(Status.CREDENTIALS_RECEIVED);
+ if (isEmptyResponse(response)) {
+ updateStatusAndInvokeCallback(Status.EMPTY_RESPONSE);
+ } else {
+ updateStatusAndInvokeCallback(Status.CREDENTIALS_RECEIVED);
+ }
+ }
+
+ private boolean isEmptyResponse(BeginGetCredentialResponse response) {
+ if ((response.getCredentialEntries() == null || response.getCredentialEntries().isEmpty())
+ && (response.getAuthenticationActions() == null || response
+ .getAuthenticationActions().isEmpty())
+ && (response.getActions() == null || response.getActions().isEmpty())
+ && response.getRemoteCredentialEntry() == null) {
+ return true;
+ }
+ return false;
}
private void onUpdateEmptyResponse() {
diff --git a/services/credentials/java/com/android/server/credentials/ProviderSession.java b/services/credentials/java/com/android/server/credentials/ProviderSession.java
index 1ae0f3c..1aec934 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderSession.java
@@ -133,7 +133,7 @@
PENDING_INTENT_INVOKED,
CREDENTIAL_RECEIVED_FROM_SELECTION,
SAVE_ENTRIES_RECEIVED, CANCELED,
- NO_CREDENTIALS, COMPLETE
+ NO_CREDENTIALS, EMPTY_RESPONSE, COMPLETE
}
/** Converts exception to a provider session status. */
diff --git a/services/credentials/java/com/android/server/credentials/RequestSession.java b/services/credentials/java/com/android/server/credentials/RequestSession.java
index 9f1bd8f..fdd0e81 100644
--- a/services/credentials/java/com/android/server/credentials/RequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/RequestSession.java
@@ -144,6 +144,11 @@
finishSession(/*propagateCancellation=*/false);
}
+ @Override
+ public void onUiSelectorInvocationFailure() {
+ Log.i(TAG, "onUiSelectorInvocationFailure");
+ }
+
protected void finishSession(boolean propagateCancellation) {
Log.i(TAG, "finishing session");
if (propagateCancellation) {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index cae6c39..271a3d3 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -142,6 +142,7 @@
import com.android.server.lights.LightsService;
import com.android.server.locales.LocaleManagerService;
import com.android.server.location.LocationManagerService;
+import com.android.server.location.altitude.AltitudeService;
import com.android.server.logcat.LogcatManagerService;
import com.android.server.media.MediaRouterService;
import com.android.server.media.metrics.MediaMetricsManagerService;
@@ -2119,6 +2120,14 @@
}
t.traceEnd();
+ t.traceBegin("StartAltitudeService");
+ try {
+ mSystemServiceManager.startService(AltitudeService.Lifecycle.class);
+ } catch (Throwable e) {
+ reportWtf("starting AltitudeService service", e);
+ }
+ t.traceEnd();
+
t.traceBegin("StartLocationTimeZoneManagerService");
try {
mSystemServiceManager.startService(LOCATION_TIME_ZONE_MANAGER_SERVICE_CLASS);
diff --git a/services/manifest_services.xml b/services/manifest_services.xml
new file mode 100644
index 0000000..7638915
--- /dev/null
+++ b/services/manifest_services.xml
@@ -0,0 +1,7 @@
+<manifest version="1.0" type="framework">
+ <hal format="aidl">
+ <name>android.frameworks.location.altitude</name>
+ <version>1</version>
+ <fqname>IAltitudeService/default</fqname>
+ </hal>
+</manifest>
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
index 32b9864..cc5c2f3 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
@@ -448,8 +448,7 @@
mA11yms.getCurrentUserIdLocked());
Settings.Secure.putIntForUser(
mTestableContext.getContentResolver(),
- // TODO: replace name with Settings Secure Key
- "accessibility_magnification_always_on_enabled",
+ Settings.Secure.ACCESSIBILITY_MAGNIFICATION_ALWAYS_ON_ENABLED,
1, mA11yms.getCurrentUserIdLocked());
mA11yms.readAlwaysOnMagnificationLocked(userState);
@@ -466,8 +465,7 @@
mA11yms.getCurrentUserIdLocked());
Settings.Secure.putIntForUser(
mTestableContext.getContentResolver(),
- // TODO: replace name with Settings Secure Key
- "accessibility_magnification_always_on_enabled",
+ Settings.Secure.ACCESSIBILITY_MAGNIFICATION_ALWAYS_ON_ENABLED,
1, mA11yms.getCurrentUserIdLocked());
mA11yms.readAlwaysOnMagnificationLocked(userState);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 38c2f40..c31c23f 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -19,6 +19,7 @@
import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
+import static android.app.Notification.EXTRA_ALLOW_DURING_SETUP;
import static android.app.Notification.FLAG_AUTO_CANCEL;
import static android.app.Notification.FLAG_BUBBLE;
import static android.app.Notification.FLAG_CAN_COLORIZE;
@@ -71,6 +72,7 @@
import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
+import static com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags.ALLOW_DISMISS_ONGOING;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
import static com.google.common.truth.Truth.assertThat;
@@ -201,6 +203,7 @@
import com.android.internal.app.IAppOpsService;
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
+import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags;
import com.android.internal.logging.InstanceIdSequence;
import com.android.internal.logging.InstanceIdSequenceFake;
import com.android.internal.messages.nano.SystemMessageProto;
@@ -373,6 +376,9 @@
BroadcastReceiver mPackageIntentReceiver;
NotificationRecordLoggerFake mNotificationRecordLogger = new NotificationRecordLoggerFake();
TestableNotificationManagerService.StrongAuthTrackerFake mStrongAuthTracker;
+
+ TestFlagResolver mTestFlagResolver = new TestFlagResolver();
+
private InstanceIdSequence mNotificationInstanceIdSequence = new InstanceIdSequenceFake(
1 << 30);
@Mock
@@ -521,7 +527,7 @@
mAppOpsManager, mAppOpsService, mUm, mHistoryManager, mStatsManager,
mock(TelephonyManager.class),
mAmi, mToastRateLimiter, mPermissionHelper, mock(UsageStatsManagerInternal.class),
- mTelecomManager, mLogger);
+ mTelecomManager, mLogger, mTestFlagResolver);
// Return first true for RoleObserver main-thread check
when(mMainLooper.isCurrentThread()).thenReturn(true).thenReturn(false);
mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY, mMainLooper);
@@ -1594,6 +1600,8 @@
@Test
public void testEnqueueNotificationWithTag_FgsAddsFlags_dismissalAllowed() throws Exception {
+ mContext.getTestablePermissions().setPermission(
+ android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, PERMISSION_GRANTED);
DeviceConfig.setProperty(
DeviceConfig.NAMESPACE_SYSTEMUI,
SystemUiDeviceConfigFlags.TASK_MANAGER_ENABLED,
@@ -1622,6 +1630,8 @@
@Test
public void testEnqueueNotificationWithTag_FGSaddsFlags_dismissalNotAllowed() throws Exception {
+ mContext.getTestablePermissions().setPermission(
+ android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, PERMISSION_GRANTED);
DeviceConfig.setProperty(
DeviceConfig.NAMESPACE_SYSTEMUI,
SystemUiDeviceConfigFlags.TASK_MANAGER_ENABLED,
@@ -4211,8 +4221,35 @@
}
@Test
+ public void testNoNotificationDuringSetupPermission() throws Exception {
+ mContext.getTestablePermissions().setPermission(
+ android.Manifest.permission.NOTIFICATION_DURING_SETUP, PERMISSION_GRANTED);
+ Bundle extras = new Bundle();
+ extras.putBoolean(EXTRA_ALLOW_DURING_SETUP, true);
+ Notification.Builder nb = new Notification.Builder(mContext,
+ mTestNotificationChannel.getId())
+ .setContentTitle("foo")
+ .addExtras(extras)
+ .setSmallIcon(android.R.drawable.sym_def_app_icon);
+ StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1,
+ "testNoNotificationDuringSetupPermission", mUid, 0,
+ nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
+ NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
+
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, sbn.getTag(),
+ nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
+ waitForIdle();
+
+ NotificationRecord posted = mService.findNotificationLocked(
+ PKG, nr.getSbn().getTag(), nr.getSbn().getId(), nr.getSbn().getUserId());
+
+ assertTrue(posted.getNotification().extras.containsKey(EXTRA_ALLOW_DURING_SETUP));
+ }
+
+ @Test
public void testNoFakeColorizedPermission() throws Exception {
- when(mPackageManagerClient.checkPermission(any(), any())).thenReturn(PERMISSION_DENIED);
+ mContext.getTestablePermissions().setPermission(
+ android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, PERMISSION_DENIED);
Notification.Builder nb = new Notification.Builder(mContext,
mTestNotificationChannel.getId())
.setContentTitle("foo")
@@ -4237,9 +4274,8 @@
@Test
public void testMediaStyleRemote_hasPermission() throws RemoteException {
String deviceName = "device";
- when(mPackageManager.checkPermission(
- eq(android.Manifest.permission.MEDIA_CONTENT_CONTROL), any(), anyInt()))
- .thenReturn(PERMISSION_GRANTED);
+ mContext.getTestablePermissions().setPermission(
+ android.Manifest.permission.MEDIA_CONTENT_CONTROL, PERMISSION_GRANTED);
Notification.MediaStyle style = new Notification.MediaStyle();
style.setRemotePlaybackInfo(deviceName, 0, null);
Notification.Builder nb = new Notification.Builder(mContext,
@@ -4266,9 +4302,8 @@
@Test
public void testMediaStyleRemote_noPermission() throws RemoteException {
String deviceName = "device";
- when(mPackageManager.checkPermission(
- eq(android.Manifest.permission.MEDIA_CONTENT_CONTROL), any(), anyInt()))
- .thenReturn(PERMISSION_DENIED);
+ mContext.getTestablePermissions().setPermission(
+ android.Manifest.permission.MEDIA_CONTENT_CONTROL, PERMISSION_DENIED);
Notification.MediaStyle style = new Notification.MediaStyle();
style.setRemotePlaybackInfo(deviceName, 0, null);
Notification.Builder nb = new Notification.Builder(mContext,
@@ -4294,9 +4329,8 @@
@Test
public void testSubstituteAppName_hasPermission() throws RemoteException {
String subName = "Substitute Name";
- when(mPackageManager.checkPermission(
- eq(android.Manifest.permission.SUBSTITUTE_NOTIFICATION_APP_NAME), any(), anyInt()))
- .thenReturn(PERMISSION_GRANTED);
+ mContext.getTestablePermissions().setPermission(
+ android.Manifest.permission.SUBSTITUTE_NOTIFICATION_APP_NAME, PERMISSION_GRANTED);
Bundle extras = new Bundle();
extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, subName);
Notification.Builder nb = new Notification.Builder(mContext,
@@ -4321,9 +4355,8 @@
@Test
public void testSubstituteAppName_noPermission() throws RemoteException {
- when(mPackageManager.checkPermission(
- eq(android.Manifest.permission.SUBSTITUTE_NOTIFICATION_APP_NAME), any(), anyInt()))
- .thenReturn(PERMISSION_DENIED);
+ mContext.getTestablePermissions().setPermission(
+ android.Manifest.permission.SUBSTITUTE_NOTIFICATION_APP_NAME, PERMISSION_DENIED);
Bundle extras = new Bundle();
extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, "Substitute Name");
Notification.Builder nb = new Notification.Builder(mContext,
@@ -8290,7 +8323,7 @@
assertNotNull(n.publicVersion.bigContentView);
assertNotNull(n.publicVersion.headsUpContentView);
- mService.fixNotification(n, PKG, "tag", 9, 0);
+ mService.fixNotification(n, PKG, "tag", 9, 0, mUid);
assertNull(n.contentView);
assertNull(n.bigContentView);
@@ -10092,8 +10125,8 @@
throws Exception {
// Given: a notification from an app on the system partition has the flag
// FLAG_ONGOING_EVENT set
- // feature flag: NOTIFICATION_ONGOING_DISMISSAL is on
- mService.setOngoingDismissal(true);
+ // feature flag: ALLOW_DISMISS_ONGOING is on
+ mTestFlagResolver.setFlagOverride(ALLOW_DISMISS_ONGOING, true);
Notification n = new Notification.Builder(mContext, "test")
.setOngoing(true)
.build();
@@ -10104,21 +10137,18 @@
.thenReturn(systemAppInfo);
// When: fix the notification with NotificationManagerService
- mService.fixNotification(n, PKG, "tag", 9, 0);
+ mService.fixNotification(n, PKG, "tag", 9, 0, mUid);
// Then: the notification's flag FLAG_NO_DISMISS should be set
assertNotSame(0, n.flags & Notification.FLAG_NO_DISMISS);
-
- // Avoid affecting other tests
- mService.setOngoingDismissal(false);
}
@Test
public void fixMediaNotification_withOnGoingFlag_shouldBeNonDismissible()
throws Exception {
// Given: a media notification has the flag FLAG_ONGOING_EVENT set
- // feature flag: NOTIFICATION_ONGOING_DISMISSAL is on
- mService.setOngoingDismissal(true);
+ // feature flag: ALLOW_DISMISS_ONGOING is on
+ mTestFlagResolver.setFlagOverride(ALLOW_DISMISS_ONGOING, true);
Notification n = new Notification.Builder(mContext, "test")
.setOngoing(true)
.setStyle(new Notification.MediaStyle()
@@ -10126,32 +10156,26 @@
.build();
// When: fix the notification with NotificationManagerService
- mService.fixNotification(n, PKG, "tag", 9, 0);
+ mService.fixNotification(n, PKG, "tag", 9, 0, mUid);
// Then: the notification's flag FLAG_NO_DISMISS should be set
assertNotSame(0, n.flags & Notification.FLAG_NO_DISMISS);
-
- // Avoid affecting other tests
- mService.setOngoingDismissal(false);
}
@Test
public void fixNonExemptNotification_withOnGoingFlag_shouldBeDismissible() throws Exception {
// Given: a non-exempt notification has the flag FLAG_ONGOING_EVENT set
- // feature flag: NOTIFICATION_ONGOING_DISMISSAL is on
- mService.setOngoingDismissal(true);
+ // feature flag: ALLOW_DISMISS_ONGOING is on
+ mTestFlagResolver.setFlagOverride(ALLOW_DISMISS_ONGOING, true);
Notification n = new Notification.Builder(mContext, "test")
.setOngoing(true)
.build();
// When: fix the notification with NotificationManagerService
- mService.fixNotification(n, PKG, "tag", 9, 0);
+ mService.fixNotification(n, PKG, "tag", 9, 0, mUid);
// Then: the notification's flag FLAG_NO_DISMISS should not be set
assertEquals(0, n.flags & Notification.FLAG_NO_DISMISS);
-
- // Avoid affecting other tests
- mService.setOngoingDismissal(false);
}
@Test
@@ -10159,28 +10183,25 @@
throws Exception {
// Given: a non-exempt notification has the flag FLAG_NO_DISMISS set (even though this is
// not allowed)
- // feature flag: NOTIFICATION_ONGOING_DISMISSAL is on
- mService.setOngoingDismissal(true);
+ // feature flag: ALLOW_DISMISS_ONGOING is on
+ mTestFlagResolver.setFlagOverride(ALLOW_DISMISS_ONGOING, true);
Notification n = new Notification.Builder(mContext, "test")
.build();
n.flags |= Notification.FLAG_NO_DISMISS;
// When: fix the notification with NotificationManagerService
- mService.fixNotification(n, PKG, "tag", 9, 0);
+ mService.fixNotification(n, PKG, "tag", 9, 0, mUid);
// Then: the notification's flag FLAG_NO_DISMISS should be cleared
assertEquals(0, n.flags & Notification.FLAG_NO_DISMISS);
-
- // Avoid affecting other tests
- mService.setOngoingDismissal(false);
}
@Test
public void fixSystemNotification_withoutOnGoingFlag_shouldBeDismissible() throws Exception {
// Given: a notification from an app on the system partition doesn't have the flag
// FLAG_ONGOING_EVENT set
- // feature flag: NOTIFICATION_ONGOING_DISMISSAL is on
- mService.setOngoingDismissal(true);
+ // feature flag: ALLOW_DISMISS_ONGOING is on
+ mTestFlagResolver.setFlagOverride(ALLOW_DISMISS_ONGOING, true);
Notification n = new Notification.Builder(mContext, "test")
.setOngoing(false)
.build();
@@ -10191,13 +10212,10 @@
.thenReturn(systemAppInfo);
// When: fix the notification with NotificationManagerService
- mService.fixNotification(n, PKG, "tag", 9, 0);
+ mService.fixNotification(n, PKG, "tag", 9, 0, mUid);
// Then: the notification's flag FLAG_NO_DISMISS should not be set
assertEquals(0, n.flags & Notification.FLAG_NO_DISMISS);
-
- // Avoid affecting other tests
- mService.setOngoingDismissal(false);
}
@Test
@@ -10205,8 +10223,8 @@
throws Exception {
// Given: a notification from an app on the system partition doesn't have the flag
// FLAG_ONGOING_EVENT set, but has the flag FLAG_NO_DISMISS set
- // feature flag: NOTIFICATION_ONGOING_DISMISSAL is on
- mService.setOngoingDismissal(true);
+ // feature flag: ALLOW_DISMISS_ONGOING is on
+ mTestFlagResolver.setFlagOverride(ALLOW_DISMISS_ONGOING, true);
Notification n = new Notification.Builder(mContext, "test")
.setOngoing(false)
.build();
@@ -10218,20 +10236,17 @@
.thenReturn(systemAppInfo);
// When: fix the notification with NotificationManagerService
- mService.fixNotification(n, PKG, "tag", 9, 0);
+ mService.fixNotification(n, PKG, "tag", 9, 0, mUid);
// Then: the notification's flag FLAG_NO_DISMISS should be cleared
assertEquals(0, n.flags & Notification.FLAG_NO_DISMISS);
-
- // Avoid affecting other tests
- mService.setOngoingDismissal(false);
}
@Test
public void fixMediaNotification_withoutOnGoingFlag_shouldBeDismissible() throws Exception {
// Given: a media notification doesn't have the flag FLAG_ONGOING_EVENT set
- // feature flag: NOTIFICATION_ONGOING_DISMISSAL is on
- mService.setOngoingDismissal(true);
+ // feature flag: ALLOW_DISMISS_ONGOING is on
+ mTestFlagResolver.setFlagOverride(ALLOW_DISMISS_ONGOING, true);
Notification n = new Notification.Builder(mContext, "test")
.setOngoing(false)
.setStyle(new Notification.MediaStyle()
@@ -10239,13 +10254,10 @@
.build();
// When: fix the notification with NotificationManagerService
- mService.fixNotification(n, PKG, "tag", 9, 0);
+ mService.fixNotification(n, PKG, "tag", 9, 0, mUid);
// Then: the notification's flag FLAG_NO_DISMISS should not be set
assertEquals(0, n.flags & Notification.FLAG_NO_DISMISS);
-
- // Avoid affecting other tests
- mService.setOngoingDismissal(false);
}
@Test
@@ -10253,8 +10265,8 @@
throws Exception {
// Given: a media notification doesn't have the flag FLAG_ONGOING_EVENT set,
// but has the flag FLAG_NO_DISMISS set
- // feature flag: NOTIFICATION_ONGOING_DISMISSAL is on
- mService.setOngoingDismissal(true);
+ // feature flag: ALLOW_DISMISS_ONGOING is on
+ mTestFlagResolver.setFlagOverride(ALLOW_DISMISS_ONGOING, true);
Notification n = new Notification.Builder(mContext, "test")
.setOngoing(false)
.setStyle(new Notification.MediaStyle()
@@ -10263,34 +10275,27 @@
n.flags |= Notification.FLAG_NO_DISMISS;
// When: fix the notification with NotificationManagerService
- mService.fixNotification(n, PKG, "tag", 9, 0);
+ mService.fixNotification(n, PKG, "tag", 9, 0, mUid);
// Then: the notification's flag FLAG_NO_DISMISS should be cleared
assertEquals(0, n.flags & Notification.FLAG_NO_DISMISS);
-
- // Avoid affecting other tests
- mService.setOngoingDismissal(false);
}
@Test
public void fixNonExempt_Notification_withoutOnGoingFlag_shouldBeDismissible()
throws Exception {
// Given: a non-exempt notification has the flag FLAG_ONGOING_EVENT set
- // feature flag: NOTIFICATION_ONGOING_DISMISSAL is on
- mService.setOngoingDismissal(true);
- mService.setOngoingDismissal(true);
+ // feature flag: ALLOW_DISMISS_ONGOING is on
+ mTestFlagResolver.setFlagOverride(ALLOW_DISMISS_ONGOING, true);
Notification n = new Notification.Builder(mContext, "test")
.setOngoing(false)
.build();
// When: fix the notification with NotificationManagerService
- mService.fixNotification(n, PKG, "tag", 9, 0);
+ mService.fixNotification(n, PKG, "tag", 9, 0, mUid);
// Then: the notification's flag FLAG_NO_DISMISS should not be set
assertEquals(0, n.flags & Notification.FLAG_NO_DISMISS);
-
- // Avoid affecting other tests
- mService.setOngoingDismissal(false);
}
@Test
@@ -10298,21 +10303,18 @@
throws Exception {
when(mDevicePolicyManager.isActiveDeviceOwner(mUid)).thenReturn(true);
// Given: a notification has the flag FLAG_ONGOING_EVENT set
- // feature flag: NOTIFICATION_ONGOING_DISMISSAL is on
- mService.setOngoingDismissal(true);
+ // feature flag: ALLOW_DISMISS_ONGOING is on
+ mTestFlagResolver.setFlagOverride(ALLOW_DISMISS_ONGOING, true);
mService.setSystemExemptFromDismissal(false);
Notification n = new Notification.Builder(mContext, "test")
.setOngoing(true)
.build();
// When: fix the notification with NotificationManagerService
- mService.fixNotification(n, PKG, "tag", 9, 0);
+ mService.fixNotification(n, PKG, "tag", 9, 0, mUid);
// Then: the notification's flag FLAG_NO_DISMISS should be set
assertNotSame(0, n.flags & Notification.FLAG_NO_DISMISS);
-
- // Avoid affecting other tests
- mService.setOngoingDismissal(false);
}
@Test
@@ -10322,21 +10324,19 @@
AppOpsManager.OP_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS, mUid,
PKG)).thenReturn(AppOpsManager.MODE_ALLOWED);
// Given: a notification has the flag FLAG_ONGOING_EVENT set
- // feature flag: NOTIFICATION_ONGOING_DISMISSAL is on
- mService.setOngoingDismissal(true);
+ // feature flag: ALLOW_DISMISS_ONGOING is on
+ mTestFlagResolver.setFlagOverride(ALLOW_DISMISS_ONGOING, true);
mService.setSystemExemptFromDismissal(true);
Notification n = new Notification.Builder(mContext, "test")
.setOngoing(true)
.build();
// When: fix the notification with NotificationManagerService
- mService.fixNotification(n, PKG, "tag", 9, 0);
+ mService.fixNotification(n, PKG, "tag", 9, 0, mUid);
// Then: the notification's flag FLAG_NO_DISMISS should be set
assertNotSame(0, n.flags & Notification.FLAG_NO_DISMISS);
- // Avoid affecting other tests
- mService.setOngoingDismissal(false);
mService.setSystemExemptFromDismissal(false);
}
@@ -10347,20 +10347,17 @@
AppOpsManager.OP_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS, mUid,
PKG)).thenReturn(AppOpsManager.MODE_ALLOWED);
// Given: a notification has the flag FLAG_ONGOING_EVENT set
- // feature flag: NOTIFICATION_ONGOING_DISMISSAL is on
- mService.setOngoingDismissal(true);
+ // feature flag: ALLOW_DISMISS_ONGOING is on
+ mTestFlagResolver.setFlagOverride(ALLOW_DISMISS_ONGOING, true);
mService.setSystemExemptFromDismissal(false);
Notification n = new Notification.Builder(mContext, "test")
.setOngoing(true)
.build();
// When: fix the notification with NotificationManagerService
- mService.fixNotification(n, PKG, "tag", 9, 0);
+ mService.fixNotification(n, PKG, "tag", 9, 0, mUid);
// Then: the notification's flag FLAG_NO_DISMISS should not be set
assertEquals(0, n.flags & Notification.FLAG_NO_DISMISS);
-
- // Avoid affecting other tests
- mService.setOngoingDismissal(false);
}
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
index 98c156e..6f2627a 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
@@ -48,7 +48,6 @@
import android.content.Context;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
-import android.content.pm.PackageManagerInternal;
import android.os.Looper;
import android.os.UserHandle;
import android.os.UserManager;
@@ -169,7 +168,7 @@
mock(ActivityManagerInternal.class),
mock(MultiRateLimiter.class), mock(PermissionHelper.class),
mock(UsageStatsManagerInternal.class), mock (TelecomManager.class),
- mock(NotificationChannelLogger.class));
+ mock(NotificationChannelLogger.class), new TestFlagResolver());
} catch (SecurityException e) {
if (!e.getMessage().contains("Permission Denial: not allowed to send broadcast")) {
throw e;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/TestFlagResolver.java b/services/tests/uiservicestests/src/com/android/server/notification/TestFlagResolver.java
new file mode 100644
index 0000000..3b9726e
--- /dev/null
+++ b/services/tests/uiservicestests/src/com/android/server/notification/TestFlagResolver.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2023 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.server.notification;
+
+import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class TestFlagResolver implements SystemUiSystemPropertiesFlags.FlagResolver {
+ private Map<SystemUiSystemPropertiesFlags.Flag, Boolean> mOverrides = new HashMap<>();
+
+ @Override
+ public boolean isEnabled(SystemUiSystemPropertiesFlags.Flag flag) {
+ return mOverrides.getOrDefault(flag, flag.mDefaultValue);
+ }
+
+ public void setFlagOverride(SystemUiSystemPropertiesFlags.Flag flag, boolean isEnabled) {
+ mOverrides.put(flag, isEnabled);
+ }
+}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/TestableNotificationManagerService.java b/services/tests/uiservicestests/src/com/android/server/notification/TestableNotificationManagerService.java
index 1306d57..dd6923d 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/TestableNotificationManagerService.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/TestableNotificationManagerService.java
@@ -36,8 +36,6 @@
int countLogSmartSuggestionsVisible = 0;
Set<Integer> mChannelToastsSent = new HashSet<>();
- public boolean ONGOING_DISMISSAL = false;
-
String stringArrayResourceValue;
@Nullable
NotificationAssistantAccessGrantedCallback mNotificationAssistantAccessGrantedCallback;
@@ -162,11 +160,6 @@
}
}
- // Mock SystemProperties
- protected void setOngoingDismissal(boolean ongoingDismissal) {
- ONGOING_DISMISSAL = ongoingDismissal;
- }
-
protected void setSystemExemptFromDismissal(boolean isOn) {
mSystemExemptFromDismissal = isOn;
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java
index 4954e89..c2b3783 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java
@@ -147,6 +147,20 @@
}
@Test
+ public void testOpenedCameraInSplitScreen_orientationNotFixed_doNotShowToast() {
+ configureActivity(SCREEN_ORIENTATION_UNSPECIFIED);
+ spyOn(mTask);
+ spyOn(mDisplayRotationCompatPolicy);
+ doReturn(WINDOWING_MODE_MULTI_WINDOW).when(mActivity).getWindowingMode();
+ doReturn(WINDOWING_MODE_MULTI_WINDOW).when(mTask).getWindowingMode();
+
+ mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
+
+ verify(mDisplayRotationCompatPolicy, never()).showToast(
+ R.string.display_rotation_camera_compat_toast_in_split_screen);
+ }
+
+ @Test
public void testOnScreenRotationAnimationFinished_treatmentNotEnabled_doNotShowToast() {
when(mLetterboxConfiguration.isCameraCompatTreatmentEnabled(
/* checkDeviceConfig */ anyBoolean()))
@@ -172,7 +186,7 @@
@Test
public void testOnScreenRotationAnimationFinished_notFullscreen_doNotShowToast() {
configureActivity(SCREEN_ORIENTATION_PORTRAIT);
- doReturn(WINDOWING_MODE_MULTI_WINDOW).when(mActivity).getWindowingMode();
+ doReturn(true).when(mActivity).inMultiWindowMode();
spyOn(mDisplayRotationCompatPolicy);
mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
@@ -184,6 +198,18 @@
}
@Test
+ public void testOnScreenRotationAnimationFinished_orientationNotFixed_doNotShowToast() {
+ configureActivity(SCREEN_ORIENTATION_UNSPECIFIED);
+ mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
+ spyOn(mDisplayRotationCompatPolicy);
+
+ mDisplayRotationCompatPolicy.onScreenRotationAnimationFinished();
+
+ verify(mDisplayRotationCompatPolicy, never()).showToast(
+ R.string.display_rotation_camera_compat_toast_after_rotation);
+ }
+
+ @Test
public void testOnScreenRotationAnimationFinished_showToast() {
configureActivity(SCREEN_ORIENTATION_PORTRAIT);
mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
diff --git a/services/tests/wmtests/src/com/android/server/wm/SurfaceControlTests.java b/services/tests/wmtests/src/com/android/server/wm/SurfaceControlTests.java
new file mode 100644
index 0000000..a27a5fd
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceControlTests.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2023 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.server.wm;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+import android.os.Parcel;
+import android.platform.test.annotations.Presubmit;
+import android.view.SurfaceControl;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Class for testing {@link SurfaceControl}.
+ *
+ * Build/Install/Run:
+ * atest WmTests:SurfaceControlTests
+ */
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class SurfaceControlTests {
+
+ @SmallTest
+ @Test
+ public void testUseValidSurface() {
+ SurfaceControl sc = buildTestSurface();
+ SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ t.setVisibility(sc, false);
+ sc.release();
+ }
+
+ @SmallTest
+ @Test
+ public void testUseInvalidSurface() {
+ SurfaceControl sc = buildTestSurface();
+ SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ sc.release();
+ try {
+ t.setVisibility(sc, false);
+ fail("Expected exception from updating invalid surface");
+ } catch (Exception e) {
+ // Expected exception
+ }
+ }
+
+ @SmallTest
+ @Test
+ public void testUseInvalidSurface_debugEnabled() {
+ SurfaceControl sc = buildTestSurface();
+ SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ try {
+ SurfaceControl.setDebugUsageAfterRelease(true);
+ sc.release();
+ try {
+ t.setVisibility(sc, false);
+ fail("Expected exception from updating invalid surface");
+ } catch (IllegalStateException ise) {
+ assertNotNull(ise.getCause());
+ } catch (Exception e) {
+ fail("Expected IllegalStateException with cause");
+ }
+ } finally {
+ SurfaceControl.setDebugUsageAfterRelease(false);
+ }
+ }
+
+ @SmallTest
+ @Test
+ public void testWriteInvalidSurface_debugEnabled() {
+ SurfaceControl sc = buildTestSurface();
+ SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ Parcel p = Parcel.obtain();
+ try {
+ SurfaceControl.setDebugUsageAfterRelease(true);
+ sc.release();
+ try {
+ sc.writeToParcel(p, 0 /* flags */);
+ fail("Expected exception from writing invalid surface to parcel");
+ } catch (IllegalStateException ise) {
+ assertNotNull(ise.getCause());
+ } catch (Exception e) {
+ fail("Expected IllegalStateException with cause");
+ }
+ } finally {
+ SurfaceControl.setDebugUsageAfterRelease(false);
+ p.recycle();
+ }
+ }
+
+ private SurfaceControl buildTestSurface() {
+ return new SurfaceControl.Builder()
+ .setContainerLayer()
+ .setName("SurfaceControlTests")
+ .setCallsite("SurfaceControlTests")
+ .build();
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 12e5ed9..77b2638 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -1627,6 +1627,8 @@
int status, int mRequest, long mFunctions, boolean mChargingFunctions);
public abstract void getUsbSpeedCb(int speed);
+
+ public abstract void resetCb(int status);
}
private static final class UsbHandlerLegacy extends UsbHandler {
@@ -1988,14 +1990,30 @@
return true;
}
+ /**
+ * This callback function is only applicable for USB Gadget HAL,
+ * USBHandlerLegacy does not supported it.
+ */
@Override
public void setCurrentUsbFunctionsCb(long functions,
int status, int mRequest, long mFunctions, boolean mChargingFunctions){
}
+ /**
+ * This callback function is only applicable for USB Gadget HAL,
+ * USBHandlerLegacy does not supported it.
+ */
@Override
public void getUsbSpeedCb(int speed){
}
+
+ /**
+ * This callback function is only applicable for USB Gadget HAL,
+ * USBHandlerLegacy does not supported it.
+ */
+ @Override
+ public void resetCb(int status){
+ }
}
private static final class UsbHandlerHal extends UsbHandler {
@@ -2147,6 +2165,7 @@
}
break;
case MSG_RESET_USB_GADGET:
+ operationId = sUsbOperationCount.incrementAndGet();
synchronized (mGadgetProxyLock) {
if (mUsbGadgetHal == null) {
Slog.e(TAG, "reset Usb Gadget mUsbGadgetHal is null");
@@ -2160,7 +2179,7 @@
if (mConfigured) {
mResetUsbGadgetDisableDebounce = true;
}
- mUsbGadgetHal.reset();
+ mUsbGadgetHal.reset(operationId);
} catch (Exception e) {
Slog.e(TAG, "reset Usb Gadget failed", e);
mResetUsbGadgetDisableDebounce = false;
@@ -2222,6 +2241,12 @@
mUsbSpeed = speed;
}
+ @Override
+ public void resetCb(int status) {
+ if (status != Status.SUCCESS)
+ Slog.e(TAG, "resetCb fail");
+ }
+
private void setUsbConfig(long config, boolean chargingFunctions, int operationId) {
if (true) Slog.d(TAG, "setUsbConfig(" + config + ") request:" + ++mCurrentRequest);
/**
@@ -2363,6 +2388,10 @@
mHandler.getUsbSpeedCb(speed);
}
+ public void resetCb(int status) {
+ mHandler.resetCb(status);
+ }
+
/**
* Returns a dup of the control file descriptor for the given function.
*/
diff --git a/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetAidl.java b/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetAidl.java
index bdfe60a..d47ccc7 100644
--- a/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetAidl.java
+++ b/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetAidl.java
@@ -23,6 +23,7 @@
import android.annotation.Nullable;
import android.hardware.usb.gadget.IUsbGadget;
import android.hardware.usb.gadget.IUsbGadgetCallback;
+import android.hardware.usb.Status;
import android.hardware.usb.UsbManager.UsbGadgetHalVersion;
import android.os.ServiceManager;
import android.os.IBinder;
@@ -139,14 +140,15 @@
}
@Override
- public void reset() {
+ public void reset(long operationId) {
try {
synchronized (mGadgetProxyLock) {
- mGadgetProxy.reset();
+ mGadgetProxy.reset(new UsbGadgetCallback(), operationId);
}
} catch (RemoteException e) {
logAndPrintException(mPw,
- "RemoteException while calling getUsbSpeed", e);
+ "RemoteException while calling getUsbSpeed"
+ + ", opID:" + operationId, e);
return;
}
}
@@ -155,7 +157,7 @@
public void setCurrentUsbFunctions(int mRequest, long mFunctions,
boolean mChargingFunctions, int timeout, long operationId) {
try {
- mUsbGadgetCallback = new UsbGadgetCallback(mRequest,
+ mUsbGadgetCallback = new UsbGadgetCallback(null, mRequest,
mFunctions, mChargingFunctions);
synchronized (mGadgetProxyLock) {
mGadgetProxy.setCurrentUsbFunctions(mFunctions, mUsbGadgetCallback,
@@ -174,6 +176,7 @@
}
private class UsbGadgetCallback extends IUsbGadgetCallback.Stub {
+ public IndentingPrintWriter mPw;
public int mRequest;
public long mFunctions;
public boolean mChargingFunctions;
@@ -181,8 +184,9 @@
UsbGadgetCallback() {
}
- UsbGadgetCallback(int request, long functions,
+ UsbGadgetCallback(IndentingPrintWriter pw, int request, long functions,
boolean chargingFunctions) {
+ mPw = pw;
mRequest = request;
mFunctions = functions;
mChargingFunctions = chargingFunctions;
@@ -191,6 +195,15 @@
@Override
public void setCurrentUsbFunctionsCb(long functions,
int status, long transactionId) {
+ if (status == Status.SUCCESS) {
+ logAndPrint(Log.INFO, mPw, "Usb setCurrentUsbFunctionsCb"
+ + " ,functions:" + functions + " ,status:" + status
+ + " ,transactionId:" + transactionId);
+ } else {
+ logAndPrint(Log.ERROR, mPw, "Usb setCurrentUsbFunctionsCb failed"
+ + " ,functions:" + functions + " ,status:" + status
+ + " ,transactionId:" + transactionId);
+ }
mDeviceManager.setCurrentUsbFunctionsCb(functions, status,
mRequest, mFunctions, mChargingFunctions);
}
@@ -198,15 +211,38 @@
@Override
public void getCurrentUsbFunctionsCb(long functions,
int status, long transactionId) {
+ if (status == Status.SUCCESS) {
+ logAndPrint(Log.INFO, mPw, "Usb getCurrentUsbFunctionsCb"
+ + " ,functions:" + functions + " ,status:" + status
+ + " ,transactionId:" + transactionId);
+ } else {
+ logAndPrint(Log.ERROR, mPw, "Usb getCurrentUsbFunctionsCb failed"
+ + " ,functions:" + functions + " ,status:" + status
+ + " ,transactionId:" + transactionId);
+ }
mDeviceManager.getCurrentUsbFunctionsCb(functions, status);
}
@Override
public void getUsbSpeedCb(int speed, long transactionId) {
+ logAndPrint(Log.INFO, mPw, "getUsbSpeedCb speed:"
+ + speed + " ,transactionId:" + transactionId);
mDeviceManager.getUsbSpeedCb(speed);
}
@Override
+ public void resetCb(int status, long transactionId) {
+ if (status == Status.SUCCESS) {
+ logAndPrint(Log.INFO, mPw, "Usb resetCb status:"
+ + status + " ,transactionId:" + transactionId);
+ } else {
+ logAndPrint(Log.ERROR, mPw, "Usb resetCb status"
+ + status + " ,transactionId:" + transactionId);
+ }
+ mDeviceManager.resetCb(status);
+ }
+
+ @Override
public String getInterfaceHash() {
return IUsbGadgetCallback.HASH;
}
diff --git a/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetHal.java b/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetHal.java
index 267247b..7b52f46 100644
--- a/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetHal.java
+++ b/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetHal.java
@@ -112,8 +112,11 @@
* This function is used to reset USB gadget driver.
* Performs USB data connection reset. The connection will disconnect and
* reconnect.
+ *
+ * @param transactionId Used for tracking the current request and is passed down to the HAL
+ * implementation as needed.
*/
- public void reset();
+ public void reset(long transactionId);
/**
* Invoked to query the version of current gadget hal implementation.
diff --git a/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetHidl.java b/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetHidl.java
index 3e5ecc5..2c5fcb8 100644
--- a/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetHidl.java
+++ b/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetHidl.java
@@ -188,7 +188,7 @@
}
@Override
- public void reset() {
+ public void reset(long transactionId) {
try {
synchronized(mGadgetProxyLock) {
if (android.hardware.usb.gadget.V1_2.IUsbGadget.castFrom(mGadgetProxy) != null) {
@@ -199,7 +199,7 @@
}
} catch (RemoteException e) {
logAndPrintException(mPw,
- "RemoteException while calling getUsbSpeed", e);
+ "RemoteException while calling reset", e);
return;
}
}
diff --git a/telephony/java/android/telephony/AnomalyReporter.java b/telephony/java/android/telephony/AnomalyReporter.java
index 061b71b..d676eee 100644
--- a/telephony/java/android/telephony/AnomalyReporter.java
+++ b/telephony/java/android/telephony/AnomalyReporter.java
@@ -110,8 +110,15 @@
return;
}
- // Don't report if the server-side flag isn't loaded, as it implies other anomaly report
- // related config hasn't loaded.
+ //always write atoms to statsd
+ TelephonyStatsLog.write(
+ TELEPHONY_ANOMALY_DETECTED,
+ carrierId,
+ eventId.getLeastSignificantBits(),
+ eventId.getMostSignificantBits());
+
+ // Don't report via Intent if the server-side flag isn't loaded, as it implies other anomaly
+ // report related config hasn't loaded.
try {
boolean isAnomalyReportEnabledFromServer = DeviceConfig.getBoolean(
DeviceConfig.NAMESPACE_TELEPHONY, KEY_IS_TELEPHONY_ANOMALY_REPORT_ENABLED,
@@ -122,12 +129,6 @@
return;
}
- TelephonyStatsLog.write(
- TELEPHONY_ANOMALY_DETECTED,
- carrierId,
- eventId.getLeastSignificantBits(),
- eventId.getMostSignificantBits());
-
// If this event has already occurred, skip sending intents for it; regardless log its
// invocation here.
Integer count = sEvents.containsKey(eventId) ? sEvents.get(eventId) + 1 : 1;
diff --git a/telephony/java/android/telephony/DataFailCause.java b/telephony/java/android/telephony/DataFailCause.java
index b83b400..c4d760f 100644
--- a/telephony/java/android/telephony/DataFailCause.java
+++ b/telephony/java/android/telephony/DataFailCause.java
@@ -1012,6 +1012,8 @@
public static final int IWLAN_DNS_RESOLUTION_NAME_FAILURE = 0x4004;
/** No response received from the DNS Server due to a timeout*/
public static final int IWLAN_DNS_RESOLUTION_TIMEOUT = 0x4005;
+ /** Expected to update or bring down an ePDG tunnel, but no tunnel found*/
+ public static final int IWLAN_TUNNEL_NOT_FOUND = 0x4006;
// OEM sepecific error codes. To be used by OEMs when they don't
// want to reveal error code which would be replaced by ERROR_UNSPECIFIED
@@ -1505,6 +1507,7 @@
sFailCauseMap.put(IWLAN_IKEV2_CERT_INVALID, "IWLAN_IKEV2_CERT_INVALID");
sFailCauseMap.put(IWLAN_DNS_RESOLUTION_NAME_FAILURE, "IWLAN_DNS_RESOLUTION_NAME_FAILURE");
sFailCauseMap.put(IWLAN_DNS_RESOLUTION_TIMEOUT, "IWLAN_DNS_RESOLUTION_TIMEOUT");
+ sFailCauseMap.put(IWLAN_TUNNEL_NOT_FOUND, "IWLAN_TUNNEL_NOT_FOUND");
sFailCauseMap.put(OEM_DCFAILCAUSE_1, "OEM_DCFAILCAUSE_1");
sFailCauseMap.put(OEM_DCFAILCAUSE_2, "OEM_DCFAILCAUSE_2");
sFailCauseMap.put(OEM_DCFAILCAUSE_3, "OEM_DCFAILCAUSE_3");
diff --git a/tests/UsbTests/src/com/android/server/usb/UsbHandlerTest.java b/tests/UsbTests/src/com/android/server/usb/UsbHandlerTest.java
index 4103ca7..210e3ea 100644
--- a/tests/UsbTests/src/com/android/server/usb/UsbHandlerTest.java
+++ b/tests/UsbTests/src/com/android/server/usb/UsbHandlerTest.java
@@ -148,6 +148,10 @@
public void getUsbSpeedCb(int speed){
}
+ @Override
+ public void resetCb(int status){
+ }
+
}
@Before