summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java5
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java2
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java2
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/ContentObserverController.java3
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java3
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/PrefetchController.java2
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java5
-rw-r--r--core/api/current.txt34
-rw-r--r--core/api/system-current.txt6
-rw-r--r--core/java/android/hardware/camera2/impl/CameraMetadataNative.java6
-rw-r--r--core/java/android/hardware/camera2/params/StreamConfigurationMap.java3
-rw-r--r--core/java/android/os/GraphicsEnvironment.java12
-rw-r--r--core/java/android/service/autofill/Dataset.java136
-rw-r--r--core/java/android/service/dreams/DreamActivity.java10
-rw-r--r--core/java/android/service/dreams/DreamService.java4
-rw-r--r--core/java/android/view/View.java18
-rw-r--r--core/java/android/view/ViewRootImpl.java22
-rw-r--r--core/java/android/view/autofill/AutofillManager.java9
-rw-r--r--core/java/android/window/SurfaceSyncGroup.java59
-rw-r--r--core/res/res/values/config.xml12
-rw-r--r--core/res/res/values/symbols.xml6
-rw-r--r--core/tests/coretests/src/android/provider/NameValueCacheTest.java54
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java129
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java10
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizer.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPip.aidl5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java14
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionState.java10
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java38
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/TaskPositioner.java24
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/TaskPositionerTest.kt92
-rw-r--r--libs/hwui/hwui/ImageDecoder.cpp11
-rw-r--r--libs/hwui/hwui/ImageDecoder.h2
-rw-r--r--libs/hwui/jni/ImageDecoder.cpp3
-rw-r--r--media/java/android/media/tv/ITvInputManager.aidl2
-rw-r--r--media/java/android/media/tv/ITvInputSession.aidl2
-rw-r--r--media/java/android/media/tv/ITvInputSessionWrapper.java4
-rw-r--r--media/java/android/media/tv/TableResponse.java147
-rw-r--r--media/java/android/media/tv/TvInputManager.java4
-rw-r--r--media/java/android/media/tv/TvInputService.java6
-rw-r--r--media/java/android/media/tv/TvRecordingInfo.java7
-rw-r--r--media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl2
-rw-r--r--media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl2
-rw-r--r--media/java/android/media/tv/interactive/ITvInteractiveAppSessionWrapper.java2
-rwxr-xr-xmedia/java/android/media/tv/interactive/TvInteractiveAppManager.java8
-rwxr-xr-xmedia/java/android/media/tv/interactive/TvInteractiveAppService.java9
-rwxr-xr-xmedia/java/android/media/tv/interactive/TvInteractiveAppView.java4
-rw-r--r--packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt1
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/GenerationRegistry.java32
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java32
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java6
-rw-r--r--packages/SettingsProvider/test/src/com/android/providers/settings/GenerationRegistryTest.java20
-rw-r--r--packages/SystemUI/res/drawable/ic_magnification_menu_large.xml4
-rw-r--r--packages/SystemUI/res/drawable/ic_magnification_menu_medium.xml4
-rw-r--r--packages/SystemUI/res/drawable/ic_magnification_menu_small.xml4
-rw-r--r--packages/SystemUI/res/drawable/ic_open_in_full.xml4
-rw-r--r--packages/SystemUI/res/layout/window_magnification_settings_view.xml45
-rw-r--r--packages/SystemUI/res/values/styles.xml1
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java11
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java10
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java15
-rw-r--r--packages/SystemUI/src/com/android/keyguard/LockIconViewController.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractor.kt71
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/Flags.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/BouncerView.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt50
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractor.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/shared/model/ScrimAlpha.kt23
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt49
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java32
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationSettingsTest.java7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java38
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractorTest.kt116
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt86
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt87
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt14
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java26
-rw-r--r--services/autofill/java/com/android/server/autofill/Session.java88
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java6
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerShellCommand.java1
-rw-r--r--services/core/java/com/android/server/am/CoreSettingsObserver.java4
-rw-r--r--services/core/java/com/android/server/appop/AppOpsCheckingServiceTracingDecorator.java2
-rw-r--r--services/core/java/com/android/server/location/contexthub/ContextHubService.java22
-rw-r--r--services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java12
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java5
-rw-r--r--services/core/java/com/android/server/policy/PowerAction.java11
-rw-r--r--services/core/java/com/android/server/policy/RestartAction.java11
-rw-r--r--services/core/java/com/android/server/tv/TvInputManagerService.java4
-rw-r--r--services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java6
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java2
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java3
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java28
-rw-r--r--services/core/java/com/android/server/wm/LetterboxUiController.java4
-rw-r--r--services/core/java/com/android/server/wm/Task.java3
-rw-r--r--services/credentials/java/com/android/server/credentials/MetricUtilities.java90
-rw-r--r--services/credentials/java/com/android/server/credentials/ProviderSession.java6
-rw-r--r--services/credentials/java/com/android/server/credentials/RequestSession.java4
-rw-r--r--services/credentials/java/com/android/server/credentials/metrics/CandidateBrowsingPhaseMetric.java75
-rw-r--r--services/credentials/java/com/android/server/credentials/metrics/CandidatePhaseMetric.java246
-rw-r--r--services/credentials/java/com/android/server/credentials/metrics/CandidateProviderMetric.java89
-rw-r--r--services/credentials/java/com/android/server/credentials/metrics/ChosenProviderMetric.java8
-rw-r--r--services/tests/servicestests/src/com/android/server/location/contexthub/ContextHubServiceTest.java5
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java18
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SurfaceSyncGroupTest.java52
-rw-r--r--telephony/java/android/telephony/PhoneNumberUtils.java26
-rw-r--r--wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java22
-rw-r--r--wifi/java/src/android/net/wifi/sharedconnectivity/service/SharedConnectivityService.java28
-rw-r--r--wifi/tests/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManagerTest.java16
-rw-r--r--wifi/tests/src/android/net/wifi/sharedconnectivity/service/SharedConnectivityServiceTest.java47
123 files changed, 2151 insertions, 707 deletions
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
index 74033f3fbf09..89eb1a9a7650 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
@@ -533,7 +533,8 @@ class JobConcurrencyManager {
mIdleContexts.add(
mInjector.createJobServiceContext(mService, this,
mNotificationCoordinator, batteryStats,
- mService.mJobPackageTracker, mContext.getMainLooper()));
+ mService.mJobPackageTracker,
+ AppSchedulingModuleThread.get().getLooper()));
}
}
@@ -1925,7 +1926,7 @@ class JobConcurrencyManager {
return mInjector.createJobServiceContext(mService, this, mNotificationCoordinator,
IBatteryStats.Stub.asInterface(
ServiceManager.getService(BatteryStats.SERVICE_NAME)),
- mService.mJobPackageTracker, mContext.getMainLooper());
+ mService.mJobPackageTracker, AppSchedulingModuleThread.get().getLooper());
}
@GuardedBy("mLock")
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 f83eeba88bfb..3cc67e7b5677 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -2009,7 +2009,7 @@ public class JobSchedulerService extends com.android.server.SystemService
mActivityManagerInternal = Objects.requireNonNull(
LocalServices.getService(ActivityManagerInternal.class));
- mHandler = new JobHandler(context.getMainLooper());
+ mHandler = new JobHandler(AppSchedulingModuleThread.get().getLooper());
mConstants = new Constants();
mConstantsObserver = new ConstantsObserver();
mJobSchedulerStub = new JobSchedulerStub();
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
index f0d019e307b0..e55bda7fab02 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
@@ -256,7 +256,7 @@ public final class ConnectivityController extends RestrictingController implemen
public ConnectivityController(JobSchedulerService service,
@NonNull FlexibilityController flexibilityController) {
super(service);
- mHandler = new CcHandler(mContext.getMainLooper());
+ mHandler = new CcHandler(AppSchedulingModuleThread.get().getLooper());
mConnManager = mContext.getSystemService(ConnectivityManager.class);
mNetPolicyManagerInternal = LocalServices.getService(NetworkPolicyManagerInternal.class);
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/ContentObserverController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/ContentObserverController.java
index 847a1bfe4465..122fe695c70b 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/ContentObserverController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/ContentObserverController.java
@@ -33,6 +33,7 @@ import android.util.SparseArray;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
+import com.android.server.AppSchedulingModuleThread;
import com.android.server.job.JobSchedulerService;
import com.android.server.job.StateControllerProto;
import com.android.server.job.StateControllerProto.ContentObserverController.Observer.TriggerContentData;
@@ -70,7 +71,7 @@ public final class ContentObserverController extends StateController {
public ContentObserverController(JobSchedulerService service) {
super(service);
- mHandler = new Handler(mContext.getMainLooper());
+ mHandler = new Handler(AppSchedulingModuleThread.get().getLooper());
}
@Override
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java
index bdf72b64d3e0..d5c9ae615486 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java
@@ -36,6 +36,7 @@ import android.util.SparseBooleanArray;
import android.util.proto.ProtoOutputStream;
import com.android.internal.util.ArrayUtils;
+import com.android.server.AppSchedulingModuleThread;
import com.android.server.DeviceIdleInternal;
import com.android.server.LocalServices;
import com.android.server.job.JobSchedulerService;
@@ -127,7 +128,7 @@ public final class DeviceIdleJobsController extends StateController {
public DeviceIdleJobsController(JobSchedulerService service) {
super(service);
- mHandler = new DeviceIdleJobsDelayHandler(mContext.getMainLooper());
+ mHandler = new DeviceIdleJobsDelayHandler(AppSchedulingModuleThread.get().getLooper());
// Register for device idle mode changes
mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
mLocalDeviceIdleController =
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/PrefetchController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/PrefetchController.java
index c065f2cfba52..2b7438c862bd 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/PrefetchController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/PrefetchController.java
@@ -130,7 +130,7 @@ public class PrefetchController extends StateController {
public PrefetchController(JobSchedulerService service) {
super(service);
mPcConstants = new PcConstants();
- mHandler = new PcHandler(mContext.getMainLooper());
+ mHandler = new PcHandler(AppSchedulingModuleThread.get().getLooper());
mThresholdAlarmListener = new ThresholdAlarmListener(
mContext, AppSchedulingModuleThread.get().getLooper());
mUsageStatsManagerInternal = LocalServices.getService(UsageStatsManagerInternal.class);
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
index 90a29d80e86d..aca0a6e9b18c 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
@@ -560,13 +560,14 @@ public final class QuotaController extends StateController {
@NonNull BackgroundJobsController backgroundJobsController,
@NonNull ConnectivityController connectivityController) {
super(service);
- mHandler = new QcHandler(mContext.getMainLooper());
+ mHandler = new QcHandler(AppSchedulingModuleThread.get().getLooper());
mAlarmManager = mContext.getSystemService(AlarmManager.class);
mQcConstants = new QcConstants();
mBackgroundJobsController = backgroundJobsController;
mConnectivityController = connectivityController;
mIsEnabled = !mConstants.USE_TARE_POLICY;
- mInQuotaAlarmQueue = new InQuotaAlarmQueue(mContext, mContext.getMainLooper());
+ mInQuotaAlarmQueue =
+ new InQuotaAlarmQueue(mContext, AppSchedulingModuleThread.get().getLooper());
// Set up the app standby bucketing tracker
AppStandbyInternal appStandby = LocalServices.getService(AppStandbyInternal.class);
diff --git a/core/api/current.txt b/core/api/current.txt
index 5b9970b6c15d..a53de83c882d 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -26782,9 +26782,7 @@ package android.media.tv {
}
public final class TableResponse extends android.media.tv.BroadcastInfoResponse implements android.os.Parcelable {
- ctor public TableResponse(int, int, int, @Nullable android.net.Uri, int, int);
- ctor public TableResponse(int, int, int, @NonNull byte[], int, int);
- ctor public TableResponse(int, int, int, @NonNull android.os.SharedMemory, int, int);
+ ctor @Deprecated public TableResponse(int, int, int, @Nullable android.net.Uri, int, int);
method public int getSize();
method @Nullable public byte[] getTableByteArray();
method @Nullable public android.os.SharedMemory getTableSharedMemory();
@@ -26793,6 +26791,14 @@ package android.media.tv {
field @NonNull public static final android.os.Parcelable.Creator<android.media.tv.TableResponse> CREATOR;
}
+ public static final class TableResponse.Builder {
+ ctor public TableResponse.Builder(int, int, int, int, int);
+ method @NonNull public android.media.tv.TableResponse build();
+ method @NonNull public android.media.tv.TableResponse.Builder setTableByteArray(@NonNull byte[]);
+ method @NonNull public android.media.tv.TableResponse.Builder setTableSharedMemory(@NonNull android.os.SharedMemory);
+ method @NonNull public android.media.tv.TableResponse.Builder setTableUri(@NonNull android.net.Uri);
+ }
+
public final class TimelineRequest extends android.media.tv.BroadcastInfoRequest implements android.os.Parcelable {
ctor public TimelineRequest(int, int, int);
ctor public TimelineRequest(int, int, int, @NonNull String);
@@ -27432,7 +27438,7 @@ package android.media.tv {
method public void notifyTvMessage(@NonNull String, @NonNull android.os.Bundle);
method public void notifyVideoAvailable();
method public void notifyVideoUnavailable(int);
- method public void onAdBuffer(@NonNull android.media.tv.AdBuffer);
+ method public void onAdBufferReady(@NonNull android.media.tv.AdBuffer);
method public void onAppPrivateCommand(@NonNull String, android.os.Bundle);
method public android.view.View onCreateOverlayView();
method public boolean onGenericMotionEvent(android.view.MotionEvent);
@@ -27501,17 +27507,17 @@ package android.media.tv {
method @NonNull public android.net.Uri getChannelUri();
method @NonNull public java.util.List<android.media.tv.TvContentRating> getContentRatings();
method @NonNull public String getDescription();
- method @NonNull public long getEndPaddingMillis();
+ method public long getEndPaddingMillis();
method @NonNull public String getName();
method @Nullable public android.net.Uri getProgramUri();
- method @IntRange(from=0xffffffff) @NonNull public long getRecordingDurationMillis();
+ method @IntRange(from=0xffffffff) public long getRecordingDurationMillis();
method @NonNull public String getRecordingId();
- method @IntRange(from=0xffffffff) @NonNull public long getRecordingStartTimeMillis();
+ method @IntRange(from=0xffffffff) public long getRecordingStartTimeMillis();
method @Nullable public android.net.Uri getRecordingUri();
- method @NonNull public int getRepeatDays();
- method @IntRange(from=0) @NonNull public long getScheduledDurationMillis();
- method @IntRange(from=0) @NonNull public long getScheduledStartTimeMillis();
- method @NonNull public long getStartPaddingMillis();
+ method public int getRepeatDays();
+ method @IntRange(from=0) public long getScheduledDurationMillis();
+ method @IntRange(from=0) public long getScheduledStartTimeMillis();
+ method public long getStartPaddingMillis();
method public void setDescription(@NonNull String);
method public void setName(@NonNull String);
method public void writeToParcel(@NonNull android.os.Parcel, int);
@@ -27743,7 +27749,7 @@ package android.media.tv.interactive {
ctor public TvInteractiveAppService.Session(@NonNull android.content.Context);
method public boolean isMediaViewEnabled();
method @CallSuper public void layoutSurface(int, int, int, int);
- method @CallSuper public void notifyAdBuffer(@NonNull android.media.tv.AdBuffer);
+ method @CallSuper public void notifyAdBufferReady(@NonNull android.media.tv.AdBuffer);
method @CallSuper public final void notifyBiInteractiveAppCreated(@NonNull android.net.Uri, @Nullable String);
method @CallSuper public void notifySessionStateChanged(int, int);
method @CallSuper public final void notifyTeletextAppStateChanged(int);
@@ -27817,7 +27823,7 @@ package android.media.tv.interactive {
method @CallSuper public void requestTimeShiftMode();
method @CallSuper public void requestTrackInfoList();
method @CallSuper public void requestTvRecordingInfo(@NonNull String);
- method @CallSuper public void requestTvRecordingInfoList(@NonNull int);
+ method @CallSuper public void requestTvRecordingInfoList(int);
method @CallSuper public void sendPlaybackCommandRequest(@NonNull String, @Nullable android.os.Bundle);
method @CallSuper public void sendTimeShiftCommandRequest(@NonNull String, @Nullable android.os.Bundle);
method @CallSuper public void setMediaViewEnabled(boolean);
@@ -27916,7 +27922,7 @@ package android.media.tv.interactive {
method public void onRequestTimeShiftMode(@NonNull String);
method public void onRequestTrackInfoList(@NonNull String);
method public void onRequestTvRecordingInfo(@NonNull String, @NonNull String);
- method public void onRequestTvRecordingInfoList(@NonNull String, @NonNull int);
+ method public void onRequestTvRecordingInfoList(@NonNull String, int);
method public void onSetTvRecordingInfo(@NonNull String, @NonNull String, @NonNull android.media.tv.TvRecordingInfo);
method public void onSetVideoBounds(@NonNull String, @NonNull android.graphics.Rect);
method public void onStateChanged(@NonNull String, int, int);
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 01b0c7d30831..995602f27d2b 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -10129,9 +10129,9 @@ package android.net.wifi.sharedconnectivity.app {
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public boolean disconnectHotspotNetwork(@NonNull android.net.wifi.sharedconnectivity.app.HotspotNetwork);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public boolean forgetKnownNetwork(@NonNull android.net.wifi.sharedconnectivity.app.KnownNetwork);
method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public android.net.wifi.sharedconnectivity.app.HotspotNetworkConnectionStatus getHotspotNetworkConnectionStatus();
- method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.List<android.net.wifi.sharedconnectivity.app.HotspotNetwork> getHotspotNetworks();
+ method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.List<android.net.wifi.sharedconnectivity.app.HotspotNetwork> getHotspotNetworks();
method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public android.net.wifi.sharedconnectivity.app.KnownNetworkConnectionStatus getKnownNetworkConnectionStatus();
- method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.List<android.net.wifi.sharedconnectivity.app.KnownNetwork> getKnownNetworks();
+ method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.List<android.net.wifi.sharedconnectivity.app.KnownNetwork> getKnownNetworks();
method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public android.net.wifi.sharedconnectivity.app.SharedConnectivitySettingsState getSettingsState();
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void registerCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.sharedconnectivity.app.SharedConnectivityClientCallback);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public boolean unregisterCallback(@NonNull android.net.wifi.sharedconnectivity.app.SharedConnectivityClientCallback);
@@ -10158,6 +10158,8 @@ package android.net.wifi.sharedconnectivity.service {
public abstract class SharedConnectivityService extends android.app.Service {
ctor public SharedConnectivityService();
+ method public static boolean areHotspotNetworksEnabledForService(@NonNull android.content.Context);
+ method public static boolean areKnownNetworksEnabledForService(@NonNull android.content.Context);
method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent);
method public abstract void onConnectHotspotNetwork(@NonNull android.net.wifi.sharedconnectivity.app.HotspotNetwork);
method public abstract void onConnectKnownNetwork(@NonNull android.net.wifi.sharedconnectivity.app.KnownNetwork);
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index 9640b0e506da..631df014a580 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -1132,6 +1132,12 @@ public class CameraMetadataNative implements Parcelable {
private boolean setGpsLocation(Location l) {
if (l == null) {
+ // If Location value being set is null, remove corresponding keys.
+ // This is safe because api1/client2/CameraParameters.cpp already erases
+ // the keys for JPEG_GPS_LOCATION for certain cases.
+ setBase(CaptureRequest.JPEG_GPS_TIMESTAMP, null);
+ setBase(CaptureRequest.JPEG_GPS_COORDINATES, null);
+ setBase(CaptureRequest.JPEG_GPS_PROCESSING_METHOD, null);
return false;
}
diff --git a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
index cb678b98a998..5a48176d29e7 100644
--- a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
+++ b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
@@ -26,7 +26,6 @@ import android.hardware.camera2.CameraMetadata;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.utils.HashCodeHelpers;
import android.hardware.camera2.utils.SurfaceUtils;
-import android.util.Log;
import android.util.Range;
import android.util.Size;
import android.util.SparseIntArray;
@@ -2019,7 +2018,7 @@ public final class StreamConfigurationMap {
/**
* @hide
*/
- public static final int HAL_DATASPACE_HEIF = 0x1003;
+ public static final int HAL_DATASPACE_HEIF = 0x1004;
/**
* @hide
*/
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index fb8f84acc8f3..a52e3d49148d 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -474,9 +474,8 @@ public class GraphicsEnvironment {
* target functionality. The ANGLE broadcast receiver code will apply a "deferlist" at
* the first boot of a newly-flashed device. However, there is a gap in time between
* when applications can start and when the deferlist is applied. For now, assume that
- * if ANGLE is the system driver and Settings.Global.ANGLE_GL_DRIVER_SELECTION_PKGS is
- * empty, that the deferlist has not yet been applied. In this case, select the Legacy
- * driver.
+ * if ANGLE is the system driver and Settings.Global.ANGLE_DEFERLIST is empty, that the
+ * deferlist has not yet been applied. In this case, select the Legacy driver.
* otherwise ...
* 3) Use ANGLE if isAngleEnabledByGameMode() returns true; otherwise ...
* 4) The global switch (i.e. use the system driver, whether ANGLE or legacy;
@@ -516,14 +515,17 @@ public class GraphicsEnvironment {
contentResolver, bundle, Settings.Global.ANGLE_GL_DRIVER_SELECTION_PKGS);
final List<String> optInValues = getGlobalSettingsString(
contentResolver, bundle, Settings.Global.ANGLE_GL_DRIVER_SELECTION_VALUES);
+ final List<String> angleDeferlist = getGlobalSettingsString(
+ contentResolver, bundle, Settings.Global.ANGLE_DEFERLIST);
Log.v(TAG, "Currently set values for:");
Log.v(TAG, " angle_gl_driver_selection_pkgs =" + optInPackages);
Log.v(TAG, " angle_gl_driver_selection_values =" + optInValues);
// If ANGLE is the system driver AND the deferlist has not yet been applied, select the
// Legacy driver
- if (mAngleIsSystemDriver && optInPackages.size() <= 1) {
- Log.v(TAG, "Ignoring angle_gl_driver_selection_* until deferlist has been applied");
+ if (mAngleIsSystemDriver && angleDeferlist.size() == 0) {
+ Log.v(TAG, "ANGLE deferlist (" + Settings.Global.ANGLE_DEFERLIST + ") has not been "
+ + "applied, defaulting to legacy driver");
return ANGLE_GL_DRIVER_TO_USE_LEGACY;
}
diff --git a/core/java/android/service/autofill/Dataset.java b/core/java/android/service/autofill/Dataset.java
index 0ef8bb64acaf..e81ca1ada98a 100644
--- a/core/java/android/service/autofill/Dataset.java
+++ b/core/java/android/service/autofill/Dataset.java
@@ -28,6 +28,7 @@ import android.content.ClipData;
import android.content.IntentSender;
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.ArrayMap;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillManager;
import android.view.autofill.AutofillValue;
@@ -434,14 +435,14 @@ public final class Dataset implements Parcelable {
* one value for a field or set an authentication intent.
*/
public static final class Builder {
- private ArrayList<AutofillId> mFieldIds;
- private ArrayList<AutofillValue> mFieldValues;
- private ArrayList<RemoteViews> mFieldPresentations;
- private ArrayList<RemoteViews> mFieldDialogPresentations;
- private ArrayList<InlinePresentation> mFieldInlinePresentations;
- private ArrayList<InlinePresentation> mFieldInlineTooltipPresentations;
- private ArrayList<DatasetFieldFilter> mFieldFilters;
- private ArrayList<String> mAutofillDatatypes;
+ private ArrayList<AutofillId> mFieldIds = new ArrayList<>();
+ private ArrayList<AutofillValue> mFieldValues = new ArrayList();
+ private ArrayList<RemoteViews> mFieldPresentations = new ArrayList();
+ private ArrayList<RemoteViews> mFieldDialogPresentations = new ArrayList();
+ private ArrayList<InlinePresentation> mFieldInlinePresentations = new ArrayList();
+ private ArrayList<InlinePresentation> mFieldInlineTooltipPresentations = new ArrayList();
+ private ArrayList<DatasetFieldFilter> mFieldFilters = new ArrayList();
+ private ArrayList<String> mAutofillDatatypes = new ArrayList();
@Nullable private ClipData mFieldContent;
private RemoteViews mPresentation;
private RemoteViews mDialogPresentation;
@@ -452,6 +453,15 @@ public final class Dataset implements Parcelable {
@Nullable private String mId;
/**
+ * Usually, a field will be associated with a single autofill id and/or datatype.
+ * There could be null field value corresponding to different autofill ids or datatye
+ * values, but the implementation is ok with duplicating that information.
+ * This map is just for the purpose of optimization, to reduce the size of the pelled data
+ * over the binder transaction.
+ */
+ private ArrayMap<Field, Integer> mFieldToIndexdMap = new ArrayMap<>();
+
+ /**
* Creates a new builder.
*
* @param presentation The presentation used to visualize this dataset.
@@ -1051,29 +1061,40 @@ public final class Dataset implements Parcelable {
*/
public @NonNull Builder setField(@NonNull AutofillId id, @Nullable Field field) {
throwIfDestroyed();
+
+ if (mFieldToIndexdMap.containsKey(field)) {
+ int index = mFieldToIndexdMap.get(field);
+ if (mFieldIds.get(index) == null) {
+ mFieldIds.set(index, id);
+ return this;
+ }
+ // if the Autofill Id is already set, ignore and proceed as if setting in a new
+ // value.
+ }
+ int index;
if (field == null) {
- setLifeTheUniverseAndEverything(id, null, null, null, null, null, null);
+ index = setLifeTheUniverseAndEverything(id, null, null, null, null, null, null);
} else {
final DatasetFieldFilter filter = field.getDatasetFieldFilter();
final Presentations presentations = field.getPresentations();
if (presentations == null) {
- setLifeTheUniverseAndEverything(id, field.getValue(), null, null, null,
+ index = setLifeTheUniverseAndEverything(id, field.getValue(), null, null, null,
filter, null);
} else {
- setLifeTheUniverseAndEverything(id, field.getValue(),
+ index = setLifeTheUniverseAndEverything(id, field.getValue(),
presentations.getMenuPresentation(),
presentations.getInlinePresentation(),
presentations.getInlineTooltipPresentation(), filter,
presentations.getDialogPresentation());
}
}
+ mFieldToIndexdMap.put(field, index);
return this;
}
/**
- * 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.
+ * Adds a field to this Dataset with a specific type. 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().
*
@@ -1086,9 +1107,6 @@ public final class Dataset implements Parcelable {
* 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()}.
*
@@ -1102,19 +1120,29 @@ public final class Dataset implements Parcelable {
public @NonNull Dataset.Builder setField(@NonNull String hint, @NonNull Field field) {
throwIfDestroyed();
+ if (mFieldToIndexdMap.containsKey(field)) {
+ int index = mFieldToIndexdMap.get(field);
+ if (mAutofillDatatypes.get(index) == null) {
+ mAutofillDatatypes.set(index, hint);
+ return this;
+ }
+ // if the hint is already set, ignore and proceed as if setting in a new hint.
+ }
+
+ int index;
final DatasetFieldFilter filter = field.getDatasetFieldFilter();
final Presentations presentations = field.getPresentations();
if (presentations == null) {
- setLifeTheUniverseAndEverything(hint, field.getValue(), null, null, null,
+ index = setLifeTheUniverseAndEverything(hint, field.getValue(), null, null, null,
filter, null);
} else {
- setLifeTheUniverseAndEverything(hint, field.getValue(),
+ index = setLifeTheUniverseAndEverything(hint, field.getValue(),
presentations.getMenuPresentation(),
presentations.getInlinePresentation(),
presentations.getInlineTooltipPresentation(), filter,
presentations.getDialogPresentation());
}
-
+ mFieldToIndexdMap.put(field, index);
return this;
}
@@ -1172,67 +1200,64 @@ public final class Dataset implements Parcelable {
return this;
}
- private void setLifeTheUniverseAndEverything(String datatype,
+ /** Returns the index at which this id was modified or inserted */
+ private int setLifeTheUniverseAndEverything(@NonNull 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;
+ Objects.requireNonNull(datatype, "datatype cannot be null");
+ final int existingIdx = mAutofillDatatypes.indexOf(datatype);
+ if (existingIdx >= 0) {
+ mAutofillDatatypes.add(datatype);
+ mFieldValues.set(existingIdx, value);
+ mFieldPresentations.set(existingIdx, presentation);
+ mFieldDialogPresentations.set(existingIdx, dialogPresentation);
+ mFieldInlinePresentations.set(existingIdx, inlinePresentation);
+ mFieldInlineTooltipPresentations.set(existingIdx, tooltip);
+ mFieldFilters.set(existingIdx, filter);
+ return existingIdx;
}
+ mFieldIds.add(null);
+ mAutofillDatatypes.add(datatype);
mFieldValues.add(value);
mFieldPresentations.add(presentation);
mFieldDialogPresentations.add(dialogPresentation);
mFieldInlinePresentations.add(inlinePresentation);
mFieldInlineTooltipPresentations.add(tooltip);
mFieldFilters.add(filter);
- mAutofillDatatypes.add(datatype);
+ return mFieldIds.size() - 1;
}
- private void setLifeTheUniverseAndEverything(@NonNull AutofillId id,
+ /** Returns the index at which this id was modified or inserted */
+ private int setLifeTheUniverseAndEverything(@NonNull AutofillId id,
@Nullable AutofillValue value, @Nullable RemoteViews presentation,
@Nullable InlinePresentation inlinePresentation,
@Nullable InlinePresentation tooltip,
@Nullable DatasetFieldFilter filter,
@Nullable RemoteViews dialogPresentation) {
Objects.requireNonNull(id, "id cannot be null");
- if (mFieldIds != null) {
- final int existingIdx = mFieldIds.indexOf(id);
- if (existingIdx >= 0) {
- mFieldValues.set(existingIdx, value);
- mFieldPresentations.set(existingIdx, presentation);
- mFieldDialogPresentations.set(existingIdx, dialogPresentation);
- mFieldInlinePresentations.set(existingIdx, inlinePresentation);
- mFieldInlineTooltipPresentations.set(existingIdx, tooltip);
- mFieldFilters.set(existingIdx, filter);
- return;
- }
- } else {
- mFieldIds = new ArrayList<>();
- mFieldValues = new ArrayList<>();
- mFieldPresentations = new ArrayList<>();
- mFieldDialogPresentations = new ArrayList<>();
- mFieldInlinePresentations = new ArrayList<>();
- mFieldInlineTooltipPresentations = new ArrayList<>();
- mFieldFilters = new ArrayList<>();
- mAutofillDatatypes = null;
+ final int existingIdx = mFieldIds.indexOf(id);
+ if (existingIdx >= 0) {
+ mFieldValues.set(existingIdx, value);
+ mFieldPresentations.set(existingIdx, presentation);
+ mFieldDialogPresentations.set(existingIdx, dialogPresentation);
+ mFieldInlinePresentations.set(existingIdx, inlinePresentation);
+ mFieldInlineTooltipPresentations.set(existingIdx, tooltip);
+ mFieldFilters.set(existingIdx, filter);
+ return existingIdx;
}
mFieldIds.add(id);
+ mAutofillDatatypes.add(null);
mFieldValues.add(value);
mFieldPresentations.add(presentation);
mFieldDialogPresentations.add(dialogPresentation);
mFieldInlinePresentations.add(inlinePresentation);
mFieldInlineTooltipPresentations.add(tooltip);
mFieldFilters.add(filter);
+ return mFieldIds.size() - 1;
}
/**
@@ -1249,11 +1274,12 @@ public final class Dataset implements Parcelable {
throwIfDestroyed();
mDestroyed = true;
if (mFieldIds == null && mAutofillDatatypes == null) {
- throw new IllegalStateException("at least one value must be set");
+ throw new IllegalStateException("at least one of field or datatype 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 (mFieldIds.size() == 0 && mAutofillDatatypes.size() == 0) {
+ throw new IllegalStateException(
+ "at least one of field or datatype must be set");
}
}
if (mFieldContent != null) {
diff --git a/core/java/android/service/dreams/DreamActivity.java b/core/java/android/service/dreams/DreamActivity.java
index a3892238f1e6..a2fa1392b079 100644
--- a/core/java/android/service/dreams/DreamActivity.java
+++ b/core/java/android/service/dreams/DreamActivity.java
@@ -58,13 +58,11 @@ public class DreamActivity extends Activity {
setTitle(title);
}
- final Object callback = getIntent().getExtras().getBinder(EXTRA_CALLBACK);
- if (callback instanceof DreamService.DreamActivityCallbacks) {
- mCallback = (DreamService.DreamActivityCallbacks) callback;
+ final Bundle extras = getIntent().getExtras();
+ mCallback = (DreamService.DreamActivityCallbacks) extras.getBinder(EXTRA_CALLBACK);
+
+ if (mCallback != null) {
mCallback.onActivityCreated(this);
- } else {
- mCallback = null;
- finishAndRemoveTask();
}
}
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index c7099fdd202a..ce8af83a58f8 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -1409,6 +1409,10 @@ public class DreamService extends Service implements Window.Callback {
// Request the DreamOverlay be told to dream with dream's window
// parameters once the window has been attached.
mDreamStartOverlayConsumer = overlay -> {
+ if (mWindow == null) {
+ Slog.d(TAG, "mWindow is null");
+ return;
+ }
try {
overlay.startDream(mWindow.getAttributes(), mOverlayCallback,
mDreamComponent.flattenToString(),
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 8bf32324dd5a..ef76ce36ec0f 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -142,7 +142,6 @@ import android.view.accessibility.AccessibilityWindowInfo;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.Transformation;
-import android.view.autofill.AutofillFeatureFlags;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillManager;
import android.view.autofill.AutofillValue;
@@ -10363,15 +10362,21 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
private boolean isAutofillable() {
if (getAutofillType() == AUTOFILL_TYPE_NONE) return false;
+ final AutofillManager afm = getAutofillManager();
+ if (afm == null) {
+ return false;
+ }
+
// Disable triggering autofill if the view is integrated with CredentialManager.
- if (AutofillFeatureFlags.shouldIgnoreCredentialViews()
- && isCredential()) return false;
+ if (afm.shouldIgnoreCredentialViews() && isCredential()) {
+ return false;
+ }
if (!isImportantForAutofill()) {
// If view matches heuristics and is not denied, it will be treated same as view that's
// important for autofill
- if (isMatchingAutofillableHeuristics()
- && !isActivityDeniedForAutofillForUnimportantView()) {
+ if (afm.isMatchingAutofillableHeuristics(this)
+ && !afm.isActivityDeniedForAutofillForUnimportantView()) {
return getAutofillViewId() > LAST_APP_AUTOFILL_ID;
}
// View is not important for "regular" autofill, so we must check if Augmented Autofill
@@ -10380,8 +10385,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
if (options == null || !options.isAugmentedAutofillEnabled(mContext)) {
return false;
}
- final AutofillManager afm = getAutofillManager();
- if (afm == null) return false;
+
afm.notifyViewEnteredForAugmentedAutofill(this);
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index a8b4da14c1c5..24dcb69f8342 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -5718,7 +5718,7 @@ public final class ViewRootImpl implements ViewParent,
private static final int MSG_WINDOW_TOUCH_MODE_CHANGED = 34;
private static final int MSG_KEEP_CLEAR_RECTS_CHANGED = 35;
private static final int MSG_REPORT_KEEP_CLEAR_RECTS = 36;
-
+ private static final int MSG_PAUSED_FOR_SYNC_TIMEOUT = 37;
final class ViewRootHandler extends Handler {
@Override
@@ -6006,6 +6006,11 @@ public final class ViewRootImpl implements ViewParent,
case MSG_REQUEST_SCROLL_CAPTURE:
handleScrollCaptureRequest((IScrollCaptureResponseListener) msg.obj);
break;
+ case MSG_PAUSED_FOR_SYNC_TIMEOUT:
+ Log.e(mTag, "Timedout waiting to unpause for sync");
+ mNumPausedForSync = 0;
+ scheduleTraversals();
+ break;
}
}
}
@@ -11584,9 +11589,16 @@ public final class ViewRootImpl implements ViewParent,
mActiveSurfaceSyncGroup = new SurfaceSyncGroup(mTag);
mActiveSurfaceSyncGroup.setAddedToSyncListener(() -> {
Runnable runnable = () -> {
- mNumPausedForSync--;
- if (!mIsInTraversal && mNumPausedForSync == 0) {
- scheduleTraversals();
+ // Check if it's already 0 because the timeout could have reset the count to
+ // 0 and we don't want to go negative.
+ if (mNumPausedForSync > 0) {
+ mNumPausedForSync--;
+ }
+ if (mNumPausedForSync == 0) {
+ mHandler.removeMessages(MSG_PAUSED_FOR_SYNC_TIMEOUT);
+ if (!mIsInTraversal) {
+ scheduleTraversals();
+ }
}
};
@@ -11613,6 +11625,8 @@ public final class ViewRootImpl implements ViewParent,
}
mNumPausedForSync++;
+ mHandler.removeMessages(MSG_PAUSED_FOR_SYNC_TIMEOUT);
+ mHandler.sendEmptyMessageDelayed(MSG_PAUSED_FOR_SYNC_TIMEOUT, 1000);
return mActiveSurfaceSyncGroup;
};
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index ab9f492694f5..14c781bb5560 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -691,6 +691,9 @@ public final class AutofillManager {
// Indicates whether called the showAutofillDialog() method.
private boolean mShowAutofillDialogCalled = false;
+ // Cached autofill feature flag
+ private boolean mShouldIgnoreCredentialViews = false;
+
private final String[] mFillDialogEnabledHints;
// Tracked all views that have appeared, including views that there are no
@@ -838,6 +841,7 @@ public final class AutofillManager {
mIsFillDialogEnabled = AutofillFeatureFlags.isFillDialogEnabled();
mFillDialogEnabledHints = AutofillFeatureFlags.getFillDialogEnabledHints();
+ mShouldIgnoreCredentialViews = AutofillFeatureFlags.shouldIgnoreCredentialViews();
if (sDebug) {
Log.d(TAG, "Fill dialog is enabled:" + mIsFillDialogEnabled
+ ", hints=" + Arrays.toString(mFillDialogEnabledHints));
@@ -2081,6 +2085,11 @@ public final class AutofillManager {
}
/** @hide */
+ public boolean shouldIgnoreCredentialViews() {
+ return mShouldIgnoreCredentialViews;
+ }
+
+ /** @hide */
public void onAuthenticationResult(int authenticationId, Intent data, View focusView) {
if (!hasAutofillFeature()) {
return;
diff --git a/core/java/android/window/SurfaceSyncGroup.java b/core/java/android/window/SurfaceSyncGroup.java
index 78de9544b59b..0672d6318212 100644
--- a/core/java/android/window/SurfaceSyncGroup.java
+++ b/core/java/android/window/SurfaceSyncGroup.java
@@ -22,6 +22,8 @@ import android.annotation.UiThread;
import android.os.Binder;
import android.os.BinderProxy;
import android.os.Debug;
+import android.os.Handler;
+import android.os.HandlerThread;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.Trace;
@@ -60,6 +62,7 @@ public final class SurfaceSyncGroup {
private static final int MAX_COUNT = 100;
private static final AtomicInteger sCounter = new AtomicInteger(0);
+ private static final int TRANSACTION_READY_TIMEOUT = 1000;
private static Supplier<Transaction> sTransactionFactory = Transaction::new;
@@ -111,6 +114,13 @@ public final class SurfaceSyncGroup {
*/
private final Binder mToken = new Binder();
+ private static final Object sHandlerThreadLock = new Object();
+ @GuardedBy("sHandlerThreadLock")
+ private static HandlerThread sHandlerThread;
+ private Handler mHandler;
+
+ private boolean mTimeoutAdded;
+
private static boolean isLocalBinder(IBinder binder) {
return !(binder instanceof BinderProxy);
}
@@ -538,6 +548,11 @@ public final class SurfaceSyncGroup {
+ transactionReadyCallback.hashCode());
}
+ // Start the timeout when this SurfaceSyncGroup has been added to a parent SurfaceSyncGroup.
+ // This is because if the other SurfaceSyncGroup has bugs and doesn't complete, this SSG
+ // will get stuck. It's better to complete this SSG even if the parent SSG is broken.
+ addTimeout();
+
boolean finished = false;
Runnable addedToSyncListener = null;
synchronized (mLock) {
@@ -641,6 +656,9 @@ public final class SurfaceSyncGroup {
}
mTransactionReadyConsumer.accept(mTransaction);
mFinished = true;
+ if (mTimeoutAdded) {
+ mHandler.removeCallbacksAndMessages(this);
+ }
}
/**
@@ -701,6 +719,12 @@ public final class SurfaceSyncGroup {
}
}
+ // Start the timeout when another SSG has been added to this SurfaceSyncGroup. This is
+ // because if the other SurfaceSyncGroup has bugs and doesn't complete, it will affect this
+ // SSGs. So it's better to just add a timeout in case the other SSG doesn't invoke the
+ // callback and complete this SSG.
+ addTimeout();
+
return transactionReadyCallback;
}
@@ -731,6 +755,41 @@ public final class SurfaceSyncGroup {
}
}
+ private void addTimeout() {
+ synchronized (sHandlerThreadLock) {
+ if (sHandlerThread == null) {
+ sHandlerThread = new HandlerThread("SurfaceSyncGroupTimer");
+ sHandlerThread.start();
+ }
+ }
+
+ synchronized (mLock) {
+ if (mTimeoutAdded) {
+ // We only need one timeout for the entire SurfaceSyncGroup since we just want to
+ // ensure it doesn't stay stuck forever.
+ return;
+ }
+
+ if (mHandler == null) {
+ mHandler = new Handler(sHandlerThread.getLooper());
+ }
+
+ mTimeoutAdded = true;
+ }
+
+ Runnable runnable = () -> {
+ Log.e(TAG, "Failed to receive transaction ready in " + TRANSACTION_READY_TIMEOUT
+ + "ms. Marking SurfaceSyncGroup as ready " + mName);
+ // Clear out any pending syncs in case the other syncs can't complete or timeout due to
+ // a crash.
+ synchronized (mLock) {
+ mPendingSyncs.clear();
+ }
+ markSyncReady();
+ };
+ mHandler.postDelayed(runnable, this, TRANSACTION_READY_TIMEOUT);
+ }
+
/**
* A frame callback that is used to synchronize SurfaceViews. The owner of the SurfaceView must
* implement onFrameStarted when trying to sync the SurfaceView. This is to ensure the sync
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 16511a678760..27c477f3f241 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3020,10 +3020,18 @@
>com.android.systemui/com.android.systemui.wifi.WifiDebuggingSecondaryUserActivity</string>
<!-- Package name of the system service that implements the shared connectivity service -->
- <string translatable="false" name="shared_connectivity_service_package"></string>
+ <string translatable="false" name="config_sharedConnectivityServicePackage"></string>
<!-- Intent action used when binding to the shared connectivity service -->
- <string translatable="false" name="shared_connectivity_service_intent_action"></string>
+ <string translatable="false" name="config_sharedConnectivityServiceIntentAction"></string>
+
+ <!-- The system and settings UI can support all the features of instant tether. If set to false,
+ instant tether will run in notifications mode -->
+ <bool name="config_hotspotNetworksEnabledForService">false</bool>
+
+ <!-- The system and settings UI can support all the features of known networks. If set to false,
+ known networks will run in notifications mode -->
+ <bool name="config_knownNetworksEnabledForService">false</bool>
<!-- Component name of the activity that shows the usb containment status. -->
<string name="config_usbContaminantActivity" translatable="false"
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index c34d31cca7ba..a15833d36870 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -4960,8 +4960,10 @@
<java-symbol type="bool" name="config_stopSystemPackagesByDefault"/>
<java-symbol type="string" name="config_wearServiceComponent" />
- <java-symbol type="string" name="shared_connectivity_service_package" />
- <java-symbol type="string" name="shared_connectivity_service_intent_action" />
+ <java-symbol type="string" name="config_sharedConnectivityServicePackage" />
+ <java-symbol type="string" name="config_sharedConnectivityServiceIntentAction" />
+ <java-symbol type="bool" name="config_hotspotNetworksEnabledForService"/>
+ <java-symbol type="bool" name="config_knownNetworksEnabledForService"/>
<!-- Whether to show weather on the lockscreen by default. -->
<java-symbol type="bool" name="config_lockscreenWeatherEnabledByDefault" />
diff --git a/core/tests/coretests/src/android/provider/NameValueCacheTest.java b/core/tests/coretests/src/android/provider/NameValueCacheTest.java
index ccf8085f87ff..b6fc137471a4 100644
--- a/core/tests/coretests/src/android/provider/NameValueCacheTest.java
+++ b/core/tests/coretests/src/android/provider/NameValueCacheTest.java
@@ -91,7 +91,7 @@ public class NameValueCacheTest {
mConfigsCacheGenerationStore = new MemoryIntArray(2);
mConfigsCacheGenerationStore.set(0, 123);
mConfigsCacheGenerationStore.set(1, 456);
- mSettingsCacheGenerationStore = new MemoryIntArray(3);
+ mSettingsCacheGenerationStore = new MemoryIntArray(2);
mSettingsCacheGenerationStore.set(0, 234);
mSettingsCacheGenerationStore.set(1, 567);
mConfigsStorage = new HashMap<>();
@@ -163,10 +163,6 @@ public class NameValueCacheTest {
Bundle incomingBundle = invocationOnMock.getArgument(4);
String key = invocationOnMock.getArgument(3);
String value = incomingBundle.getString(Settings.NameValueTable.VALUE);
- boolean newSetting = false;
- if (!mSettingsStorage.containsKey(key)) {
- newSetting = true;
- }
mSettingsStorage.put(key, value);
int currentGeneration;
// Different settings have different generation codes
@@ -177,18 +173,12 @@ public class NameValueCacheTest {
currentGeneration = mSettingsCacheGenerationStore.get(1);
mSettingsCacheGenerationStore.set(1, ++currentGeneration);
}
- if (newSetting) {
- // Tracking the generation of all unset settings.
- // Increment when a new setting is inserted
- currentGeneration = mSettingsCacheGenerationStore.get(2);
- mSettingsCacheGenerationStore.set(2, ++currentGeneration);
- }
return null;
});
// Returns the value corresponding to a setting, or null if the setting
- // doesn't have a value stored for it. Returns the generation key
- // if the caller asked for the generation key.
+ // doesn't have a value stored for it. Returns the generation key if the value isn't null
+ // and the caller asked for the generation key.
when(mMockIContentProvider.call(any(), eq(Settings.Secure.CONTENT_URI.getAuthority()),
eq(Settings.CALL_METHOD_GET_SECURE), any(), any(Bundle.class))).thenAnswer(
invocationOnMock -> {
@@ -199,15 +189,9 @@ public class NameValueCacheTest {
Bundle bundle = new Bundle();
bundle.putSerializable(Settings.NameValueTable.VALUE, value);
- if (incomingBundle.containsKey(
+ if (value != null && incomingBundle.containsKey(
Settings.CALL_METHOD_TRACK_GENERATION_KEY)) {
- int index;
- if (value != null) {
- index = key.equals(SETTING) ? 0 : 1;
- } else {
- // special index for unset settings
- index = 2;
- }
+ int index = key.equals(SETTING) ? 0 : 1;
bundle.putParcelable(Settings.CALL_METHOD_TRACK_GENERATION_KEY,
mSettingsCacheGenerationStore);
bundle.putInt(Settings.CALL_METHOD_GENERATION_INDEX_KEY, index);
@@ -377,38 +361,16 @@ public class NameValueCacheTest {
}
@Test
- public void testCaching_unsetSetting() throws Exception {
+ public void testCaching_nullSetting() throws Exception {
String returnedValue = Settings.Secure.getString(mMockContentResolver, SETTING);
verify(mMockIContentProvider, times(1)).call(any(), any(),
eq(Settings.CALL_METHOD_GET_SECURE), any(), any(Bundle.class));
assertThat(returnedValue).isNull();
String cachedValue = Settings.Secure.getString(mMockContentResolver, SETTING);
- // The first unset setting's generation number is cached
- verifyNoMoreInteractions(mMockIContentProvider);
- assertThat(cachedValue).isNull();
-
- String returnedValue2 = Settings.Secure.getString(mMockContentResolver, SETTING2);
+ // Empty list won't be cached
verify(mMockIContentProvider, times(2)).call(any(), any(),
eq(Settings.CALL_METHOD_GET_SECURE), any(), any(Bundle.class));
- assertThat(returnedValue2).isNull();
-
- String cachedValue2 = Settings.Secure.getString(mMockContentResolver, SETTING);
- // The second unset setting's generation number is cached
- verifyNoMoreInteractions(mMockIContentProvider);
- assertThat(cachedValue2).isNull();
-
- Settings.Secure.putString(mMockContentResolver, SETTING, "a");
- // The generation for unset settings should have changed
- returnedValue2 = Settings.Secure.getString(mMockContentResolver, SETTING2);
- verify(mMockIContentProvider, times(3)).call(any(), any(),
- eq(Settings.CALL_METHOD_GET_SECURE), any(), any(Bundle.class));
- assertThat(returnedValue2).isNull();
-
- // The generation tracker for the first setting should have change because it's set now
- returnedValue = Settings.Secure.getString(mMockContentResolver, SETTING);
- verify(mMockIContentProvider, times(4)).call(any(), any(),
- eq(Settings.CALL_METHOD_GET_SECURE), any(), any(Bundle.class));
- assertThat(returnedValue).isEqualTo("a");
+ assertThat(cachedValue).isNull();
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index 852fae695046..ef53839cb2ea 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -139,6 +139,30 @@ public class BubbleController implements ConfigurationChangeListener {
private static final boolean BUBBLE_BAR_ENABLED =
SystemProperties.getBoolean("persist.wm.debug.bubble_bar", false);
+
+ /**
+ * Common interface to send updates to bubble views.
+ */
+ public interface BubbleViewCallback {
+ /** Called when the provided bubble should be removed. */
+ void removeBubble(Bubble removedBubble);
+ /** Called when the provided bubble should be added. */
+ void addBubble(Bubble addedBubble);
+ /** Called when the provided bubble should be updated. */
+ void updateBubble(Bubble updatedBubble);
+ /** Called when the provided bubble should be selected. */
+ void selectionChanged(BubbleViewProvider selectedBubble);
+ /** Called when the provided bubble's suppression state has changed. */
+ void suppressionChanged(Bubble bubble, boolean isSuppressed);
+ /** Called when the expansion state of bubbles has changed. */
+ void expansionChanged(boolean isExpanded);
+ /**
+ * Called when the order of the bubble list has changed. Depending on the expanded state
+ * the pointer might need to be updated.
+ */
+ void bubbleOrderChanged(List<Bubble> bubbleOrder, boolean updatePointer);
+ }
+
private final Context mContext;
private final BubblesImpl mImpl = new BubblesImpl();
private Bubbles.BubbleExpandListener mExpandListener;
@@ -162,7 +186,6 @@ public class BubbleController implements ConfigurationChangeListener {
// Used to post to main UI thread
private final ShellExecutor mMainExecutor;
private final Handler mMainHandler;
-
private final ShellExecutor mBackgroundExecutor;
private BubbleLogger mLogger;
@@ -1320,6 +1343,58 @@ public class BubbleController implements ConfigurationChangeListener {
});
}
+ private final BubbleViewCallback mBubbleViewCallback = new BubbleViewCallback() {
+ @Override
+ public void removeBubble(Bubble removedBubble) {
+ if (mStackView != null) {
+ mStackView.removeBubble(removedBubble);
+ }
+ }
+
+ @Override
+ public void addBubble(Bubble addedBubble) {
+ if (mStackView != null) {
+ mStackView.addBubble(addedBubble);
+ }
+ }
+
+ @Override
+ public void updateBubble(Bubble updatedBubble) {
+ if (mStackView != null) {
+ mStackView.updateBubble(updatedBubble);
+ }
+ }
+
+ @Override
+ public void bubbleOrderChanged(List<Bubble> bubbleOrder, boolean updatePointer) {
+ if (mStackView != null) {
+ mStackView.updateBubbleOrder(bubbleOrder, updatePointer);
+ }
+ }
+
+ @Override
+ public void suppressionChanged(Bubble bubble, boolean isSuppressed) {
+ if (mStackView != null) {
+ mStackView.setBubbleSuppressed(bubble, isSuppressed);
+ }
+ }
+
+ @Override
+ public void expansionChanged(boolean isExpanded) {
+ if (mStackView != null) {
+ mStackView.setExpanded(isExpanded);
+ }
+ }
+
+ @Override
+ public void selectionChanged(BubbleViewProvider selectedBubble) {
+ if (mStackView != null) {
+ mStackView.setSelectedBubble(selectedBubble);
+ }
+
+ }
+ };
+
@SuppressWarnings("FieldCanBeLocal")
private final BubbleData.Listener mBubbleDataListener = new BubbleData.Listener() {
@@ -1342,7 +1417,8 @@ public class BubbleController implements ConfigurationChangeListener {
// Lazy load overflow bubbles from disk
loadOverflowBubblesFromDisk();
- mStackView.updateOverflowButtonDot();
+ // If bubbles in the overflow have a dot, make sure the overflow shows a dot
+ updateOverflowButtonDot();
// Update bubbles in overflow.
if (mOverflowListener != null) {
@@ -1357,9 +1433,7 @@ public class BubbleController implements ConfigurationChangeListener {
final Bubble bubble = removed.first;
@Bubbles.DismissReason final int reason = removed.second;
- if (mStackView != null) {
- mStackView.removeBubble(bubble);
- }
+ mBubbleViewCallback.removeBubble(bubble);
// Leave the notification in place if we're dismissing due to user switching, or
// because DND is suppressing the bubble. In both of those cases, we need to be able
@@ -1389,49 +1463,47 @@ public class BubbleController implements ConfigurationChangeListener {
}
mDataRepository.removeBubbles(mCurrentUserId, bubblesToBeRemovedFromRepository);
- if (update.addedBubble != null && mStackView != null) {
+ if (update.addedBubble != null) {
mDataRepository.addBubble(mCurrentUserId, update.addedBubble);
- mStackView.addBubble(update.addedBubble);
+ mBubbleViewCallback.addBubble(update.addedBubble);
}
- if (update.updatedBubble != null && mStackView != null) {
- mStackView.updateBubble(update.updatedBubble);
+ if (update.updatedBubble != null) {
+ mBubbleViewCallback.updateBubble(update.updatedBubble);
}
- if (update.suppressedBubble != null && mStackView != null) {
- mStackView.setBubbleSuppressed(update.suppressedBubble, true);
+ if (update.suppressedBubble != null) {
+ mBubbleViewCallback.suppressionChanged(update.suppressedBubble, true);
}
- if (update.unsuppressedBubble != null && mStackView != null) {
- mStackView.setBubbleSuppressed(update.unsuppressedBubble, false);
+ if (update.unsuppressedBubble != null) {
+ mBubbleViewCallback.suppressionChanged(update.unsuppressedBubble, false);
}
boolean collapseStack = update.expandedChanged && !update.expanded;
// At this point, the correct bubbles are inflated in the stack.
// Make sure the order in bubble data is reflected in bubble row.
- if (update.orderChanged && mStackView != null) {
+ if (update.orderChanged) {
mDataRepository.addBubbles(mCurrentUserId, update.bubbles);
// if the stack is going to be collapsed, do not update pointer position
// after reordering
- mStackView.updateBubbleOrder(update.bubbles, !collapseStack);
+ mBubbleViewCallback.bubbleOrderChanged(update.bubbles, !collapseStack);
}
if (collapseStack) {
- mStackView.setExpanded(false);
+ mBubbleViewCallback.expansionChanged(/* expanded= */ false);
mSysuiProxy.requestNotificationShadeTopUi(false, TAG);
}
- if (update.selectionChanged && mStackView != null) {
- mStackView.setSelectedBubble(update.selectedBubble);
+ if (update.selectionChanged) {
+ mBubbleViewCallback.selectionChanged(update.selectedBubble);
}
// Expanding? Apply this last.
if (update.expandedChanged && update.expanded) {
- if (mStackView != null) {
- mStackView.setExpanded(true);
- mSysuiProxy.requestNotificationShadeTopUi(true, TAG);
- }
+ mBubbleViewCallback.expansionChanged(/* expanded= */ true);
+ mSysuiProxy.requestNotificationShadeTopUi(true, TAG);
}
mSysuiProxy.notifyInvalidateNotifications("BubbleData.Listener.applyUpdate");
@@ -1442,6 +1514,19 @@ public class BubbleController implements ConfigurationChangeListener {
}
};
+ private void updateOverflowButtonDot() {
+ BubbleOverflow overflow = mBubbleData.getOverflow();
+ if (overflow == null) return;
+
+ for (Bubble b : mBubbleData.getOverflowBubbles()) {
+ if (b.showDot()) {
+ overflow.setShowDot(true);
+ return;
+ }
+ }
+ overflow.setShowDot(false);
+ }
+
private boolean handleDismissalInterception(BubbleEntry entry,
@Nullable List<BubbleEntry> children, IntConsumer removeCallback) {
if (isSummaryOfBubbles(entry)) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index 7d71089ef4fa..0b947c8b9b08 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -1359,16 +1359,6 @@ public class BubbleStackView extends FrameLayout
updateOverflowVisibility();
}
- void updateOverflowButtonDot() {
- for (Bubble b : mBubbleData.getOverflowBubbles()) {
- if (b.showDot()) {
- mBubbleOverflow.setShowDot(true);
- return;
- }
- }
- mBubbleOverflow.setShowDot(false);
- }
-
/**
* Handle theme changes.
*/
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizer.java
index 9796e4c29352..2d84d211e30a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizer.java
@@ -267,6 +267,11 @@ public class KidsModeTaskOrganizer extends ShellTaskOrganizer {
mLaunchRootTask = taskInfo;
}
+ if (mHomeTask != null && mHomeTask.taskId == taskInfo.taskId
+ && !taskInfo.equals(mHomeTask)) {
+ mHomeTask = taskInfo;
+ }
+
super.onTaskInfoChanged(taskInfo);
}
@@ -376,6 +381,7 @@ public class KidsModeTaskOrganizer extends ShellTaskOrganizer {
final WindowContainerTransaction wct = getWindowContainerTransaction();
final Rect taskBounds = calculateBounds();
wct.setBounds(mLaunchRootTask.token, taskBounds);
+ wct.setBounds(mHomeTask.token, new Rect(0, 0, mDisplayWidth, mDisplayHeight));
mSyncQueue.queue(wct);
final SurfaceControl finalLeash = mLaunchRootLeash;
mSyncQueue.runInSync(t -> {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPip.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPip.aidl
index 2624ee536b58..d961d8658b98 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPip.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPip.aidl
@@ -70,4 +70,9 @@ interface IPip {
* Sets the next pip animation type to be the alpha animation.
*/
oneway void setPipAnimationTypeToAlpha() = 5;
+
+ /**
+ * Sets the height and visibility of the Launcher keep clear area.
+ */
+ oneway void setLauncherKeepClearAreaHeight(boolean visible, int height) = 6;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index e9d257139779..eb336d56b62c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -1179,6 +1179,20 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
}
/**
+ * Directly update the animator bounds.
+ */
+ public void updateAnimatorBounds(Rect bounds) {
+ final PipAnimationController.PipTransitionAnimator animator =
+ mPipAnimationController.getCurrentAnimator();
+ if (animator != null && animator.isRunning()) {
+ if (animator.getAnimationType() == ANIM_TYPE_BOUNDS) {
+ animator.updateEndValue(bounds);
+ }
+ animator.setDestinationBounds(bounds);
+ }
+ }
+
+ /**
* Handles all changes to the PictureInPictureParams.
*/
protected void applyNewPictureInPictureParams(@NonNull PictureInPictureParams params) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionState.java
index c6b5ce93fd35..db6138a0891f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionState.java
@@ -93,6 +93,11 @@ public class PipTransitionState {
return hasEnteredPip(mState);
}
+ /** Returns true if activity is currently entering PiP mode. */
+ public boolean isEnteringPip() {
+ return isEnteringPip(mState);
+ }
+
public void setInSwipePipToHomeTransition(boolean inSwipePipToHomeTransition) {
mInSwipePipToHomeTransition = inSwipePipToHomeTransition;
}
@@ -130,6 +135,11 @@ public class PipTransitionState {
return state == ENTERED_PIP;
}
+ /** Returns true if activity is currently entering PiP mode. */
+ public static boolean isEnteringPip(@TransitionState int state) {
+ return state == ENTERING_PIP;
+ }
+
public interface OnPipTransitionStateChangedListener {
void onPipTransitionStateChanged(@TransitionState int oldState,
@TransitionState int newState);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index a1483a8dedae..99cd00a67cf7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -101,6 +101,7 @@ import com.android.wm.shell.sysui.UserChangeListener;
import com.android.wm.shell.transition.Transitions;
import java.io.PrintWriter;
+import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
@@ -181,14 +182,20 @@ public class PipController implements PipTransitionController.PipTransitionCallb
// early bail out if the keep clear areas feature is disabled
return;
}
- // only move if already in pip, other transitions account for keep clear areas
- if (mPipTransitionState.hasEnteredPip()) {
+ // only move if we're in PiP or transitioning into PiP
+ if (!mPipTransitionState.shouldBlockResizeRequest()) {
Rect destBounds = mPipKeepClearAlgorithm.adjust(mPipBoundsState,
mPipBoundsAlgorithm);
// only move if the bounds are actually different
if (destBounds != mPipBoundsState.getBounds()) {
- mPipTaskOrganizer.scheduleAnimateResizePip(destBounds,
- mEnterAnimationDuration, null);
+ if (mPipTransitionState.hasEnteredPip()) {
+ // if already in PiP, schedule separate animation
+ mPipTaskOrganizer.scheduleAnimateResizePip(destBounds,
+ mEnterAnimationDuration, null);
+ } else if (mPipTransitionState.isEnteringPip()) {
+ // while entering PiP we just need to update animator bounds
+ mPipTaskOrganizer.updateAnimatorBounds(destBounds);
+ }
}
}
}
@@ -874,6 +881,21 @@ public class PipController implements PipTransitionController.PipTransitionCallb
}
}
+ private void setLauncherKeepClearAreaHeight(boolean visible, int height) {
+ if (visible) {
+ Rect rect = new Rect(
+ 0, mPipBoundsState.getDisplayBounds().bottom - height,
+ mPipBoundsState.getDisplayBounds().right,
+ mPipBoundsState.getDisplayBounds().bottom);
+ Set<Rect> restrictedKeepClearAreas = new HashSet<>(
+ mPipBoundsState.getRestrictedKeepClearAreas());
+ restrictedKeepClearAreas.add(rect);
+ mPipBoundsState.setKeepClearAreas(restrictedKeepClearAreas,
+ mPipBoundsState.getUnrestrictedKeepClearAreas());
+ updatePipPositionForKeepClearAreas();
+ }
+ }
+
private void setOnIsInPipStateChangedListener(Consumer<Boolean> callback) {
mOnIsInPipStateChangedListener = callback;
if (mOnIsInPipStateChangedListener != null) {
@@ -1240,6 +1262,14 @@ public class PipController implements PipTransitionController.PipTransitionCallb
}
@Override
+ public void setLauncherKeepClearAreaHeight(boolean visible, int height) {
+ executeRemoteCallWithTaskPermission(mController, "setLauncherKeepClearAreaHeight",
+ (controller) -> {
+ controller.setLauncherKeepClearAreaHeight(visible, height);
+ });
+ }
+
+ @Override
public void setPipAnimationListener(IPipAnimationListener listener) {
executeRemoteCallWithTaskPermission(mController, "setPipAnimationListener",
(controller) -> {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/TaskPositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/TaskPositioner.java
index a3d364a0068e..0bce3acecb3c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/TaskPositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/TaskPositioner.java
@@ -40,6 +40,7 @@ class TaskPositioner implements DragPositioningCallback {
private final DisplayController mDisplayController;
private final WindowDecoration mWindowDecoration;
+ private final Rect mTempBounds = new Rect();
private final Rect mTaskBoundsAtDragStart = new Rect();
private final PointF mRepositionStartPoint = new PointF();
private final Rect mRepositionTaskBounds = new Rect();
@@ -117,17 +118,32 @@ class TaskPositioner implements DragPositioningCallback {
final float deltaX = x - mRepositionStartPoint.x;
final float deltaY = y - mRepositionStartPoint.y;
mRepositionTaskBounds.set(mTaskBoundsAtDragStart);
+
+ final Rect stableBounds = mTempBounds;
+ // Make sure the new resizing destination in any direction falls within the stable bounds.
+ // If not, set the bounds back to the old location that was valid to avoid conflicts with
+ // some regions such as the gesture area.
+ mDisplayController.getDisplayLayout(mWindowDecoration.mDisplay.getDisplayId())
+ .getStableBounds(stableBounds);
if ((mCtrlType & CTRL_TYPE_LEFT) != 0) {
- mRepositionTaskBounds.left += deltaX;
+ final int candidateLeft = mRepositionTaskBounds.left + (int) deltaX;
+ mRepositionTaskBounds.left = (candidateLeft > stableBounds.left)
+ ? candidateLeft : oldLeft;
}
if ((mCtrlType & CTRL_TYPE_RIGHT) != 0) {
- mRepositionTaskBounds.right += deltaX;
+ final int candidateRight = mRepositionTaskBounds.right + (int) deltaX;
+ mRepositionTaskBounds.right = (candidateRight < stableBounds.right)
+ ? candidateRight : oldRight;
}
if ((mCtrlType & CTRL_TYPE_TOP) != 0) {
- mRepositionTaskBounds.top += deltaY;
+ final int candidateTop = mRepositionTaskBounds.top + (int) deltaY;
+ mRepositionTaskBounds.top = (candidateTop > stableBounds.top)
+ ? candidateTop : oldTop;
}
if ((mCtrlType & CTRL_TYPE_BOTTOM) != 0) {
- mRepositionTaskBounds.bottom += deltaY;
+ final int candidateBottom = mRepositionTaskBounds.bottom + (int) deltaY;
+ mRepositionTaskBounds.bottom = (candidateBottom < stableBounds.bottom)
+ ? candidateBottom : oldBottom;
}
if (mCtrlType == CTRL_TYPE_UNDEFINED) {
mRepositionTaskBounds.offset((int) deltaX, (int) deltaY);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/TaskPositionerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/TaskPositionerTest.kt
index 8f66f4e7e47b..94c064bda763 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/TaskPositionerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/TaskPositionerTest.kt
@@ -5,13 +5,16 @@ import android.app.WindowConfiguration
import android.graphics.Rect
import android.os.IBinder
import android.testing.AndroidTestingRunner
+import android.view.Display
import android.window.WindowContainerToken
+import android.window.WindowContainerTransaction
import android.window.WindowContainerTransaction.Change.CHANGE_DRAG_RESIZING
import androidx.test.filters.SmallTest
import com.android.wm.shell.common.DisplayController
import com.android.wm.shell.common.DisplayLayout
import com.android.wm.shell.ShellTaskOrganizer
import com.android.wm.shell.ShellTestCase
+import com.android.wm.shell.windowdecor.TaskPositioner.CTRL_TYPE_BOTTOM
import com.android.wm.shell.windowdecor.TaskPositioner.CTRL_TYPE_RIGHT
import com.android.wm.shell.windowdecor.TaskPositioner.CTRL_TYPE_TOP
import com.android.wm.shell.windowdecor.TaskPositioner.CTRL_TYPE_UNDEFINED
@@ -19,10 +22,11 @@ import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
+import org.mockito.Mockito.`when`
+import org.mockito.Mockito.any
import org.mockito.Mockito.argThat
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
/**
@@ -51,6 +55,8 @@ class TaskPositionerTest : ShellTestCase() {
private lateinit var mockDisplayController: DisplayController
@Mock
private lateinit var mockDisplayLayout: DisplayLayout
+ @Mock
+ private lateinit var mockDisplay: Display
private lateinit var taskPositioner: TaskPositioner
@@ -68,6 +74,9 @@ class TaskPositionerTest : ShellTestCase() {
`when`(taskToken.asBinder()).thenReturn(taskBinder)
`when`(mockDisplayController.getDisplayLayout(DISPLAY_ID)).thenReturn(mockDisplayLayout)
`when`(mockDisplayLayout.densityDpi()).thenReturn(DENSITY_DPI)
+ `when`(mockDisplayLayout.getStableBounds(any())).thenAnswer { i ->
+ (i.arguments.first() as Rect).set(STABLE_BOUNDS)
+ }
mockWindowDecoration.mTaskInfo = ActivityManager.RunningTaskInfo().apply {
taskId = TASK_ID
@@ -78,6 +87,8 @@ class TaskPositionerTest : ShellTestCase() {
displayId = DISPLAY_ID
configuration.windowConfiguration.bounds = STARTING_BOUNDS
}
+ mockWindowDecoration.mDisplay = mockDisplay
+ `when`(mockDisplay.displayId).thenAnswer { DISPLAY_ID }
}
@Test
@@ -451,6 +462,72 @@ class TaskPositionerTest : ShellTestCase() {
})
}
+ fun testDragResize_toDisallowedBounds_freezesAtLimit() {
+ taskPositioner.onDragPositioningStart(
+ CTRL_TYPE_RIGHT or CTRL_TYPE_BOTTOM, // Resize right-bottom corner
+ STARTING_BOUNDS.right.toFloat(),
+ STARTING_BOUNDS.bottom.toFloat()
+ )
+
+ // Resize the task by 10px to the right and bottom, a valid destination
+ val newBounds = Rect(
+ STARTING_BOUNDS.left,
+ STARTING_BOUNDS.top,
+ STARTING_BOUNDS.right + 10,
+ STARTING_BOUNDS.bottom + 10)
+ taskPositioner.onDragPositioningMove(
+ newBounds.right.toFloat(),
+ newBounds.bottom.toFloat()
+ )
+
+ // Resize the task by another 10px to the right (allowed) and to just in the disallowed
+ // area of the Y coordinate.
+ val newBounds2 = Rect(
+ newBounds.left,
+ newBounds.top,
+ newBounds.right + 10,
+ DISALLOWED_RESIZE_AREA.top
+ )
+ taskPositioner.onDragPositioningMove(
+ newBounds2.right.toFloat(),
+ newBounds2.bottom.toFloat()
+ )
+
+ taskPositioner.onDragPositioningEnd(newBounds2.right.toFloat(), newBounds2.bottom.toFloat())
+
+ // The first resize falls in the allowed area, verify there's a change for it.
+ verify(mockShellTaskOrganizer).applyTransaction(argThat { wct ->
+ return@argThat wct.changes.any { (token, change) ->
+ token == taskBinder && change.ofBounds(newBounds)
+ }
+ })
+ // The second resize falls in the disallowed area, verify there's no change for it.
+ verify(mockShellTaskOrganizer, never()).applyTransaction(argThat { wct ->
+ return@argThat wct.changes.any { (token, change) ->
+ token == taskBinder && change.ofBounds(newBounds2)
+ }
+ })
+ // Instead, there should be a change for its allowed portion (the X movement) with the Y
+ // staying frozen in the last valid resize position.
+ verify(mockShellTaskOrganizer).applyTransaction(argThat { wct ->
+ return@argThat wct.changes.any { (token, change) ->
+ token == taskBinder && change.ofBounds(
+ Rect(
+ newBounds2.left,
+ newBounds2.top,
+ newBounds2.right,
+ newBounds.bottom // Stayed at the first resize destination.
+ )
+ )
+ }
+ })
+ }
+
+ private fun WindowContainerTransaction.Change.ofBounds(bounds: Rect): Boolean {
+ return ((windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0) &&
+ bounds == configuration.windowConfiguration.bounds
+ }
+
companion object {
private const val TASK_ID = 5
private const val MIN_WIDTH = 10
@@ -458,6 +535,19 @@ class TaskPositionerTest : ShellTestCase() {
private const val DENSITY_DPI = 20
private const val DEFAULT_MIN = 40
private const val DISPLAY_ID = 1
+ private const val NAVBAR_HEIGHT = 50
+ private val DISPLAY_BOUNDS = Rect(0, 0, 2400, 1600)
private val STARTING_BOUNDS = Rect(0, 0, 100, 100)
+ private val DISALLOWED_RESIZE_AREA = Rect(
+ DISPLAY_BOUNDS.left,
+ DISPLAY_BOUNDS.bottom - NAVBAR_HEIGHT,
+ DISPLAY_BOUNDS.right,
+ DISPLAY_BOUNDS.bottom)
+ private val STABLE_BOUNDS = Rect(
+ DISPLAY_BOUNDS.left,
+ DISPLAY_BOUNDS.top,
+ DISPLAY_BOUNDS.right,
+ DISPLAY_BOUNDS.bottom - NAVBAR_HEIGHT
+ )
}
}
diff --git a/libs/hwui/hwui/ImageDecoder.cpp b/libs/hwui/hwui/ImageDecoder.cpp
index 8266beb4ee8c..9a06be006dca 100644
--- a/libs/hwui/hwui/ImageDecoder.cpp
+++ b/libs/hwui/hwui/ImageDecoder.cpp
@@ -498,7 +498,7 @@ SkCodec::Result ImageDecoder::decode(void* pixels, size_t rowBytes) {
return result;
}
-SkCodec::Result ImageDecoder::extractGainmap(Bitmap* destination) {
+SkCodec::Result ImageDecoder::extractGainmap(Bitmap* destination, bool isShared) {
ATRACE_CALL();
SkGainmapInfo gainmapInfo;
std::unique_ptr<SkStream> gainmapStream;
@@ -553,9 +553,12 @@ SkCodec::Result ImageDecoder::extractGainmap(Bitmap* destination) {
return SkCodec::kInternalError;
}
- // TODO: We don't currently parcel the gainmap, but if we should then also support
- // the shared allocator
- sk_sp<Bitmap> nativeBitmap = Bitmap::allocateHeapBitmap(&bm);
+ sk_sp<Bitmap> nativeBitmap;
+ if (isShared) {
+ nativeBitmap = Bitmap::allocateAshmemBitmap(&bm);
+ } else {
+ nativeBitmap = Bitmap::allocateHeapBitmap(&bm);
+ }
if (!nativeBitmap) {
ALOGE("OOM allocating Bitmap with dimensions %i x %i", bitmapInfo.width(),
bitmapInfo.height());
diff --git a/libs/hwui/hwui/ImageDecoder.h b/libs/hwui/hwui/ImageDecoder.h
index 97573e1e8207..b3781b52a418 100644
--- a/libs/hwui/hwui/ImageDecoder.h
+++ b/libs/hwui/hwui/ImageDecoder.h
@@ -79,7 +79,7 @@ public:
// Set whether the ImageDecoder should handle RestorePrevious frames.
void setHandleRestorePrevious(bool handle);
- SkCodec::Result extractGainmap(Bitmap* destination);
+ SkCodec::Result extractGainmap(Bitmap* destination, bool isShared);
private:
// State machine for keeping track of how to handle RestorePrevious (RP)
diff --git a/libs/hwui/jni/ImageDecoder.cpp b/libs/hwui/jni/ImageDecoder.cpp
index ad80460da5a9..db1c188e425e 100644
--- a/libs/hwui/jni/ImageDecoder.cpp
+++ b/libs/hwui/jni/ImageDecoder.cpp
@@ -354,7 +354,8 @@ static jobject ImageDecoder_nDecodeBitmap(JNIEnv* env, jobject /*clazz*/, jlong
// cost of RAM
if (result == SkCodec::kSuccess && !jpostProcess && !preferRamOverQuality) {
// The gainmap costs RAM to improve quality, so skip this if we're prioritizing RAM instead
- result = decoder->extractGainmap(nativeBitmap.get());
+ result = decoder->extractGainmap(nativeBitmap.get(),
+ allocator == kSharedMemory_Allocator ? true : false);
jexception = get_and_clear_exception(env);
}
diff --git a/media/java/android/media/tv/ITvInputManager.aidl b/media/java/android/media/tv/ITvInputManager.aidl
index 113c85802fa2..3b00f20e724a 100644
--- a/media/java/android/media/tv/ITvInputManager.aidl
+++ b/media/java/android/media/tv/ITvInputManager.aidl
@@ -116,7 +116,7 @@ interface ITvInputManager {
// For ad request
void requestAd(in IBinder sessionToken, in AdRequest request, int userId);
- void notifyAdBuffer(in IBinder sessionToken, in AdBuffer buffer, int userId);
+ void notifyAdBufferReady(in IBinder sessionToken, in AdBuffer buffer, int userId);
// For TV Message
void notifyTvMessage(in IBinder sessionToken, in String type, in Bundle data, int userId);
diff --git a/media/java/android/media/tv/ITvInputSession.aidl b/media/java/android/media/tv/ITvInputSession.aidl
index 165a9ddc26e9..6d65e1f95271 100644
--- a/media/java/android/media/tv/ITvInputSession.aidl
+++ b/media/java/android/media/tv/ITvInputSession.aidl
@@ -75,7 +75,7 @@ oneway interface ITvInputSession {
// For ad request
void requestAd(in AdRequest request);
- void notifyAdBuffer(in AdBuffer buffer);
+ void notifyAdBufferReady(in AdBuffer buffer);
// For TV messages
void notifyTvMessage(in String type, in Bundle data);
diff --git a/media/java/android/media/tv/ITvInputSessionWrapper.java b/media/java/android/media/tv/ITvInputSessionWrapper.java
index 8389706b501c..2810a7e65067 100644
--- a/media/java/android/media/tv/ITvInputSessionWrapper.java
+++ b/media/java/android/media/tv/ITvInputSessionWrapper.java
@@ -275,7 +275,7 @@ public class ITvInputSessionWrapper extends ITvInputSession.Stub implements Hand
break;
}
case DO_NOTIFY_AD_BUFFER: {
- mTvInputSessionImpl.notifyAdBuffer((AdBuffer) msg.obj);
+ mTvInputSessionImpl.notifyAdBufferReady((AdBuffer) msg.obj);
break;
}
case DO_NOTIFY_TV_MESSAGE: {
@@ -465,7 +465,7 @@ public class ITvInputSessionWrapper extends ITvInputSession.Stub implements Hand
}
@Override
- public void notifyAdBuffer(AdBuffer buffer) {
+ public void notifyAdBufferReady(AdBuffer buffer) {
mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_NOTIFY_AD_BUFFER, buffer));
}
diff --git a/media/java/android/media/tv/TableResponse.java b/media/java/android/media/tv/TableResponse.java
index fb4e99cb1098..c4fc26ef1932 100644
--- a/media/java/android/media/tv/TableResponse.java
+++ b/media/java/android/media/tv/TableResponse.java
@@ -64,7 +64,10 @@ public final class TableResponse extends BroadcastInfoResponse implements Parcel
* @param tableUri The URI of the table in the database.
* @param version The version number of requested table.
* @param size The Size number of table in bytes.
+ *
+ * @deprecated use {@link Builder} instead.
*/
+ @Deprecated
public TableResponse(int requestId, int sequence, @ResponseResult int responseResult,
@Nullable Uri tableUri, int version, int size) {
super(RESPONSE_TYPE, requestId, sequence, responseResult);
@@ -76,30 +79,7 @@ public final class TableResponse extends BroadcastInfoResponse implements Parcel
}
/**
- * Constructs a TableResponse with a table URI.
- *
- * @param requestId The ID is used to associate the response with the request.
- * @param sequence The sequence number which indicates the order of related responses.
- * @param responseResult The result for the response. It's one of {@link #RESPONSE_RESULT_OK},
- * {@link #RESPONSE_RESULT_CANCEL}, {@link #RESPONSE_RESULT_ERROR}.
- * @param tableByteArray The byte array which stores the table in bytes. The structure and
- * syntax of the table depends on the table name in
- * {@link TableRequest#getTableName()} and the corresponding standard.
- * @param version The version number of requested table.
- * @param size The Size number of table in bytes.
- */
- public TableResponse(int requestId, int sequence, @ResponseResult int responseResult,
- @NonNull byte[] tableByteArray, int version, int size) {
- super(RESPONSE_TYPE, requestId, sequence, responseResult);
- mVersion = version;
- mSize = size;
- mTableUri = null;
- mTableByteArray = tableByteArray;
- mTableSharedMemory = null;
- }
-
- /**
- * Constructs a TableResponse with a table URI.
+ * Constructs a TableResponse.
*
* @param requestId The ID is used to associate the response with the request.
* @param sequence The sequence number which indicates the order of related responses.
@@ -112,17 +92,128 @@ public final class TableResponse extends BroadcastInfoResponse implements Parcel
* {@link TableRequest#getTableName()} and the corresponding standard.
* @param version The version number of requested table.
* @param size The Size number of table in bytes.
+ * @param tableUri The URI of the table in the database.
+ * @param tableByteArray The byte array which stores the table in bytes. The structure and
+ * syntax of the table depends on the table name in
+ * @param tableSharedMemory The shared memory which stores the table. The table size can be
+ * large so using a shared memory optimizes the data
+ * communication between the table data source and the receiver. The
+ * structure syntax of the table depends on the table name in
+ * {@link TableRequest#getTableName()} and the corresponding standard.
*/
- public TableResponse(int requestId, int sequence, @ResponseResult int responseResult,
- @NonNull SharedMemory tableSharedMemory, int version, int size) {
+ private TableResponse(int requestId, int sequence, @ResponseResult int responseResult,
+ int version, int size, Uri tableUri, byte[] tableByteArray,
+ SharedMemory tableSharedMemory) {
super(RESPONSE_TYPE, requestId, sequence, responseResult);
mVersion = version;
mSize = size;
- mTableUri = null;
- mTableByteArray = null;
+ mTableUri = tableUri;
+ mTableByteArray = tableByteArray;
mTableSharedMemory = tableSharedMemory;
}
+ /**
+ * Builder for {@link TableResponse}.
+ */
+ public static final class Builder {
+ private final int mRequestId;
+ private final int mSequence;
+ @ResponseResult
+ private final int mResponseResult;
+ private final int mVersion;
+ private final int mSize;
+ private Uri mTableUri;
+ private byte[] mTableByteArray;
+ private SharedMemory mTableSharedMemory;
+
+ /**
+ * Constructs a Builder object of {@link TableResponse}.
+ *
+ * @param requestId The ID is used to associate the response with the request.
+ * @param sequence The sequence number which indicates the order of related responses.
+ * @param responseResult The result for the response. It's one of
+ * {@link #RESPONSE_RESULT_OK}, {@link #RESPONSE_RESULT_CANCEL},
+ * {@link #RESPONSE_RESULT_ERROR}.
+ * @param version The version number of requested table.
+ * @param size The Size number of table in bytes.
+ */
+ public Builder(int requestId, int sequence, @ResponseResult int responseResult, int version,
+ int size) {
+ mRequestId = requestId;
+ mSequence = sequence;
+ mResponseResult = responseResult;
+ mVersion = version;
+ mSize = size;
+ }
+
+ /**
+ * Sets table URI.
+ *
+ * <p>For a single builder instance, at most one of table URI, table byte array, and table
+ * shared memory can be set. If more than one are set, only the last call takes precedence
+ * and others are reset to {@code null}.
+ *
+ * @param uri The URI of the table.
+ */
+ @NonNull
+ public Builder setTableUri(@NonNull Uri uri) {
+ mTableUri = uri;
+ mTableByteArray = null;
+ mTableSharedMemory = null;
+ return this;
+ }
+
+ /**
+ * Sets table byte array.
+ *
+ * <p>For a single builder instance, at most one of table URI, table byte array, and table
+ * shared memory can be set. If more than one are set, only the last call takes precedence
+ * and others are reset to {@code null}.
+ *
+ * @param bytes The byte array which stores the table in bytes. The structure and
+ * syntax of the table depends on the table name in
+ * {@link TableRequest#getTableName()} and the corresponding standard.
+ */
+ @NonNull
+ public Builder setTableByteArray(@NonNull byte[] bytes) {
+ mTableByteArray = bytes;
+ mTableUri = null;
+ mTableSharedMemory = null;
+ return this;
+ }
+
+
+ /**
+ * Sets table shared memory.
+ *
+ * <p>For a single builder instance, at most one of table URI, table byte array, and table
+ * shared memory can be set. If more than one are set, only the last call takes precedence
+ * and others are reset to {@code null}.
+ *
+ * @param sharedMemory The shared memory which stores the table. The table size can be
+ * large so using a shared memory optimizes the data
+ * communication between the table data source and the receiver. The
+ * structure syntax of the table depends on the table name in
+ * {@link TableRequest#getTableName()} and the corresponding standard.
+ */
+ @NonNull
+ public Builder setTableSharedMemory(@NonNull SharedMemory sharedMemory) {
+ mTableSharedMemory = sharedMemory;
+ mTableUri = null;
+ mTableByteArray = null;
+ return this;
+ }
+
+ /**
+ * Builds a {@link TableResponse} object.
+ */
+ @NonNull
+ public TableResponse build() {
+ return new TableResponse(mRequestId, mSequence, mResponseResult, mVersion, mSize,
+ mTableUri, mTableByteArray, mTableSharedMemory);
+ }
+ }
+
TableResponse(Parcel source) {
super(RESPONSE_TYPE, source);
String uriString = source.readString();
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index 55a753f663c8..97403a44f75f 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -3642,13 +3642,13 @@ public final class TvInputManager {
/**
* Notifies when the advertisement buffer is filled and ready to be read.
*/
- public void notifyAdBuffer(AdBuffer buffer) {
+ public void notifyAdBufferReady(AdBuffer buffer) {
if (mToken == null) {
Log.w(TAG, "The session has been already released");
return;
}
try {
- mService.notifyAdBuffer(mToken, buffer, mUserId);
+ mService.notifyAdBufferReady(mToken, buffer, mUserId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java
index 9f40d704f7ac..afc124028ce2 100644
--- a/media/java/android/media/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -1351,7 +1351,7 @@ public abstract class TvInputService extends Service {
*
* @param buffer The {@link AdBuffer} that became ready for playback.
*/
- public void onAdBuffer(@NonNull AdBuffer buffer) {
+ public void onAdBufferReady(@NonNull AdBuffer buffer) {
}
/**
@@ -2050,8 +2050,8 @@ public abstract class TvInputService extends Service {
onRequestAd(request);
}
- void notifyAdBuffer(AdBuffer buffer) {
- onAdBuffer(buffer);
+ void notifyAdBufferReady(AdBuffer buffer) {
+ onAdBufferReady(buffer);
}
void onTvMessageReceived(String type, Bundle data) {
diff --git a/media/java/android/media/tv/TvRecordingInfo.java b/media/java/android/media/tv/TvRecordingInfo.java
index 60ceb8394159..59915fc078c0 100644
--- a/media/java/android/media/tv/TvRecordingInfo.java
+++ b/media/java/android/media/tv/TvRecordingInfo.java
@@ -131,7 +131,6 @@ public final class TvRecordingInfo implements Parcelable {
* cause the recording to start later than the specified time. This should cause the actual
* duration of the recording to decrease.
*/
- @NonNull
public long getStartPaddingMillis() {
return mStartPaddingMillis;
}
@@ -144,7 +143,6 @@ public final class TvRecordingInfo implements Parcelable {
* cause the recording to end earlier than the specified time. This should cause the actual
* duration of the recording to decrease.
*/
- @NonNull
public long getEndPaddingMillis() {
return mEndPaddingMillis;
}
@@ -176,7 +174,6 @@ public final class TvRecordingInfo implements Parcelable {
* https://www.oipf.tv/docs/OIPF-T1-R2_Specification-Volume-5-Declarative-Application-Environment-v2_3-2014-01-24.pdf
* ">Open IPTV Forum Release 2 Specification</a>. It is described in Volume 5, section 7.10.1.1.
*/
- @NonNull
@DaysOfWeek
public int getRepeatDays() {
return mRepeatDays;
@@ -228,7 +225,6 @@ public final class TvRecordingInfo implements Parcelable {
* Returns the scheduled start time of the recording in milliseconds since the epoch.
*/
@IntRange(from = 0)
- @NonNull
public long getScheduledStartTimeMillis() {
return mScheduledStartTimeMillis;
}
@@ -237,7 +233,6 @@ public final class TvRecordingInfo implements Parcelable {
* Returns the scheduled duration of the recording in milliseconds since the epoch.
*/
@IntRange(from = 0)
- @NonNull
public long getScheduledDurationMillis() {
return mScheduledDurationMillis;
}
@@ -292,7 +287,6 @@ public final class TvRecordingInfo implements Parcelable {
* <p> Returns -1 for recordings that have not yet started.
*/
@IntRange(from = -1)
- @NonNull
public long getRecordingStartTimeMillis() {
return mRecordingStartTimeMillis;
}
@@ -306,7 +300,6 @@ public final class TvRecordingInfo implements Parcelable {
* <p> Returns -1 for recordings that have not yet started.
*/
@IntRange(from = -1)
- @NonNull
public long getRecordingDurationMillis() {
return mRecordingDurationMillis;
}
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl
index 36954ad00f5f..77391841c6fe 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl
@@ -39,7 +39,7 @@ oneway interface ITvInteractiveAppClient {
void onSessionStateChanged(int state, int err, int seq);
void onBiInteractiveAppCreated(in Uri biIAppUri, in String biIAppId, int seq);
void onTeletextAppStateChanged(int state, int seq);
- void onAdBuffer(in AdBuffer buffer, int seq);
+ void onAdBufferReady(in AdBuffer buffer, int seq);
void onCommandRequest(in String cmdType, in Bundle parameters, int seq);
void onTimeShiftCommandRequest(in String cmdType, in Bundle parameters, int seq);
void onSetVideoBounds(in Rect rect, int seq);
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl
index 7db860489e8a..9e43e79144fd 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl
@@ -38,7 +38,7 @@ oneway interface ITvInteractiveAppSessionCallback {
void onSessionStateChanged(int state, int err);
void onBiInteractiveAppCreated(in Uri biIAppUri, in String biIAppId);
void onTeletextAppStateChanged(int state);
- void onAdBuffer(in AdBuffer buffer);
+ void onAdBufferReady(in AdBuffer buffer);
void onCommandRequest(in String cmdType, in Bundle parameters);
void onTimeShiftCommandRequest(in String cmdType, in Bundle parameters);
void onSetVideoBounds(in Rect rect);
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionWrapper.java b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionWrapper.java
index 6eed4832847f..705e6c4e960c 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionWrapper.java
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionWrapper.java
@@ -558,7 +558,7 @@ public class ITvInteractiveAppSessionWrapper
@Override
public void notifyRecordingStarted(String recordingId, String requestId) {
mCaller.executeOrSendMessage(mCaller.obtainMessageOO(
- DO_NOTIFY_RECORDING_STARTED, recordingId, recordingId));
+ DO_NOTIFY_RECORDING_STARTED, recordingId, requestId));
}
@Override
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppManager.java b/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
index 3e31bce30baa..1b26deff3822 100755
--- a/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
@@ -681,14 +681,14 @@ public final class TvInteractiveAppManager {
}
@Override
- public void onAdBuffer(AdBuffer buffer, int seq) {
+ public void onAdBufferReady(AdBuffer buffer, int seq) {
synchronized (mSessionCallbackRecordMap) {
SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
if (record == null) {
Log.e(TAG, "Callback not found for seq " + seq);
return;
}
- record.postAdBuffer(buffer);
+ record.postAdBufferReady(buffer);
}
}
};
@@ -2245,12 +2245,12 @@ public final class TvInteractiveAppManager {
});
}
- void postAdBuffer(AdBuffer buffer) {
+ void postAdBufferReady(AdBuffer buffer) {
mHandler.post(new Runnable() {
@Override
public void run() {
if (mSession.getInputSession() != null) {
- mSession.getInputSession().notifyAdBuffer(buffer);
+ mSession.getInputSession().notifyAdBufferReady(buffer);
}
}
});
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppService.java b/media/java/android/media/tv/interactive/TvInteractiveAppService.java
index 1ae82f43b9dd..d78d277edd8a 100755
--- a/media/java/android/media/tv/interactive/TvInteractiveAppService.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppService.java
@@ -1507,8 +1507,7 @@ public abstract class TvInteractiveAppService extends Service {
* @param type The type of recording to retrieve.
*/
@CallSuper
- public void requestTvRecordingInfoList(@NonNull @TvRecordingInfo.TvRecordingListType
- int type) {
+ public void requestTvRecordingInfoList(@TvRecordingInfo.TvRecordingListType int type) {
executeOrPostRunnableOnMainThread(() -> {
try {
if (DEBUG) {
@@ -1942,7 +1941,7 @@ public abstract class TvInteractiveAppService extends Service {
* @param buffer The {@link AdBuffer} to be received
*/
@CallSuper
- public void notifyAdBuffer(@NonNull AdBuffer buffer) {
+ public void notifyAdBufferReady(@NonNull AdBuffer buffer) {
executeOrPostRunnableOnMainThread(new Runnable() {
@MainThread
@Override
@@ -1950,10 +1949,10 @@ public abstract class TvInteractiveAppService extends Service {
try {
if (DEBUG) {
Log.d(TAG,
- "notifyAdBuffer(buffer=" + buffer + ")");
+ "notifyAdBufferReady(buffer=" + buffer + ")");
}
if (mSessionCallback != null) {
- mSessionCallback.onAdBuffer(buffer);
+ mSessionCallback.onAdBufferReady(buffer);
}
} catch (RemoteException e) {
Log.w(TAG, "error in notifyAdBuffer", e);
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppView.java b/media/java/android/media/tv/interactive/TvInteractiveAppView.java
index 0a8de127b6c9..a894cd800e81 100755
--- a/media/java/android/media/tv/interactive/TvInteractiveAppView.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppView.java
@@ -682,7 +682,7 @@ public class TvInteractiveAppView extends ViewGroup {
Log.d(TAG, "notifyRecordingStarted");
}
if (mSession != null) {
- mSession.notifyRecordingStarted(recordingId, recordingId);
+ mSession.notifyRecordingStarted(recordingId, requestId);
}
}
@@ -1350,7 +1350,7 @@ public class TvInteractiveAppView extends ViewGroup {
*/
public void onRequestTvRecordingInfoList(
@NonNull String iAppServiceId,
- @NonNull @TvRecordingInfo.TvRecordingListType int type) {
+ @TvRecordingInfo.TvRecordingListType int type) {
}
}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
index 16827da39b14..76f10a7c80f3 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
@@ -446,6 +446,7 @@ fun MoreOptionsRowIntroCard(
BodyMediumText(text = stringResource(
R.string.use_provider_for_all_description, entryInfo.userProviderDisplayName))
}
+ item { Divider(thickness = 24.dp, color = Color.Transparent) }
item {
CtaButtonRow(
leftButton = {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/GenerationRegistry.java b/packages/SettingsProvider/src/com/android/providers/settings/GenerationRegistry.java
index db6cc1a39ef1..7f3b0ff8c838 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/GenerationRegistry.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/GenerationRegistry.java
@@ -16,7 +16,6 @@
package com.android.providers.settings;
-import android.annotation.NonNull;
import android.os.Bundle;
import android.provider.Settings;
import android.util.ArrayMap;
@@ -60,10 +59,6 @@ final class GenerationRegistry {
// Maximum size of an individual backing store
static final int MAX_BACKING_STORE_SIZE = MemoryIntArray.getMaxSize();
- // Use an empty string to track the generation number of all non-predefined, unset settings
- // The generation number is only increased when a new non-predefined setting is inserted
- private static final String DEFAULT_MAP_KEY_FOR_UNSET_SETTINGS = "";
-
public GenerationRegistry(Object lock) {
mLock = lock;
}
@@ -77,10 +72,6 @@ final class GenerationRegistry {
(SettingsState.getTypeFromKey(key) == SettingsState.SETTINGS_TYPE_CONFIG);
// Only store the prefix if the mutated setting is a config
final String indexMapKey = isConfig ? (name.split("/")[0] + "/") : name;
- incrementGenerationInternal(key, indexMapKey);
- }
-
- private void incrementGenerationInternal(int key, @NonNull String indexMapKey) {
synchronized (mLock) {
final MemoryIntArray backingStore = getBackingStoreLocked(key,
/* createIfNotExist= */ false);
@@ -96,8 +87,7 @@ final class GenerationRegistry {
final int generation = backingStore.get(index) + 1;
backingStore.set(index, generation);
if (DEBUG) {
- Slog.i(LOG_TAG, "Incremented generation for "
- + (indexMapKey.isEmpty() ? "unset settings" : "setting:" + indexMapKey)
+ Slog.i(LOG_TAG, "Incremented generation for setting:" + indexMapKey
+ " key:" + SettingsState.keyToString(key)
+ " at index:" + index);
}
@@ -108,18 +98,6 @@ final class GenerationRegistry {
}
}
- // A new, non-predefined setting has been inserted, increment the tracking number for all unset
- // settings
- public void incrementGenerationForUnsetSettings(int key) {
- final boolean isConfig =
- (SettingsState.getTypeFromKey(key) == SettingsState.SETTINGS_TYPE_CONFIG);
- if (isConfig) {
- // No need to track new settings for configs
- return;
- }
- incrementGenerationInternal(key, DEFAULT_MAP_KEY_FOR_UNSET_SETTINGS);
- }
-
/**
* Return the backing store's reference, the index and the current generation number
* of a cached setting. If it was not in the backing store, first create the entry in it before
@@ -146,8 +124,8 @@ final class GenerationRegistry {
bundle.putInt(Settings.CALL_METHOD_GENERATION_KEY,
backingStore.get(index));
if (DEBUG) {
- Slog.i(LOG_TAG, "Exported index:" + index + " for "
- + (indexMapKey.isEmpty() ? "unset settings" : "setting:" + indexMapKey)
+ Slog.i(LOG_TAG, "Exported index:" + index
+ + " for setting:" + indexMapKey
+ " key:" + SettingsState.keyToString(key));
}
} catch (IOException e) {
@@ -157,10 +135,6 @@ final class GenerationRegistry {
}
}
- public void addGenerationDataForUnsetSettings(Bundle bundle, int key) {
- addGenerationData(bundle, key, /* indexMapKey= */ DEFAULT_MAP_KEY_FOR_UNSET_SETTINGS);
- }
-
public void onUserRemoved(int userId) {
final int secureKey = SettingsState.makeKey(
SettingsState.SETTINGS_TYPE_SECURE, userId);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 27c8cdfe98f3..ba275ebca168 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -2327,15 +2327,11 @@ public class SettingsProvider extends ContentProvider {
result.putString(Settings.NameValueTable.VALUE,
(setting != null && !setting.isNull()) ? setting.getValue() : null);
- synchronized (mLock) {
- if ((setting != null && !setting.isNull()) || isSettingPreDefined(name, type)) {
- // Individual generation tracking for predefined settings even if they are unset
+ if ((setting != null && !setting.isNull()) || isSettingPreDefined(name, type)) {
+ // Don't track generation for non-existent settings unless the name is predefined
+ synchronized (mLock) {
mSettingsRegistry.mGenerationRegistry.addGenerationData(result,
SettingsState.makeKey(type, userId), name);
- } else {
- // All non-predefined, unset settings are tracked using the same generation number
- mSettingsRegistry.mGenerationRegistry.addGenerationDataForUnsetSettings(result,
- SettingsState.makeKey(type, userId));
}
}
return result;
@@ -2349,8 +2345,7 @@ public class SettingsProvider extends ContentProvider {
} else if (type == SETTINGS_TYPE_SYSTEM) {
return sAllSystemSettings.contains(name);
} else {
- // Consider all config settings predefined because they are used by system apps only
- return type == SETTINGS_TYPE_CONFIG;
+ return false;
}
}
@@ -2359,13 +2354,14 @@ public class SettingsProvider extends ContentProvider {
Bundle result = new Bundle();
result.putSerializable(Settings.NameValueTable.VALUE, keyValues);
if (trackingGeneration) {
+ // Track generation even if the namespace is empty because this is for system apps
synchronized (mLock) {
- // Track generation even if namespace is empty because this is for system apps only
mSettingsRegistry.mGenerationRegistry.addGenerationData(result,
- SettingsState.makeKey(SETTINGS_TYPE_CONFIG, UserHandle.USER_SYSTEM),
- prefix);
+ mSettingsRegistry.getSettingsLocked(SETTINGS_TYPE_CONFIG,
+ UserHandle.USER_SYSTEM).mKey, prefix);
}
}
+
return result;
}
@@ -3056,15 +3052,10 @@ public class SettingsProvider extends ContentProvider {
final int key = makeKey(type, userId);
boolean success = false;
- boolean wasUnsetNonPredefinedSetting = false;
SettingsState settingsState = peekSettingsStateLocked(key);
if (settingsState != null) {
- if (!isSettingPreDefined(name, type) && !settingsState.hasSetting(name)) {
- wasUnsetNonPredefinedSetting = true;
- }
success = settingsState.insertSettingLocked(name, value,
- tag, makeDefault, forceNonSystemPackage, packageName,
- overrideableByRestore);
+ tag, makeDefault, forceNonSystemPackage, packageName, overrideableByRestore);
}
if (success && criticalSettings != null && criticalSettings.contains(name)) {
@@ -3073,11 +3064,6 @@ public class SettingsProvider extends ContentProvider {
if (forceNotify || success) {
notifyForSettingsChange(key, name);
- if (wasUnsetNonPredefinedSetting) {
- // Increment the generation number for all non-predefined, unset settings,
- // because a new non-predefined setting has been inserted
- mGenerationRegistry.incrementGenerationForUnsetSettings(key);
- }
}
if (success) {
logSettingChanged(userId, name, type, CHANGE_TYPE_INSERT);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
index 4d8705f135af..c3888268a61d 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
@@ -759,12 +759,6 @@ final class SettingsState {
mPackageToMemoryUsage.put(packageName, newSize);
}
- public boolean hasSetting(String name) {
- synchronized (mLock) {
- return hasSettingLocked(name);
- }
- }
-
@GuardedBy("mLock")
private boolean hasSettingLocked(String name) {
return mSettings.indexOfKey(name) >= 0;
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/GenerationRegistryTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/GenerationRegistryTest.java
index 6ec8146baee0..d34fe6943153 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/GenerationRegistryTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/GenerationRegistryTest.java
@@ -151,26 +151,6 @@ public class GenerationRegistryTest {
checkBundle(b, 0, 1, false);
}
- @Test
- public void testUnsetSettings() throws IOException {
- final GenerationRegistry generationRegistry = new GenerationRegistry(new Object());
- final int secureKey = SettingsState.makeKey(SettingsState.SETTINGS_TYPE_SECURE, 0);
- final String testSecureSetting = "test_secure_setting";
- Bundle b = new Bundle();
- generationRegistry.addGenerationData(b, secureKey, testSecureSetting);
- checkBundle(b, 0, 1, false);
- generationRegistry.addGenerationDataForUnsetSettings(b, secureKey);
- checkBundle(b, 1, 1, false);
- generationRegistry.addGenerationDataForUnsetSettings(b, secureKey);
- // Test that unset settings always have the same index
- checkBundle(b, 1, 1, false);
- generationRegistry.incrementGenerationForUnsetSettings(secureKey);
- // Test that the generation number of the unset settings have increased
- generationRegistry.addGenerationDataForUnsetSettings(b, secureKey);
- checkBundle(b, 1, 2, false);
- }
-
-
private void checkBundle(Bundle b, int expectedIndex, int expectedGeneration, boolean isNull)
throws IOException {
final MemoryIntArray array = getArray(b);
diff --git a/packages/SystemUI/res/drawable/ic_magnification_menu_large.xml b/packages/SystemUI/res/drawable/ic_magnification_menu_large.xml
index 92c952794f57..401ac73f3e0a 100644
--- a/packages/SystemUI/res/drawable/ic_magnification_menu_large.xml
+++ b/packages/SystemUI/res/drawable/ic_magnification_menu_large.xml
@@ -14,8 +14,8 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="48dp"
- android:height="48dp"
+ android:width="32dp"
+ android:height="32dp"
android:viewportWidth="48"
android:viewportHeight="48"
android:tint="?attr/colorControlNormal">
diff --git a/packages/SystemUI/res/drawable/ic_magnification_menu_medium.xml b/packages/SystemUI/res/drawable/ic_magnification_menu_medium.xml
index 209681f29548..9a850e8fb811 100644
--- a/packages/SystemUI/res/drawable/ic_magnification_menu_medium.xml
+++ b/packages/SystemUI/res/drawable/ic_magnification_menu_medium.xml
@@ -14,8 +14,8 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="48dp"
- android:height="48dp"
+ android:width="32dp"
+ android:height="32dp"
android:viewportWidth="48"
android:viewportHeight="48"
android:tint="?attr/colorControlNormal">
diff --git a/packages/SystemUI/res/drawable/ic_magnification_menu_small.xml b/packages/SystemUI/res/drawable/ic_magnification_menu_small.xml
index a3dc816f6755..54322c562c5d 100644
--- a/packages/SystemUI/res/drawable/ic_magnification_menu_small.xml
+++ b/packages/SystemUI/res/drawable/ic_magnification_menu_small.xml
@@ -14,8 +14,8 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="48dp"
- android:height="48dp"
+ android:width="32dp"
+ android:height="32dp"
android:viewportWidth="48"
android:viewportHeight="48"
android:tint="?attr/colorControlNormal">
diff --git a/packages/SystemUI/res/drawable/ic_open_in_full.xml b/packages/SystemUI/res/drawable/ic_open_in_full.xml
index c7f3236f94cf..7081c4b91bca 100644
--- a/packages/SystemUI/res/drawable/ic_open_in_full.xml
+++ b/packages/SystemUI/res/drawable/ic_open_in_full.xml
@@ -14,8 +14,8 @@
~ limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="48dp"
- android:height="48dp"
+ android:width="24dp"
+ android:height="24dp"
android:viewportWidth="48"
android:viewportHeight="48"
android:tint="?attr/colorControlNormal">
diff --git a/packages/SystemUI/res/layout/window_magnification_settings_view.xml b/packages/SystemUI/res/layout/window_magnification_settings_view.xml
index ae0f8f46599d..3d0741c80450 100644
--- a/packages/SystemUI/res/layout/window_magnification_settings_view.xml
+++ b/packages/SystemUI/res/layout/window_magnification_settings_view.xml
@@ -35,7 +35,7 @@
android:text="@string/accessibility_magnifier_size"
android:textAppearance="@style/TextAppearance.MagnificationSetting.Title"
android:focusable="true"
- android:layout_gravity="center_vertical|left" />
+ android:layout_gravity="center_vertical" />
<Button
android:id="@+id/magnifier_edit_button"
@@ -45,25 +45,22 @@
android:text="@string/accessibility_magnifier_edit"
android:textAppearance="@style/TextAppearance.MagnificationSetting.EditButton"
android:focusable="true"
- android:layout_gravity="right" />
+ android:layout_gravity="center_vertical" />
</LinearLayout>
<LinearLayout
android:background="@drawable/accessibility_magnification_setting_view_image_btn_layout_bg"
- android:layout_width="@dimen/magnification_setting_image_button_background_width"
+ android:layout_width="match_parent"
android:layout_height="@dimen/magnification_setting_image_button_height"
+ android:minWidth="@dimen/magnification_setting_image_button_background_width"
android:orientation="horizontal">
<ImageButton
android:id="@+id/magnifier_small_button"
android:layout_width="0dp"
android:layout_height="@dimen/magnification_setting_image_button_height"
android:layout_weight="1"
- android:scaleType="fitCenter"
+ android:scaleType="center"
android:background="@drawable/accessibility_magnification_setting_view_image_btn_bg"
- android:paddingLeft="@dimen/magnification_setting_image_button_padding_horizontal"
- android:paddingRight="@dimen/magnification_setting_image_button_padding_horizontal"
- android:paddingTop="@dimen/magnification_setting_image_button_padding_vertical"
- android:paddingBottom="@dimen/magnification_setting_image_button_padding_vertical"
android:src="@drawable/ic_magnification_menu_small"
android:tint="@color/accessibility_magnification_image_button_tint"
android:tintMode="src_atop" />
@@ -73,12 +70,8 @@
android:layout_width="0dp"
android:layout_height="@dimen/magnification_setting_image_button_height"
android:layout_weight="1"
- android:scaleType="fitCenter"
+ android:scaleType="center"
android:background="@drawable/accessibility_magnification_setting_view_image_btn_bg"
- android:paddingLeft="@dimen/magnification_setting_image_button_padding_horizontal"
- android:paddingRight="@dimen/magnification_setting_image_button_padding_horizontal"
- android:paddingTop="@dimen/magnification_setting_image_button_padding_vertical"
- android:paddingBottom="@dimen/magnification_setting_image_button_padding_vertical"
android:src="@drawable/ic_magnification_menu_medium"
android:tint="@color/accessibility_magnification_image_button_tint"
android:tintMode="src_atop" />
@@ -88,12 +81,8 @@
android:layout_width="0dp"
android:layout_height="@dimen/magnification_setting_image_button_height"
android:layout_weight="1"
- android:scaleType="fitCenter"
+ android:scaleType="center"
android:background="@drawable/accessibility_magnification_setting_view_image_btn_bg"
- android:paddingLeft="@dimen/magnification_setting_image_button_padding_horizontal"
- android:paddingRight="@dimen/magnification_setting_image_button_padding_horizontal"
- android:paddingTop="@dimen/magnification_setting_image_button_padding_vertical"
- android:paddingBottom="@dimen/magnification_setting_image_button_padding_vertical"
android:src="@drawable/ic_magnification_menu_large"
android:tint="@color/accessibility_magnification_image_button_tint"
android:tintMode="src_atop" />
@@ -103,16 +92,8 @@
android:layout_width="0dp"
android:layout_height="@dimen/magnification_setting_image_button_height"
android:layout_weight="1"
- android:scaleType="fitCenter"
+ android:scaleType="center"
android:background="@drawable/accessibility_magnification_setting_view_image_btn_bg"
- android:paddingLeft
- ="@dimen/magnification_setting_image_button_open_in_full_padding_horizontal"
- android:paddingRight
- ="@dimen/magnification_setting_image_button_open_in_full_padding_horizontal"
- android:paddingTop
- ="@dimen/magnification_setting_image_button_open_in_full_padding_vertical"
- android:paddingBottom
- ="@dimen/magnification_setting_image_button_open_in_full_padding_vertical"
android:src="@drawable/ic_open_in_full"
android:tint="@color/accessibility_magnification_image_button_tint"
android:tintMode="src_atop" />
@@ -130,7 +111,6 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
- android:singleLine="true"
android:text="@string/accessibility_allow_diagonal_scrolling"
android:textAppearance="@style/TextAppearance.MagnificationSetting.Title"
android:layout_gravity="center_vertical" />
@@ -166,16 +146,11 @@
<Button
android:id="@+id/magnifier_done_button"
android:background="@drawable/accessibility_window_magnification_button_done_bg"
- android:minHeight="@dimen/magnification_setting_button_done_height"
- android:layout_width="@dimen/magnification_setting_button_done_width"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/accessibility_magnification_done"
android:textAppearance="@style/TextAppearance.MagnificationSetting.DoneButton"
android:focusable="true"
android:layout_gravity="center_horizontal"
- android:layout_marginTop="@dimen/magnification_setting_view_margin"
- android:paddingLeft="@dimen/magnification_setting_button_done_padding_horizontal"
- android:paddingRight="@dimen/magnification_setting_button_done_padding_horizontal"
- android:paddingTop="@dimen/magnification_setting_button_done_padding_vertical"
- android:paddingBottom="@dimen/magnification_setting_button_done_padding_vertical" />
+ android:layout_marginTop="@dimen/magnification_setting_view_margin"/>
</LinearLayout>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 2cd217395588..6596ed2cbb05 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -1358,6 +1358,7 @@
<item name="android:fontFamily">google-sans</item>
<item name="android:textColor">?androidprv:attr/textColorPrimary</item>
<item name="android:textSize">@dimen/magnification_setting_text_size</item>
+ <item name="android:singleLine">true</item>
</style>
<style name="TextAppearance.MagnificationSetting.EditButton">
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index 2f937a949e78..ba5a8c94dc23 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -39,6 +39,7 @@ import static java.lang.Integer.max;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.app.Activity;
@@ -1067,10 +1068,14 @@ public class KeyguardSecurityContainer extends ConstraintLayout {
int yTranslation = mResources.getDimensionPixelSize(R.dimen.disappear_y_translation);
+ AnimatorSet anims = new AnimatorSet();
ObjectAnimator yAnim = ObjectAnimator.ofFloat(mView, View.TRANSLATION_Y, yTranslation);
- yAnim.setInterpolator(Interpolators.STANDARD_ACCELERATE);
- yAnim.setDuration(500);
- yAnim.start();
+ ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(mUserSwitcherViewGroup, View.ALPHA,
+ 0f);
+
+ anims.setInterpolator(Interpolators.STANDARD_ACCELERATE);
+ anims.playTogether(alphaAnim, yAnim);
+ anims.start();
}
private void setupUserSwitcher() {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index 06258b20e06f..98866c694526 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -127,6 +127,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
private View.OnKeyListener mOnKeyListener = (v, keyCode, event) -> interceptMediaKey(event);
private ActivityStarter.OnDismissAction mDismissAction;
private Runnable mCancelAction;
+ private boolean mWillRunDismissFromKeyguard;
private int mLastOrientation = Configuration.ORIENTATION_UNDEFINED;
@@ -262,8 +263,10 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
// If there's a pending runnable because the user interacted with a widget
// and we're leaving keyguard, then run it.
boolean deferKeyguardDone = false;
+ mWillRunDismissFromKeyguard = false;
if (mDismissAction != null) {
deferKeyguardDone = mDismissAction.onDismiss();
+ mWillRunDismissFromKeyguard = mDismissAction.willRunAnimationOnKeyguard();
mDismissAction = null;
mCancelAction = null;
}
@@ -527,6 +530,13 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
}
/**
+ * @return will the dismissal run from the keyguard layout (instead of from bouncer)
+ */
+ public boolean willRunDismissFromKeyguard() {
+ return mWillRunDismissFromKeyguard;
+ }
+
+ /**
* Remove any dismiss action or cancel action that was set.
*/
public void cancelDismissAction() {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 64fe645b9c28..aaf6307ebc96 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -2459,8 +2459,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
Boolean isFaceEnrolled = mFaceManager != null && !mFaceSensorProperties.isEmpty()
&& mBiometricEnabledForUser.get(userId)
&& mAuthController.isFaceAuthEnrolled(userId);
+ if (mIsFaceEnrolled != isFaceEnrolled) {
+ mLogger.logFaceEnrolledUpdated(mIsFaceEnrolled, isFaceEnrolled);
+ }
mIsFaceEnrolled = isFaceEnrolled;
- mLogger.logFaceEnrolledUpdated(mIsFaceEnrolled, isFaceEnrolled);
}
public boolean isFaceSupported() {
@@ -3132,13 +3134,14 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
@VisibleForTesting
boolean isUnlockWithFingerprintPossible(int userId) {
// TODO (b/242022358), make this rely on onEnrollmentChanged event and update it only once.
- boolean fpEnrolled = mFpm != null
+ boolean newFpEnrolled = mFpm != null
&& !mFingerprintSensorProperties.isEmpty()
&& !isFingerprintDisabled(userId) && mFpm.hasEnrolledTemplates(userId);
- mLogger.logFpEnrolledUpdated(userId,
- mIsUnlockWithFingerprintPossible.getOrDefault(userId, false),
- fpEnrolled);
- mIsUnlockWithFingerprintPossible.put(userId, fpEnrolled);
+ Boolean oldFpEnrolled = mIsUnlockWithFingerprintPossible.getOrDefault(userId, false);
+ if (oldFpEnrolled != newFpEnrolled) {
+ mLogger.logFpEnrolledUpdated(userId, oldFpEnrolled, newFpEnrolled);
+ }
+ mIsUnlockWithFingerprintPossible.put(userId, newFpEnrolled);
return mIsUnlockWithFingerprintPossible.get(userId);
}
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index bfd99d355a2a..1ae380e53c52 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -51,6 +51,7 @@ import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
+import com.android.settingslib.udfps.UdfpsOverlayParams;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
import com.android.systemui.biometrics.AuthController;
@@ -778,7 +779,7 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
}
@Override
- public void onUdfpsLocationChanged() {
+ public void onUdfpsLocationChanged(UdfpsOverlayParams udfpsOverlayParams) {
updateUdfpsConfig();
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
index d811d30b5693..57c99187c302 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
@@ -403,15 +403,21 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
mAnimationController.deleteWindowMagnification(animationCallback);
}
+ void deleteWindowMagnification() {
+ deleteWindowMagnification(/* closeSettingPanel= */ true);
+ }
+
/**
* Deletes the magnification window.
*/
- void deleteWindowMagnification() {
+ void deleteWindowMagnification(boolean closeSettingPanel) {
if (!isWindowVisible()) {
return;
}
- closeMagnificationSettings();
+ if (closeSettingPanel) {
+ closeMagnificationSettings();
+ }
if (mMirrorSurface != null) {
mTransaction.remove(mMirrorSurface).apply();
@@ -489,7 +495,7 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
// Recreate the window again to correct the window appearance due to density or
// window size changed not caused by rotation.
if (isWindowVisible() && reCreateWindow) {
- deleteWindowMagnification();
+ deleteWindowMagnification(/* closeSettingPanel= */ false);
enableWindowMagnificationInternal(Float.NaN, Float.NaN, Float.NaN);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java
index 9ad64e293fe5..d9f5544c39b9 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java
@@ -230,14 +230,6 @@ class WindowMagnificationSettings implements MagnificationGestureDetector.OnGest
}
};
- private void applyResourcesValuesWithDensityChanged() {
- if (mIsVisible) {
- // Reset button to make its window layer always above the mirror window.
- hideSettingPanel();
- showSettingPanel(false);
- }
- }
-
private boolean onTouch(View v, MotionEvent event) {
if (!mIsVisible) {
return false;
@@ -354,10 +346,6 @@ class WindowMagnificationSettings implements MagnificationGestureDetector.OnGest
}
mWindowManager.addView(mSettingView, mParams);
- if (resetPosition) {
- // Request focus on the settings panel when position of the panel is reset.
- mSettingView.requestFocus();
- }
// Exclude magnification switch button from system gesture area.
setSystemGestureExclusion();
@@ -445,7 +433,15 @@ class WindowMagnificationSettings implements MagnificationGestureDetector.OnGest
void onConfigurationChanged(int configDiff) {
if ((configDiff & ActivityInfo.CONFIG_UI_MODE) != 0
- || (configDiff & ActivityInfo.CONFIG_ASSETS_PATHS) != 0) {
+ || (configDiff & ActivityInfo.CONFIG_ASSETS_PATHS) != 0
+ || (configDiff & ActivityInfo.CONFIG_FONT_SCALE) != 0
+ || (configDiff & ActivityInfo.CONFIG_DENSITY) != 0) {
+ // We listen to following config changes to trigger layout inflation:
+ // CONFIG_UI_MODE: theme change
+ // CONFIG_ASSETS_PATHS: wallpaper change
+ // CONFIG_FONT_SCALE: font size change
+ // CONFIG_DENSITY: display size change
+
boolean showSettingPanelAfterThemeChange = mIsVisible;
hideSettingPanel(/* resetPosition= */ false);
inflateView();
@@ -454,6 +450,7 @@ class WindowMagnificationSettings implements MagnificationGestureDetector.OnGest
}
return;
}
+
if ((configDiff & ActivityInfo.CONFIG_ORIENTATION) != 0) {
final Rect previousDraggableBounds = new Rect(mDraggableWindowBounds);
mDraggableWindowBounds.set(getDraggableWindowBounds());
@@ -465,10 +462,7 @@ class WindowMagnificationSettings implements MagnificationGestureDetector.OnGest
+ mDraggableWindowBounds.top;
return;
}
- if ((configDiff & ActivityInfo.CONFIG_DENSITY) != 0) {
- applyResourcesValuesWithDensityChanged();
- return;
- }
+
if ((configDiff & ActivityInfo.CONFIG_LOCALE) != 0) {
updateAccessibilityWindowTitle();
return;
@@ -536,7 +530,7 @@ class WindowMagnificationSettings implements MagnificationGestureDetector.OnGest
LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT,
LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY,
- /* _flags= */ 0,
+ LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSPARENT);
params.gravity = Gravity.TOP | Gravity.START;
params.accessibilityTitle = getAccessibilityWindowTitle(context);
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index 08efd89029ed..c31d45ff0b83 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -148,6 +148,7 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks,
@NonNull private final WindowManager mWindowManager;
@NonNull private final DisplayManager mDisplayManager;
@Nullable private UdfpsController mUdfpsController;
+ @Nullable private UdfpsOverlayParams mUdfpsOverlayParams;
@Nullable private IUdfpsRefreshRateRequestCallback mUdfpsRefreshRateRequestCallback;
@Nullable private SideFpsController mSideFpsController;
@Nullable private UdfpsLogger mUdfpsLogger;
@@ -806,6 +807,8 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks,
final FingerprintSensorPropertiesInternal udfpsProp = mUdfpsProps.get(0);
final Rect previousUdfpsBounds = mUdfpsBounds;
+ final UdfpsOverlayParams previousUdfpsOverlayParams = mUdfpsOverlayParams;
+
mUdfpsBounds = udfpsProp.getLocation().getRect();
mUdfpsBounds.scale(mScaleFactor);
@@ -815,7 +818,7 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks,
mCachedDisplayInfo.getNaturalWidth(), /* right */
mCachedDisplayInfo.getNaturalHeight() /* botom */);
- final UdfpsOverlayParams overlayParams = new UdfpsOverlayParams(
+ mUdfpsOverlayParams = new UdfpsOverlayParams(
mUdfpsBounds,
overlayBounds,
mCachedDisplayInfo.getNaturalWidth(),
@@ -823,10 +826,11 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks,
mScaleFactor,
mCachedDisplayInfo.rotation);
- mUdfpsController.updateOverlayParams(udfpsProp, overlayParams);
- if (!Objects.equals(previousUdfpsBounds, mUdfpsBounds)) {
+ mUdfpsController.updateOverlayParams(udfpsProp, mUdfpsOverlayParams);
+ if (!Objects.equals(previousUdfpsBounds, mUdfpsBounds) || !Objects.equals(
+ previousUdfpsOverlayParams, mUdfpsOverlayParams)) {
for (Callback cb : mCallbacks) {
- cb.onUdfpsLocationChanged();
+ cb.onUdfpsLocationChanged(mUdfpsOverlayParams);
}
}
}
@@ -1336,7 +1340,7 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks,
* On devices with UDFPS, this is always called alongside
* {@link #onFingerprintLocationChanged}.
*/
- default void onUdfpsLocationChanged() {}
+ default void onUdfpsLocationChanged(UdfpsOverlayParams udfpsOverlayParams) {}
/**
* Called when the location of the face unlock sensor (typically the front facing camera)
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
index 93b57dc127dd..fbb6451973c7 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
@@ -28,6 +28,7 @@ import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.keyguard.logging.KeyguardLogger
import com.android.settingslib.Utils
+import com.android.settingslib.udfps.UdfpsOverlayParams
import com.android.systemui.R
import com.android.systemui.animation.Interpolators
import com.android.systemui.flags.FeatureFlags
@@ -326,7 +327,7 @@ class AuthRippleController @Inject constructor(
updateUdfpsDependentParams()
}
- override fun onUdfpsLocationChanged() {
+ override fun onUdfpsLocationChanged(udfpsOverlayParams: UdfpsOverlayParams) {
updateUdfpsDependentParams()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 9e8326400e13..bb35355ba03a 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -100,6 +100,8 @@ import com.android.systemui.util.concurrency.Execution;
import com.android.systemui.util.settings.SecureSettings;
import com.android.systemui.util.time.SystemClock;
+import kotlin.Unit;
+
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashSet;
@@ -110,8 +112,6 @@ import java.util.concurrent.Executor;
import javax.inject.Inject;
import javax.inject.Provider;
-import kotlin.Unit;
-
/**
* Shows and hides the under-display fingerprint sensor (UDFPS) overlay, handles UDFPS touch events,
* and toggles the UDFPS display mode.
@@ -598,14 +598,20 @@ public class UdfpsController implements DozeReceiver, Dumpable {
mFalsingManager.isFalseTouch(UDFPS_AUTHENTICATION);
break;
+ case UNCHANGED:
+ if (!isWithinSensorArea(mOverlay.getOverlayView(), event.getX(), event.getY(),
+ true) && mActivePointerId == MotionEvent.INVALID_POINTER_ID
+ && event.getActionMasked() == MotionEvent.ACTION_DOWN
+ && mAlternateBouncerInteractor.isVisibleState()) {
+ // No pointer on sensor, forward to keyguard if alternateBouncer is visible
+ mKeyguardViewManager.onTouch(event);
+ }
+
default:
break;
}
logBiometricTouch(processedTouch.getEvent(), data);
- // We should only consume touches that are within the sensor. By returning "false" for
- // touches outside of the sensor, we let other UI components consume these events and act on
- // them appropriately.
return processedTouch.getTouchData().isWithinSensor(mOverlayParams.getNativeSensorBounds());
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractor.kt
new file mode 100644
index 000000000000..92a7094c22bf
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractor.kt
@@ -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 com.android.systemui.biometrics.domain.interactor
+
+import android.view.MotionEvent
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.settingslib.udfps.UdfpsOverlayParams
+import com.android.systemui.biometrics.AuthController
+import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.stateIn
+
+/** Encapsulates business logic for interacting with the UDFPS overlay. */
+@SysUISingleton
+class UdfpsOverlayInteractor
+@Inject
+constructor(private val authController: AuthController, @Application scope: CoroutineScope) {
+
+ /** Whether a touch should be intercepted or allowed to pass to the UdfpsOverlay */
+ fun canInterceptTouchInUdfpsBounds(ev: MotionEvent): Boolean {
+ val isUdfpsEnrolled = authController.isUdfpsEnrolled(KeyguardUpdateMonitor.getCurrentUser())
+ val isWithinUdfpsOverlayBounds =
+ udfpsOverlayParams.value.overlayBounds.contains(ev.rawX.toInt(), ev.rawY.toInt())
+ return !isUdfpsEnrolled || !isWithinUdfpsOverlayBounds
+ }
+
+ /** Returns the current udfpsOverlayParams */
+ val udfpsOverlayParams: StateFlow<UdfpsOverlayParams> =
+ ConflatedCallbackFlow.conflatedCallbackFlow {
+ val callback =
+ object : AuthController.Callback {
+ override fun onUdfpsLocationChanged(
+ udfpsOverlayParams: UdfpsOverlayParams
+ ) {
+ trySendWithFailureLogging(
+ udfpsOverlayParams,
+ TAG,
+ "update udfpsOverlayParams"
+ )
+ }
+ }
+ authController.addCallback(callback)
+ awaitClose { authController.removeCallback(callback) }
+ }
+ .stateIn(scope, started = SharingStarted.Eagerly, initialValue = UdfpsOverlayParams())
+
+ companion object {
+ private const val TAG = "UdfpsOverlayInteractor"
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index b6edcf52b302..6209c0ba47de 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -485,6 +485,13 @@ object Flags {
val ENABLE_PIP_APP_ICON_OVERLAY =
sysPropBooleanFlag(1115, "persist.wm.debug.enable_pip_app_icon_overlay", default = true)
+ // TODO(b/272110828): Tracking bug
+ @Keep
+ @JvmField
+ val ENABLE_MOVE_FLOATING_WINDOW_IN_TABLETOP =
+ sysPropBooleanFlag(
+ 1116, "persist.wm.debug.enable_move_floating_window_in_tabletop", default = false)
+
// 1200 - predictive back
@Keep
@JvmField
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
index e43f83b876ba..07753ca1e6dc 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
@@ -788,6 +788,11 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
@Override
public boolean onLongPress() {
+ // don't actually trigger the reboot if we are running stability
+ // tests via monkey
+ if (ActivityManager.isUserAMonkey()) {
+ return false;
+ }
mUiEventLogger.log(GlobalActionsEvent.GA_SHUTDOWN_LONG_PRESS);
if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_SAFE_BOOT)) {
mWindowManagerFuncs.reboot(true);
@@ -808,6 +813,11 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
@Override
public void onPress() {
+ // don't actually trigger the shutdown if we are running stability
+ // tests via monkey
+ if (ActivityManager.isUserAMonkey()) {
+ return;
+ }
mUiEventLogger.log(GlobalActionsEvent.GA_SHUTDOWN_PRESS);
// shutdown by making sure radio and power are handled accordingly.
mWindowManagerFuncs.shutdown();
@@ -919,6 +929,11 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
@Override
public boolean onLongPress() {
+ // don't actually trigger the reboot if we are running stability
+ // tests via monkey
+ if (ActivityManager.isUserAMonkey()) {
+ return false;
+ }
mUiEventLogger.log(GlobalActionsEvent.GA_REBOOT_LONG_PRESS);
if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_SAFE_BOOT)) {
mWindowManagerFuncs.reboot(true);
@@ -939,6 +954,11 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
@Override
public void onPress() {
+ // don't actually trigger the reboot if we are running stability
+ // tests via monkey
+ if (ActivityManager.isUserAMonkey()) {
+ return;
+ }
mUiEventLogger.log(GlobalActionsEvent.GA_REBOOT_PRESS);
mWindowManagerFuncs.reboot(false);
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
index 57c4b36b8b7a..3e52ff2c2da0 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
@@ -380,10 +380,7 @@ class KeyguardUnlockAnimationController @Inject constructor(
// If the launcher is underneath, but we're about to launch an activity, don't do
// the animations since they won't be visible.
!notificationShadeWindowController.isLaunchingActivity &&
- launcherUnlockController != null &&
- // Temporarily disable for foldables since foldable launcher has two first pages,
- // which breaks the in-window animation.
- !isFoldable(context)
+ launcherUnlockController != null
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/BouncerView.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/BouncerView.kt
index faeb48526ae4..a2589d3d4116 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/BouncerView.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/BouncerView.kt
@@ -52,6 +52,7 @@ interface BouncerViewDelegate {
cancelAction: Runnable?,
)
fun willDismissWithActions(): Boolean
+ fun willRunDismissFromKeyguard(): Boolean
/** @return the {@link OnBackAnimationCallback} to animate Bouncer during a back gesture. */
fun getBackCallback(): OnBackAnimationCallback
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt
index 2dc8fee25379..1fbfff95ab7e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt
@@ -47,6 +47,7 @@ constructor(
listenForOccludedToLockscreen()
listenForOccludedToDreaming()
listenForOccludedToAodOrDozing()
+ listenForOccludedToGone()
}
private fun listenForOccludedToDreaming() {
@@ -72,11 +73,22 @@ constructor(
private fun listenForOccludedToLockscreen() {
scope.launch {
keyguardInteractor.isKeyguardOccluded
- .sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
- .collect { (isOccluded, lastStartedKeyguardState) ->
+ .sample(
+ combine(
+ keyguardInteractor.isKeyguardShowing,
+ keyguardTransitionInteractor.startedKeyguardTransitionStep,
+ ::Pair
+ ),
+ ::toTriple
+ )
+ .collect { (isOccluded, isShowing, lastStartedKeyguardState) ->
// Occlusion signals come from the framework, and should interrupt any
// existing transition
- if (!isOccluded && lastStartedKeyguardState.to == KeyguardState.OCCLUDED) {
+ if (
+ !isOccluded &&
+ isShowing &&
+ lastStartedKeyguardState.to == KeyguardState.OCCLUDED
+ ) {
keyguardTransitionRepository.startTransition(
TransitionInfo(
name,
@@ -90,6 +102,38 @@ constructor(
}
}
+ private fun listenForOccludedToGone() {
+ scope.launch {
+ keyguardInteractor.isKeyguardOccluded
+ .sample(
+ combine(
+ keyguardInteractor.isKeyguardShowing,
+ keyguardTransitionInteractor.startedKeyguardTransitionStep,
+ ::Pair
+ ),
+ ::toTriple
+ )
+ .collect { (isOccluded, isShowing, lastStartedKeyguardState) ->
+ // Occlusion signals come from the framework, and should interrupt any
+ // existing transition
+ if (
+ !isOccluded &&
+ !isShowing &&
+ lastStartedKeyguardState.to == KeyguardState.OCCLUDED
+ ) {
+ keyguardTransitionRepository.startTransition(
+ TransitionInfo(
+ name,
+ KeyguardState.OCCLUDED,
+ KeyguardState.GONE,
+ getAnimator(),
+ )
+ )
+ }
+ }
+ }
+ }
+
private fun listenForOccludedToAodOrDozing() {
scope.launch {
keyguardInteractor.wakefulnessModel
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractor.kt
index d092337adfcb..3d2c472b8648 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractor.kt
@@ -372,6 +372,11 @@ constructor(
return primaryBouncerView.delegate?.willDismissWithActions() == true
}
+ /** Will the dismissal run from the keyguard layout (instead of from bouncer) */
+ fun willRunDismissFromKeyguard(): Boolean {
+ return primaryBouncerView.delegate?.willRunDismissFromKeyguard() == true
+ }
+
/** Returns whether the bouncer should be full screen. */
private fun needsFullscreenBouncer(): Boolean {
val mode: KeyguardSecurityModel.SecurityMode =
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/ScrimAlpha.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/ScrimAlpha.kt
new file mode 100644
index 000000000000..1db77336109e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/ScrimAlpha.kt
@@ -0,0 +1,23 @@
+/*
+ * 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.keyguard.shared.model
+
+/** Alpha values for scrim updates */
+data class ScrimAlpha(
+ val frontAlpha: Float = 0f,
+ val behindAlpha: Float = 0f,
+ val notificationsAlpha: Float = 0f,
+)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt
index 2337ffc35fa6..bb617bd50c69 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt
@@ -97,6 +97,10 @@ object KeyguardBouncerViewBinder {
override fun willDismissWithActions(): Boolean {
return securityContainerController.hasDismissActions()
}
+
+ override fun willRunDismissFromKeyguard(): Boolean {
+ return securityContainerController.willRunDismissFromKeyguard()
+ }
}
view.repeatWhenAttached {
repeatOnLifecycle(Lifecycle.State.CREATED) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt
index 92038e24edf3..b23247c30256 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt
@@ -20,11 +20,14 @@ import com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor.Companion.TO_GONE_DURATION
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor
+import com.android.systemui.keyguard.shared.model.ScrimAlpha
import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
import com.android.systemui.statusbar.SysuiStatusBarStateController
import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.map
/**
* Breaks down PRIMARY_BOUNCER->GONE transition into discrete steps for corresponding views to
@@ -36,6 +39,7 @@ class PrimaryBouncerToGoneTransitionViewModel
constructor(
private val interactor: KeyguardTransitionInteractor,
private val statusBarStateController: SysuiStatusBarStateController,
+ private val primaryBouncerInteractor: PrimaryBouncerInteractor,
) {
private val transitionAnimation =
KeyguardTransitionAnimationFlow(
@@ -44,26 +48,49 @@ constructor(
)
private var leaveShadeOpen: Boolean = false
+ private var willRunDismissFromKeyguard: Boolean = false
/** Bouncer container alpha */
val bouncerAlpha: Flow<Float> =
transitionAnimation.createFlow(
duration = 200.milliseconds,
- onStep = { 1f - it },
- )
-
- /** Scrim behind alpha */
- val scrimBehindAlpha: Flow<Float> =
- transitionAnimation.createFlow(
- duration = TO_GONE_DURATION,
- interpolator = EMPHASIZED_ACCELERATE,
- onStart = { leaveShadeOpen = statusBarStateController.leaveOpenOnKeyguardHide() },
+ onStart = {
+ willRunDismissFromKeyguard = primaryBouncerInteractor.willRunDismissFromKeyguard()
+ },
onStep = {
- if (leaveShadeOpen) {
- 1f
+ if (willRunDismissFromKeyguard) {
+ 0f
} else {
1f - it
}
},
)
+
+ /** Scrim alpha values */
+ val scrimAlpha: Flow<ScrimAlpha> =
+ transitionAnimation
+ .createFlow(
+ duration = TO_GONE_DURATION,
+ interpolator = EMPHASIZED_ACCELERATE,
+ onStart = {
+ leaveShadeOpen = statusBarStateController.leaveOpenOnKeyguardHide()
+ willRunDismissFromKeyguard =
+ primaryBouncerInteractor.willRunDismissFromKeyguard()
+ },
+ onStep = { 1f - it },
+ )
+ .map {
+ if (willRunDismissFromKeyguard) {
+ ScrimAlpha(
+ notificationsAlpha = 1f,
+ )
+ } else if (leaveShadeOpen) {
+ ScrimAlpha(
+ behindAlpha = 1f,
+ notificationsAlpha = 1f,
+ )
+ } else {
+ ScrimAlpha(behindAlpha = it)
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
index c130b3913b64..c09524bac613 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
@@ -36,6 +36,7 @@ import com.android.keyguard.AuthKeyguardMessageArea;
import com.android.keyguard.LockIconViewController;
import com.android.keyguard.dagger.KeyguardBouncerComponent;
import com.android.systemui.R;
+import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.dock.DockManager;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
@@ -86,7 +87,7 @@ public class NotificationShadeWindowViewController {
private final PulsingGestureListener mPulsingGestureListener;
private final NotificationInsetsController mNotificationInsetsController;
private final AlternateBouncerInteractor mAlternateBouncerInteractor;
-
+ private final UdfpsOverlayInteractor mUdfpsOverlayInteractor;
private GestureDetector mPulsingWakeupGestureHandler;
private View mBrightnessMirror;
private boolean mTouchActive;
@@ -134,6 +135,7 @@ public class NotificationShadeWindowViewController {
KeyguardBouncerViewModel keyguardBouncerViewModel,
KeyguardBouncerComponent.Factory keyguardBouncerComponentFactory,
AlternateBouncerInteractor alternateBouncerInteractor,
+ UdfpsOverlayInteractor udfpsOverlayInteractor,
KeyguardTransitionInteractor keyguardTransitionInteractor,
PrimaryBouncerToGoneTransitionViewModel primaryBouncerToGoneTransitionViewModel
) {
@@ -156,6 +158,7 @@ public class NotificationShadeWindowViewController {
mPulsingGestureListener = pulsingGestureListener;
mNotificationInsetsController = notificationInsetsController;
mAlternateBouncerInteractor = alternateBouncerInteractor;
+ mUdfpsOverlayInteractor = udfpsOverlayInteractor;
// This view is not part of the newly inflated expanded status bar.
mBrightnessMirror = mView.findViewById(R.id.brightness_mirror_container);
@@ -240,7 +243,6 @@ public class NotificationShadeWindowViewController {
mFalsingCollector.onTouchEvent(ev);
mPulsingWakeupGestureHandler.onTouchEvent(ev);
- mStatusBarKeyguardViewManager.onTouch(ev);
if (mBrightnessMirror != null
&& mBrightnessMirror.getVisibility() == View.VISIBLE) {
// Disallow new pointers while the brightness mirror is visible. This is so that
@@ -316,8 +318,8 @@ public class NotificationShadeWindowViewController {
}
if (mAlternateBouncerInteractor.isVisibleState()) {
- // capture all touches if the alt auth bouncer is showing
- return true;
+ // If using UDFPS, don't intercept touches that are within its overlay bounds
+ return mUdfpsOverlayInteractor.canInterceptTouchInUdfpsBounds(ev);
}
if (mLockIconViewController.onInterceptTouchEvent(ev)) {
@@ -355,6 +357,7 @@ public class NotificationShadeWindowViewController {
if (mAlternateBouncerInteractor.isVisibleState()) {
// eat the touch
+ mStatusBarKeyguardViewManager.onTouch(ev);
handled = true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 9f8bf358bfb6..0bded7327ea6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -59,13 +59,13 @@ import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants;
+import com.android.systemui.keyguard.shared.model.ScrimAlpha;
import com.android.systemui.keyguard.shared.model.TransitionState;
import com.android.systemui.keyguard.shared.model.TransitionStep;
import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel;
import com.android.systemui.scrim.ScrimView;
import com.android.systemui.shade.NotificationPanelViewController;
import com.android.systemui.shade.transition.LargeScreenShadeInterpolator;
-import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.stack.ViewState;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -209,7 +209,6 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
private final ScreenOffAnimationController mScreenOffAnimationController;
private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
- private final SysuiStatusBarStateController mStatusBarStateController;
private GradientColors mColors;
private boolean mNeedsDrawableColorUpdate;
@@ -270,12 +269,16 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
private CoroutineDispatcher mMainDispatcher;
private boolean mIsBouncerToGoneTransitionRunning = false;
private PrimaryBouncerToGoneTransitionViewModel mPrimaryBouncerToGoneTransitionViewModel;
- private final Consumer<Float> mScrimAlphaConsumer =
- (Float alpha) -> {
+ private final Consumer<ScrimAlpha> mScrimAlphaConsumer =
+ (ScrimAlpha alphas) -> {
+ mInFrontAlpha = alphas.getFrontAlpha();
mScrimInFront.setViewAlpha(mInFrontAlpha);
+
+ mNotificationsAlpha = alphas.getNotificationsAlpha();
mNotificationsScrim.setViewAlpha(mNotificationsAlpha);
- mBehindAlpha = alpha;
- mScrimBehind.setViewAlpha(alpha);
+
+ mBehindAlpha = alphas.getBehindAlpha();
+ mScrimBehind.setViewAlpha(mBehindAlpha);
};
Consumer<TransitionStep> mPrimaryBouncerToGoneTransition;
@@ -297,7 +300,6 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
StatusBarKeyguardViewManager statusBarKeyguardViewManager,
PrimaryBouncerToGoneTransitionViewModel primaryBouncerToGoneTransitionViewModel,
KeyguardTransitionInteractor keyguardTransitionInteractor,
- SysuiStatusBarStateController sysuiStatusBarStateController,
@Main CoroutineDispatcher mainDispatcher,
LargeScreenShadeInterpolator largeScreenShadeInterpolator,
FeatureFlags featureFlags) {
@@ -309,7 +311,6 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
mKeyguardStateController = keyguardStateController;
mDarkenWhileDragging = !mKeyguardStateController.canDismissLockScreen();
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
- mStatusBarStateController = sysuiStatusBarStateController;
mKeyguardVisibilityCallback = new KeyguardVisibilityCallback();
mHandler = handler;
mMainExecutor = mainExecutor;
@@ -409,7 +410,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
collectFlow(behindScrim, mKeyguardTransitionInteractor.getPrimaryBouncerToGoneTransition(),
mPrimaryBouncerToGoneTransition, mMainDispatcher);
- collectFlow(behindScrim, mPrimaryBouncerToGoneTransitionViewModel.getScrimBehindAlpha(),
+ collectFlow(behindScrim, mPrimaryBouncerToGoneTransitionViewModel.getScrimAlpha(),
mScrimAlphaConsumer, mMainDispatcher);
}
@@ -1127,8 +1128,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
mBehindAlpha = 1;
}
// Prevent notification scrim flicker when transitioning away from keyguard.
- if (mKeyguardStateController.isKeyguardGoingAway()
- && !mStatusBarStateController.leaveOpenOnKeyguardHide()) {
+ if (mKeyguardStateController.isKeyguardGoingAway()) {
mNotificationsAlpha = 0;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 66f5b6508494..aa71b51b5459 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -733,7 +733,9 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
} else {
showBouncerOrKeyguard(hideBouncerWhenShowing);
}
- hideAlternateBouncer(false);
+ if (hideBouncerWhenShowing) {
+ hideAlternateBouncer(false);
+ }
mKeyguardUpdateManager.sendKeyguardReset();
updateStates();
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
index 064bc9c0036d..38d3a3eec606 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
@@ -521,6 +521,38 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase {
}
@Test
+ public void testWillRunDismissFromKeyguardIsTrue() {
+ ActivityStarter.OnDismissAction action = mock(ActivityStarter.OnDismissAction.class);
+ when(action.willRunAnimationOnKeyguard()).thenReturn(true);
+ mKeyguardSecurityContainerController.setOnDismissAction(action, null /* cancelAction */);
+
+ mKeyguardSecurityContainerController.finish(false /* strongAuth */, 0 /* currentUser */);
+
+ assertThat(mKeyguardSecurityContainerController.willRunDismissFromKeyguard()).isTrue();
+ }
+
+ @Test
+ public void testWillRunDismissFromKeyguardIsFalse() {
+ ActivityStarter.OnDismissAction action = mock(ActivityStarter.OnDismissAction.class);
+ when(action.willRunAnimationOnKeyguard()).thenReturn(false);
+ mKeyguardSecurityContainerController.setOnDismissAction(action, null /* cancelAction */);
+
+ mKeyguardSecurityContainerController.finish(false /* strongAuth */, 0 /* currentUser */);
+
+ assertThat(mKeyguardSecurityContainerController.willRunDismissFromKeyguard()).isFalse();
+ }
+
+ @Test
+ public void testWillRunDismissFromKeyguardIsFalseWhenNoDismissActionSet() {
+ mKeyguardSecurityContainerController.setOnDismissAction(null /* action */,
+ null /* cancelAction */);
+
+ mKeyguardSecurityContainerController.finish(false /* strongAuth */, 0 /* currentUser */);
+
+ assertThat(mKeyguardSecurityContainerController.willRunDismissFromKeyguard()).isFalse();
+ }
+
+ @Test
public void testOnStartingToHide() {
mKeyguardSecurityContainerController.onStartingToHide();
verify(mInputViewController).onStartingToHide();
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java
index f370ad6dc298..33f0ae5563f7 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java
@@ -36,6 +36,7 @@ import android.util.Pair;
import androidx.test.filters.SmallTest;
+import com.android.settingslib.udfps.UdfpsOverlayParams;
import com.android.systemui.doze.util.BurnInHelperKt;
import org.junit.Test;
@@ -107,7 +108,7 @@ public class LockIconViewControllerTest extends LockIconViewControllerBaseTest {
Pair<Float, Point> udfps = setupUdfps();
// WHEN udfps location changes
- mAuthControllerCallback.onUdfpsLocationChanged();
+ mAuthControllerCallback.onUdfpsLocationChanged(new UdfpsOverlayParams());
mDelayableExecutor.runAllReady();
// THEN lock icon view location is updated with the same coordinates as auth controller vals
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationSettingsTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationSettingsTest.java
index 52a70ee9cce2..47c91911e52a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationSettingsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationSettingsTest.java
@@ -201,13 +201,6 @@ public class WindowMagnificationSettingsTest extends SysuiTestCase {
assertThat(magnifierMediumButton.isSelected()).isTrue();
}
- @Test
- public void showSettingPanel_focusOnThePanel() {
- mWindowMagnificationSettings.showSettingPanel();
-
- assertThat(mSettingView.isFocused()).isTrue();
- }
-
private <T extends View> T getInternalView(@IdRes int idRes) {
T view = mSettingView.findViewById(idRes);
assertNotNull(view);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index 05266f1894ac..9a73898ca7c7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -1224,6 +1224,44 @@ public class UdfpsControllerTest extends SysuiTestCase {
}
@Test
+ public void onTouch_WithNewTouchDetection_forwardToKeyguard() throws RemoteException {
+ final NormalizedTouchData touchData = new NormalizedTouchData(0, 0f, 0f, 0f, 0f, 0f, 0L,
+ 0L);
+ final TouchProcessorResult processorResultDown = new TouchProcessorResult.ProcessedTouch(
+ InteractionEvent.UNCHANGED, -1 /* pointerOnSensorId */, touchData);
+
+ // Enable new touch detection.
+ when(mFeatureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)).thenReturn(true);
+
+ // Configure UdfpsController to use FingerprintManager as opposed to AlternateTouchProvider.
+ initUdfpsController(mOpticalProps, false /* hasAlternateTouchProvider */);
+
+ // Configure UdfpsView to accept the ACTION_DOWN event
+ when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
+ when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(false);
+
+ // GIVEN that the overlay is showing and a11y touch exploration NOT enabled
+ when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true);
+ when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(false);
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
+ BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ mFgExecutor.runAllReady();
+
+ verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
+
+ // WHEN ACTION_DOWN is received
+ when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
+ processorResultDown);
+ MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
+ mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
+ mBiometricExecutor.runAllReady();
+
+ // THEN the touch is forwarded to Keyguard
+ verify(mStatusBarKeyguardViewManager).onTouch(downEvent);
+ downEvent.recycle();
+ }
+
+ @Test
public void onAodInterrupt_onAcquiredGood_fingerNoLongerDown() throws RemoteException {
// GIVEN UDFPS overlay is showing
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractorTest.kt
new file mode 100644
index 000000000000..87d5ae64dee8
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractorTest.kt
@@ -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.systemui.biometrics.domain.interactor
+
+import android.graphics.Rect
+import android.test.suitebuilder.annotation.SmallTest
+import android.view.MotionEvent
+import android.view.Surface
+import com.android.settingslib.udfps.UdfpsOverlayParams
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.AuthController
+import com.android.systemui.coroutines.collectLastValue
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.ArgumentCaptor
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.Captor
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when` as whenever
+import org.mockito.junit.MockitoJUnit
+
+@SmallTest
+@RunWith(JUnit4::class)
+class UdfpsOverlayInteractorTest : SysuiTestCase() {
+
+ @JvmField @Rule var mockitoRule = MockitoJUnit.rule()
+
+ private lateinit var testScope: TestScope
+
+ @Mock private lateinit var authController: AuthController
+ @Captor private lateinit var authControllerCallback: ArgumentCaptor<AuthController.Callback>
+
+ @Mock private lateinit var udfpsOverlayParams: UdfpsOverlayParams
+ @Mock private lateinit var overlayBounds: Rect
+
+ private lateinit var underTest: UdfpsOverlayInteractor
+
+ @Before
+ fun setUp() {
+ testScope = TestScope(StandardTestDispatcher())
+ }
+
+ @Test
+ fun testShouldInterceptTouch() =
+ testScope.runTest {
+ createUdpfsOverlayInteractor()
+
+ // When fingerprint enrolled and touch is within bounds
+ verify(authController).addCallback(authControllerCallback.capture())
+ authControllerCallback.value.onUdfpsLocationChanged(udfpsOverlayParams)
+ whenever(authController.isUdfpsEnrolled(anyInt())).thenReturn(true)
+ whenever(udfpsOverlayParams.overlayBounds).thenReturn(overlayBounds)
+ whenever(overlayBounds.contains(downEv.x.toInt(), downEv.y.toInt())).thenReturn(true)
+
+ runCurrent()
+
+ // Then touch should not be intercepted
+ val canInterceptTrue = underTest.canInterceptTouchInUdfpsBounds(downEv)
+ assertThat(canInterceptTrue).isFalse()
+
+ // When touch is outside of bounds
+ whenever(overlayBounds.contains(downEv.x.toInt(), downEv.y.toInt())).thenReturn(false)
+
+ // Then touch should be intercepted
+ val canInterceptFalse = underTest.canInterceptTouchInUdfpsBounds(downEv)
+ assertThat(canInterceptFalse).isTrue()
+ }
+
+ @Test
+ fun testUdfpsOverlayParamsChange() =
+ testScope.runTest {
+ createUdpfsOverlayInteractor()
+ val udfpsOverlayParams = collectLastValue(underTest.udfpsOverlayParams)
+ runCurrent()
+
+ verify(authController).addCallback(authControllerCallback.capture())
+
+ // When udfpsLocationChanges in authcontroller
+ authControllerCallback.value.onUdfpsLocationChanged(firstParams)
+
+ // Then the value in the interactor should be updated
+ assertThat(udfpsOverlayParams()).isEqualTo(firstParams)
+ }
+
+ private fun createUdpfsOverlayInteractor() {
+ underTest = UdfpsOverlayInteractor(authController, testScope.backgroundScope)
+ testScope.runCurrent()
+ }
+}
+
+private val firstParams =
+ UdfpsOverlayParams(Rect(0, 0, 10, 10), Rect(0, 0, 10, 10), 1, 1, 1f, Surface.ROTATION_0)
+private val downEv = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
index fe9098fa5c25..fc3a6383cd88 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
@@ -967,6 +967,92 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
coroutineContext.cancelChildren()
}
+ @Test
+ fun `OCCLUDED to GONE`() =
+ testScope.runTest {
+ // GIVEN a device on lockscreen
+ keyguardRepository.setKeyguardShowing(true)
+ runCurrent()
+
+ // GIVEN a prior transition has run to OCCLUDED
+ runner.startTransition(
+ testScope,
+ TransitionInfo(
+ ownerName = "",
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.OCCLUDED,
+ animator =
+ ValueAnimator().apply {
+ duration = 10
+ interpolator = Interpolators.LINEAR
+ },
+ )
+ )
+ keyguardRepository.setKeyguardOccluded(true)
+ runCurrent()
+ reset(mockTransitionRepository)
+
+ // WHEN keyguard goes away
+ keyguardRepository.setKeyguardShowing(false)
+ // AND occlusion ends
+ keyguardRepository.setKeyguardOccluded(false)
+ runCurrent()
+
+ val info =
+ withArgCaptor<TransitionInfo> {
+ verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ }
+ // THEN a transition to GONE should occur
+ assertThat(info.ownerName).isEqualTo("FromOccludedTransitionInteractor")
+ assertThat(info.from).isEqualTo(KeyguardState.OCCLUDED)
+ assertThat(info.to).isEqualTo(KeyguardState.GONE)
+ assertThat(info.animator).isNotNull()
+
+ coroutineContext.cancelChildren()
+ }
+
+ @Test
+ fun `OCCLUDED to LOCKSCREEN`() =
+ testScope.runTest {
+ // GIVEN a device on lockscreen
+ keyguardRepository.setKeyguardShowing(true)
+ runCurrent()
+
+ // GIVEN a prior transition has run to OCCLUDED
+ runner.startTransition(
+ testScope,
+ TransitionInfo(
+ ownerName = "",
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.OCCLUDED,
+ animator =
+ ValueAnimator().apply {
+ duration = 10
+ interpolator = Interpolators.LINEAR
+ },
+ )
+ )
+ keyguardRepository.setKeyguardOccluded(true)
+ runCurrent()
+ reset(mockTransitionRepository)
+
+ // WHEN occlusion ends
+ keyguardRepository.setKeyguardOccluded(false)
+ runCurrent()
+
+ val info =
+ withArgCaptor<TransitionInfo> {
+ verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ }
+ // THEN a transition to LOCKSCREEN should occur
+ assertThat(info.ownerName).isEqualTo("FromOccludedTransitionInteractor")
+ assertThat(info.from).isEqualTo(KeyguardState.OCCLUDED)
+ assertThat(info.to).isEqualTo(KeyguardState.LOCKSCREEN)
+ assertThat(info.animator).isNotNull()
+
+ coroutineContext.cancelChildren()
+ }
+
private fun startingToWake() =
WakefulnessModel(
WakefulnessState.STARTING_TO_WAKE,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt
index 2a91799741b7..746f66881a88 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt
@@ -21,7 +21,9 @@ import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.ScrimAlpha
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.statusbar.SysuiStatusBarStateController
@@ -44,21 +46,86 @@ class PrimaryBouncerToGoneTransitionViewModelTest : SysuiTestCase() {
private lateinit var underTest: PrimaryBouncerToGoneTransitionViewModel
private lateinit var repository: FakeKeyguardTransitionRepository
@Mock private lateinit var statusBarStateController: SysuiStatusBarStateController
+ @Mock private lateinit var primaryBouncerInteractor: PrimaryBouncerInteractor
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
repository = FakeKeyguardTransitionRepository()
val interactor = KeyguardTransitionInteractor(repository)
- underTest = PrimaryBouncerToGoneTransitionViewModel(interactor, statusBarStateController)
+ underTest =
+ PrimaryBouncerToGoneTransitionViewModel(
+ interactor,
+ statusBarStateController,
+ primaryBouncerInteractor
+ )
+
+ whenever(primaryBouncerInteractor.willRunDismissFromKeyguard()).thenReturn(false)
+ whenever(statusBarStateController.leaveOpenOnKeyguardHide()).thenReturn(false)
}
@Test
- fun scrimBehindAlpha_leaveShadeOpen() =
+ fun bouncerAlpha() =
runTest(UnconfinedTestDispatcher()) {
val values = mutableListOf<Float>()
- val job = underTest.scrimBehindAlpha.onEach { values.add(it) }.launchIn(this)
+ val job = underTest.bouncerAlpha.onEach { values.add(it) }.launchIn(this)
+
+ repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+ repository.sendTransitionStep(step(0.3f))
+ repository.sendTransitionStep(step(0.6f))
+
+ assertThat(values.size).isEqualTo(3)
+ values.forEach { assertThat(it).isIn(Range.closed(0f, 1f)) }
+
+ job.cancel()
+ }
+
+ @Test
+ fun bouncerAlpha_runDimissFromKeyguard() =
+ runTest(UnconfinedTestDispatcher()) {
+ val values = mutableListOf<Float>()
+
+ val job = underTest.bouncerAlpha.onEach { values.add(it) }.launchIn(this)
+
+ whenever(primaryBouncerInteractor.willRunDismissFromKeyguard()).thenReturn(true)
+
+ repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+ repository.sendTransitionStep(step(0.3f))
+ repository.sendTransitionStep(step(0.6f))
+
+ assertThat(values.size).isEqualTo(3)
+ values.forEach { assertThat(it).isEqualTo(0f) }
+
+ job.cancel()
+ }
+
+ @Test
+ fun scrimAlpha_runDimissFromKeyguard() =
+ runTest(UnconfinedTestDispatcher()) {
+ val values = mutableListOf<ScrimAlpha>()
+
+ val job = underTest.scrimAlpha.onEach { values.add(it) }.launchIn(this)
+
+ whenever(primaryBouncerInteractor.willRunDismissFromKeyguard()).thenReturn(true)
+
+ repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+ repository.sendTransitionStep(step(0.3f))
+ repository.sendTransitionStep(step(0.6f))
+ repository.sendTransitionStep(step(1f))
+
+ assertThat(values.size).isEqualTo(4)
+ values.forEach { assertThat(it).isEqualTo(ScrimAlpha(notificationsAlpha = 1f)) }
+
+ job.cancel()
+ }
+
+ @Test
+ fun scrimBehindAlpha_leaveShadeOpen() =
+ runTest(UnconfinedTestDispatcher()) {
+ val values = mutableListOf<ScrimAlpha>()
+
+ val job = underTest.scrimAlpha.onEach { values.add(it) }.launchIn(this)
whenever(statusBarStateController.leaveOpenOnKeyguardHide()).thenReturn(true)
@@ -68,7 +135,9 @@ class PrimaryBouncerToGoneTransitionViewModelTest : SysuiTestCase() {
repository.sendTransitionStep(step(1f))
assertThat(values.size).isEqualTo(4)
- values.forEach { assertThat(it).isEqualTo(1f) }
+ values.forEach {
+ assertThat(it).isEqualTo(ScrimAlpha(notificationsAlpha = 1f, behindAlpha = 1f))
+ }
job.cancel()
}
@@ -76,9 +145,9 @@ class PrimaryBouncerToGoneTransitionViewModelTest : SysuiTestCase() {
@Test
fun scrimBehindAlpha_doNotLeaveShadeOpen() =
runTest(UnconfinedTestDispatcher()) {
- val values = mutableListOf<Float>()
+ val values = mutableListOf<ScrimAlpha>()
- val job = underTest.scrimBehindAlpha.onEach { values.add(it) }.launchIn(this)
+ val job = underTest.scrimAlpha.onEach { values.add(it) }.launchIn(this)
whenever(statusBarStateController.leaveOpenOnKeyguardHide()).thenReturn(false)
@@ -88,8 +157,10 @@ class PrimaryBouncerToGoneTransitionViewModelTest : SysuiTestCase() {
repository.sendTransitionStep(step(1f))
assertThat(values.size).isEqualTo(4)
- values.forEach { assertThat(it).isIn(Range.closed(0f, 1f)) }
- assertThat(values[3]).isEqualTo(0f)
+ values.forEach { assertThat(it.notificationsAlpha).isEqualTo(0f) }
+ values.forEach { assertThat(it.frontAlpha).isEqualTo(0f) }
+ values.forEach { assertThat(it.behindAlpha).isIn(Range.closed(0f, 1f)) }
+ assertThat(values[3].behindAlpha).isEqualTo(0f)
job.cancel()
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
index 82a57438052f..51492eb8e532 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
@@ -26,6 +26,7 @@ import com.android.keyguard.LockIconViewController
import com.android.keyguard.dagger.KeyguardBouncerComponent
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor
import com.android.systemui.classifier.FalsingCollectorFake
import com.android.systemui.dock.DockManager
import com.android.systemui.keyguard.KeyguardUnlockAnimationController
@@ -86,6 +87,7 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
@Mock private lateinit var pulsingGestureListener: PulsingGestureListener
@Mock private lateinit var notificationInsetsController: NotificationInsetsController
@Mock private lateinit var alternateBouncerInteractor: AlternateBouncerInteractor
+ @Mock private lateinit var udfpsOverlayInteractor: UdfpsOverlayInteractor
@Mock lateinit var keyguardBouncerComponentFactory: KeyguardBouncerComponent.Factory
@Mock lateinit var keyguardBouncerComponent: KeyguardBouncerComponent
@Mock lateinit var keyguardSecurityContainerController: KeyguardSecurityContainerController
@@ -133,6 +135,7 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
keyguardBouncerViewModel,
keyguardBouncerComponentFactory,
alternateBouncerInteractor,
+ udfpsOverlayInteractor,
keyguardTransitionInteractor,
primaryBouncerToGoneTransitionViewModel,
)
@@ -265,6 +268,17 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
}
@Test
+ fun shouldInterceptTouchEvent_downEventAlternateBouncer_ignoreIfInUdfpsOverlay() {
+ // Down event within udfpsOverlay bounds while alternateBouncer is showing
+ whenever(udfpsOverlayInteractor.canInterceptTouchInUdfpsBounds(downEv)).thenReturn(false)
+ whenever(alternateBouncerInteractor.isVisibleState()).thenReturn(true)
+
+ // Then touch should not be intercepted
+ val shouldIntercept = interactionEventHandler.shouldInterceptTouchEvent(downEv)
+ assertThat(shouldIntercept).isFalse()
+ }
+
+ @Test
fun testGetBouncerContainer() {
Mockito.clearInvocations(view)
underTest.bouncerContainer
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.java
index faa6221b675c..2f528a86cc2d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.java
@@ -40,6 +40,7 @@ import com.android.keyguard.LockIconViewController;
import com.android.keyguard.dagger.KeyguardBouncerComponent;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor;
import com.android.systemui.classifier.FalsingCollectorFake;
import com.android.systemui.dock.DockManager;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
@@ -101,6 +102,7 @@ public class NotificationShadeWindowViewTest extends SysuiTestCase {
@Mock private KeyguardSecurityContainerController mKeyguardSecurityContainerController;
@Mock private NotificationInsetsController mNotificationInsetsController;
@Mock private AlternateBouncerInteractor mAlternateBouncerInteractor;
+ @Mock private UdfpsOverlayInteractor mUdfpsOverlayInteractor;
@Mock private KeyguardTransitionInteractor mKeyguardTransitionInteractor;
@Mock private PrimaryBouncerToGoneTransitionViewModel mPrimaryBouncerToGoneTransitionViewModel;
@@ -152,6 +154,7 @@ public class NotificationShadeWindowViewTest extends SysuiTestCase {
mKeyguardBouncerViewModel,
mKeyguardBouncerComponentFactory,
mAlternateBouncerInteractor,
+ mUdfpsOverlayInteractor,
mKeyguardTransitionInteractor,
mPrimaryBouncerToGoneTransitionViewModel
);
@@ -177,6 +180,7 @@ public class NotificationShadeWindowViewTest extends SysuiTestCase {
// WHEN showing alt auth, not dozing, drag down helper doesn't want to intercept
when(mStatusBarStateController.isDozing()).thenReturn(false);
when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true);
+ when(mUdfpsOverlayInteractor.canInterceptTouchInUdfpsBounds(any())).thenReturn(true);
when(mDragDownHelper.onInterceptTouchEvent(any())).thenReturn(false);
// THEN we should intercept touch
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index d487ba93859a..7a1270f3521d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -71,7 +71,6 @@ import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransition
import com.android.systemui.scrim.ScrimView;
import com.android.systemui.shade.transition.LargeScreenShadeInterpolator;
import com.android.systemui.shade.transition.LinearLargeScreenShadeInterpolator;
-import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.policy.FakeConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.concurrency.FakeExecutor;
@@ -134,7 +133,6 @@ public class ScrimControllerTest extends SysuiTestCase {
@Mock private PrimaryBouncerToGoneTransitionViewModel mPrimaryBouncerToGoneTransitionViewModel;
@Mock private KeyguardTransitionInteractor mKeyguardTransitionInteractor;
@Mock private CoroutineDispatcher mMainDispatcher;
- @Mock private SysuiStatusBarStateController mSysuiStatusBarStateController;
// TODO(b/204991468): Use a real PanelExpansionStateManager object once this bug is fixed. (The
// event-dispatch-on-registration pattern caused some of these unit tests to fail.)
@@ -249,7 +247,7 @@ public class ScrimControllerTest extends SysuiTestCase {
when(mKeyguardTransitionInteractor.getPrimaryBouncerToGoneTransition())
.thenReturn(emptyFlow());
- when(mPrimaryBouncerToGoneTransitionViewModel.getScrimBehindAlpha())
+ when(mPrimaryBouncerToGoneTransitionViewModel.getScrimAlpha())
.thenReturn(emptyFlow());
mScrimController = new ScrimController(
@@ -268,7 +266,6 @@ public class ScrimControllerTest extends SysuiTestCase {
mStatusBarKeyguardViewManager,
mPrimaryBouncerToGoneTransitionViewModel,
mKeyguardTransitionInteractor,
- mSysuiStatusBarStateController,
mMainDispatcher,
mLinearLargeScreenShadeInterpolator,
mFeatureFlags);
@@ -984,7 +981,6 @@ public class ScrimControllerTest extends SysuiTestCase {
mStatusBarKeyguardViewManager,
mPrimaryBouncerToGoneTransitionViewModel,
mKeyguardTransitionInteractor,
- mSysuiStatusBarStateController,
mMainDispatcher,
mLinearLargeScreenShadeInterpolator,
mFeatureFlags);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index 158e9adcff43..e2019b2814d9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -683,4 +683,30 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
// the following call before registering centralSurfaces should NOT throw a NPE:
mStatusBarKeyguardViewManager.hideAlternateBouncer(true);
}
+
+ @Test
+ public void testResetHideBouncerWhenShowing_alternateBouncerHides() {
+ // GIVEN the keyguard is showing
+ reset(mAlternateBouncerInteractor);
+ when(mKeyguardStateController.isShowing()).thenReturn(true);
+
+ // WHEN SBKV is reset with hideBouncerWhenShowing=true
+ mStatusBarKeyguardViewManager.reset(true);
+
+ // THEN alternate bouncer is hidden
+ verify(mAlternateBouncerInteractor).hide();
+ }
+
+ @Test
+ public void testResetHideBouncerWhenShowingIsFalse_alternateBouncerHides() {
+ // GIVEN the keyguard is showing
+ reset(mAlternateBouncerInteractor);
+ when(mKeyguardStateController.isShowing()).thenReturn(true);
+
+ // WHEN SBKV is reset with hideBouncerWhenShowing=false
+ mStatusBarKeyguardViewManager.reset(false);
+
+ // THEN alternate bouncer is NOT hidden
+ verify(mAlternateBouncerInteractor, never()).hide();
+ }
}
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index b54dbbf14ce2..7f6ad431c601 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -742,6 +742,9 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
return Collections.EMPTY_LIST;
}
final String typeHints = mService.getMaster().getPccProviderHints();
+ if (sVerbose) {
+ Slog.v(TAG, "TypeHints flag:" + typeHints);
+ }
if (TextUtils.isEmpty(typeHints)) {
return new ArrayList<>();
}
@@ -757,7 +760,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
@GuardedBy("mLock")
void maybeRequestFieldClassificationFromServiceLocked() {
if (mClassificationState.mPendingFieldClassificationRequest == null) {
- Log.w(TAG, "Received AssistData without pending classification request");
+ Slog.w(TAG, "Received AssistData without pending classification request");
return;
}
@@ -791,7 +794,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
final int requestId = receiverExtras.getInt(EXTRA_REQUEST_ID);
if (sVerbose) {
- Slog.v(TAG, "New structure for requestId " + requestId + ": " + structure);
+ Slog.v(TAG, "New structure for PCC Detection: requestId " + requestId + ": "
+ + structure);
}
synchronized (mLock) {
@@ -1125,6 +1129,13 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
// structure is taken. This causes only one fill request per burst of focus changes.
cancelCurrentRequestLocked();
+ if (mClassificationState.mHintsToAutofillIdMap == null) {
+ if (sVerbose) {
+ Slog.v(TAG, "triggering field classification");
+ }
+ requestAssistStructureForPccLocked(flags | FLAG_PCC_DETECTION);
+ }
+
// Only ask IME to create inline suggestions request when
// 1. Autofill provider supports it or client enabled client suggestions.
// 2. The render service is available.
@@ -1376,7 +1387,6 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
@Override
public void onFillRequestSuccess(int requestId, @Nullable FillResponse response,
@NonNull String servicePackageName, int requestFlags) {
-
final AutofillId[] fieldClassificationIds;
final LogMaker requestLog;
@@ -1609,10 +1619,68 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
Set<Dataset> eligibleDatasets = new ArraySet<>();
Set<AutofillId> eligibleAutofillIds = new ArraySet<>();
for (Dataset dataset : response.getDatasets()) {
- if (dataset.getFieldIds() == null) continue;
+ if (dataset.getFieldIds() == null || dataset.getFieldIds().isEmpty()) continue;
if (dataset.getAutofillDatatypes() != null
- && dataset.getAutofillDatatypes().size() > 0) {
- continue;
+ && !dataset.getAutofillDatatypes().isEmpty()) {
+ // This dataset has information relevant for detection too, so we should filter
+ // them out. It's possible that some fields are applicable to hints only, as such,
+ // they need to be filtered off.
+ // TODO(b/266379948): Verify the logic and add tests
+ // Update dataset to only have non-null fieldValues
+
+ // Figure out if we need to process results.
+ boolean conversionRequired = false;
+ int newSize = dataset.getFieldIds().size();
+ for (AutofillId id : dataset.getFieldIds()) {
+ if (id == null) {
+ conversionRequired = true;
+ newSize--;
+ }
+ }
+
+ if (conversionRequired) {
+ ArrayList<AutofillId> fieldIds = new ArrayList<>(newSize);
+ ArrayList<AutofillValue> fieldValues = new ArrayList<>(newSize);
+ ArrayList<RemoteViews> fieldPresentations = new ArrayList<>(newSize);
+ ArrayList<RemoteViews> fieldDialogPresentations = new ArrayList<>(newSize);
+ ArrayList<InlinePresentation> fieldInlinePresentations =
+ new ArrayList<>(newSize);
+ ArrayList<InlinePresentation> fieldInlineTooltipPresentations =
+ new ArrayList<>(newSize);
+ ArrayList<Dataset.DatasetFieldFilter> fieldFilters = new ArrayList<>(newSize);
+
+ for (int i = 0; i < dataset.getFieldIds().size(); i++) {
+ AutofillId id = dataset.getFieldIds().get(i);
+ if (id != null) {
+ // Copy over
+ fieldIds.add(id);
+ fieldValues.add(dataset.getFieldValues().get(i));
+ fieldPresentations.add(dataset.getFieldPresentation(i));
+ fieldDialogPresentations.add(dataset.getFieldDialogPresentation(i));
+ fieldInlinePresentations.add(dataset.getFieldInlinePresentation(i));
+ fieldInlineTooltipPresentations.add(
+ dataset.getFieldInlineTooltipPresentation(i));
+ fieldFilters.add(dataset.getFilter(i));
+ }
+ }
+ dataset =
+ new Dataset(
+ fieldIds,
+ fieldValues,
+ fieldPresentations,
+ fieldDialogPresentations,
+ fieldInlinePresentations,
+ fieldInlineTooltipPresentations,
+ fieldFilters,
+ new ArrayList<>(),
+ dataset.getFieldContent(),
+ null,
+ null,
+ null,
+ null,
+ dataset.getId(),
+ dataset.getAuthentication());
+ }
}
eligibleDatasets.add(dataset);
for (AutofillId id : dataset.getFieldIds()) {
@@ -1639,6 +1707,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
ArrayMap<String, Set<AutofillId>> hintsToAutofillIdMap =
mClassificationState.mHintsToAutofillIdMap;
+ // TODO(266379948): Handle group hints too.
ArrayMap<String, Set<AutofillId>> groupHintsToAutofillIdMap =
mClassificationState.mGroupHintsToAutofillIdMap;
@@ -1649,7 +1718,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
for (int i = 0; i < datasets.size(); i++) {
Dataset dataset = datasets.get(i);
- if (dataset.getAutofillDatatypes() == null) continue;
+ if (dataset.getAutofillDatatypes() == null
+ || dataset.getAutofillDatatypes().isEmpty()) continue;
if (dataset.getFieldIds() != null && dataset.getFieldIds().size() > 0) continue;
ArrayList<AutofillId> fieldIds = new ArrayList<>();
@@ -1661,6 +1731,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
ArrayList<Dataset.DatasetFieldFilter> fieldFilters = new ArrayList<>();
for (int j = 0; j < dataset.getAutofillDatatypes().size(); j++) {
+ if (dataset.getAutofillDatatypes().get(0) == null) continue;
String hint = dataset.getAutofillDatatypes().get(j);
if (hintsToAutofillIdMap.containsKey(hint)) {
@@ -4560,7 +4631,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
if (mResponses == null) {
// Set initial capacity as 2 to handle cases where service always requires auth.
// TODO: add a metric for number of responses set by server, so we can use its average
- // as the initial array capacitiy.
+ // as the initial array capacity.
mResponses = new SparseArray<>(2);
}
mResponses.put(requestId, newResponse);
@@ -4982,6 +5053,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
mClassificationGroupHintsMap = new ArrayMap<>();
mHintsToAutofillIdMap = new ArrayMap<>();
mGroupHintsToAutofillIdMap = new ArrayMap<>();
+ mClassificationCombinedHintsMap = new ArrayMap<>();
Set<android.service.assist.classification.FieldClassification> classifications =
response.getClassifications();
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index c3aea6241f7a..10450f032ffb 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -9866,7 +9866,6 @@ public class ActivityManagerService extends IActivityManager.Stub
boolean dumpNormalPriority = false;
boolean dumpVisibleStacksOnly = false;
boolean dumpFocusedStackOnly = false;
- boolean dumpVerbose = false;
int dumpDisplayId = INVALID_DISPLAY;
String dumpPackage = null;
int dumpUserId = UserHandle.USER_ALL;
@@ -9925,8 +9924,6 @@ public class ActivityManagerService extends IActivityManager.Stub
return;
}
dumpClient = true;
- } else if ("--verbose".equals(opt)) {
- dumpVerbose = true;
} else if ("-h".equals(opt)) {
ActivityManagerShellCommand.dumpHelp(pw, true);
return;
@@ -10213,8 +10210,7 @@ public class ActivityManagerService extends IActivityManager.Stub
} else {
// Dumping a single activity?
if (!mAtmInternal.dumpActivity(fd, pw, cmd, args, opti, dumpAll,
- dumpVisibleStacksOnly, dumpFocusedStackOnly, dumpVerbose, dumpDisplayId,
- dumpUserId)) {
+ dumpVisibleStacksOnly, dumpFocusedStackOnly, dumpDisplayId, dumpUserId)) {
ActivityManagerShellCommand shell = new ActivityManagerShellCommand(this, true);
int res = shell.exec(this, null, fd, null, args, null,
new ResultReceiver(null));
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 01bb549630b8..809f3f7ff857 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -3957,7 +3957,6 @@ final class ActivityManagerShellCommand extends ShellCommand {
pw.println(" --checkin: output checkin format, resetting data.");
pw.println(" --C: output checkin format, not resetting data.");
pw.println(" --proto: output dump in protocol buffer format.");
- pw.println(" --verbose: dumps extra information.");
pw.printf(" %s: dump just the DUMPABLE-related state of an activity. Use the %s "
+ "option to list the supported DUMPABLEs\n", Activity.DUMP_ARG_DUMP_DUMPABLE,
Activity.DUMP_ARG_LIST_DUMPABLES);
diff --git a/services/core/java/com/android/server/am/CoreSettingsObserver.java b/services/core/java/com/android/server/am/CoreSettingsObserver.java
index 2e3e635c1157..ddc9e9166faa 100644
--- a/services/core/java/com/android/server/am/CoreSettingsObserver.java
+++ b/services/core/java/com/android/server/am/CoreSettingsObserver.java
@@ -96,6 +96,10 @@ final class CoreSettingsObserver extends ContentObserver {
sGlobalSettingToTypeMap.put(
Settings.Global.ANGLE_EGL_FEATURES, String.class);
sGlobalSettingToTypeMap.put(
+ Settings.Global.ANGLE_DEFERLIST, String.class);
+ sGlobalSettingToTypeMap.put(
+ Settings.Global.ANGLE_DEFERLIST_MODE, String.class);
+ sGlobalSettingToTypeMap.put(
Settings.Global.SHOW_ANGLE_IN_USE_DIALOG_BOX, String.class);
sGlobalSettingToTypeMap.put(Settings.Global.ENABLE_GPU_DEBUG_LAYERS, int.class);
sGlobalSettingToTypeMap.put(Settings.Global.GPU_DEBUG_APP, String.class);
diff --git a/services/core/java/com/android/server/appop/AppOpsCheckingServiceTracingDecorator.java b/services/core/java/com/android/server/appop/AppOpsCheckingServiceTracingDecorator.java
index dd06464c4699..a028ae16da2f 100644
--- a/services/core/java/com/android/server/appop/AppOpsCheckingServiceTracingDecorator.java
+++ b/services/core/java/com/android/server/appop/AppOpsCheckingServiceTracingDecorator.java
@@ -32,7 +32,7 @@ import java.io.PrintWriter;
* Trace.traceEnd. These traces are used for performance testing.
*/
public class AppOpsCheckingServiceTracingDecorator implements AppOpsCheckingServiceInterface {
- private static final long TRACE_TAG = Trace.TRACE_TAG_SYSTEM_SERVER;
+ private static final long TRACE_TAG = Trace.TRACE_TAG_ACTIVITY_MANAGER;
private final AppOpsCheckingServiceInterface mService;
AppOpsCheckingServiceTracingDecorator(
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubService.java b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
index 94f12dd7ff01..653b71828c5b 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubService.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
@@ -1148,7 +1148,7 @@ public class ContextHubService extends IContextHubService.Stub {
super.getPreloadedNanoAppIds_enforcePermission();
Objects.requireNonNull(hubInfo, "hubInfo cannot be null");
- long[] nanoappIds = mContextHubWrapper.getPreloadedNanoappIds();
+ long[] nanoappIds = mContextHubWrapper.getPreloadedNanoappIds(hubInfo.getId());
if (nanoappIds == null) {
return new long[0];
}
@@ -1261,13 +1261,19 @@ public class ContextHubService extends IContextHubService.Stub {
return;
}
- long[] preloadedNanoappIds = mContextHubWrapper.getPreloadedNanoappIds();
- if (preloadedNanoappIds == null) {
- return;
- }
- for (long preloadedNanoappId : preloadedNanoappIds) {
- pw.print("ID: 0x");
- pw.println(Long.toHexString(preloadedNanoappId));
+ for (int contextHubId: mContextHubIdToInfoMap.keySet()) {
+ long[] preloadedNanoappIds = mContextHubWrapper.getPreloadedNanoappIds(contextHubId);
+ if (preloadedNanoappIds == null) {
+ return;
+ }
+
+ pw.print("Context Hub (id=");
+ pw.print(contextHubId);
+ pw.println("):");
+ for (long preloadedNanoappId : preloadedNanoappIds) {
+ pw.print(" ID: 0x");
+ pw.println(Long.toHexString(preloadedNanoappId));
+ }
}
}
diff --git a/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java b/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
index 1e32ad613eba..eb1a0e27090f 100644
--- a/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
+++ b/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
@@ -363,9 +363,11 @@ public abstract class IContextHubWrapper {
* Provides the list of preloaded nanoapp IDs on the system. The output of this API must
* not change.
*
- * @return The list of preloaded nanoapp IDs
+ * @param contextHubId The context Hub ID.
+ *
+ * @return The list of preloaded nanoapp IDs.
*/
- public abstract long[] getPreloadedNanoappIds();
+ public abstract long[] getPreloadedNanoappIds(int contextHubId);
/**
* Registers a callback with the Context Hub.
@@ -714,14 +716,14 @@ public abstract class IContextHubWrapper {
}
}
- public long[] getPreloadedNanoappIds() {
+ public long[] getPreloadedNanoappIds(int contextHubId) {
android.hardware.contexthub.IContextHub hub = getHub();
if (hub == null) {
return null;
}
try {
- return hub.getPreloadedNanoappIds();
+ return hub.getPreloadedNanoappIds(contextHubId);
} catch (RemoteException e) {
Log.e(TAG, "Exception while getting preloaded nanoapp IDs: " + e.getMessage());
return null;
@@ -924,7 +926,7 @@ public abstract class IContextHubWrapper {
mHub.queryApps(contextHubId));
}
- public long[] getPreloadedNanoappIds() {
+ public long[] getPreloadedNanoappIds(int contextHubId) {
return new long[0];
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 6a962625049f..4ec8afde62e8 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -1247,6 +1247,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {
case LONG_PRESS_POWER_SHUT_OFF:
case LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM:
mPowerKeyHandled = true;
+ // don't actually trigger the shutdown if we are running stability
+ // tests via monkey
+ if (ActivityManager.isUserAMonkey()) {
+ break;
+ }
performHapticFeedback(HapticFeedbackConstants.LONG_PRESS_POWER_BUTTON, false,
"Power - Long Press - Shut Off");
sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
diff --git a/services/core/java/com/android/server/policy/PowerAction.java b/services/core/java/com/android/server/policy/PowerAction.java
index d2de58e96551..deb86b575529 100644
--- a/services/core/java/com/android/server/policy/PowerAction.java
+++ b/services/core/java/com/android/server/policy/PowerAction.java
@@ -15,6 +15,7 @@
*/
package com.android.server.policy;
+import android.app.ActivityManager;
import android.content.Context;
import android.os.UserManager;
import com.android.internal.globalactions.LongPressAction;
@@ -35,6 +36,11 @@ public final class PowerAction extends SinglePressAction implements LongPressAct
@Override
public boolean onLongPress() {
+ // don't actually trigger the reboot if we are running stability
+ // tests via monkey
+ if (ActivityManager.isUserAMonkey()) {
+ return false;
+ }
UserManager um = mContext.getSystemService(UserManager.class);
if (!um.hasUserRestriction(UserManager.DISALLOW_SAFE_BOOT)) {
mWindowManagerFuncs.rebootSafeMode(true);
@@ -55,6 +61,11 @@ public final class PowerAction extends SinglePressAction implements LongPressAct
@Override
public void onPress() {
+ // don't actually trigger the shutdown if we are running stability
+ // tests via monkey
+ if (ActivityManager.isUserAMonkey()) {
+ return;
+ }
// shutdown by making sure radio and power are handled accordingly.
mWindowManagerFuncs.shutdown(false /* confirm */);
}
diff --git a/services/core/java/com/android/server/policy/RestartAction.java b/services/core/java/com/android/server/policy/RestartAction.java
index 0f13da82dad3..24c921e4d111 100644
--- a/services/core/java/com/android/server/policy/RestartAction.java
+++ b/services/core/java/com/android/server/policy/RestartAction.java
@@ -15,6 +15,7 @@
*/
package com.android.server.policy;
+import android.app.ActivityManager;
import android.content.Context;
import android.os.UserManager;
import com.android.internal.globalactions.LongPressAction;
@@ -35,6 +36,11 @@ public final class RestartAction extends SinglePressAction implements LongPressA
@Override
public boolean onLongPress() {
+ // don't actually trigger the reboot if we are running stability
+ // tests via monkey
+ if (ActivityManager.isUserAMonkey()) {
+ return false;
+ }
UserManager um = mContext.getSystemService(UserManager.class);
if (!um.hasUserRestriction(UserManager.DISALLOW_SAFE_BOOT)) {
mWindowManagerFuncs.rebootSafeMode(true);
@@ -55,6 +61,11 @@ public final class RestartAction extends SinglePressAction implements LongPressA
@Override
public void onPress() {
+ // don't actually trigger the reboot if we are running stability
+ // tests via monkey
+ if (ActivityManager.isUserAMonkey()) {
+ return;
+ }
mWindowManagerFuncs.reboot(false /* confirm */);
}
}
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index c6684dfdb6e0..11294b7c46fc 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -2590,7 +2590,7 @@ public final class TvInputManagerService extends SystemService {
}
@Override
- public void notifyAdBuffer(
+ public void notifyAdBufferReady(
IBinder sessionToken, AdBuffer buffer, int userId) {
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
@@ -2602,7 +2602,7 @@ public final class TvInputManagerService extends SystemService {
try {
SessionState sessionState = getSessionStateLocked(sessionToken, callingUid,
resolvedUserId);
- getSessionLocked(sessionState).notifyAdBuffer(buffer);
+ getSessionLocked(sessionState).notifyAdBufferReady(buffer);
} catch (RemoteException | SessionNotFoundException e) {
Slog.e(TAG, "error in notifyAdBuffer", e);
}
diff --git a/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java b/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java
index 61c137ed1c5b..bef349f177aa 100644
--- a/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java
+++ b/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java
@@ -3047,16 +3047,16 @@ public class TvInteractiveAppManagerService extends SystemService {
}
@Override
- public void onAdBuffer(AdBuffer buffer) {
+ public void onAdBufferReady(AdBuffer buffer) {
synchronized (mLock) {
if (DEBUG) {
- Slogf.d(TAG, "onAdBuffer(buffer=" + buffer + ")");
+ Slogf.d(TAG, "onAdBufferReady(buffer=" + buffer + ")");
}
if (mSessionState.mSession == null || mSessionState.mClient == null) {
return;
}
try {
- mSessionState.mClient.onAdBuffer(buffer, mSessionState.mSeq);
+ mSessionState.mClient.onAdBufferReady(buffer, mSessionState.mSeq);
} catch (RemoteException e) {
Slogf.e(TAG, "error in onAdBuffer", e);
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 28b974c7330a..424c3271cde6 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -1734,7 +1734,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
: null;
}
- private void clearLastParentBeforePip() {
+ void clearLastParentBeforePip() {
if (mLastParentBeforePip != null) {
mLastParentBeforePip.mChildPipActivity = null;
mLastParentBeforePip = null;
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 5ea28542207e..bfb735de2d0a 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -490,8 +490,7 @@ public abstract class ActivityTaskManagerInternal {
/** Dump the current activities state. */
public abstract boolean dumpActivity(FileDescriptor fd, PrintWriter pw, String name,
String[] args, int opti, boolean dumpAll, boolean dumpVisibleRootTasksOnly,
- boolean dumpFocusedRootTaskOnly, boolean dumpVerbose, int displayIdFilter,
- @UserIdInt int userId);
+ boolean dumpFocusedRootTaskOnly, int displayIdFilter, @UserIdInt int userId);
/** Dump the current state for inclusion in oom dump. */
public abstract void dumpForOom(PrintWriter pw);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 6681a32611f1..992743ab8593 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -1496,7 +1496,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
a.persistableMode = ActivityInfo.PERSIST_NEVER;
a.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
a.colorMode = ActivityInfo.COLOR_MODE_DEFAULT;
- a.flags |= ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS | ActivityInfo.FLAG_NO_HISTORY;
+ a.flags |= ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
a.resizeMode = RESIZE_MODE_UNRESIZEABLE;
a.configChanges = 0xffffffff;
@@ -4205,8 +4205,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
*/
protected boolean dumpActivity(FileDescriptor fd, PrintWriter pw, String name, String[] args,
int opti, boolean dumpAll, boolean dumpVisibleRootTasksOnly,
- boolean dumpFocusedRootTaskOnly, boolean dumpVerbose, int displayIdFilter,
- @UserIdInt int userId) {
+ boolean dumpFocusedRootTaskOnly, int displayIdFilter, @UserIdInt int userId) {
ArrayList<ActivityRecord> activities;
synchronized (mGlobalLock) {
@@ -4251,7 +4250,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
}
}
- dumpActivity(" ", fd, pw, activities.get(i), newArgs, dumpAll, dumpVerbose);
+ dumpActivity(" ", fd, pw, activities.get(i), newArgs, dumpAll);
}
if (!printedAnything) {
// Typically happpens when no task matches displayIdFilter
@@ -4265,7 +4264,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
* there is a thread associated with the activity.
*/
private void dumpActivity(String prefix, FileDescriptor fd, PrintWriter pw,
- ActivityRecord r, String[] args, boolean dumpAll, boolean dumpVerbose) {
+ ActivityRecord r, String[] args, boolean dumpAll) {
String innerPrefix = prefix + " ";
IApplicationThread appThread = null;
synchronized (mGlobalLock) {
@@ -4281,15 +4280,11 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
} else {
pw.print("(not running)");
}
- if (dumpVerbose) {
- pw.print(" userId=");
- pw.print(r.mUserId);
- pw.print(" uid=");
- pw.print(r.getUid());
- printDisplayInfoAndNewLine(pw, r);
- } else {
- pw.println();
- }
+ pw.print(" userId=");
+ pw.print(r.mUserId);
+ pw.print(" uid=");
+ pw.print(r.getUid());
+ printDisplayInfoAndNewLine(pw, r);
if (dumpAll) {
r.dump(pw, innerPrefix, /* dumpAll= */ true);
}
@@ -6618,11 +6613,10 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
@Override
public boolean dumpActivity(FileDescriptor fd, PrintWriter pw, String name,
String[] args, int opti, boolean dumpAll, boolean dumpVisibleRootTasksOnly,
- boolean dumpFocusedRootTaskOnly, boolean dumpVerbose, int displayIdFilter,
+ boolean dumpFocusedRootTaskOnly, int displayIdFilter,
@UserIdInt int userId) {
return ActivityTaskManagerService.this.dumpActivity(fd, pw, name, args, opti, dumpAll,
- dumpVisibleRootTasksOnly, dumpFocusedRootTaskOnly, dumpVerbose, displayIdFilter,
- userId);
+ dumpVisibleRootTasksOnly, dumpFocusedRootTaskOnly, displayIdFilter, userId);
}
@Override
diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java
index 7208934efd51..f355f088b608 100644
--- a/services/core/java/com/android/server/wm/LetterboxUiController.java
+++ b/services/core/java/com/android/server/wm/LetterboxUiController.java
@@ -1395,9 +1395,9 @@ final class LetterboxUiController {
FIRST_OPAQUE_NOT_FINISHING_ACTIVITY_PREDICATE /* callback */,
mActivityRecord /* boundary */, false /* includeBoundary */,
true /* traverseTopToBottom */);
- if (firstOpaqueActivityBeneath == null) {
+ if (firstOpaqueActivityBeneath == null || firstOpaqueActivityBeneath.isEmbedded()) {
// We skip letterboxing if the translucent activity doesn't have any opaque
- // activities beneath
+ // activities beneath or the activity below is embedded which never has letterbox.
return;
}
inheritConfiguration(firstOpaqueActivityBeneath);
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 3680e6dff9fe..254c911a52da 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -2584,6 +2584,9 @@ class Task extends TaskFragment {
EventLogTags.writeWmTaskRemoved(mTaskId, getRootTaskId(), getDisplayId(), reason);
clearPinnedTaskIfNeed();
+ if (mChildPipActivity != null) {
+ mChildPipActivity.clearLastParentBeforePip();
+ }
// If applicable let the TaskOrganizer know the Task is vanishing.
setTaskOrganizer(null);
diff --git a/services/credentials/java/com/android/server/credentials/MetricUtilities.java b/services/credentials/java/com/android/server/credentials/MetricUtilities.java
index 91470f685920..2dc930d42d62 100644
--- a/services/credentials/java/com/android/server/credentials/MetricUtilities.java
+++ b/services/credentials/java/com/android/server/credentials/MetricUtilities.java
@@ -24,7 +24,7 @@ import android.util.Log;
import com.android.internal.util.FrameworkStatsLog;
import com.android.server.credentials.metrics.ApiName;
import com.android.server.credentials.metrics.ApiStatus;
-import com.android.server.credentials.metrics.CandidateProviderMetric;
+import com.android.server.credentials.metrics.CandidatePhaseMetric;
import com.android.server.credentials.metrics.ChosenProviderMetric;
import java.util.Map;
@@ -90,33 +90,37 @@ public class MetricUtilities {
protected static void logApiCalled(ApiName apiName, ApiStatus apiStatus,
Map<String, ProviderSession> providers, int callingUid,
ChosenProviderMetric chosenProviderMetric) {
- var providerSessions = providers.values();
- int providerSize = providerSessions.size();
- int[] candidateUidList = new int[providerSize];
- int[] candidateQueryRoundTripTimeList = new int[providerSize];
- int[] candidateStatusList = new int[providerSize];
- int index = 0;
- for (var session : providerSessions) {
- CandidateProviderMetric metric = session.mCandidateProviderMetric;
- candidateUidList[index] = metric.getCandidateUid();
- candidateQueryRoundTripTimeList[index] = metric.getQueryLatencyMicroseconds();
- candidateStatusList[index] = metric.getProviderQueryStatus();
- index++;
+ try {
+ var providerSessions = providers.values();
+ int providerSize = providerSessions.size();
+ int[] candidateUidList = new int[providerSize];
+ int[] candidateQueryRoundTripTimeList = new int[providerSize];
+ int[] candidateStatusList = new int[providerSize];
+ int index = 0;
+ for (var session : providerSessions) {
+ CandidatePhaseMetric metric = session.mCandidateProviderMetric;
+ candidateUidList[index] = metric.getCandidateUid();
+ candidateQueryRoundTripTimeList[index] = metric.getQueryLatencyMicroseconds();
+ candidateStatusList[index] = metric.getProviderQueryStatus();
+ index++;
+ }
+ FrameworkStatsLog.write(FrameworkStatsLog.CREDENTIAL_MANAGER_API_CALLED,
+ /* api_name */apiName.getMetricCode(),
+ /* caller_uid */ callingUid,
+ /* api_status */ apiStatus.getMetricCode(),
+ /* repeated_candidate_provider_uid */ candidateUidList,
+ /* repeated_candidate_provider_round_trip_time_query_microseconds */
+ candidateQueryRoundTripTimeList,
+ /* repeated_candidate_provider_status */ candidateStatusList,
+ /* chosen_provider_uid */ chosenProviderMetric.getChosenUid(),
+ /* chosen_provider_round_trip_time_overall_microseconds */
+ chosenProviderMetric.getEntireProviderLatencyMicroseconds(),
+ /* chosen_provider_final_phase_microseconds (backwards compat only) */
+ DEFAULT_INT_32,
+ /* chosen_provider_status */ chosenProviderMetric.getChosenProviderStatus());
+ } catch (Exception e) {
+ Log.w(TAG, "Unexpected error during metric logging: " + e);
}
- FrameworkStatsLog.write(FrameworkStatsLog.CREDENTIAL_MANAGER_API_CALLED,
- /* api_name */apiName.getMetricCode(),
- /* caller_uid */ callingUid,
- /* api_status */ apiStatus.getMetricCode(),
- /* repeated_candidate_provider_uid */ candidateUidList,
- /* repeated_candidate_provider_round_trip_time_query_microseconds */
- candidateQueryRoundTripTimeList,
- /* repeated_candidate_provider_status */ candidateStatusList,
- /* chosen_provider_uid */ chosenProviderMetric.getChosenUid(),
- /* chosen_provider_round_trip_time_overall_microseconds */
- chosenProviderMetric.getEntireProviderLatencyMicroseconds(),
- /* chosen_provider_final_phase_microseconds (backwards compat only) */
- DEFAULT_INT_32,
- /* chosen_provider_status */ chosenProviderMetric.getChosenProviderStatus());
}
/**
@@ -131,20 +135,24 @@ public class MetricUtilities {
*/
protected static void logApiCalled(ApiName apiName, ApiStatus apiStatus,
int callingUid) {
- FrameworkStatsLog.write(FrameworkStatsLog.CREDENTIAL_MANAGER_API_CALLED,
- /* api_name */apiName.getMetricCode(),
- /* caller_uid */ callingUid,
- /* api_status */ apiStatus.getMetricCode(),
- /* repeated_candidate_provider_uid */ DEFAULT_REPEATED_INT_32,
- /* repeated_candidate_provider_round_trip_time_query_microseconds */
- DEFAULT_REPEATED_INT_32,
- /* repeated_candidate_provider_status */ DEFAULT_REPEATED_INT_32,
- /* chosen_provider_uid */ DEFAULT_INT_32,
- /* chosen_provider_round_trip_time_overall_microseconds */
- DEFAULT_INT_32,
- /* chosen_provider_final_phase_microseconds */
- DEFAULT_INT_32,
- /* chosen_provider_status */ DEFAULT_INT_32);
+ try {
+ FrameworkStatsLog.write(FrameworkStatsLog.CREDENTIAL_MANAGER_API_CALLED,
+ /* api_name */apiName.getMetricCode(),
+ /* caller_uid */ callingUid,
+ /* api_status */ apiStatus.getMetricCode(),
+ /* repeated_candidate_provider_uid */ DEFAULT_REPEATED_INT_32,
+ /* repeated_candidate_provider_round_trip_time_query_microseconds */
+ DEFAULT_REPEATED_INT_32,
+ /* repeated_candidate_provider_status */ DEFAULT_REPEATED_INT_32,
+ /* chosen_provider_uid */ DEFAULT_INT_32,
+ /* chosen_provider_round_trip_time_overall_microseconds */
+ DEFAULT_INT_32,
+ /* chosen_provider_final_phase_microseconds */
+ DEFAULT_INT_32,
+ /* chosen_provider_status */ DEFAULT_INT_32);
+ } catch (Exception e) {
+ Log.w(TAG, "Unexpected error during metric logging: " + e);
+ }
}
}
diff --git a/services/credentials/java/com/android/server/credentials/ProviderSession.java b/services/credentials/java/com/android/server/credentials/ProviderSession.java
index a8b9bf6b1fd6..3a72dbc44007 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderSession.java
@@ -31,7 +31,7 @@ import android.os.ICancellationSignal;
import android.os.RemoteException;
import android.util.Log;
-import com.android.server.credentials.metrics.CandidateProviderMetric;
+import com.android.server.credentials.metrics.CandidatePhaseMetric;
import com.android.server.credentials.metrics.ProviderStatusForMetrics;
import java.util.UUID;
@@ -59,7 +59,7 @@ public abstract class ProviderSession<T, R>
@Nullable protected R mProviderResponse;
@NonNull protected Boolean mProviderResponseSet = false;
// Specific candidate provider metric for the provider this session handles
- @Nullable protected CandidateProviderMetric mCandidateProviderMetric;
+ @Nullable protected CandidatePhaseMetric mCandidateProviderMetric;
@NonNull private int mProviderSessionUid;
/**
@@ -126,7 +126,7 @@ public abstract class ProviderSession<T, R>
mUserId = userId;
mComponentName = info.getServiceInfo().getComponentName();
mRemoteCredentialService = remoteCredentialService;
- mCandidateProviderMetric = new CandidateProviderMetric();
+ mCandidateProviderMetric = new CandidatePhaseMetric();
mProviderSessionUid = MetricUtilities.getPackageUid(mContext, mComponentName);
}
diff --git a/services/credentials/java/com/android/server/credentials/RequestSession.java b/services/credentials/java/com/android/server/credentials/RequestSession.java
index c1f35d0f8195..42ec42b170ca 100644
--- a/services/credentials/java/com/android/server/credentials/RequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/RequestSession.java
@@ -36,7 +36,7 @@ import android.util.Log;
import com.android.internal.R;
import com.android.server.credentials.metrics.ApiName;
import com.android.server.credentials.metrics.ApiStatus;
-import com.android.server.credentials.metrics.CandidateProviderMetric;
+import com.android.server.credentials.metrics.CandidatePhaseMetric;
import com.android.server.credentials.metrics.ChosenProviderMetric;
import java.util.ArrayList;
@@ -218,7 +218,7 @@ abstract class RequestSession<T, U> implements CredentialManagerUi.CredentialMan
* @param componentName the componentName to associate with a provider
*/
protected void setChosenMetric(ComponentName componentName) {
- CandidateProviderMetric metric = this.mProviders.get(componentName.flattenToString())
+ CandidatePhaseMetric metric = this.mProviders.get(componentName.flattenToString())
.mCandidateProviderMetric;
mChosenProviderMetric.setChosenUid(metric.getCandidateUid());
mChosenProviderMetric.setFinalFinishTimeNanoseconds(System.nanoTime());
diff --git a/services/credentials/java/com/android/server/credentials/metrics/CandidateBrowsingPhaseMetric.java b/services/credentials/java/com/android/server/credentials/metrics/CandidateBrowsingPhaseMetric.java
new file mode 100644
index 000000000000..37ec8f06c3eb
--- /dev/null
+++ b/services/credentials/java/com/android/server/credentials/metrics/CandidateBrowsingPhaseMetric.java
@@ -0,0 +1,75 @@
+/*
+ * 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.credentials.metrics;
+
+/**
+ * A part of the Candidate Phase, but emitted alongside {@link ChosenProviderMetric}. The user is
+ * shown various entries from the provider responses, and may selectively browse through many
+ * entries. It is possible that the initial set of browsing is for a provider that is ultimately
+ * not chosen. This metric will be gathered PER browsing click, and aggregated, so that we can
+ * understand where user interaction is more cumbersome, informing us for future improvements. This
+ * can only be complete when the browsing is finished, ending in a final user choice, or possibly
+ * a cancellation. Thus, this will be collected and emitted in the final phase, though collection
+ * will begin in the candidate phase when the user begins browsing options.
+ */
+public class CandidateBrowsingPhaseMetric {
+
+ private static final String TAG = "CandidateSelectionPhaseMetric";
+ private static final int SEQUENCE_ID = 3;
+ // The session id associated with the API Call this candidate provider is a part of, default -1
+ private int mSessionId = -1;
+ // The EntryEnum that was pressed, defaults to -1 (TODO immediately, generate entry enum).
+ private int mEntryEnum = -1;
+ // The provider associated with the press, defaults to -1
+ private int mProviderUid = -1;
+
+ /* -- The session ID -- */
+
+ public void setSessionId(int sessionId) {
+ mSessionId = sessionId;
+ }
+
+ public int getSessionId() {
+ return mSessionId;
+ }
+
+ /* -- The sequence ID -- */
+
+ public int getSequenceId() {
+ return SEQUENCE_ID;
+ }
+
+ /* -- The Entry of this tap -- */
+
+ public void setEntryEnum(int entryEnum) {
+ mEntryEnum = entryEnum;
+ }
+
+ public int getEntryEnum() {
+ return mEntryEnum;
+ }
+
+ /* -- The Provider UID of this Tap -- */
+
+ public void setProviderUid(int providerUid) {
+ mProviderUid = providerUid;
+ }
+
+ public int getProviderUid() {
+ return mProviderUid;
+ }
+}
diff --git a/services/credentials/java/com/android/server/credentials/metrics/CandidatePhaseMetric.java b/services/credentials/java/com/android/server/credentials/metrics/CandidatePhaseMetric.java
new file mode 100644
index 000000000000..1c7fb69548fc
--- /dev/null
+++ b/services/credentials/java/com/android/server/credentials/metrics/CandidatePhaseMetric.java
@@ -0,0 +1,246 @@
+/*
+ * 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.credentials.metrics;
+
+import android.util.Log;
+
+import com.android.server.credentials.MetricUtilities;
+
+/**
+ * The central candidate provider metric object that mimics our defined metric setup.
+ * Some types are redundant across these metric collectors, but that has debug use-cases as
+ * these data-types are available at different moments of the flow (and typically, one can feed
+ * into the next).
+ * TODO(b/270403549) - iterate on this in V3+
+ */
+public class CandidatePhaseMetric {
+
+ private static final String TAG = "CandidateProviderMetric";
+ // Since this will always be the second in the split sequence, this is statically 2
+ private static final int SESSION_ID = 2;
+ // The sequence number of this emit of the API call, default -1, equal for all candidates
+ private int mSequenceId = -1;
+ // Indicates if this provider returned from the query phase, default false
+ private boolean mQueryReturned = false;
+
+ // The candidate provider uid
+ private int mCandidateUid = -1;
+
+ // Raw timestamp in nanoseconds, will be converted to microseconds for logging
+
+ //For reference, the initial log timestamp when the service started running the API call
+ private long mServiceBeganTimeNanoseconds = -1;
+ // The moment when the query phase began
+ private long mStartQueryTimeNanoseconds = -1;
+ // The moment when the query phase ended
+ private long mQueryFinishTimeNanoseconds = -1;
+
+ // The status of this particular provider
+ private int mProviderQueryStatus = -1;
+ // Indicates if an exception was thrown by this provider, false by default
+ private boolean mHasException = false;
+ // Indicates the number of total entries available. We can also locally store the entries, but
+ // cannot emit them in the current split form. TODO(b/271135048) - possibly readjust candidate
+ // entries. Also, it may be okay to remove this and instead aggregate from inner counts.
+ // Defaults to -1
+ private int mNumEntriesTotal = -1;
+ // The count of action entries from this provider, defaults to -1
+ private int mActionEntryCount = -1;
+ // The count of credential entries from this provider, defaults to -1
+ private int mCredentialEntryCount = -1;
+ // The *type-count* of the credential entries, defaults to -1
+ private int mCredentialEntryTypeCount = -1;
+ // The count of remote entries from this provider, defaults to -1
+ private int mRemoteEntryCount = -1;
+ // The count of authentication entries from this provider, defaults to -1
+ private int mAuthenticationEntryCount = -1;
+
+ public CandidatePhaseMetric() {
+ }
+
+ /* ---------- Latencies ---------- */
+
+ /* -- Timestamps -- */
+
+ public void setServiceBeganTimeNanoseconds(long serviceBeganTimeNanoseconds) {
+ this.mServiceBeganTimeNanoseconds = serviceBeganTimeNanoseconds;
+ }
+
+ public void setStartQueryTimeNanoseconds(long startQueryTimeNanoseconds) {
+ this.mStartQueryTimeNanoseconds = startQueryTimeNanoseconds;
+ }
+
+ public void setQueryFinishTimeNanoseconds(long queryFinishTimeNanoseconds) {
+ this.mQueryFinishTimeNanoseconds = queryFinishTimeNanoseconds;
+ }
+
+ public long getServiceBeganTimeNanoseconds() {
+ return this.mServiceBeganTimeNanoseconds;
+ }
+
+ public long getStartQueryTimeNanoseconds() {
+ return this.mStartQueryTimeNanoseconds;
+ }
+
+ public long getQueryFinishTimeNanoseconds() {
+ return this.mQueryFinishTimeNanoseconds;
+ }
+
+ /* -- Actual time delta latencies (for local utility) -- */
+
+ /**
+ * Returns the latency in microseconds for the query phase.
+ */
+ public int getQueryLatencyMicroseconds() {
+ return (int) ((this.getQueryFinishTimeNanoseconds()
+ - this.getStartQueryTimeNanoseconds()) / 1000);
+ }
+
+ /* --- Time Stamp Conversion to Microseconds from Reference --- */
+
+ /**
+ * We collect raw timestamps in nanoseconds for ease of collection. However, given the scope
+ * of our logging timeframe, and size considerations of the metric, we require these to give us
+ * the microsecond timestamps from the start reference point.
+ *
+ * @param specificTimestamp the timestamp to consider, must be greater than the reference
+ * @return the microsecond integer timestamp from service start to query began
+ */
+ public int getTimestampFromReferenceStartMicroseconds(long specificTimestamp) {
+ if (specificTimestamp < this.mServiceBeganTimeNanoseconds) {
+ Log.i(TAG, "The timestamp is before service started, falling back to default int");
+ return MetricUtilities.DEFAULT_INT_32;
+ }
+ return (int) ((specificTimestamp
+ - this.mServiceBeganTimeNanoseconds) / 1000);
+ }
+
+ /* ------------- Provider Query Status ------------ */
+
+ public void setProviderQueryStatus(int providerQueryStatus) {
+ this.mProviderQueryStatus = providerQueryStatus;
+ }
+
+ public int getProviderQueryStatus() {
+ return this.mProviderQueryStatus;
+ }
+
+ /* -------------- Candidate Uid ---------------- */
+
+ public void setCandidateUid(int candidateUid) {
+ this.mCandidateUid = candidateUid;
+ }
+
+ public int getCandidateUid() {
+ return this.mCandidateUid;
+ }
+
+ /* -------------- Session Id ---------------- */
+ public int getSessionId() {
+ return SESSION_ID;
+ }
+
+ /* -------------- Sequence Id ---------------- */
+
+ public void setSequenceId(int sequenceId) {
+ mSequenceId = sequenceId;
+ }
+
+ public int getSequenceId() {
+ return mSequenceId;
+ }
+
+ /* -------------- Query Returned Status ---------------- */
+
+ public void setQueryReturned(boolean queryReturned) {
+ mQueryReturned = queryReturned;
+ }
+
+ public boolean isQueryReturned() {
+ return mQueryReturned;
+ }
+
+ /* -------------- Has Exception Status ---------------- */
+
+ public void setHasException(boolean hasException) {
+ mHasException = hasException;
+ }
+
+ public boolean isHasException() {
+ return mHasException;
+ }
+
+ /* -------------- Number of Entries ---------------- */
+
+ public void setNumEntriesTotal(int numEntriesTotal) {
+ mNumEntriesTotal = numEntriesTotal;
+ }
+
+ public int getNumEntriesTotal() {
+ return mNumEntriesTotal;
+ }
+
+ /* -------------- Count of Action Entries ---------------- */
+
+ public void setActionEntryCount(int actionEntryCount) {
+ mActionEntryCount = actionEntryCount;
+ }
+
+ public int getActionEntryCount() {
+ return mActionEntryCount;
+ }
+
+ /* -------------- Count of Credential Entries ---------------- */
+
+ public void setCredentialEntryCount(int credentialEntryCount) {
+ mCredentialEntryCount = credentialEntryCount;
+ }
+
+ public int getCredentialEntryCount() {
+ return mCredentialEntryCount;
+ }
+
+ /* -------------- Count of Credential Entry Types ---------------- */
+
+ public void setCredentialEntryTypeCount(int credentialEntryTypeCount) {
+ mCredentialEntryTypeCount = credentialEntryTypeCount;
+ }
+
+ public int getCredentialEntryTypeCount() {
+ return mCredentialEntryTypeCount;
+ }
+
+ /* -------------- Count of Remote Entries ---------------- */
+
+ public void setRemoteEntryCount(int remoteEntryCount) {
+ mRemoteEntryCount = remoteEntryCount;
+ }
+
+ public int getRemoteEntryCount() {
+ return mRemoteEntryCount;
+ }
+
+ /* -------------- Count of Authentication Entries ---------------- */
+
+ public void setAuthenticationEntryCount(int authenticationEntryCount) {
+ mAuthenticationEntryCount = authenticationEntryCount;
+ }
+
+ public int getAuthenticationEntryCount() {
+ return mAuthenticationEntryCount;
+ }
+}
diff --git a/services/credentials/java/com/android/server/credentials/metrics/CandidateProviderMetric.java b/services/credentials/java/com/android/server/credentials/metrics/CandidateProviderMetric.java
deleted file mode 100644
index 9f438ecc1146..000000000000
--- a/services/credentials/java/com/android/server/credentials/metrics/CandidateProviderMetric.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * 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.credentials.metrics;
-
-/**
- * The central candidate provider metric object that mimics our defined metric setup.
- * Some types are redundant across these metric collectors, but that has debug use-cases as
- * these data-types are available at different moments of the flow (and typically, one can feed
- * into the next).
- * TODO(b/270403549) - iterate on this in V3+
- */
-public class CandidateProviderMetric {
-
- private static final String TAG = "CandidateProviderMetric";
- private int mCandidateUid = -1;
-
- // Raw timestamp in nanoseconds, will be converted to microseconds for logging
-
- private long mStartQueryTimeNanoseconds = -1;
- private long mQueryFinishTimeNanoseconds = -1;
-
- private int mProviderQueryStatus = -1;
-
- public CandidateProviderMetric() {
- }
-
- /* ---------- Latencies ---------- */
-
- public void setStartQueryTimeNanoseconds(long startQueryTimeNanoseconds) {
- this.mStartQueryTimeNanoseconds = startQueryTimeNanoseconds;
- }
-
- public void setQueryFinishTimeNanoseconds(long queryFinishTimeNanoseconds) {
- this.mQueryFinishTimeNanoseconds = queryFinishTimeNanoseconds;
- }
-
- public long getStartQueryTimeNanoseconds() {
- return this.mStartQueryTimeNanoseconds;
- }
-
- public long getQueryFinishTimeNanoseconds() {
- return this.mQueryFinishTimeNanoseconds;
- }
-
- /**
- * Returns the latency in microseconds for the query phase.
- */
- public int getQueryLatencyMicroseconds() {
- return (int) ((this.getQueryFinishTimeNanoseconds()
- - this.getStartQueryTimeNanoseconds()) / 1000);
- }
-
- // TODO (in direct next dependent CL, so this is transient) - add reference timestamp in micro
- // seconds for this too.
-
- /* ------------- Provider Query Status ------------ */
-
- public void setProviderQueryStatus(int providerQueryStatus) {
- this.mProviderQueryStatus = providerQueryStatus;
- }
-
- public int getProviderQueryStatus() {
- return this.mProviderQueryStatus;
- }
-
- /* -------------- Candidate Uid ---------------- */
-
- public void setCandidateUid(int candidateUid) {
- this.mCandidateUid = candidateUid;
- }
-
- public int getCandidateUid() {
- return this.mCandidateUid;
- }
-}
diff --git a/services/credentials/java/com/android/server/credentials/metrics/ChosenProviderMetric.java b/services/credentials/java/com/android/server/credentials/metrics/ChosenProviderMetric.java
index 03102558d21b..1a6109116d38 100644
--- a/services/credentials/java/com/android/server/credentials/metrics/ChosenProviderMetric.java
+++ b/services/credentials/java/com/android/server/credentials/metrics/ChosenProviderMetric.java
@@ -64,7 +64,7 @@ public class ChosenProviderMetric {
/* ---------------- Latencies ------------------ */
- /* ----- Direct Latencies ------- */
+ /* ----- Direct Delta Latencies for Local Utility ------- */
/**
* In order for a chosen provider to be selected, the call must have successfully begun.
@@ -85,7 +85,7 @@ public class ChosenProviderMetric {
* metric.
*
* @param queryPhaseLatencyMicroseconds the millisecond latency for the query phase, typically
- * passed in through the {@link CandidateProviderMetric}
+ * passed in through the {@link CandidatePhaseMetric}
*/
public void setQueryPhaseLatencyMicroseconds(int queryPhaseLatencyMicroseconds) {
mQueryPhaseLatencyMicroseconds = queryPhaseLatencyMicroseconds;
@@ -106,7 +106,7 @@ public class ChosenProviderMetric {
/**
* Returns the full provider (invocation to response) latency in microseconds. Expects the
- * start time to be provided, such as from {@link CandidateProviderMetric}.
+ * start time to be provided, such as from {@link CandidatePhaseMetric}.
*/
public int getEntireProviderLatencyMicroseconds() {
return (int) ((this.mFinalFinishTimeNanoseconds
@@ -172,7 +172,7 @@ public class ChosenProviderMetric {
return mFinalFinishTimeNanoseconds;
}
- /* --- Time Stamp Conversion to Microseconds --- */
+ /* --- Time Stamp Conversion to Microseconds from Reference Point --- */
/**
* We collect raw timestamps in nanoseconds for ease of collection. However, given the scope
diff --git a/services/tests/servicestests/src/com/android/server/location/contexthub/ContextHubServiceTest.java b/services/tests/servicestests/src/com/android/server/location/contexthub/ContextHubServiceTest.java
index c0a994ba340a..685e8d6a3bc5 100644
--- a/services/tests/servicestests/src/com/android/server/location/contexthub/ContextHubServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/location/contexthub/ContextHubServiceTest.java
@@ -18,7 +18,8 @@ package com.android.server.location.contexthub;
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -75,7 +76,7 @@ public class ContextHubServiceTest {
@Test
public void testDump_emptyPreloadedNanoappList() {
- when(mMockContextHubWrapper.getPreloadedNanoappIds()).thenReturn(null);
+ when(mMockContextHubWrapper.getPreloadedNanoappIds(anyInt())).thenReturn(null);
StringWriter stringWriter = new StringWriter();
ContextHubService service = new ContextHubService(mContext, mMockContextHubWrapper);
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index 65c71255cd2f..00d7a52752dd 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -384,6 +384,24 @@ public class SizeCompatTests extends WindowTestsBase {
}
@Test
+ public void testNotApplyStrategyToTranslucentActivitiesOverEmbeddedActivities() {
+ mWm.mLetterboxConfiguration.setTranslucentLetterboxingOverrideEnabled(true);
+ setUpDisplaySizeWithApp(2000, 1000);
+ mActivity.info.screenOrientation = SCREEN_ORIENTATION_PORTRAIT;
+ mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+ // Mock the activity as embedded without additional TaskFragment layer in the task for
+ // simplicity.
+ doReturn(true).when(mActivity).isEmbedded();
+ // Translucent Activity
+ final ActivityRecord translucentActivity = new ActivityBuilder(mAtm).build();
+ doReturn(false).when(translucentActivity).matchParentBounds();
+ doReturn(false).when(translucentActivity).fillsParent();
+ mTask.addChild(translucentActivity);
+ // Check the strategy has not being applied
+ assertFalse(translucentActivity.mLetterboxUiController.hasInheritedLetterboxBehavior());
+ }
+
+ @Test
public void testTranslucentActivitiesDontGoInSizeCompactMode() {
mWm.mLetterboxConfiguration.setTranslucentLetterboxingOverrideEnabled(true);
setUpDisplaySizeWithApp(2800, 1400);
diff --git a/services/tests/wmtests/src/com/android/server/wm/SurfaceSyncGroupTest.java b/services/tests/wmtests/src/com/android/server/wm/SurfaceSyncGroupTest.java
index c5387272f0bf..e30206ee0a64 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SurfaceSyncGroupTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceSyncGroupTest.java
@@ -41,6 +41,7 @@ import java.util.concurrent.TimeUnit;
@Presubmit
public class SurfaceSyncGroupTest {
private static final String TAG = "SurfaceSyncGroupTest";
+ private static final int TIMEOUT_MS = 100;
private final Executor mExecutor = Runnable::run;
@@ -86,7 +87,7 @@ public class SurfaceSyncGroupTest {
syncTarget2.markSyncReady();
- finishedLatch.await(5, TimeUnit.SECONDS);
+ finishedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS);
assertEquals(0, finishedLatch.getCount());
}
@@ -124,13 +125,13 @@ public class SurfaceSyncGroupTest {
syncTarget1.markSyncReady();
- finishedLatch1.await(5, TimeUnit.SECONDS);
+ finishedLatch1.await(TIMEOUT_MS, TimeUnit.MILLISECONDS);
assertEquals(0, finishedLatch1.getCount());
assertNotEquals(0, finishedLatch2.getCount());
syncTarget2.markSyncReady();
- finishedLatch2.await(5, TimeUnit.SECONDS);
+ finishedLatch2.await(TIMEOUT_MS, TimeUnit.MILLISECONDS);
assertEquals(0, finishedLatch2.getCount());
}
@@ -156,17 +157,17 @@ public class SurfaceSyncGroupTest {
// Finish syncTarget2 first to test that the syncGroup is not complete until the merged sync
// is also done.
syncTarget2.markSyncReady();
- finishedLatch2.await(1, TimeUnit.SECONDS);
+ finishedLatch2.await(TIMEOUT_MS, TimeUnit.MILLISECONDS);
// Sync did not complete yet
assertNotEquals(0, finishedLatch2.getCount());
syncTarget1.markSyncReady();
// The first sync will still get a callback when it's sync requirements are done.
- finishedLatch1.await(5, TimeUnit.SECONDS);
+ finishedLatch1.await(TIMEOUT_MS, TimeUnit.MILLISECONDS);
assertEquals(0, finishedLatch1.getCount());
- finishedLatch2.await(5, TimeUnit.SECONDS);
+ finishedLatch2.await(TIMEOUT_MS, TimeUnit.MILLISECONDS);
assertEquals(0, finishedLatch2.getCount());
}
@@ -189,7 +190,7 @@ public class SurfaceSyncGroupTest {
syncTarget1.markSyncReady();
// The first sync will still get a callback when it's sync requirements are done.
- finishedLatch1.await(5, TimeUnit.SECONDS);
+ finishedLatch1.await(TIMEOUT_MS, TimeUnit.MILLISECONDS);
assertEquals(0, finishedLatch1.getCount());
syncGroup2.add(syncGroup1, null /* runnable */);
@@ -198,7 +199,7 @@ public class SurfaceSyncGroupTest {
// Verify that the second sync will receive complete since the merged sync was already
// completed before the merge.
- finishedLatch2.await(5, TimeUnit.SECONDS);
+ finishedLatch2.await(TIMEOUT_MS, TimeUnit.MILLISECONDS);
assertEquals(0, finishedLatch2.getCount());
}
@@ -232,8 +233,8 @@ public class SurfaceSyncGroupTest {
syncTarget3.markSyncReady();
// Neither SyncGroup will be ready.
- finishedLatch1.await(1, TimeUnit.SECONDS);
- finishedLatch2.await(1, TimeUnit.SECONDS);
+ finishedLatch1.await(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ finishedLatch2.await(TIMEOUT_MS, TimeUnit.MILLISECONDS);
assertEquals(1, finishedLatch1.getCount());
assertEquals(1, finishedLatch2.getCount());
@@ -241,8 +242,8 @@ public class SurfaceSyncGroupTest {
syncTarget2.markSyncReady();
// Both sync groups should be ready after target2 completed.
- finishedLatch1.await(5, TimeUnit.SECONDS);
- finishedLatch2.await(5, TimeUnit.SECONDS);
+ finishedLatch1.await(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ finishedLatch2.await(TIMEOUT_MS, TimeUnit.MILLISECONDS);
assertEquals(0, finishedLatch1.getCount());
assertEquals(0, finishedLatch2.getCount());
}
@@ -275,8 +276,8 @@ public class SurfaceSyncGroupTest {
syncTarget1.markSyncReady();
// Only SyncGroup1 will be ready, but SyncGroup2 still needs its own targets to be ready.
- finishedLatch1.await(1, TimeUnit.SECONDS);
- finishedLatch2.await(1, TimeUnit.SECONDS);
+ finishedLatch1.await(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ finishedLatch2.await(TIMEOUT_MS, TimeUnit.MILLISECONDS);
assertEquals(0, finishedLatch1.getCount());
assertEquals(1, finishedLatch2.getCount());
@@ -284,7 +285,7 @@ public class SurfaceSyncGroupTest {
syncTarget3.markSyncReady();
// SyncGroup2 is finished after target3 completed.
- finishedLatch2.await(1, TimeUnit.SECONDS);
+ finishedLatch2.await(TIMEOUT_MS, TimeUnit.MILLISECONDS);
assertEquals(0, finishedLatch2.getCount());
}
@@ -357,6 +358,27 @@ public class SurfaceSyncGroupTest {
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
+
+ assertEquals(0, finishedLatch.getCount());
+ }
+
+ public void testSurfaceSyncGroupTimeout() throws InterruptedException {
+ final CountDownLatch finishedLatch = new CountDownLatch(1);
+ SurfaceSyncGroup syncGroup = new SurfaceSyncGroup(TAG);
+ syncGroup.addSyncCompleteCallback(mExecutor, finishedLatch::countDown);
+ SurfaceSyncGroup syncTarget1 = new SurfaceSyncGroup("FakeSyncTarget1");
+ SurfaceSyncGroup syncTarget2 = new SurfaceSyncGroup("FakeSyncTarget2");
+
+ syncGroup.add(syncTarget1, null /* runnable */);
+ syncGroup.add(syncTarget2, null /* runnable */);
+ syncGroup.markSyncReady();
+
+ syncTarget1.markSyncReady();
+ assertNotEquals(0, finishedLatch.getCount());
+
+ // Never finish syncTarget2 so it forces the timeout. Timeout is 1 second so wait a little
+ // over 1 second to make sure it completes.
+ finishedLatch.await(1100, TimeUnit.MILLISECONDS);
assertEquals(0, finishedLatch.getCount());
}
}
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index 788d0e88170d..cf0561db2ae3 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -1530,6 +1530,10 @@ public class PhoneNumberUtils {
* @return the E.164 representation, or null if the given phone number is not valid.
*/
public static String formatNumberToE164(String phoneNumber, String defaultCountryIso) {
+ if (defaultCountryIso != null) {
+ defaultCountryIso = defaultCountryIso.toUpperCase(Locale.ROOT);
+ }
+
return formatNumberInternal(phoneNumber, defaultCountryIso, PhoneNumberFormat.E164);
}
@@ -1541,6 +1545,10 @@ public class PhoneNumberUtils {
* @return the RFC3966 representation, or null if the given phone number is not valid.
*/
public static String formatNumberToRFC3966(String phoneNumber, String defaultCountryIso) {
+ if (defaultCountryIso != null) {
+ defaultCountryIso = defaultCountryIso.toUpperCase(Locale.ROOT);
+ }
+
return formatNumberInternal(phoneNumber, defaultCountryIso, PhoneNumberFormat.RFC3966);
}
@@ -1591,6 +1599,10 @@ public class PhoneNumberUtils {
return false;
}
+ if (defaultCountryIso != null) {
+ defaultCountryIso = defaultCountryIso.toUpperCase(Locale.ROOT);
+ }
+
PhoneNumberUtil util = PhoneNumberUtil.getInstance();
try {
PhoneNumber pn = util.parseAndKeepRawInput(phoneNumber, defaultCountryIso);
@@ -1619,6 +1631,10 @@ public class PhoneNumberUtils {
return phoneNumber;
}
+ if (defaultCountryIso != null) {
+ defaultCountryIso = defaultCountryIso.toUpperCase(Locale.ROOT);
+ }
+
PhoneNumberUtil util = PhoneNumberUtil.getInstance();
String result = null;
try {
@@ -1671,6 +1687,10 @@ public class PhoneNumberUtils {
*/
public static String formatNumber(
String phoneNumber, String phoneNumberE164, String defaultCountryIso) {
+ if (defaultCountryIso != null) {
+ defaultCountryIso = defaultCountryIso.toUpperCase(Locale.ROOT);
+ }
+
int len = phoneNumber.length();
for (int i = 0; i < len; i++) {
if (!isDialable(phoneNumber.charAt(i))) {
@@ -2900,7 +2920,11 @@ public class PhoneNumberUtils {
PhoneNumberUtil util = PhoneNumberUtil.getInstance();
PhoneNumber n1;
PhoneNumber n2;
- defaultCountryIso = defaultCountryIso.toUpperCase(Locale.ROOT);
+
+ if (defaultCountryIso != null) {
+ defaultCountryIso = defaultCountryIso.toUpperCase(Locale.ROOT);
+ }
+
try {
n1 = util.parseAndKeepRawInput(number1, defaultCountryIso);
n2 = util.parseAndKeepRawInput(number2, defaultCountryIso);
diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java b/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java
index 684b385d60e8..15fd817ba73b 100644
--- a/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java
+++ b/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java
@@ -161,9 +161,9 @@ public class SharedConnectivityManager {
Resources resources = context.getResources();
try {
String servicePackageName = resources.getString(
- R.string.shared_connectivity_service_package);
+ R.string.config_sharedConnectivityServicePackage);
String serviceIntentAction = resources.getString(
- R.string.shared_connectivity_service_intent_action);
+ R.string.config_sharedConnectivityServiceIntentAction);
return new SharedConnectivityManager(context, servicePackageName, serviceIntentAction);
} catch (Resources.NotFoundException e) {
Log.e(TAG, "To support shared connectivity service on this device, the service's"
@@ -434,14 +434,15 @@ public class SharedConnectivityManager {
/**
* Gets the list of hotspot networks the user can select to connect to.
*
- * @return Returns a {@link List} of {@link HotspotNetwork} objects, empty list on failure.
+ * @return Returns a {@link List} of {@link HotspotNetwork} objects, null on failure.
*/
@RequiresPermission(anyOf = {android.Manifest.permission.NETWORK_SETTINGS,
android.Manifest.permission.NETWORK_SETUP_WIZARD})
- @NonNull
+ @SuppressWarnings("NullableCollection")
+ @Nullable
public List<HotspotNetwork> getHotspotNetworks() {
if (mService == null) {
- return List.of();
+ return null;
}
try {
@@ -449,20 +450,21 @@ public class SharedConnectivityManager {
} catch (RemoteException e) {
Log.e(TAG, "Exception in getHotspotNetworks", e);
}
- return List.of();
+ return null;
}
/**
* Gets the list of known networks the user can select to connect to.
*
- * @return Returns a {@link List} of {@link KnownNetwork} objects, empty list on failure.
+ * @return Returns a {@link List} of {@link KnownNetwork} objects, null on failure.
*/
@RequiresPermission(anyOf = {android.Manifest.permission.NETWORK_SETTINGS,
android.Manifest.permission.NETWORK_SETUP_WIZARD})
- @NonNull
+ @SuppressWarnings("NullableCollection")
+ @Nullable
public List<KnownNetwork> getKnownNetworks() {
if (mService == null) {
- return List.of();
+ return null;
}
try {
@@ -470,7 +472,7 @@ public class SharedConnectivityManager {
} catch (RemoteException e) {
Log.e(TAG, "Exception in getKnownNetworks", e);
}
- return List.of();
+ return null;
}
/**
diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/service/SharedConnectivityService.java b/wifi/java/src/android/net/wifi/sharedconnectivity/service/SharedConnectivityService.java
index c53da9c15d4d..57108e4aa227 100644
--- a/wifi/java/src/android/net/wifi/sharedconnectivity/service/SharedConnectivityService.java
+++ b/wifi/java/src/android/net/wifi/sharedconnectivity/service/SharedConnectivityService.java
@@ -25,6 +25,7 @@ import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.app.Service;
+import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.wifi.sharedconnectivity.app.HotspotNetwork;
@@ -40,8 +41,11 @@ import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.util.Log;
+import com.android.internal.R;
+
import java.util.Collections;
import java.util.List;
+import java.util.Objects;
/**
@@ -382,6 +386,30 @@ public abstract class SharedConnectivityService extends Service {
}
/**
+ * System and settings UI support on the device for instant tether.
+ * @return True if the UI can display Instant Tether network data. False otherwise.
+ */
+ public static boolean areHotspotNetworksEnabledForService(@NonNull Context context) {
+ String servicePackage = context.getResources()
+ .getString(R.string.config_sharedConnectivityServicePackage);
+ return Objects.equals(context.getPackageName(), servicePackage)
+ && context.getResources()
+ .getBoolean(R.bool.config_hotspotNetworksEnabledForService);
+ }
+
+ /**
+ * System and settings UI support on the device for known networks.
+ * @return True if the UI can display known networks data. False otherwise.
+ */
+ public static boolean areKnownNetworksEnabledForService(@NonNull Context context) {
+ String servicePackage = context.getResources()
+ .getString(R.string.config_sharedConnectivityServicePackage);
+ return Objects.equals(context.getPackageName(), servicePackage)
+ && context.getResources()
+ .getBoolean(R.bool.config_knownNetworksEnabledForService);
+ }
+
+ /**
* Implementing application should implement this method.
*
* Implementation should initiate a connection to the Hotspot Network indicated.
diff --git a/wifi/tests/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManagerTest.java b/wifi/tests/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManagerTest.java
index 8c573e302213..7578dfd11225 100644
--- a/wifi/tests/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManagerTest.java
@@ -423,20 +423,20 @@ public class SharedConnectivityManagerTest {
* Verify getters.
*/
@Test
- public void getHotspotNetworks_serviceNotConnected_shouldReturnEmptyList() {
+ public void getHotspotNetworks_serviceNotConnected_shouldReturnNull() {
SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
manager.setService(null);
- assertThat(manager.getKnownNetworks()).isEmpty();
+ assertThat(manager.getHotspotNetworks()).isNull();
}
@Test
- public void getHotspotNetworks_remoteException_shouldReturnEmptyList() throws RemoteException {
+ public void getHotspotNetworks_remoteException_shouldReturnNull() throws RemoteException {
SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
manager.setService(mService);
doThrow(new RemoteException()).when(mService).getHotspotNetworks();
- assertThat(manager.getKnownNetworks()).isEmpty();
+ assertThat(manager.getHotspotNetworks()).isNull();
}
@Test
@@ -450,21 +450,21 @@ public class SharedConnectivityManagerTest {
}
@Test
- public void getKnownNetworks_serviceNotConnected_shouldReturnEmptyList()
+ public void getKnownNetworks_serviceNotConnected_shouldReturnNull()
throws RemoteException {
SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
manager.setService(null);
- assertThat(manager.getKnownNetworks()).isEmpty();
+ assertThat(manager.getKnownNetworks()).isNull();
}
@Test
- public void getKnownNetworks_remoteException_shouldReturnEmptyList() throws RemoteException {
+ public void getKnownNetworks_remoteException_shouldReturnNull() throws RemoteException {
SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
manager.setService(mService);
doThrow(new RemoteException()).when(mService).getKnownNetworks();
- assertThat(manager.getKnownNetworks()).isEmpty();
+ assertThat(manager.getKnownNetworks()).isNull();
}
@Test
diff --git a/wifi/tests/src/android/net/wifi/sharedconnectivity/service/SharedConnectivityServiceTest.java b/wifi/tests/src/android/net/wifi/sharedconnectivity/service/SharedConnectivityServiceTest.java
index 19effe5d6f14..b8b6b767eed3 100644
--- a/wifi/tests/src/android/net/wifi/sharedconnectivity/service/SharedConnectivityServiceTest.java
+++ b/wifi/tests/src/android/net/wifi/sharedconnectivity/service/SharedConnectivityServiceTest.java
@@ -26,10 +26,12 @@ import static android.net.wifi.sharedconnectivity.app.NetworkProviderInfo.DEVICE
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.Intent;
+import android.content.res.Resources;
import android.net.wifi.sharedconnectivity.app.HotspotNetwork;
import android.net.wifi.sharedconnectivity.app.HotspotNetworkConnectionStatus;
import android.net.wifi.sharedconnectivity.app.KnownNetwork;
@@ -86,6 +88,9 @@ public class SharedConnectivityServiceTest {
@Mock
Context mContext;
+ @Mock
+ Resources mResources;
+
static class FakeSharedConnectivityService extends SharedConnectivityService {
public void attachBaseContext(Context context) {
super.attachBaseContext(context);
@@ -180,6 +185,48 @@ public class SharedConnectivityServiceTest {
.isEqualTo(KNOWN_NETWORK_CONNECTION_STATUS);
}
+ @Test
+ public void areHotspotNetworksEnabledForService() {
+ when(mContext.getResources()).thenReturn(mResources);
+ when(mContext.getPackageName()).thenReturn("package");
+ when(mResources.getString(anyInt())).thenReturn("package");
+ when(mResources.getBoolean(anyInt())).thenReturn(true);
+
+ assertThat(SharedConnectivityService.areHotspotNetworksEnabledForService(mContext))
+ .isTrue();
+ }
+
+ @Test
+ public void areHotspotNetworksEnabledForService_notSamePackage_shouldReturnFalse() {
+ when(mContext.getResources()).thenReturn(mResources);
+ when(mContext.getPackageName()).thenReturn("package");
+ when(mResources.getString(anyInt())).thenReturn("other_package");
+ when(mResources.getBoolean(anyInt())).thenReturn(true);
+
+ assertThat(SharedConnectivityService.areHotspotNetworksEnabledForService(mContext))
+ .isFalse();
+ }
+
+ @Test
+ public void areKnownNetworksEnabledForService() {
+ when(mContext.getResources()).thenReturn(mResources);
+ when(mContext.getPackageName()).thenReturn("package");
+ when(mResources.getString(anyInt())).thenReturn("package");
+ when(mResources.getBoolean(anyInt())).thenReturn(true);
+
+ assertThat(SharedConnectivityService.areKnownNetworksEnabledForService(mContext)).isTrue();
+ }
+
+ @Test
+ public void areKnownNetworksEnabledForService_notSamePackage_shouldReturnFalse() {
+ when(mContext.getResources()).thenReturn(mResources);
+ when(mContext.getPackageName()).thenReturn("package");
+ when(mResources.getString(anyInt())).thenReturn("other_package");
+ when(mResources.getBoolean(anyInt())).thenReturn(true);
+
+ assertThat(SharedConnectivityService.areKnownNetworksEnabledForService(mContext)).isFalse();
+ }
+
private SharedConnectivityService createService() {
FakeSharedConnectivityService service = new FakeSharedConnectivityService();
service.attachBaseContext(mContext);