summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java43
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java42
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/BatteryController.java11
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java13
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/ContentObserverController.java8
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java25
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/IdleController.java8
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java94
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java59
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/StorageController.java7
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/TimeController.java6
-rw-r--r--cmds/screencap/screencap.cpp1
-rw-r--r--core/api/current.txt5
-rw-r--r--core/api/system-current.txt2
-rw-r--r--core/api/test-current.txt1
-rw-r--r--core/java/android/app/AppOpsManager.java20
-rw-r--r--core/java/android/app/time/ExternalTimeSuggestion.java69
-rw-r--r--core/java/android/app/time/TimeManager.java23
-rw-r--r--core/java/android/app/timedetector/TimeDetector.java9
-rw-r--r--core/java/android/app/timedetector/TimeDetectorImpl.java13
-rw-r--r--core/java/android/content/pm/dex/DexMetadataHelper.java16
-rw-r--r--core/java/android/hardware/SystemSensorManager.java5
-rw-r--r--core/java/android/os/PowerManager.java5
-rw-r--r--core/java/android/os/Process.java6
-rw-r--r--core/java/android/os/storage/StorageManager.java1
-rw-r--r--core/java/android/view/InsetsState.java61
-rw-r--r--core/java/android/view/RoundedCorners.java2
-rw-r--r--core/java/android/view/SurfaceControl.java134
-rw-r--r--core/java/android/widget/AbsListView.java194
-rw-r--r--core/java/com/android/internal/app/IAppOpsNotedCallback.aidl2
-rw-r--r--core/java/com/android/internal/app/IAppOpsStartedCallback.aidl2
-rw-r--r--core/jni/android_hardware_SensorManager.cpp38
-rw-r--r--core/jni/android_view_SurfaceControl.cpp238
-rw-r--r--core/tests/coretests/src/android/app/time/ExternalTimeSuggestionTest.java15
-rw-r--r--data/etc/services.core.protolog.json6
-rw-r--r--graphics/java/android/graphics/BlurShader.java89
-rw-r--r--libs/WindowManager/Shell/res/layout/size_compat_mode_hint.xml73
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatHintPopup.java71
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatRestartButton.java87
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUIController.java16
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUILayout.java149
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUIWindowManager.java33
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatHintPopupTest.java85
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatRestartButtonTest.java34
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatUILayoutTest.java77
-rw-r--r--libs/hwui/RecordingCanvas.cpp21
-rw-r--r--libs/hwui/hwui/Canvas.cpp3
-rw-r--r--libs/hwui/hwui/Canvas.h8
-rw-r--r--libs/hwui/tests/common/TestContext.cpp8
-rw-r--r--libs/hwui/tests/common/TestContext.h4
-rw-r--r--libs/input/MouseCursorController.h1
-rw-r--r--libs/input/PointerController.h1
-rw-r--r--libs/input/PointerControllerContext.h1
-rw-r--r--media/java/android/media/AudioDeviceInfo.java22
-rw-r--r--media/jni/tuner/DemuxClient.cpp2
-rw-r--r--native/android/surface_control.cpp12
-rw-r--r--packages/SettingsLib/res/values/strings.xml3
-rw-r--r--packages/SystemUI/AndroidManifest.xml5
-rw-r--r--packages/SystemUI/res/layout/status_bar_expanded.xml2
-rw-r--r--packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java201
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java186
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinator.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java18
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java11
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java31
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java52
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinatorTest.java35
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java89
-rw-r--r--services/core/java/com/android/server/SensorPrivacyService.java15
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java6
-rw-r--r--services/core/java/com/android/server/appop/AppOpsService.java46
-rw-r--r--services/core/java/com/android/server/display/ColorFade.java2
-rw-r--r--services/core/java/com/android/server/display/DisplayDeviceInfo.java2
-rw-r--r--services/core/java/com/android/server/display/LocalDisplayAdapter.java180
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java78
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java4
-rw-r--r--services/core/java/com/android/server/power/PowerManagerService.java1
-rw-r--r--services/core/java/com/android/server/wm/ActivityClientController.java5
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java14
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskSupervisor.java13
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java43
-rw-r--r--services/core/java/com/android/server/wm/DisplayFrames.java25
-rw-r--r--services/core/java/com/android/server/wm/InsetsStateController.java73
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java4
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java38
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java134
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java221
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java5
-rw-r--r--services/tests/servicestests/src/com/android/server/appop/AppOpsNotedWatcherTest.java9
-rw-r--r--services/tests/servicestests/src/com/android/server/appop/AppOpsStartedWatcherTest.java9
-rw-r--r--services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java3
-rw-r--r--services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java5
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java6
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java91
-rw-r--r--tests/ApkVerityTest/src/com/android/apkverity/ApkVerityTest.java147
102 files changed, 2303 insertions, 1566 deletions
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 ac6eb3229a25..c5d3b7a726b9 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -53,6 +53,7 @@ import android.net.Uri;
import android.os.BatteryStats;
import android.os.BatteryStatsInternal;
import android.os.Binder;
+import android.os.Build;
import android.os.Handler;
import android.os.LimitExceededException;
import android.os.Looper;
@@ -151,6 +152,9 @@ public class JobSchedulerService extends com.android.server.SystemService
private static final boolean ENFORCE_MAX_JOBS = true;
/** The maximum number of jobs that we allow an unprivileged app to schedule */
private static final int MAX_JOBS_PER_APP = 100;
+ /** The number of the most recently completed jobs to keep track of for debugging purposes. */
+ private static final int NUM_COMPLETED_JOB_HISTORY =
+ Build.IS_USERDEBUG || Build.IS_ENG ? 25 : 0;
@VisibleForTesting
public static Clock sSystemClock = Clock.systemUTC();
@@ -297,6 +301,10 @@ public class JobSchedulerService extends com.android.server.SystemService
*/
boolean mReportedActive;
+ private int mLastCompletedJobIndex = 0;
+ private final JobStatus[] mLastCompletedJobs = new JobStatus[NUM_COMPLETED_JOB_HISTORY];
+ private final long[] mLastCompletedJobTimeElapsed = new long[NUM_COMPLETED_JOB_HISTORY];
+
/**
* A mapping of which uids are currently in the foreground to their effective priority.
*/
@@ -1752,6 +1760,10 @@ public class JobSchedulerService extends com.android.server.SystemService
Slog.d(TAG, "Completed " + jobStatus + ", reschedule=" + needsReschedule);
}
+ mLastCompletedJobs[mLastCompletedJobIndex] = jobStatus;
+ mLastCompletedJobTimeElapsed[mLastCompletedJobIndex] = sElapsedRealtimeClock.millis();
+ mLastCompletedJobIndex = (mLastCompletedJobIndex + 1) % NUM_COMPLETED_JOB_HISTORY;
+
// Intentionally not checking expedited job quota here. An app can't find out if it's run
// out of quota when it asks JS to reschedule an expedited job. Instead, the rescheduled
// EJ will just be demoted to a regular job if the app has no EJ quota left.
@@ -3298,6 +3310,37 @@ public class JobSchedulerService extends com.android.server.SystemService
}
}
pw.decreaseIndent();
+
+ pw.println();
+ boolean recentPrinted = false;
+ pw.println("Recently completed jobs:");
+ pw.increaseIndent();
+ for (int r = 1; r <= NUM_COMPLETED_JOB_HISTORY; ++r) {
+ // Print most recent first
+ final int idx = (mLastCompletedJobIndex + NUM_COMPLETED_JOB_HISTORY - r)
+ % NUM_COMPLETED_JOB_HISTORY;
+ final JobStatus job = mLastCompletedJobs[idx];
+ if (job != null) {
+ if (!predicate.test(job)) {
+ continue;
+ }
+ recentPrinted = true;
+ TimeUtils.formatDuration(mLastCompletedJobTimeElapsed[idx], nowElapsed, pw);
+ pw.println();
+ // Double indent for readability
+ pw.increaseIndent();
+ pw.increaseIndent();
+ job.dump(pw, true, nowElapsed);
+ pw.decreaseIndent();
+ pw.decreaseIndent();
+ }
+ }
+ if (!recentPrinted) {
+ pw.println("None");
+ }
+ pw.decreaseIndent();
+ pw.println();
+
if (filterUid == -1) {
pw.println();
pw.print("mReadyToRock="); pw.println(mReadyToRock);
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java
index 58396eb69d14..a230b23f03a4 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java
@@ -17,6 +17,7 @@
package com.android.server.job.controllers;
import static com.android.server.job.JobSchedulerService.NEVER_INDEX;
+import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
import android.os.SystemClock;
import android.os.UserHandle;
@@ -59,6 +60,8 @@ public final class BackgroundJobsController extends StateController {
private final AppStateTrackerImpl mAppStateTracker;
+ private final UpdateJobFunctor mUpdateJobFunctor = new UpdateJobFunctor();
+
public BackgroundJobsController(JobSchedulerService service) {
super(service);
@@ -69,7 +72,7 @@ public final class BackgroundJobsController extends StateController {
@Override
public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) {
- updateSingleJobRestrictionLocked(jobStatus, UNKNOWN);
+ updateSingleJobRestrictionLocked(jobStatus, sElapsedRealtimeClock.millis(), UNKNOWN);
}
@Override
@@ -79,7 +82,7 @@ public final class BackgroundJobsController extends StateController {
@Override
public void evaluateStateLocked(JobStatus jobStatus) {
- updateSingleJobRestrictionLocked(jobStatus, UNKNOWN);
+ updateSingleJobRestrictionLocked(jobStatus, sElapsedRealtimeClock.millis(), UNKNOWN);
}
@Override
@@ -163,33 +166,34 @@ public final class BackgroundJobsController extends StateController {
}
private void updateJobRestrictionsLocked(int filterUid, int newActiveState) {
- final UpdateJobFunctor updateTrackedJobs = new UpdateJobFunctor(newActiveState);
+ mUpdateJobFunctor.prepare(newActiveState);
final long start = DEBUG ? SystemClock.elapsedRealtimeNanos() : 0;
final JobStore store = mService.getJobStore();
if (filterUid > 0) {
- store.forEachJobForSourceUid(filterUid, updateTrackedJobs);
+ store.forEachJobForSourceUid(filterUid, mUpdateJobFunctor);
} else {
- store.forEachJob(updateTrackedJobs);
+ store.forEachJob(mUpdateJobFunctor);
}
final long time = DEBUG ? (SystemClock.elapsedRealtimeNanos() - start) : 0;
if (DEBUG) {
Slog.d(TAG, String.format(
"Job status updated: %d/%d checked/total jobs, %d us",
- updateTrackedJobs.mCheckedCount,
- updateTrackedJobs.mTotalCount,
+ mUpdateJobFunctor.mCheckedCount,
+ mUpdateJobFunctor.mTotalCount,
(time / 1000)
- ));
+ ));
}
- if (updateTrackedJobs.mChanged) {
+ if (mUpdateJobFunctor.mChanged) {
mStateChangedListener.onControllerStateChanged();
}
}
- boolean updateSingleJobRestrictionLocked(JobStatus jobStatus, int activeState) {
+ boolean updateSingleJobRestrictionLocked(JobStatus jobStatus, final long nowElapsed,
+ int activeState) {
final int uid = jobStatus.getSourceUid();
final String packageName = jobStatus.getSourcePackageName();
@@ -205,26 +209,32 @@ public final class BackgroundJobsController extends StateController {
if (isActive && jobStatus.getStandbyBucket() == NEVER_INDEX) {
jobStatus.maybeLogBucketMismatch();
}
- boolean didChange = jobStatus.setBackgroundNotRestrictedConstraintSatisfied(canRun);
+ boolean didChange =
+ jobStatus.setBackgroundNotRestrictedConstraintSatisfied(nowElapsed, canRun);
didChange |= jobStatus.setUidActive(isActive);
return didChange;
}
private final class UpdateJobFunctor implements Consumer<JobStatus> {
- final int activeState;
+ int mActiveState;
boolean mChanged = false;
int mTotalCount = 0;
int mCheckedCount = 0;
-
- public UpdateJobFunctor(int newActiveState) {
- activeState = newActiveState;
+ long mUpdateTimeElapsed = 0;
+
+ void prepare(int newActiveState) {
+ mActiveState = newActiveState;
+ mUpdateTimeElapsed = sElapsedRealtimeClock.millis();
+ mChanged = false;
+ mTotalCount = 0;
+ mCheckedCount = 0;
}
@Override
public void accept(JobStatus jobStatus) {
mTotalCount++;
mCheckedCount++;
- if (updateSingleJobRestrictionLocked(jobStatus, activeState)) {
+ if (updateSingleJobRestrictionLocked(jobStatus, mUpdateTimeElapsed, mActiveState)) {
mChanged = true;
}
}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/BatteryController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/BatteryController.java
index 28269c89d13b..6fd094844cd6 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/BatteryController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/BatteryController.java
@@ -65,10 +65,12 @@ public final class BatteryController extends RestrictingController {
@Override
public void maybeStartTrackingJobLocked(JobStatus taskStatus, JobStatus lastJob) {
if (taskStatus.hasPowerConstraint()) {
+ final long nowElapsed = sElapsedRealtimeClock.millis();
mTrackedTasks.add(taskStatus);
taskStatus.setTrackingController(JobStatus.TRACKING_BATTERY);
- taskStatus.setChargingConstraintSatisfied(mChargeTracker.isOnStablePower());
- taskStatus.setBatteryNotLowConstraintSatisfied(mChargeTracker.isBatteryNotLow());
+ taskStatus.setChargingConstraintSatisfied(nowElapsed, mChargeTracker.isOnStablePower());
+ taskStatus.setBatteryNotLowConstraintSatisfied(
+ nowElapsed, mChargeTracker.isBatteryNotLow());
}
}
@@ -97,14 +99,15 @@ public final class BatteryController extends RestrictingController {
if (DEBUG) {
Slog.d(TAG, "maybeReportNewChargingStateLocked: " + stablePower);
}
+ final long nowElapsed = sElapsedRealtimeClock.millis();
boolean reportChange = false;
for (int i = mTrackedTasks.size() - 1; i >= 0; i--) {
final JobStatus ts = mTrackedTasks.valueAt(i);
- boolean previous = ts.setChargingConstraintSatisfied(stablePower);
+ boolean previous = ts.setChargingConstraintSatisfied(nowElapsed, stablePower);
if (previous != stablePower) {
reportChange = true;
}
- previous = ts.setBatteryNotLowConstraintSatisfied(batteryNotLow);
+ previous = ts.setBatteryNotLowConstraintSatisfied(nowElapsed, batteryNotLow);
if (previous != batteryNotLow) {
reportChange = true;
}
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 14484ff441ca..6e542f346f81 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
@@ -20,6 +20,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static com.android.server.job.JobSchedulerService.RESTRICTED_INDEX;
+import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
import android.annotation.Nullable;
import android.app.job.JobInfo;
@@ -461,11 +462,12 @@ public final class ConnectivityController extends RestrictingController implemen
final Network network = mConnManager.getActiveNetworkForUid(
jobStatus.getSourceUid(), jobStatus.shouldIgnoreNetworkBlocking());
final NetworkCapabilities capabilities = getNetworkCapabilities(network);
- return updateConstraintsSatisfied(jobStatus, network, capabilities);
+ return updateConstraintsSatisfied(jobStatus, sElapsedRealtimeClock.millis(),
+ network, capabilities);
}
- private boolean updateConstraintsSatisfied(JobStatus jobStatus, Network network,
- NetworkCapabilities capabilities) {
+ private boolean updateConstraintsSatisfied(JobStatus jobStatus, final long nowElapsed,
+ Network network, NetworkCapabilities capabilities) {
// TODO: consider matching against non-active networks
final boolean ignoreBlocked = jobStatus.shouldIgnoreNetworkBlocking();
@@ -476,7 +478,7 @@ public final class ConnectivityController extends RestrictingController implemen
final boolean satisfied = isSatisfied(jobStatus, network, capabilities, mConstants);
final boolean changed = jobStatus
- .setConnectivityConstraintSatisfied(connected && satisfied);
+ .setConnectivityConstraintSatisfied(nowElapsed, connected && satisfied);
// Pass along the evaluated network for job to use; prevents race
// conditions as default routes change over time, and opens the door to
@@ -530,6 +532,7 @@ public final class ConnectivityController extends RestrictingController implemen
NetworkCapabilities exemptedNetworkCapabilities = null;
boolean exemptedNetworkMatch = false;
+ final long nowElapsed = sElapsedRealtimeClock.millis();
boolean changed = false;
for (int i = jobs.size() - 1; i >= 0; i--) {
final JobStatus js = jobs.valueAt(i);
@@ -555,7 +558,7 @@ public final class ConnectivityController extends RestrictingController implemen
// job hasn't yet been evaluated against the currently
// active network; typically when we just lost a network.
if (match || !Objects.equals(js.network, net)) {
- changed |= updateConstraintsSatisfied(js, net, netCap);
+ changed |= updateConstraintsSatisfied(js, nowElapsed, net, netCap);
}
}
return changed;
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 131a6d4f4791..8b0da3471781 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
@@ -16,6 +16,8 @@
package com.android.server.job.controllers;
+import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
+
import android.annotation.UserIdInt;
import android.app.job.JobInfo;
import android.database.ContentObserver;
@@ -74,6 +76,7 @@ public final class ContentObserverController extends StateController {
@Override
public void maybeStartTrackingJobLocked(JobStatus taskStatus, JobStatus lastJob) {
if (taskStatus.hasContentTriggerConstraint()) {
+ final long nowElapsed = sElapsedRealtimeClock.millis();
if (taskStatus.contentObserverJobInstance == null) {
taskStatus.contentObserverJobInstance = new JobInstance(taskStatus);
}
@@ -110,7 +113,7 @@ public final class ContentObserverController extends StateController {
}
taskStatus.changedAuthorities = null;
taskStatus.changedUris = null;
- taskStatus.setContentTriggerConstraintSatisfied(havePendingUris);
+ taskStatus.setContentTriggerConstraintSatisfied(nowElapsed, havePendingUris);
}
if (lastJob != null && lastJob.contentObserverJobInstance != null) {
// And now we can detach the instance state from the last job.
@@ -295,7 +298,8 @@ public final class ContentObserverController extends StateController {
boolean reportChange = false;
synchronized (mLock) {
if (mTriggerPending) {
- if (mJobStatus.setContentTriggerConstraintSatisfied(true)) {
+ final long nowElapsed = sElapsedRealtimeClock.millis();
+ if (mJobStatus.setContentTriggerConstraintSatisfied(nowElapsed, true)) {
reportChange = true;
}
unscheduleLocked();
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 04b41646b48b..192f5e66255d 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
@@ -16,6 +16,8 @@
package com.android.server.job.controllers;
+import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
+
import android.app.job.JobInfo;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -104,8 +106,10 @@ public final class DeviceIdleJobsController extends StateController {
+ Arrays.toString(mPowerSaveTempWhitelistAppIds));
}
boolean changed = false;
+ final long nowElapsed = sElapsedRealtimeClock.millis();
for (int i = 0; i < mAllowInIdleJobs.size(); i++) {
- changed |= updateTaskStateLocked(mAllowInIdleJobs.valueAt(i));
+ changed |=
+ updateTaskStateLocked(mAllowInIdleJobs.valueAt(i), nowElapsed);
}
if (changed) {
mStateChangedListener.onControllerStateChanged();
@@ -147,6 +151,7 @@ public final class DeviceIdleJobsController extends StateController {
}
mDeviceIdleMode = enabled;
if (DEBUG) Slog.d(TAG, "mDeviceIdleMode=" + mDeviceIdleMode);
+ mDeviceIdleUpdateFunctor.prepare();
if (enabled) {
mHandler.removeMessages(PROCESS_BACKGROUND_JOBS);
mService.getJobStore().forEachJob(mDeviceIdleUpdateFunctor);
@@ -180,7 +185,7 @@ public final class DeviceIdleJobsController extends StateController {
Slog.d(TAG, "uid " + uid + " going " + (active ? "active" : "inactive"));
}
mForegroundUids.put(uid, active);
- mDeviceIdleUpdateFunctor.mChanged = false;
+ mDeviceIdleUpdateFunctor.prepare();
mService.getJobStore().forEachJobForSourceUid(uid, mDeviceIdleUpdateFunctor);
if (mDeviceIdleUpdateFunctor.mChanged) {
mStateChangedListener.onControllerStateChanged();
@@ -203,12 +208,12 @@ public final class DeviceIdleJobsController extends StateController {
UserHandle.getAppId(job.getSourceUid()));
}
- private boolean updateTaskStateLocked(JobStatus task) {
+ private boolean updateTaskStateLocked(JobStatus task, final long nowElapsed) {
final boolean allowInIdle = ((task.getFlags()&JobInfo.FLAG_IMPORTANT_WHILE_FOREGROUND) != 0)
&& (mForegroundUids.get(task.getSourceUid()) || isTempWhitelistedLocked(task));
final boolean whitelisted = isWhitelistedLocked(task);
final boolean enableTask = !mDeviceIdleMode || whitelisted || allowInIdle;
- return task.setDeviceNotDozingConstraintSatisfied(enableTask, whitelisted);
+ return task.setDeviceNotDozingConstraintSatisfied(nowElapsed, enableTask, whitelisted);
}
@Override
@@ -216,7 +221,7 @@ public final class DeviceIdleJobsController extends StateController {
if ((jobStatus.getFlags()&JobInfo.FLAG_IMPORTANT_WHILE_FOREGROUND) != 0) {
mAllowInIdleJobs.add(jobStatus);
}
- updateTaskStateLocked(jobStatus);
+ updateTaskStateLocked(jobStatus, sElapsedRealtimeClock.millis());
}
@Override
@@ -282,10 +287,16 @@ public final class DeviceIdleJobsController extends StateController {
final class DeviceIdleUpdateFunctor implements Consumer<JobStatus> {
boolean mChanged;
+ long mUpdateTimeElapsed = 0;
+
+ void prepare() {
+ mChanged = false;
+ mUpdateTimeElapsed = sElapsedRealtimeClock.millis();
+ }
@Override
public void accept(JobStatus jobStatus) {
- mChanged |= updateTaskStateLocked(jobStatus);
+ mChanged |= updateTaskStateLocked(jobStatus, mUpdateTimeElapsed);
}
}
@@ -300,7 +311,7 @@ public final class DeviceIdleJobsController extends StateController {
case PROCESS_BACKGROUND_JOBS:
// Just process all the jobs, the ones in foreground should already be running.
synchronized (mLock) {
- mDeviceIdleUpdateFunctor.mChanged = false;
+ mDeviceIdleUpdateFunctor.prepare();
mService.getJobStore().forEachJob(mDeviceIdleUpdateFunctor);
if (mDeviceIdleUpdateFunctor.mChanged) {
mStateChangedListener.onControllerStateChanged();
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/IdleController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/IdleController.java
index 2fe827e338e9..e26a3c6962d5 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/IdleController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/IdleController.java
@@ -16,6 +16,8 @@
package com.android.server.job.controllers;
+import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
+
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.UserHandle;
@@ -58,9 +60,10 @@ public final class IdleController extends RestrictingController implements Idlen
@Override
public void maybeStartTrackingJobLocked(JobStatus taskStatus, JobStatus lastJob) {
if (taskStatus.hasIdleConstraint()) {
+ final long nowElapsed = sElapsedRealtimeClock.millis();
mTrackedTasks.add(taskStatus);
taskStatus.setTrackingController(JobStatus.TRACKING_IDLE);
- taskStatus.setIdleConstraintSatisfied(mIdleTracker.isIdle());
+ taskStatus.setIdleConstraintSatisfied(nowElapsed, mIdleTracker.isIdle());
}
}
@@ -90,8 +93,9 @@ public final class IdleController extends RestrictingController implements Idlen
@Override
public void reportNewIdleState(boolean isIdle) {
synchronized (mLock) {
+ final long nowElapsed = sElapsedRealtimeClock.millis();
for (int i = mTrackedTasks.size()-1; i >= 0; i--) {
- mTrackedTasks.valueAt(i).setIdleConstraintSatisfied(isIdle);
+ mTrackedTasks.valueAt(i).setIdleConstraintSatisfied(nowElapsed, isIdle);
}
}
mStateChangedListener.onControllerStateChanged();
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
index 6917fb531ac4..5bdeb38a1424 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
@@ -73,6 +73,8 @@ public final class JobStatus {
private static final String TAG = "JobScheduler.JobStatus";
static final boolean DEBUG = JobSchedulerService.DEBUG;
+ private static final int NUM_CONSTRAINT_CHANGE_HISTORY = 10;
+
public static final long NO_LATEST_RUNTIME = Long.MAX_VALUE;
public static final long NO_EARLIEST_RUNTIME = 0L;
@@ -350,6 +352,10 @@ public final class JobStatus {
*/
private Pair<Long, Long> mPersistedUtcTimes;
+ private int mConstraintChangeHistoryIndex = 0;
+ private final long[] mConstraintUpdatedTimesElapsed = new long[NUM_CONSTRAINT_CHANGE_HISTORY];
+ private final int[] mConstraintStatusHistory = new int[NUM_CONSTRAINT_CHANGE_HISTORY];
+
/**
* For use only by ContentObserverController: state it is maintaining about content URIs
* being observed.
@@ -1090,28 +1096,28 @@ public final class JobStatus {
}
/** @return true if the constraint was changed, false otherwise. */
- boolean setChargingConstraintSatisfied(boolean state) {
- return setConstraintSatisfied(CONSTRAINT_CHARGING, state);
+ boolean setChargingConstraintSatisfied(final long nowElapsed, boolean state) {
+ return setConstraintSatisfied(CONSTRAINT_CHARGING, nowElapsed, state);
}
/** @return true if the constraint was changed, false otherwise. */
- boolean setBatteryNotLowConstraintSatisfied(boolean state) {
- return setConstraintSatisfied(CONSTRAINT_BATTERY_NOT_LOW, state);
+ boolean setBatteryNotLowConstraintSatisfied(final long nowElapsed, boolean state) {
+ return setConstraintSatisfied(CONSTRAINT_BATTERY_NOT_LOW, nowElapsed, state);
}
/** @return true if the constraint was changed, false otherwise. */
- boolean setStorageNotLowConstraintSatisfied(boolean state) {
- return setConstraintSatisfied(CONSTRAINT_STORAGE_NOT_LOW, state);
+ boolean setStorageNotLowConstraintSatisfied(final long nowElapsed, boolean state) {
+ return setConstraintSatisfied(CONSTRAINT_STORAGE_NOT_LOW, nowElapsed, state);
}
/** @return true if the constraint was changed, false otherwise. */
- boolean setTimingDelayConstraintSatisfied(boolean state) {
- return setConstraintSatisfied(CONSTRAINT_TIMING_DELAY, state);
+ boolean setTimingDelayConstraintSatisfied(final long nowElapsed, boolean state) {
+ return setConstraintSatisfied(CONSTRAINT_TIMING_DELAY, nowElapsed, state);
}
/** @return true if the constraint was changed, false otherwise. */
- boolean setDeadlineConstraintSatisfied(boolean state) {
- if (setConstraintSatisfied(CONSTRAINT_DEADLINE, state)) {
+ boolean setDeadlineConstraintSatisfied(final long nowElapsed, boolean state) {
+ if (setConstraintSatisfied(CONSTRAINT_DEADLINE, nowElapsed, state)) {
// The constraint was changed. Update the ready flag.
mReadyDeadlineSatisfied = !job.isPeriodic() && hasDeadlineConstraint() && state;
return true;
@@ -1120,24 +1126,25 @@ public final class JobStatus {
}
/** @return true if the constraint was changed, false otherwise. */
- boolean setIdleConstraintSatisfied(boolean state) {
- return setConstraintSatisfied(CONSTRAINT_IDLE, state);
+ boolean setIdleConstraintSatisfied(final long nowElapsed, boolean state) {
+ return setConstraintSatisfied(CONSTRAINT_IDLE, nowElapsed, state);
}
/** @return true if the constraint was changed, false otherwise. */
- boolean setConnectivityConstraintSatisfied(boolean state) {
- return setConstraintSatisfied(CONSTRAINT_CONNECTIVITY, state);
+ boolean setConnectivityConstraintSatisfied(final long nowElapsed, boolean state) {
+ return setConstraintSatisfied(CONSTRAINT_CONNECTIVITY, nowElapsed, state);
}
/** @return true if the constraint was changed, false otherwise. */
- boolean setContentTriggerConstraintSatisfied(boolean state) {
- return setConstraintSatisfied(CONSTRAINT_CONTENT_TRIGGER, state);
+ boolean setContentTriggerConstraintSatisfied(final long nowElapsed, boolean state) {
+ return setConstraintSatisfied(CONSTRAINT_CONTENT_TRIGGER, nowElapsed, state);
}
/** @return true if the constraint was changed, false otherwise. */
- boolean setDeviceNotDozingConstraintSatisfied(boolean state, boolean whitelisted) {
+ boolean setDeviceNotDozingConstraintSatisfied(final long nowElapsed,
+ boolean state, boolean whitelisted) {
dozeWhitelisted = whitelisted;
- if (setConstraintSatisfied(CONSTRAINT_DEVICE_NOT_DOZING, state)) {
+ if (setConstraintSatisfied(CONSTRAINT_DEVICE_NOT_DOZING, nowElapsed, state)) {
// The constraint was changed. Update the ready flag.
mReadyNotDozing = state || canRunInDoze();
return true;
@@ -1146,8 +1153,8 @@ public final class JobStatus {
}
/** @return true if the constraint was changed, false otherwise. */
- boolean setBackgroundNotRestrictedConstraintSatisfied(boolean state) {
- if (setConstraintSatisfied(CONSTRAINT_BACKGROUND_NOT_RESTRICTED, state)) {
+ boolean setBackgroundNotRestrictedConstraintSatisfied(final long nowElapsed, boolean state) {
+ if (setConstraintSatisfied(CONSTRAINT_BACKGROUND_NOT_RESTRICTED, nowElapsed, state)) {
// The constraint was changed. Update the ready flag.
mReadyNotRestrictedInBg = state;
return true;
@@ -1156,8 +1163,8 @@ public final class JobStatus {
}
/** @return true if the constraint was changed, false otherwise. */
- boolean setQuotaConstraintSatisfied(boolean state) {
- if (setConstraintSatisfied(CONSTRAINT_WITHIN_QUOTA, state)) {
+ boolean setQuotaConstraintSatisfied(final long nowElapsed, boolean state) {
+ if (setConstraintSatisfied(CONSTRAINT_WITHIN_QUOTA, nowElapsed, state)) {
// The constraint was changed. Update the ready flag.
mReadyWithinQuota = state;
return true;
@@ -1166,8 +1173,8 @@ public final class JobStatus {
}
/** @return true if the constraint was changed, false otherwise. */
- boolean setExpeditedJobQuotaConstraintSatisfied(boolean state) {
- if (setConstraintSatisfied(CONSTRAINT_WITHIN_EXPEDITED_QUOTA, state)) {
+ boolean setExpeditedJobQuotaConstraintSatisfied(final long nowElapsed, boolean state) {
+ if (setConstraintSatisfied(CONSTRAINT_WITHIN_EXPEDITED_QUOTA, nowElapsed, state)) {
// The constraint was changed. Update the ready flag.
mReadyWithinExpeditedQuota = state;
// DeviceIdleJobsController currently only tracks jobs with the WILL_BE_FOREGROUND flag.
@@ -1190,7 +1197,7 @@ public final class JobStatus {
}
/** @return true if the constraint was changed, false otherwise. */
- boolean setConstraintSatisfied(int constraint, boolean state) {
+ boolean setConstraintSatisfied(int constraint, final long nowElapsed, boolean state) {
boolean old = (satisfiedConstraints&constraint) != 0;
if (old == state) {
return false;
@@ -1212,6 +1219,12 @@ public final class JobStatus {
: FrameworkStatsLog
.SCHEDULED_JOB_CONSTRAINT_CHANGED__STATE__UNSATISFIED);
}
+
+ mConstraintUpdatedTimesElapsed[mConstraintChangeHistoryIndex] = nowElapsed;
+ mConstraintStatusHistory[mConstraintChangeHistoryIndex] = satisfiedConstraints;
+ mConstraintChangeHistoryIndex =
+ (mConstraintChangeHistoryIndex + 1) % NUM_CONSTRAINT_CHANGE_HISTORY;
+
return true;
}
@@ -1700,7 +1713,7 @@ public final class JobStatus {
}
// Dumpsys infrastructure
- public void dump(IndentingPrintWriter pw, boolean full, long elapsedRealtimeMillis) {
+ public void dump(IndentingPrintWriter pw, boolean full, long nowElapsed) {
UserHandle.formatUid(pw, callingUid);
pw.print(" tag="); pw.println(tag);
@@ -1830,6 +1843,22 @@ public final class JobStatus {
dumpConstraints(pw,
((requiredConstraints | CONSTRAINT_WITHIN_QUOTA) & ~satisfiedConstraints));
pw.println();
+
+ pw.println("Constraint history:");
+ pw.increaseIndent();
+ for (int h = 0; h < NUM_CONSTRAINT_CHANGE_HISTORY; ++h) {
+ final int idx = (h + mConstraintChangeHistoryIndex) % NUM_CONSTRAINT_CHANGE_HISTORY;
+ if (mConstraintUpdatedTimesElapsed[idx] == 0) {
+ continue;
+ }
+ TimeUtils.formatDuration(mConstraintUpdatedTimesElapsed[idx], nowElapsed, pw);
+ // dumpConstraints prepends with a space, so no need to add a space after the =
+ pw.print(" =");
+ dumpConstraints(pw, mConstraintStatusHistory[idx]);
+ pw.println();
+ }
+ pw.decreaseIndent();
+
if (dozeWhitelisted) {
pw.println("Doze whitelisted: true");
}
@@ -1910,26 +1939,25 @@ public final class JobStatus {
pw.increaseIndent();
if (whenStandbyDeferred != 0) {
pw.print("Deferred since: ");
- TimeUtils.formatDuration(whenStandbyDeferred, elapsedRealtimeMillis, pw);
+ TimeUtils.formatDuration(whenStandbyDeferred, nowElapsed, pw);
pw.println();
}
if (mFirstForceBatchedTimeElapsed != 0) {
pw.print("Time since first force batch attempt: ");
- TimeUtils.formatDuration(mFirstForceBatchedTimeElapsed, elapsedRealtimeMillis, pw);
+ TimeUtils.formatDuration(mFirstForceBatchedTimeElapsed, nowElapsed, pw);
pw.println();
}
pw.decreaseIndent();
pw.print("Enqueue time: ");
- TimeUtils.formatDuration(enqueueTime, elapsedRealtimeMillis, pw);
+ TimeUtils.formatDuration(enqueueTime, nowElapsed, pw);
pw.println();
pw.print("Run time: earliest=");
- formatRunTime(pw, earliestRunTimeElapsedMillis, NO_EARLIEST_RUNTIME, elapsedRealtimeMillis);
+ formatRunTime(pw, earliestRunTimeElapsedMillis, NO_EARLIEST_RUNTIME, nowElapsed);
pw.print(", latest=");
- formatRunTime(pw, latestRunTimeElapsedMillis, NO_LATEST_RUNTIME, elapsedRealtimeMillis);
+ formatRunTime(pw, latestRunTimeElapsedMillis, NO_LATEST_RUNTIME, nowElapsed);
pw.print(", original latest=");
- formatRunTime(pw, mOriginalLatestRunTimeElapsedMillis,
- NO_LATEST_RUNTIME, elapsedRealtimeMillis);
+ formatRunTime(pw, mOriginalLatestRunTimeElapsedMillis, NO_LATEST_RUNTIME, nowElapsed);
pw.println();
if (numFailures != 0) {
pw.print("Num failures: "); pw.println(numFailures);
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 2196b16e0846..824fa7fc1659 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
@@ -626,6 +626,7 @@ public final class QuotaController extends StateController {
@Override
public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) {
+ final long nowElapsed = sElapsedRealtimeClock.millis();
final int userId = jobStatus.getSourceUserId();
final String pkgName = jobStatus.getSourcePackageName();
ArraySet<JobStatus> jobs = mTrackedJobs.get(userId, pkgName);
@@ -636,11 +637,11 @@ public final class QuotaController extends StateController {
jobs.add(jobStatus);
jobStatus.setTrackingController(JobStatus.TRACKING_QUOTA);
final boolean isWithinQuota = isWithinQuotaLocked(jobStatus);
- setConstraintSatisfied(jobStatus, isWithinQuota);
+ setConstraintSatisfied(jobStatus, nowElapsed, isWithinQuota);
final boolean outOfEJQuota;
if (jobStatus.isRequestedExpeditedJob()) {
final boolean isWithinEJQuota = isWithinEJQuotaLocked(jobStatus);
- setExpeditedConstraintSatisfied(jobStatus, isWithinEJQuota);
+ setExpeditedConstraintSatisfied(jobStatus, nowElapsed, isWithinEJQuota);
outOfEJQuota = !isWithinEJQuota;
} else {
outOfEJQuota = false;
@@ -1397,7 +1398,8 @@ public final class QuotaController extends StateController {
synchronized (mLock) {
final ShrinkableDebits quota = getEJQuotaLocked(userId, packageName);
quota.transactOnDebitsLocked(-credit);
- if (maybeUpdateConstraintForPkgLocked(userId, packageName)) {
+ if (maybeUpdateConstraintForPkgLocked(sElapsedRealtimeClock.millis(),
+ userId, packageName)) {
mStateChangedListener.onControllerStateChanged();
}
}
@@ -1499,11 +1501,12 @@ public final class QuotaController extends StateController {
private void maybeUpdateAllConstraintsLocked() {
boolean changed = false;
+ final long nowElapsed = sElapsedRealtimeClock.millis();
for (int u = 0; u < mTrackedJobs.numMaps(); ++u) {
final int userId = mTrackedJobs.keyAt(u);
for (int p = 0; p < mTrackedJobs.numElementsForKey(userId); ++p) {
final String packageName = mTrackedJobs.keyAt(u, p);
- changed |= maybeUpdateConstraintForPkgLocked(userId, packageName);
+ changed |= maybeUpdateConstraintForPkgLocked(nowElapsed, userId, packageName);
}
}
if (changed) {
@@ -1516,7 +1519,7 @@ public final class QuotaController extends StateController {
*
* @return true if at least one job had its bit changed
*/
- private boolean maybeUpdateConstraintForPkgLocked(final int userId,
+ private boolean maybeUpdateConstraintForPkgLocked(final long nowElapsed, final int userId,
@NonNull final String packageName) {
ArraySet<JobStatus> jobs = mTrackedJobs.get(userId, packageName);
if (jobs == null || jobs.size() == 0) {
@@ -1533,21 +1536,21 @@ public final class QuotaController extends StateController {
if (isTopStartedJobLocked(js)) {
// Job was started while the app was in the TOP state so we should allow it to
// finish.
- changed |= js.setQuotaConstraintSatisfied(true);
+ changed |= js.setQuotaConstraintSatisfied(nowElapsed, true);
} else if (realStandbyBucket != ACTIVE_INDEX
&& realStandbyBucket == js.getEffectiveStandbyBucket()) {
// An app in the ACTIVE bucket may be out of quota while the job could be in quota
// for some reason. Therefore, avoid setting the real value here and check each job
// individually.
- changed |= setConstraintSatisfied(js, realInQuota);
+ changed |= setConstraintSatisfied(js, nowElapsed, realInQuota);
} else {
// This job is somehow exempted. Need to determine its own quota status.
- changed |= setConstraintSatisfied(js, isWithinQuotaLocked(js));
+ changed |= setConstraintSatisfied(js, nowElapsed, isWithinQuotaLocked(js));
}
if (js.isRequestedExpeditedJob()) {
boolean isWithinEJQuota = isWithinEJQuotaLocked(js);
- changed |= setExpeditedConstraintSatisfied(js, isWithinEJQuota);
+ changed |= setExpeditedConstraintSatisfied(js, nowElapsed, isWithinEJQuota);
outOfEJQuota |= !isWithinEJQuota;
}
}
@@ -1566,14 +1569,21 @@ public final class QuotaController extends StateController {
private final SparseArrayMap<String, Integer> mToScheduleStartAlarms =
new SparseArrayMap<>();
public boolean wasJobChanged;
+ long mUpdateTimeElapsed = 0;
+
+ void prepare() {
+ mUpdateTimeElapsed = sElapsedRealtimeClock.millis();
+ }
@Override
public void accept(JobStatus jobStatus) {
- wasJobChanged |= setConstraintSatisfied(jobStatus, isWithinQuotaLocked(jobStatus));
+ wasJobChanged |= setConstraintSatisfied(
+ jobStatus, mUpdateTimeElapsed, isWithinQuotaLocked(jobStatus));
final boolean outOfEJQuota;
if (jobStatus.isRequestedExpeditedJob()) {
final boolean isWithinEJQuota = isWithinEJQuotaLocked(jobStatus);
- wasJobChanged |= setExpeditedConstraintSatisfied(jobStatus, isWithinEJQuota);
+ wasJobChanged |= setExpeditedConstraintSatisfied(
+ jobStatus, mUpdateTimeElapsed, isWithinEJQuota);
outOfEJQuota = !isWithinEJQuota;
} else {
outOfEJQuota = false;
@@ -1611,6 +1621,7 @@ public final class QuotaController extends StateController {
private final UidConstraintUpdater mUpdateUidConstraints = new UidConstraintUpdater();
private boolean maybeUpdateConstraintForUidLocked(final int uid) {
+ mUpdateUidConstraints.prepare();
mService.getJobStore().forEachJobForSourceUid(uid, mUpdateUidConstraints);
mUpdateUidConstraints.postProcess();
@@ -1716,21 +1727,22 @@ public final class QuotaController extends StateController {
mInQuotaAlarmListener.addAlarmLocked(userId, packageName, inQuotaTimeElapsed);
}
- private boolean setConstraintSatisfied(@NonNull JobStatus jobStatus, boolean isWithinQuota) {
+ private boolean setConstraintSatisfied(@NonNull JobStatus jobStatus, long nowElapsed,
+ boolean isWithinQuota) {
if (!isWithinQuota && jobStatus.getWhenStandbyDeferred() == 0) {
// Mark that the job is being deferred due to buckets.
- jobStatus.setWhenStandbyDeferred(sElapsedRealtimeClock.millis());
+ jobStatus.setWhenStandbyDeferred(nowElapsed);
}
- return jobStatus.setQuotaConstraintSatisfied(isWithinQuota);
+ return jobStatus.setQuotaConstraintSatisfied(nowElapsed, isWithinQuota);
}
/**
* If the satisfaction changes, this will tell connectivity & background jobs controller to
* also re-evaluate their state.
*/
- private boolean setExpeditedConstraintSatisfied(@NonNull JobStatus jobStatus,
+ private boolean setExpeditedConstraintSatisfied(@NonNull JobStatus jobStatus, long nowElapsed,
boolean isWithinQuota) {
- if (jobStatus.setExpeditedJobQuotaConstraintSatisfied(isWithinQuota)) {
+ if (jobStatus.setExpeditedJobQuotaConstraintSatisfied(nowElapsed, isWithinQuota)) {
mBackgroundJobsController.evaluateStateLocked(jobStatus);
mConnectivityController.evaluateStateLocked(jobStatus);
if (isWithinQuota && jobStatus.isReady()) {
@@ -2188,7 +2200,8 @@ public final class QuotaController extends StateController {
final ShrinkableDebits quota =
getEJQuotaLocked(mPkg.userId, mPkg.packageName);
quota.transactOnDebitsLocked(-mEJRewardTopAppMs * numTimeChunks);
- if (maybeUpdateConstraintForPkgLocked(mPkg.userId, mPkg.packageName)) {
+ if (maybeUpdateConstraintForPkgLocked(nowElapsed,
+ mPkg.userId, mPkg.packageName)) {
mStateChangedListener.onControllerStateChanged();
}
}
@@ -2292,7 +2305,8 @@ public final class QuotaController extends StateController {
if (timer != null && timer.isActive()) {
timer.rescheduleCutoff();
}
- if (maybeUpdateConstraintForPkgLocked(userId, packageName)) {
+ if (maybeUpdateConstraintForPkgLocked(sElapsedRealtimeClock.millis(),
+ userId, packageName)) {
mStateChangedListener.onControllerStateChanged();
}
}
@@ -2417,7 +2431,8 @@ public final class QuotaController extends StateController {
if (timeRemainingMs <= 50) {
// Less than 50 milliseconds left. Start process of shutting down jobs.
if (DEBUG) Slog.d(TAG, pkg + " has reached its quota.");
- if (maybeUpdateConstraintForPkgLocked(pkg.userId, pkg.packageName)) {
+ if (maybeUpdateConstraintForPkgLocked(sElapsedRealtimeClock.millis(),
+ pkg.userId, pkg.packageName)) {
mStateChangedListener.onControllerStateChanged();
}
} else {
@@ -2444,7 +2459,8 @@ public final class QuotaController extends StateController {
pkg.userId, pkg.packageName);
if (timeRemainingMs <= 0) {
if (DEBUG) Slog.d(TAG, pkg + " has reached its EJ quota.");
- if (maybeUpdateConstraintForPkgLocked(pkg.userId, pkg.packageName)) {
+ if (maybeUpdateConstraintForPkgLocked(sElapsedRealtimeClock.millis(),
+ pkg.userId, pkg.packageName)) {
mStateChangedListener.onControllerStateChanged();
}
} else {
@@ -2475,7 +2491,8 @@ public final class QuotaController extends StateController {
if (DEBUG) {
Slog.d(TAG, "Checking pkg " + string(userId, packageName));
}
- if (maybeUpdateConstraintForPkgLocked(userId, packageName)) {
+ if (maybeUpdateConstraintForPkgLocked(sElapsedRealtimeClock.millis(),
+ userId, packageName)) {
mStateChangedListener.onControllerStateChanged();
}
break;
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/StorageController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/StorageController.java
index 0731918d83a1..867891363912 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/StorageController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/StorageController.java
@@ -61,9 +61,11 @@ public final class StorageController extends StateController {
@Override
public void maybeStartTrackingJobLocked(JobStatus taskStatus, JobStatus lastJob) {
if (taskStatus.hasStorageNotLowConstraint()) {
+ final long nowElapsed = sElapsedRealtimeClock.millis();
mTrackedTasks.add(taskStatus);
taskStatus.setTrackingController(JobStatus.TRACKING_STORAGE);
- taskStatus.setStorageNotLowConstraintSatisfied(mStorageTracker.isStorageNotLow());
+ taskStatus.setStorageNotLowConstraintSatisfied(
+ nowElapsed, mStorageTracker.isStorageNotLow());
}
}
@@ -76,12 +78,13 @@ public final class StorageController extends StateController {
}
private void maybeReportNewStorageState() {
+ final long nowElapsed = sElapsedRealtimeClock.millis();
final boolean storageNotLow = mStorageTracker.isStorageNotLow();
boolean reportChange = false;
synchronized (mLock) {
for (int i = mTrackedTasks.size() - 1; i >= 0; i--) {
final JobStatus ts = mTrackedTasks.valueAt(i);
- reportChange |= ts.setStorageNotLowConstraintSatisfied(storageNotLow);
+ reportChange |= ts.setStorageNotLowConstraintSatisfied(nowElapsed, storageNotLow);
}
}
if (storageNotLow) {
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/TimeController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/TimeController.java
index ede14ec06c71..e8ebfb53fde8 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/TimeController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/TimeController.java
@@ -258,9 +258,9 @@ public final class TimeController extends StateController {
if (jobDeadline <= nowElapsedMillis) {
if (job.hasTimingDelayConstraint()) {
- job.setTimingDelayConstraintSatisfied(true);
+ job.setTimingDelayConstraintSatisfied(nowElapsedMillis, true);
}
- job.setDeadlineConstraintSatisfied(true);
+ job.setDeadlineConstraintSatisfied(nowElapsedMillis, true);
return true;
}
return false;
@@ -332,7 +332,7 @@ public final class TimeController extends StateController {
private boolean evaluateTimingDelayConstraint(JobStatus job, long nowElapsedMillis) {
final long jobDelayTime = job.getEarliestRunTime();
if (jobDelayTime <= nowElapsedMillis) {
- job.setTimingDelayConstraintSatisfied(true);
+ job.setTimingDelayConstraintSatisfied(nowElapsedMillis, true);
return true;
}
return false;
diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp
index 5c08704a6623..d4da5e554591 100644
--- a/cmds/screencap/screencap.cpp
+++ b/cmds/screencap/screencap.cpp
@@ -34,7 +34,6 @@
#include <gui/SurfaceComposerClient.h>
#include <gui/SyncScreenCaptureListener.h>
-#include <ui/DisplayInfo.h>
#include <ui/GraphicTypes.h>
#include <ui/PixelFormat.h>
diff --git a/core/api/current.txt b/core/api/current.txt
index 4382b3207e1e..dddca3e58b0d 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -14615,11 +14615,6 @@ package android.graphics {
enum_constant public static final android.graphics.BlurMaskFilter.Blur SOLID;
}
- public final class BlurShader extends android.graphics.Shader {
- ctor public BlurShader(float, float, @Nullable android.graphics.Shader);
- ctor public BlurShader(float, float, @Nullable android.graphics.Shader, @NonNull android.graphics.Shader.TileMode);
- }
-
public class Camera {
ctor public Camera();
method public void applyToCanvas(android.graphics.Canvas);
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 7b7518d05345..fbe24c43f027 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -8580,7 +8580,7 @@ package android.os {
method @RequiresPermission(allOf={android.Manifest.permission.READ_DREAM_STATE, android.Manifest.permission.WRITE_DREAM_STATE}) public void dream(long);
method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public boolean forceSuspend();
method @NonNull public android.os.BatterySaverPolicyConfig getFullPowerSavePolicy();
- method @RequiresPermission(android.Manifest.permission.POWER_SAVER) public int getPowerSaveModeTrigger();
+ method public int getPowerSaveModeTrigger();
method @RequiresPermission(android.Manifest.permission.READ_DREAM_STATE) public boolean isAmbientDisplayAvailable();
method @RequiresPermission(android.Manifest.permission.READ_DREAM_STATE) public boolean isAmbientDisplaySuppressed();
method @RequiresPermission(android.Manifest.permission.READ_DREAM_STATE) public boolean isAmbientDisplaySuppressedForToken(@NonNull String);
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index e0e84537368f..d7b43c0bc48e 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -1640,6 +1640,7 @@ package android.os.storage {
public class StorageManager {
method @NonNull public static java.util.UUID convert(@NonNull String);
method @NonNull public static String convert(@NonNull java.util.UUID);
+ method public static boolean isUserKeyUnlocked(int);
}
public final class StorageVolume implements android.os.Parcelable {
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 1906ee4d85d2..b8735c731817 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -6553,14 +6553,15 @@ public class AppOpsManager {
public interface OnOpNotedListener {
/**
* Called when an op was noted.
- *
* @param code The op code.
* @param uid The UID performing the operation.
* @param packageName The package performing the operation.
+ * @param attributionTag The attribution tag performing the operation.
* @param flags The flags of this op
* @param result The result of the note.
*/
- void onOpNoted(int code, int uid, String packageName, @OpFlags int flags, @Mode int result);
+ void onOpNoted(int code, int uid, String packageName, String attributionTag,
+ @OpFlags int flags, @Mode int result);
}
/**
@@ -6593,14 +6594,15 @@ public class AppOpsManager {
* Called when an op was started.
*
* Note: This is only for op starts. It is not called when an op is noted or stopped.
- *
* @param op The op code.
* @param uid The UID performing the operation.
* @param packageName The package performing the operation.
+ * @param attributionTag The attribution tag performing the operation.
* @param flags The flags of this op
* @param result The result of the start.
*/
- void onOpStarted(int op, int uid, String packageName, @OpFlags int flags, @Mode int result);
+ void onOpStarted(int op, int uid, String packageName, String attributionTag,
+ @OpFlags int flags, @Mode int result);
}
AppOpsManager(Context context, IAppOpsService service) {
@@ -7183,8 +7185,9 @@ public class AppOpsManager {
}
cb = new IAppOpsStartedCallback.Stub() {
@Override
- public void opStarted(int op, int uid, String packageName, int flags, int mode) {
- callback.onOpStarted(op, uid, packageName, flags, mode);
+ public void opStarted(int op, int uid, String packageName, String attributionTag,
+ int flags, int mode) {
+ callback.onOpStarted(op, uid, packageName, attributionTag, flags, mode);
}
};
mStartedWatchers.put(callback, cb);
@@ -7250,8 +7253,9 @@ public class AppOpsManager {
}
cb = new IAppOpsNotedCallback.Stub() {
@Override
- public void opNoted(int op, int uid, String packageName, int flags, int mode) {
- callback.onOpNoted(op, uid, packageName, flags, mode);
+ public void opNoted(int op, int uid, String packageName, String attributionTag,
+ int flags, int mode) {
+ callback.onOpNoted(op, uid, packageName, attributionTag, flags, mode);
}
};
mNotedWatchers.put(callback, cb);
diff --git a/core/java/android/app/time/ExternalTimeSuggestion.java b/core/java/android/app/time/ExternalTimeSuggestion.java
index b566eab9867d..61defb588170 100644
--- a/core/java/android/app/time/ExternalTimeSuggestion.java
+++ b/core/java/android/app/time/ExternalTimeSuggestion.java
@@ -16,6 +16,8 @@
package android.app.time;
+import android.annotation.CurrentTimeMillisLong;
+import android.annotation.ElapsedRealtimeLong;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Parcel;
@@ -31,9 +33,9 @@ import java.util.Objects;
/**
* A time signal from an External source.
*
- * External time suggestions are for use in situations where the Android device is part of a wider
- * network of devices that are required to use a single time source, and where authority for the
- * time is external to the Android device. For example, for the Android Auto use case where the
+ * <p>External time suggestions are for use in situations where the Android device is part of a
+ * wider network of devices that are required to use a single time source, and where authority for
+ * the time is external to the Android device. For example, for the Android Auto use case where the
* Android device is part of a wider in-car network of devices that should display the same time.
*
* <p>Android allows for a single external source for time. If there are several external sources
@@ -49,19 +51,19 @@ import java.util.Objects;
* capture the elapsed realtime reference clock, e.g. via {@link SystemClock#elapsedRealtime()},
* when the UTC time is first obtained (usually under a wakelock). This enables Android to adjust
* for latency introduced between suggestion creation and eventual use. Adjustments for other
- * sources of latency, i.e. those before the external time suggestion is created, must be handled
- * by the creator.
+ * sources of latency, i.e. those before the external time suggestion is created, must be handled by
+ * the creator.
*
- * <p>{@code utcTime} is the suggested time. The {@code utcTime.value} is the number of milliseconds
- * elapsed since 1/1/1970 00:00:00 UTC. The {@code utcTime.referenceTimeMillis} is the value of the
- * elapsed realtime clock when the {@code utcTime.value} was established.
- * Note that the elapsed realtime clock is considered accurate but it is volatile, so time
- * suggestions cannot be persisted across device resets.
+ * <p>{@code elapsedRealtimeMillis} and {@code suggestionMillis} represent the suggested time.
+ * {@code suggestionMillis} is the number of milliseconds elapsed since 1/1/1970 00:00:00 UTC.
+ * {@code elapsedRealtimeMillis} is the value of the elapsed realtime clock when {@code
+ * suggestionMillis} was established. Note that the elapsed realtime clock is considered accurate
+ * but it is volatile, so time suggestions cannot be persisted across device resets.
*
* <p>{@code debugInfo} contains debugging metadata associated with the suggestion. This is used to
* record why the suggestion exists and how it was entered. This information exists only to aid in
- * debugging and therefore is used by {@link #toString()}, but it is not for use in detection
- * logic and is not considered in {@link #hashCode()} or {@link #equals(Object)}.
+ * debugging and therefore is used by {@link #toString()}, but it is not for use in detection logic
+ * and is not considered in {@link #hashCode()} or {@link #equals(Object)}.
*
* @hide
*/
@@ -78,17 +80,28 @@ public final class ExternalTimeSuggestion implements Parcelable {
}
};
- @NonNull private final TimestampedValue<Long> mUtcTime;
- @Nullable private ArrayList<String> mDebugInfo;
+ @NonNull
+ private final TimestampedValue<Long> mUtcTime;
+ @Nullable
+ private ArrayList<String> mDebugInfo;
- public ExternalTimeSuggestion(@NonNull TimestampedValue<Long> utcTime) {
- mUtcTime = Objects.requireNonNull(utcTime);
- Objects.requireNonNull(utcTime.getValue());
+ /**
+ * Creates a time suggestion cross-referenced to the elapsed realtime clock. See {@link
+ * ExternalTimeSuggestion} for more details.
+ *
+ * @param elapsedRealtimeMillis the elapsed realtime clock reference for the suggestion
+ * @param suggestionMillis the suggested UTC time in milliseconds since the start of the
+ * Unix epoch
+ */
+ public ExternalTimeSuggestion(@ElapsedRealtimeLong long elapsedRealtimeMillis,
+ @CurrentTimeMillisLong long suggestionMillis) {
+ mUtcTime = new TimestampedValue(elapsedRealtimeMillis, suggestionMillis);
}
private static ExternalTimeSuggestion createFromParcel(Parcel in) {
TimestampedValue<Long> utcTime = in.readParcelable(null /* classLoader */);
- ExternalTimeSuggestion suggestion = new ExternalTimeSuggestion(utcTime);
+ ExternalTimeSuggestion suggestion =
+ new ExternalTimeSuggestion(utcTime.getReferenceTimeMillis(), utcTime.getValue());
@SuppressWarnings("unchecked")
ArrayList<String> debugInfo = (ArrayList<String>) in.readArrayList(null /* classLoader */);
suggestion.mDebugInfo = debugInfo;
@@ -106,23 +119,31 @@ public final class ExternalTimeSuggestion implements Parcelable {
dest.writeList(mDebugInfo);
}
+ /**
+ * {@hide}
+ */
@NonNull
public TimestampedValue<Long> getUtcTime() {
return mUtcTime;
}
+ /**
+ * Returns information that can be useful for debugging / logging. See {@link #addDebugInfo}.
+ * {@hide}
+ */
@NonNull
public List<String> getDebugInfo() {
return mDebugInfo == null
- ? Collections.emptyList() : Collections.unmodifiableList(mDebugInfo);
+ ? Collections.emptyList()
+ : Collections.unmodifiableList(mDebugInfo);
}
/**
* Associates information with the instance that can be useful for debugging / logging. The
- * information is present in {@link #toString()} but is not considered for
- * {@link #equals(Object)} and {@link #hashCode()}.
+ * information is present in {@link #toString()} but is not considered for {@link
+ * #equals(Object)} and {@link #hashCode()}.
*/
- public void addDebugInfo(String... debugInfos) {
+ public void addDebugInfo(@NonNull String... debugInfos) {
if (mDebugInfo == null) {
mDebugInfo = new ArrayList<>();
}
@@ -148,9 +169,7 @@ public final class ExternalTimeSuggestion implements Parcelable {
@Override
public String toString() {
- return "ExternalTimeSuggestion{"
- + "mUtcTime=" + mUtcTime
- + ", mDebugInfo=" + mDebugInfo
+ return "ExternalTimeSuggestion{" + "mUtcTime=" + mUtcTime + ", mDebugInfo=" + mDebugInfo
+ '}';
}
}
diff --git a/core/java/android/app/time/TimeManager.java b/core/java/android/app/time/TimeManager.java
index 262d244c5b1c..430960fb11a8 100644
--- a/core/java/android/app/time/TimeManager.java
+++ b/core/java/android/app/time/TimeManager.java
@@ -20,6 +20,7 @@ import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
+import android.app.timedetector.ITimeDetectorService;
import android.app.timezonedetector.ITimeZoneDetectorService;
import android.content.Context;
import android.os.RemoteException;
@@ -45,6 +46,7 @@ public final class TimeManager {
private final Object mLock = new Object();
private final ITimeZoneDetectorService mITimeZoneDetectorService;
+ private final ITimeDetectorService mITimeDetectorService;
@GuardedBy("mLock")
private ITimeZoneDetectorListener mTimeZoneDetectorReceiver;
@@ -62,6 +64,8 @@ public final class TimeManager {
// internal refactoring.
mITimeZoneDetectorService = ITimeZoneDetectorService.Stub.asInterface(
ServiceManager.getServiceOrThrow(Context.TIME_ZONE_DETECTOR_SERVICE));
+ mITimeDetectorService = ITimeDetectorService.Stub.asInterface(
+ ServiceManager.getServiceOrThrow(Context.TIME_DETECTOR_SERVICE));
}
/**
@@ -214,4 +218,23 @@ public final class TimeManager {
}
}
}
+
+ /**
+ * Suggests the current time from an external time source. For example, a form factor-specific
+ * HAL. This time <em>may</em> be used to set the device system clock, depending on the device
+ * configuration and user settings. This method call is processed asynchronously.
+ * See {@link ExternalTimeSuggestion} for more details.
+ * {@hide}
+ */
+ @RequiresPermission(android.Manifest.permission.SET_TIME)
+ public void suggestExternalTime(@NonNull ExternalTimeSuggestion timeSuggestion) {
+ if (DEBUG) {
+ Log.d(TAG, "suggestExternalTime called: " + timeSuggestion);
+ }
+ try {
+ mITimeDetectorService.suggestExternalTime(timeSuggestion);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/app/timedetector/TimeDetector.java b/core/java/android/app/timedetector/TimeDetector.java
index 76f378590ae2..52016b65688b 100644
--- a/core/java/android/app/timedetector/TimeDetector.java
+++ b/core/java/android/app/timedetector/TimeDetector.java
@@ -19,7 +19,6 @@ package android.app.timedetector;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.SystemService;
-import android.app.time.ExternalTimeSuggestion;
import android.content.Context;
import android.os.SystemClock;
import android.os.TimestampedValue;
@@ -80,12 +79,4 @@ public interface TimeDetector {
*/
@RequiresPermission(android.Manifest.permission.SET_TIME)
void suggestGnssTime(GnssTimeSuggestion timeSuggestion);
-
- /**
- * Suggests the time according to an external time source (form factor specific HAL, etc).
- *
- * @hide
- */
- @RequiresPermission(android.Manifest.permission.SET_TIME)
- void suggestExternalTime(ExternalTimeSuggestion timeSuggestion);
}
diff --git a/core/java/android/app/timedetector/TimeDetectorImpl.java b/core/java/android/app/timedetector/TimeDetectorImpl.java
index ef818ef647d6..b0aa3c8d4575 100644
--- a/core/java/android/app/timedetector/TimeDetectorImpl.java
+++ b/core/java/android/app/timedetector/TimeDetectorImpl.java
@@ -17,7 +17,6 @@
package android.app.timedetector;
import android.annotation.NonNull;
-import android.app.time.ExternalTimeSuggestion;
import android.content.Context;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -87,16 +86,4 @@ public final class TimeDetectorImpl implements TimeDetector {
throw e.rethrowFromSystemServer();
}
}
-
- @Override
- public void suggestExternalTime(ExternalTimeSuggestion timeSuggestion) {
- if (DEBUG) {
- Log.d(TAG, "suggestExternalTime called: " + timeSuggestion);
- }
- try {
- mITimeDetectorService.suggestExternalTime(timeSuggestion);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
}
diff --git a/core/java/android/content/pm/dex/DexMetadataHelper.java b/core/java/android/content/pm/dex/DexMetadataHelper.java
index bc5d14a533e2..0d5b33cd8672 100644
--- a/core/java/android/content/pm/dex/DexMetadataHelper.java
+++ b/core/java/android/content/pm/dex/DexMetadataHelper.java
@@ -24,16 +24,16 @@ import android.content.pm.parsing.ApkLiteParseUtils;
import android.content.pm.parsing.PackageLite;
import android.os.SystemProperties;
import android.util.ArrayMap;
-import android.util.jar.StrictJarFile;
import android.util.JsonReader;
import android.util.Log;
+import android.util.jar.StrictJarFile;
import com.android.internal.annotations.VisibleForTesting;
import java.io.File;
+import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
-import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.file.Files;
import java.nio.file.Paths;
@@ -53,7 +53,10 @@ public class DexMetadataHelper {
/** $> adb shell 'setprop log.tag.DexMetadataHelper VERBOSE' */
public static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
/** $> adb shell 'setprop pm.dexopt.dm.require_manifest true' */
- private static String PROPERTY_DM_JSON_MANIFEST_REQUIRED = "pm.dexopt.dm.require_manifest";
+ private static final String PROPERTY_DM_JSON_MANIFEST_REQUIRED =
+ "pm.dexopt.dm.require_manifest";
+ /** $> adb shell 'setprop pm.dexopt.dm.require_fsverity true' */
+ private static final String PROPERTY_DM_FSVERITY_REQUIRED = "pm.dexopt.dm.require_fsverity";
private static final String DEX_METADATA_FILE_EXTENSION = ".dm";
@@ -70,6 +73,13 @@ public class DexMetadataHelper {
}
/**
+ * Returns whether fs-verity is required to install a dex metadata
+ */
+ public static boolean isFsVerityRequired() {
+ return SystemProperties.getBoolean(PROPERTY_DM_FSVERITY_REQUIRED, false);
+ }
+
+ /**
* Return the size (in bytes) of all dex metadata files associated with the given package.
*/
public static long getPackageDexMetadataSize(PackageLite pkg) {
diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java
index 1ffd18fc1ac8..788afe3bdb8e 100644
--- a/core/java/android/hardware/SystemSensorManager.java
+++ b/core/java/android/hardware/SystemSensorManager.java
@@ -667,7 +667,7 @@ public class SystemSensorManager extends SensorManager {
private abstract static class BaseEventQueue {
private static native long nativeInitBaseEventQueue(long nativeManager,
WeakReference<BaseEventQueue> eventQWeak, MessageQueue msgQ,
- String packageName, int mode, String opPackageName);
+ String packageName, int mode, String opPackageName, String attributionTag);
private static native int nativeEnableSensor(long eventQ, int handle, int rateUs,
int maxBatchReportLatencyUs);
private static native int nativeDisableSensor(long eventQ, int handle);
@@ -689,7 +689,8 @@ public class SystemSensorManager extends SensorManager {
if (packageName == null) packageName = "";
mNativeSensorEventQueue = nativeInitBaseEventQueue(manager.mNativeInstance,
new WeakReference<>(this), looper.getQueue(),
- packageName, mode, manager.mContext.getOpPackageName());
+ packageName, mode, manager.mContext.getOpPackageName(),
+ manager.mContext.getAttributionTag());
mCloseGuard.open("dispose");
mManager = manager;
}
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index ff9b4f41ef3b..e5163d83de69 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -1881,6 +1881,10 @@ public final class PowerManager {
* Returns the current battery saver control mode. Values it may return are defined in
* AutoPowerSaveModeTriggers. Note that this is a global device state, not a per user setting.
*
+ * <p>Note: Prior to Android version {@link Build.VERSION_CODES#S}, any app calling this method
+ * was required to hold the {@link android.Manifest.permission#POWER_SAVER} permission. Starting
+ * from Android version {@link Build.VERSION_CODES#S}, that permission is no longer required.
+ *
* @return The current value power saver mode for the system.
*
* @see AutoPowerSaveModeTriggers
@@ -1889,7 +1893,6 @@ public final class PowerManager {
*/
@AutoPowerSaveModeTriggers
@SystemApi
- @RequiresPermission(android.Manifest.permission.POWER_SAVER)
public int getPowerSaveModeTrigger() {
try {
return mService.getPowerSaveModeTrigger();
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 54d2df865c39..136dc388022f 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -207,6 +207,12 @@ public class Process {
public static final int SE_UID = 1068;
/**
+ * Defines the UID/GID for the iorapd.
+ * @hide
+ */
+ public static final int IORAPD_UID = 1071;
+
+ /**
* Defines the UID/GID for the NetworkStack app.
* @hide
*/
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index a5d3c2acc577..3a5426c60b24 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -1536,6 +1536,7 @@ public class StorageManager {
}
/** {@hide} */
+ @TestApi
public static boolean isUserKeyUnlocked(int userId) {
if (sStorageManager == null) {
sStorageManager = IStorageManager.Stub
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index 219190f554ea..21dd1fb05615 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -20,8 +20,6 @@ import static android.view.InsetsStateProto.DISPLAY_CUTOUT;
import static android.view.InsetsStateProto.DISPLAY_FRAME;
import static android.view.InsetsStateProto.SOURCES;
import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
-import static android.view.WindowInsets.Type.MANDATORY_SYSTEM_GESTURES;
-import static android.view.WindowInsets.Type.SYSTEM_GESTURES;
import static android.view.WindowInsets.Type.displayCutout;
import static android.view.WindowInsets.Type.ime;
import static android.view.WindowInsets.Type.indexOf;
@@ -106,14 +104,11 @@ public class InsetsState implements Parcelable {
public static final int ITYPE_NAVIGATION_BAR = 1;
public static final int ITYPE_CAPTION_BAR = 2;
- // The always visible types are visible to all windows regardless of the z-order.
- public static final int FIRST_ALWAYS_VISIBLE_TYPE = 3;
- public static final int ITYPE_TOP_GESTURES = FIRST_ALWAYS_VISIBLE_TYPE;
+ public static final int ITYPE_TOP_GESTURES = 3;
public static final int ITYPE_BOTTOM_GESTURES = 4;
public static final int ITYPE_LEFT_GESTURES = 5;
public static final int ITYPE_RIGHT_GESTURES = 6;
- /** Additional gesture inset types that map into {@link Type.MANDATORY_SYSTEM_GESTURES}. */
public static final int ITYPE_TOP_MANDATORY_GESTURES = 7;
public static final int ITYPE_BOTTOM_MANDATORY_GESTURES = 8;
public static final int ITYPE_LEFT_MANDATORY_GESTURES = 9;
@@ -123,7 +118,6 @@ public class InsetsState implements Parcelable {
public static final int ITYPE_TOP_DISPLAY_CUTOUT = 12;
public static final int ITYPE_RIGHT_DISPLAY_CUTOUT = 13;
public static final int ITYPE_BOTTOM_DISPLAY_CUTOUT = 14;
- public static final int LAST_ALWAYS_VISIBLE_TYPE = ITYPE_BOTTOM_DISPLAY_CUTOUT;
public static final int ITYPE_LEFT_TAPPABLE_ELEMENT = 15;
public static final int ITYPE_TOP_TAPPABLE_ELEMENT = 16;
@@ -188,18 +182,6 @@ public class InsetsState implements Parcelable {
}
/**
- * Mirror the always visible sources from the other state. They will share the same object for
- * the always visible types.
- *
- * @param other the state to mirror the mirrored sources from.
- */
- public void mirrorAlwaysVisibleInsetsSources(InsetsState other) {
- for (int type = FIRST_ALWAYS_VISIBLE_TYPE; type <= LAST_ALWAYS_VISIBLE_TYPE; type++) {
- mSources[type] = other.mSources[type];
- }
- }
-
- /**
* Calculates {@link WindowInsets} based on the current source configuration.
*
* @param frame The frame to calculate the insets relative to.
@@ -380,14 +362,14 @@ public class InsetsState implements Parcelable {
processSourceAsPublicType(source, typeInsetsMap, typeSideMap, typeVisibilityMap,
insets, type);
- if (type == MANDATORY_SYSTEM_GESTURES) {
+ if (type == Type.MANDATORY_SYSTEM_GESTURES) {
// Mandatory system gestures are also system gestures.
// TODO: find a way to express this more generally. One option would be to define
// Type.systemGestureInsets() as NORMAL | MANDATORY, but then we lose the
// ability to set systemGestureInsets() independently from
// mandatorySystemGestureInsets() in the Builder.
processSourceAsPublicType(source, typeInsetsMap, typeSideMap, typeVisibilityMap,
- insets, SYSTEM_GESTURES);
+ insets, Type.SYSTEM_GESTURES);
}
}
@@ -493,9 +475,14 @@ public class InsetsState implements Parcelable {
* to the client.
*
* @param type The {@link InternalInsetsType} of the source to remove
+ * @return {@code true} if this InsetsState was modified; {@code false} otherwise.
*/
- public void removeSource(@InternalInsetsType int type) {
+ public boolean removeSource(@InternalInsetsType int type) {
+ if (mSources[type] == null) {
+ return false;
+ }
mSources[type] = null;
+ return true;
}
/**
@@ -552,6 +539,24 @@ public class InsetsState implements Parcelable {
}
}
+ /**
+ * Sets the values from the other InsetsState. But for sources, only specific types of source
+ * would be set.
+ *
+ * @param other the other InsetsState.
+ * @param types the only types of sources would be set.
+ */
+ public void set(InsetsState other, @InsetsType int types) {
+ mDisplayFrame.set(other.mDisplayFrame);
+ mDisplayCutout.set(other.mDisplayCutout);
+ mRoundedCorners = other.getRoundedCorners();
+ final ArraySet<Integer> t = toInternalType(types);
+ for (int i = t.size() - 1; i >= 0; i--) {
+ final int type = t.valueAt(i);
+ mSources[type] = other.mSources[type];
+ }
+ }
+
public void addSource(InsetsSource source) {
mSources[source.getType()] = source;
}
@@ -575,6 +580,18 @@ public class InsetsState implements Parcelable {
if ((types & Type.CAPTION_BAR) != 0) {
result.add(ITYPE_CAPTION_BAR);
}
+ if ((types & Type.SYSTEM_GESTURES) != 0) {
+ result.add(ITYPE_LEFT_GESTURES);
+ result.add(ITYPE_TOP_GESTURES);
+ result.add(ITYPE_RIGHT_GESTURES);
+ result.add(ITYPE_BOTTOM_GESTURES);
+ }
+ if ((types & Type.MANDATORY_SYSTEM_GESTURES) != 0) {
+ result.add(ITYPE_LEFT_MANDATORY_GESTURES);
+ result.add(ITYPE_TOP_MANDATORY_GESTURES);
+ result.add(ITYPE_RIGHT_MANDATORY_GESTURES);
+ result.add(ITYPE_BOTTOM_MANDATORY_GESTURES);
+ }
if ((types & Type.DISPLAY_CUTOUT) != 0) {
result.add(ITYPE_LEFT_DISPLAY_CUTOUT);
result.add(ITYPE_TOP_DISPLAY_CUTOUT);
diff --git a/core/java/android/view/RoundedCorners.java b/core/java/android/view/RoundedCorners.java
index 015e804da2f6..569c287901c7 100644
--- a/core/java/android/view/RoundedCorners.java
+++ b/core/java/android/view/RoundedCorners.java
@@ -335,7 +335,7 @@ public class RoundedCorners implements Parcelable {
}
if (o instanceof RoundedCorners) {
RoundedCorners r = (RoundedCorners) o;
- return Arrays.deepEquals(mRoundedCorners, ((RoundedCorners) o).mRoundedCorners);
+ return Arrays.deepEquals(mRoundedCorners, r.mRoundedCorners);
}
return false;
}
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 66b9617714a6..7d049d09a677 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -68,6 +68,7 @@ import java.lang.ref.WeakReference;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -161,25 +162,21 @@ public final class SurfaceControl implements Parcelable {
int L, int T, int R, int B);
private static native void nativeSetDisplaySize(long transactionObj, IBinder displayToken,
int width, int height);
- private static native DisplayInfo nativeGetDisplayInfo(IBinder displayToken);
- private static native DisplayMode[] nativeGetDisplayModes(
- IBinder displayToken);
+ private static native StaticDisplayInfo nativeGetStaticDisplayInfo(IBinder displayToken);
+ private static native DynamicDisplayInfo nativeGetDynamicDisplayInfo(IBinder displayToken);
private static native DisplayedContentSamplingAttributes
nativeGetDisplayedContentSamplingAttributes(IBinder displayToken);
private static native boolean nativeSetDisplayedContentSamplingEnabled(IBinder displayToken,
boolean enable, int componentMask, int maxFrames);
private static native DisplayedContentSample nativeGetDisplayedContentSample(
IBinder displayToken, long numFrames, long timestamp);
- private static native int nativeGetActiveDisplayMode(IBinder displayToken);
private static native boolean nativeSetDesiredDisplayModeSpecs(IBinder displayToken,
DesiredDisplayModeSpecs desiredDisplayModeSpecs);
private static native DesiredDisplayModeSpecs
nativeGetDesiredDisplayModeSpecs(IBinder displayToken);
- private static native int[] nativeGetDisplayColorModes(IBinder displayToken);
private static native DisplayPrimaries nativeGetDisplayNativePrimaries(
IBinder displayToken);
private static native int[] nativeGetCompositionDataspaces();
- private static native int nativeGetActiveColorMode(IBinder displayToken);
private static native boolean nativeSetActiveColorMode(IBinder displayToken,
int colorMode);
private static native void nativeSetAutoLowLatencyMode(IBinder displayToken, boolean on);
@@ -191,8 +188,6 @@ public final class SurfaceControl implements Parcelable {
private static native void nativeReparent(long transactionObj, long nativeObject,
long newParentNativeObject);
- private static native Display.HdrCapabilities nativeGetHdrCapabilities(IBinder displayToken);
-
private static native boolean nativeGetAutoLowLatencyModeSupport(IBinder displayToken);
private static native boolean nativeGetGameContentTypeSupport(IBinder displayToken);
@@ -1707,7 +1702,7 @@ public final class SurfaceControl implements Parcelable {
*
* @hide
*/
- public static final class DisplayInfo {
+ public static final class StaticDisplayInfo {
public boolean isInternal;
public float density;
public boolean secure;
@@ -1715,7 +1710,7 @@ public final class SurfaceControl implements Parcelable {
@Override
public String toString() {
- return "DisplayInfo{isInternal=" + isInternal
+ return "StaticDisplayInfo{isInternal=" + isInternal
+ ", density=" + density
+ ", secure=" + secure
+ ", deviceProductInfo=" + deviceProductInfo + "}";
@@ -1725,7 +1720,7 @@ public final class SurfaceControl implements Parcelable {
public boolean equals(@Nullable Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
- DisplayInfo that = (DisplayInfo) o;
+ StaticDisplayInfo that = (StaticDisplayInfo) o;
return isInternal == that.isInternal
&& density == that.density
&& secure == that.secure
@@ -1739,6 +1734,49 @@ public final class SurfaceControl implements Parcelable {
}
/**
+ * Dynamic information about physical display.
+ *
+ * @hide
+ */
+ public static final class DynamicDisplayInfo {
+ public DisplayMode[] supportedDisplayModes;
+ public int activeDisplayModeId;
+
+ public int[] supportedColorModes;
+ public int activeColorMode;
+
+ public Display.HdrCapabilities hdrCapabilities;
+
+ @Override
+ public String toString() {
+ return "DynamicDisplayInfo{"
+ + "supportedDisplayModes=" + Arrays.toString(supportedDisplayModes)
+ + ", activeDisplayModeId=" + activeDisplayModeId
+ + ", supportedColorModes=" + Arrays.toString(supportedColorModes)
+ + ", activeColorMode=" + activeColorMode
+ + ", hdrCapabilities=" + hdrCapabilities + "}";
+ }
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ DynamicDisplayInfo that = (DynamicDisplayInfo) o;
+ return Arrays.equals(supportedDisplayModes, that.supportedDisplayModes)
+ && activeDisplayModeId == that.activeDisplayModeId
+ && Arrays.equals(supportedColorModes, that.supportedColorModes)
+ && activeColorMode == that.activeColorMode
+ && Objects.equals(hdrCapabilities, that.hdrCapabilities);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(supportedDisplayModes, activeDisplayModeId, activeDisplayModeId,
+ activeColorMode, hdrCapabilities);
+ }
+ }
+
+ /**
* Configuration supported by physical display.
*
* @hide
@@ -1749,6 +1787,7 @@ public final class SurfaceControl implements Parcelable {
*/
public static final int INVALID_DISPLAY_MODE_ID = -1;
+ public int id;
public int width;
public int height;
public float xDpi;
@@ -1768,7 +1807,8 @@ public final class SurfaceControl implements Parcelable {
@Override
public String toString() {
- return "DisplayConfig{width=" + width
+ return "DisplayMode{id=" + id
+ + ", width=" + width
+ ", height=" + height
+ ", xDpi=" + xDpi
+ ", yDpi=" + yDpi
@@ -1777,46 +1817,58 @@ public final class SurfaceControl implements Parcelable {
+ ", presentationDeadlineNanos=" + presentationDeadlineNanos
+ ", group=" + group + "}";
}
- }
- /**
- * @hide
- */
- public static void setDisplayPowerMode(IBinder displayToken, int mode) {
- if (displayToken == null) {
- throw new IllegalArgumentException("displayToken must not be null");
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ DisplayMode that = (DisplayMode) o;
+ return id == that.id
+ && width == that.width
+ && height == that.height
+ && Float.compare(that.xDpi, xDpi) == 0
+ && Float.compare(that.yDpi, yDpi) == 0
+ && Float.compare(that.refreshRate, refreshRate) == 0
+ && appVsyncOffsetNanos == that.appVsyncOffsetNanos
+ && presentationDeadlineNanos == that.presentationDeadlineNanos
+ && group == that.group;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(id, width, height, xDpi, yDpi, refreshRate, appVsyncOffsetNanos,
+ presentationDeadlineNanos, group);
}
- nativeSetDisplayPowerMode(displayToken, mode);
}
/**
* @hide
*/
- public static SurfaceControl.DisplayInfo getDisplayInfo(IBinder displayToken) {
+ public static void setDisplayPowerMode(IBinder displayToken, int mode) {
if (displayToken == null) {
throw new IllegalArgumentException("displayToken must not be null");
}
- return nativeGetDisplayInfo(displayToken);
+ nativeSetDisplayPowerMode(displayToken, mode);
}
/**
* @hide
*/
- public static DisplayMode[] getDisplayModes(IBinder displayToken) {
+ public static StaticDisplayInfo getStaticDisplayInfo(IBinder displayToken) {
if (displayToken == null) {
throw new IllegalArgumentException("displayToken must not be null");
}
- return nativeGetDisplayModes(displayToken);
+ return nativeGetStaticDisplayInfo(displayToken);
}
/**
* @hide
*/
- public static int getActiveDisplayMode(IBinder displayToken) {
+ public static DynamicDisplayInfo getDynamicDisplayInfo(IBinder displayToken) {
if (displayToken == null) {
throw new IllegalArgumentException("displayToken must not be null");
}
- return nativeGetActiveDisplayMode(displayToken);
+ return nativeGetDynamicDisplayInfo(displayToken);
}
/**
@@ -1978,16 +2030,6 @@ public final class SurfaceControl implements Parcelable {
}
/**
- * @hide
- */
- public static int[] getDisplayColorModes(IBinder displayToken) {
- if (displayToken == null) {
- throw new IllegalArgumentException("displayToken must not be null");
- }
- return nativeGetDisplayColorModes(displayToken);
- }
-
- /**
* Color coordinates in CIE1931 XYZ color space
*
* @hide
@@ -2057,16 +2099,6 @@ public final class SurfaceControl implements Parcelable {
/**
* @hide
*/
- public static int getActiveColorMode(IBinder displayToken) {
- if (displayToken == null) {
- throw new IllegalArgumentException("displayToken must not be null");
- }
- return nativeGetActiveColorMode(displayToken);
- }
-
- /**
- * @hide
- */
public static boolean setActiveColorMode(IBinder displayToken, int colorMode) {
if (displayToken == null) {
throw new IllegalArgumentException("displayToken must not be null");
@@ -2169,16 +2201,6 @@ public final class SurfaceControl implements Parcelable {
/**
* @hide
*/
- public static Display.HdrCapabilities getHdrCapabilities(IBinder displayToken) {
- if (displayToken == null) {
- throw new IllegalArgumentException("displayToken must not be null");
- }
- return nativeGetHdrCapabilities(displayToken);
- }
-
- /**
- * @hide
- */
public static boolean getAutoLowLatencyModeSupport(IBinder displayToken) {
if (displayToken == null) {
throw new IllegalArgumentException("displayToken must not be null");
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index d5f97743c257..05b177ebbb45 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -715,7 +715,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
*/
@NonNull
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769408)
- private EdgeEffect mEdgeGlowTop = new EdgeEffect(mContext);
+ private EdgeEffect mEdgeGlowTop;
/**
* Tracks the state of the bottom edge glow.
@@ -725,7 +725,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
*/
@NonNull
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768444)
- private EdgeEffect mEdgeGlowBottom = new EdgeEffect(mContext);
+ private EdgeEffect mEdgeGlowBottom;
/**
* An estimate of how many pixels are between the top of the list and
@@ -847,6 +847,8 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
public AbsListView(Context context) {
super(context);
+ mEdgeGlowBottom = new EdgeEffect(context);
+ mEdgeGlowTop = new EdgeEffect(context);
initAbsListView();
mOwnerThread = Thread.currentThread();
@@ -867,6 +869,8 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
public AbsListView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
+ mEdgeGlowBottom = new EdgeEffect(context, attrs);
+ mEdgeGlowTop = new EdgeEffect(context, attrs);
initAbsListView();
mOwnerThread = Thread.currentThread();
@@ -3584,6 +3588,9 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
mLastY != Integer.MIN_VALUE ? y - mLastY + scrollConsumedCorrection : deltaY;
int lastYCorrection = 0;
+ // First allow releasing existing overscroll effect:
+ incrementalDeltaY = releaseGlow(incrementalDeltaY, x);
+
if (mTouchMode == TOUCH_MODE_SCROLL) {
if (PROFILE_SCROLLING) {
if (!mScrollProfilingStarted) {
@@ -3666,14 +3673,14 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
mTouchMode = TOUCH_MODE_OVERSCROLL;
}
if (incrementalDeltaY > 0) {
- mEdgeGlowTop.onPull((float) -overscroll / getHeight(),
+ mEdgeGlowTop.onPullDistance((float) -overscroll / getHeight(),
(float) x / getWidth());
if (!mEdgeGlowBottom.isFinished()) {
mEdgeGlowBottom.onRelease();
}
invalidateTopGlow();
} else if (incrementalDeltaY < 0) {
- mEdgeGlowBottom.onPull((float) overscroll / getHeight(),
+ mEdgeGlowBottom.onPullDistance((float) overscroll / getHeight(),
1.f - (float) x / getWidth());
if (!mEdgeGlowTop.isFinished()) {
mEdgeGlowTop.onRelease();
@@ -3713,14 +3720,15 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
(overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS &&
!contentFits())) {
if (rawDeltaY > 0) {
- mEdgeGlowTop.onPull((float) overScrollDistance / getHeight(),
+ mEdgeGlowTop.onPullDistance((float) overScrollDistance / getHeight(),
(float) x / getWidth());
if (!mEdgeGlowBottom.isFinished()) {
mEdgeGlowBottom.onRelease();
}
invalidateTopGlow();
} else if (rawDeltaY < 0) {
- mEdgeGlowBottom.onPull((float) overScrollDistance / getHeight(),
+ mEdgeGlowBottom.onPullDistance(
+ (float) -overScrollDistance / getHeight(),
1.f - (float) x / getWidth());
if (!mEdgeGlowTop.isFinished()) {
mEdgeGlowTop.onRelease();
@@ -3757,6 +3765,44 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
}
}
+ /**
+ * If the edge glow is currently active, this consumes part or all of deltaY
+ * on the edge glow.
+ *
+ * @param deltaY The pointer motion, in pixels, in the vertical direction, positive
+ * for moving down and negative for moving up.
+ * @param x The horizontal position of the pointer.
+ * @return The remainder of <code>deltaY</code> that has not been consumed by the
+ * edge glow.
+ */
+ private int releaseGlow(int deltaY, int x) {
+ // First allow releasing existing overscroll effect:
+ float consumed = 0;
+ if (mEdgeGlowTop.getDistance() != 0) {
+ consumed = mEdgeGlowTop.onPullDistance((float) deltaY / getHeight(),
+ (float) x / getWidth());
+ if (consumed != 0f) {
+ invalidateTopGlow();
+ }
+ } else if (mEdgeGlowBottom.getDistance() != 0) {
+ consumed = -mEdgeGlowBottom.onPullDistance((float) -deltaY / getHeight(),
+ 1f - (float) x / getWidth());
+ if (consumed != 0f) {
+ invalidateBottomGlow();
+ }
+ }
+ int pixelsConsumed = Math.round(consumed * getHeight());
+ return deltaY - pixelsConsumed;
+ }
+
+ /**
+ * @return <code>true</code> if either the top or bottom edge glow is currently active or
+ * <code>false</code> if it has no value to release.
+ */
+ private boolean isGlowActive() {
+ return mEdgeGlowBottom.getDistance() != 0 || mEdgeGlowTop.getDistance() != 0;
+ }
+
private void invalidateTopGlow() {
if (!shouldDisplayEdgeEffects()) {
return;
@@ -3926,7 +3972,9 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
if (mTouchMode == TOUCH_MODE_OVERFLING) {
// Stopped the fling. It is a scroll.
- mFlingRunnable.endFling();
+ if (mFlingRunnable != null) {
+ mFlingRunnable.endFling();
+ }
if (mPositionScroller != null) {
mPositionScroller.stop();
}
@@ -3936,6 +3984,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
mLastY = mMotionY;
mMotionCorrection = 0;
mDirection = 0;
+ stopEdgeGlowRecede(ev.getX());
} else {
final int x = (int) ev.getX();
final int y = (int) ev.getY();
@@ -3948,7 +3997,10 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
mTouchMode = TOUCH_MODE_SCROLL;
mMotionCorrection = 0;
motionPosition = findMotionRow(y);
- mFlingRunnable.flywheelTouch();
+ if (mFlingRunnable != null) {
+ mFlingRunnable.flywheelTouch();
+ }
+ stopEdgeGlowRecede(x);
} else if ((motionPosition >= 0) && getAdapter().isEnabled(motionPosition)) {
// User clicked on an actual view (and was not stopping a
// fling). It might be a click or a scroll. Assume it is a
@@ -3984,6 +4036,15 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
}
}
+ private void stopEdgeGlowRecede(float x) {
+ if (mEdgeGlowTop.getDistance() != 0) {
+ mEdgeGlowTop.onPullDistance(0, x / getWidth());
+ }
+ if (mEdgeGlowBottom.getDistance() != 0) {
+ mEdgeGlowBottom.onPullDistance(0, x / getWidth());
+ }
+ }
+
private void onTouchMove(MotionEvent ev, MotionEvent vtev) {
if (mHasPerformedLongPress) {
// Consume all move events following a successful long press.
@@ -4489,73 +4550,76 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
}
switch (actionMasked) {
- case MotionEvent.ACTION_DOWN: {
- int touchMode = mTouchMode;
- if (touchMode == TOUCH_MODE_OVERFLING || touchMode == TOUCH_MODE_OVERSCROLL) {
- mMotionCorrection = 0;
- return true;
- }
-
- final int x = (int) ev.getX();
- final int y = (int) ev.getY();
- mActivePointerId = ev.getPointerId(0);
+ case MotionEvent.ACTION_DOWN: {
+ int touchMode = mTouchMode;
+ if (touchMode == TOUCH_MODE_OVERFLING || touchMode == TOUCH_MODE_OVERSCROLL) {
+ mMotionCorrection = 0;
+ return true;
+ }
- int motionPosition = findMotionRow(y);
- if (touchMode != TOUCH_MODE_FLING && motionPosition >= 0) {
- // User clicked on an actual view (and was not stopping a fling).
- // Remember where the motion event started
- v = getChildAt(motionPosition - mFirstPosition);
- mMotionViewOriginalTop = v.getTop();
- mMotionX = x;
- mMotionY = y;
- mMotionPosition = motionPosition;
- mTouchMode = TOUCH_MODE_DOWN;
- clearScrollingCache();
- }
- mLastY = Integer.MIN_VALUE;
- initOrResetVelocityTracker();
- mVelocityTracker.addMovement(ev);
- mNestedYOffset = 0;
- startNestedScroll(SCROLL_AXIS_VERTICAL);
- if (touchMode == TOUCH_MODE_FLING) {
- return true;
- }
- break;
- }
+ final int x = (int) ev.getX();
+ final int y = (int) ev.getY();
+ mActivePointerId = ev.getPointerId(0);
- case MotionEvent.ACTION_MOVE: {
- switch (mTouchMode) {
- case TOUCH_MODE_DOWN:
- int pointerIndex = ev.findPointerIndex(mActivePointerId);
- if (pointerIndex == -1) {
- pointerIndex = 0;
- mActivePointerId = ev.getPointerId(pointerIndex);
+ int motionPosition = findMotionRow(y);
+ if (isGlowActive()) {
+ // Pressed during edge effect, so this is considered the same as a fling catch.
+ mTouchMode = TOUCH_MODE_FLING;
+ } else if (touchMode != TOUCH_MODE_FLING && motionPosition >= 0) {
+ // User clicked on an actual view (and was not stopping a fling).
+ // Remember where the motion event started
+ v = getChildAt(motionPosition - mFirstPosition);
+ mMotionViewOriginalTop = v.getTop();
+ mMotionX = x;
+ mMotionY = y;
+ mMotionPosition = motionPosition;
+ mTouchMode = TOUCH_MODE_DOWN;
+ clearScrollingCache();
}
- final int y = (int) ev.getY(pointerIndex);
- initVelocityTrackerIfNotExists();
+ mLastY = Integer.MIN_VALUE;
+ initOrResetVelocityTracker();
mVelocityTracker.addMovement(ev);
- if (startScrollIfNeeded((int) ev.getX(pointerIndex), y, null)) {
+ mNestedYOffset = 0;
+ startNestedScroll(SCROLL_AXIS_VERTICAL);
+ if (touchMode == TOUCH_MODE_FLING) {
return true;
}
break;
}
- break;
- }
- case MotionEvent.ACTION_CANCEL:
- case MotionEvent.ACTION_UP: {
- mTouchMode = TOUCH_MODE_REST;
- mActivePointerId = INVALID_POINTER;
- recycleVelocityTracker();
- reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
- stopNestedScroll();
- break;
- }
+ case MotionEvent.ACTION_MOVE: {
+ switch (mTouchMode) {
+ case TOUCH_MODE_DOWN:
+ int pointerIndex = ev.findPointerIndex(mActivePointerId);
+ if (pointerIndex == -1) {
+ pointerIndex = 0;
+ mActivePointerId = ev.getPointerId(pointerIndex);
+ }
+ final int y = (int) ev.getY(pointerIndex);
+ initVelocityTrackerIfNotExists();
+ mVelocityTracker.addMovement(ev);
+ if (startScrollIfNeeded((int) ev.getX(pointerIndex), y, null)) {
+ return true;
+ }
+ break;
+ }
+ break;
+ }
- case MotionEvent.ACTION_POINTER_UP: {
- onSecondaryPointerUp(ev);
- break;
- }
+ case MotionEvent.ACTION_CANCEL:
+ case MotionEvent.ACTION_UP: {
+ mTouchMode = TOUCH_MODE_REST;
+ mActivePointerId = INVALID_POINTER;
+ recycleVelocityTracker();
+ reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
+ stopNestedScroll();
+ break;
+ }
+
+ case MotionEvent.ACTION_POINTER_UP: {
+ onSecondaryPointerUp(ev);
+ break;
+ }
}
return false;
diff --git a/core/java/com/android/internal/app/IAppOpsNotedCallback.aidl b/core/java/com/android/internal/app/IAppOpsNotedCallback.aidl
index cb280cd14180..f3759e091ed6 100644
--- a/core/java/com/android/internal/app/IAppOpsNotedCallback.aidl
+++ b/core/java/com/android/internal/app/IAppOpsNotedCallback.aidl
@@ -18,5 +18,5 @@ package com.android.internal.app;
// Iterface to observe op note/checks of ops
oneway interface IAppOpsNotedCallback {
- void opNoted(int op, int uid, String packageName, int flags, int mode);
+ void opNoted(int op, int uid, String packageName, String attributionTag, int flags, int mode);
}
diff --git a/core/java/com/android/internal/app/IAppOpsStartedCallback.aidl b/core/java/com/android/internal/app/IAppOpsStartedCallback.aidl
index b0cb2a8ceb64..3a108e7e1d94 100644
--- a/core/java/com/android/internal/app/IAppOpsStartedCallback.aidl
+++ b/core/java/com/android/internal/app/IAppOpsStartedCallback.aidl
@@ -18,5 +18,5 @@ package com.android.internal.app;
// Iterface to observe op starts
oneway interface IAppOpsStartedCallback {
- void opStarted(int op, int uid, String packageName, int flags, int mode);
+ void opStarted(int op, int uid, String packageName, String attributionTag, int flags, int mode);
}
diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp
index 5b327d40ac69..d0504fb481ca 100644
--- a/core/jni/android_hardware_SensorManager.cpp
+++ b/core/jni/android_hardware_SensorManager.cpp
@@ -421,11 +421,18 @@ private:
};
static jlong nativeInitSensorEventQueue(JNIEnv *env, jclass clazz, jlong sensorManager,
- jobject eventQWeak, jobject msgQ, jstring packageName, jint mode) {
+ jobject eventQWeak, jobject msgQ, jstring packageName,
+ jint mode, jstring opPackageName, jstring attributionTag) {
SensorManager* mgr = reinterpret_cast<SensorManager*>(sensorManager);
ScopedUtfChars packageUtf(env, packageName);
String8 clientName(packageUtf.c_str());
- sp<SensorEventQueue> queue(mgr->createEventQueue(clientName, mode));
+
+ String16 attributionTagName("");
+ if (attributionTag != nullptr) {
+ ScopedUtfChars attrUtf(env, attributionTag);
+ attributionTagName = String16(attrUtf.c_str());
+ }
+ sp<SensorEventQueue> queue(mgr->createEventQueue(clientName, mode, attributionTagName));
if (queue == NULL) {
jniThrowRuntimeException(env, "Cannot construct native SensorEventQueue.");
@@ -517,29 +524,20 @@ static const JNINativeMethod gSystemSensorManagerMethods[] = {
};
static const JNINativeMethod gBaseEventQueueMethods[] = {
- {"nativeInitBaseEventQueue",
- "(JLjava/lang/ref/WeakReference;Landroid/os/MessageQueue;Ljava/lang/String;ILjava/lang/String;)J",
- (void*)nativeInitSensorEventQueue },
+ {"nativeInitBaseEventQueue",
+ "(JLjava/lang/ref/WeakReference;Landroid/os/MessageQueue;Ljava/lang/String;ILjava/lang/"
+ "String;Ljava/lang/String;)J",
+ (void *)nativeInitSensorEventQueue},
- {"nativeEnableSensor",
- "(JIII)I",
- (void*)nativeEnableSensor },
+ {"nativeEnableSensor", "(JIII)I", (void *)nativeEnableSensor},
- {"nativeDisableSensor",
- "(JI)I",
- (void*)nativeDisableSensor },
+ {"nativeDisableSensor", "(JI)I", (void *)nativeDisableSensor},
- {"nativeDestroySensorEventQueue",
- "(J)V",
- (void*)nativeDestroySensorEventQueue },
+ {"nativeDestroySensorEventQueue", "(J)V", (void *)nativeDestroySensorEventQueue},
- {"nativeFlushSensor",
- "(J)I",
- (void*)nativeFlushSensor },
+ {"nativeFlushSensor", "(J)I", (void *)nativeFlushSensor},
- {"nativeInjectSensorData",
- "(JI[FIJ)I",
- (void*)nativeInjectSensorData },
+ {"nativeInjectSensorData", "(JI[FIJ)I", (void *)nativeInjectSensorData},
};
} //unnamed namespace
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 961d4cb23679..094ca1843eea 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -45,14 +45,15 @@
#include <ui/BlurRegion.h>
#include <ui/ConfigStoreTypes.h>
#include <ui/DeviceProductInfo.h>
-#include <ui/DisplayInfo.h>
#include <ui/DisplayMode.h>
#include <ui/DisplayedFrameStats.h>
+#include <ui/DynamicDisplayInfo.h>
#include <ui/FrameStats.h>
#include <ui/GraphicTypes.h>
#include <ui/HdrCapabilities.h>
#include <ui/Rect.h>
#include <ui/Region.h>
+#include <ui/StaticDisplayInfo.h>
#include <utils/LightRefBase.h>
#include <utils/Log.h>
@@ -87,11 +88,22 @@ static struct {
jfieldID density;
jfieldID secure;
jfieldID deviceProductInfo;
-} gDisplayInfoClassInfo;
+} gStaticDisplayInfoClassInfo;
static struct {
jclass clazz;
jmethodID ctor;
+ jfieldID supportedDisplayModes;
+ jfieldID activeDisplayModeId;
+ jfieldID supportedColorModes;
+ jfieldID activeColorMode;
+ jfieldID hdrCapabilities;
+} gDynamicDisplayInfoClassInfo;
+
+static struct {
+ jclass clazz;
+ jmethodID ctor;
+ jfieldID id;
jfieldID width;
jfieldID height;
jfieldID xDpi;
@@ -1020,51 +1032,100 @@ static jobject convertDeviceProductInfoToJavaObject(
connectionToSinkType);
}
-static jobject nativeGetDisplayInfo(JNIEnv* env, jclass clazz, jobject tokenObj) {
- DisplayInfo info;
+static jobject nativeGetStaticDisplayInfo(JNIEnv* env, jclass clazz, jobject tokenObj) {
+ ui::StaticDisplayInfo info;
if (const auto token = ibinderForJavaObject(env, tokenObj);
- !token || SurfaceComposerClient::getDisplayInfo(token, &info) != NO_ERROR) {
+ !token || SurfaceComposerClient::getStaticDisplayInfo(token, &info) != NO_ERROR) {
return nullptr;
}
- jobject object = env->NewObject(gDisplayInfoClassInfo.clazz, gDisplayInfoClassInfo.ctor);
- env->SetBooleanField(object, gDisplayInfoClassInfo.isInternal,
- info.connectionType == DisplayConnectionType::Internal);
- env->SetFloatField(object, gDisplayInfoClassInfo.density, info.density);
- env->SetBooleanField(object, gDisplayInfoClassInfo.secure, info.secure);
- env->SetObjectField(object, gDisplayInfoClassInfo.deviceProductInfo,
+ jobject object =
+ env->NewObject(gStaticDisplayInfoClassInfo.clazz, gStaticDisplayInfoClassInfo.ctor);
+ env->SetBooleanField(object, gStaticDisplayInfoClassInfo.isInternal,
+ info.connectionType == ui::DisplayConnectionType::Internal);
+ env->SetFloatField(object, gStaticDisplayInfoClassInfo.density, info.density);
+ env->SetBooleanField(object, gStaticDisplayInfoClassInfo.secure, info.secure);
+ env->SetObjectField(object, gStaticDisplayInfoClassInfo.deviceProductInfo,
convertDeviceProductInfoToJavaObject(env, info.deviceProductInfo));
return object;
}
-static jobjectArray nativeGetDisplayModes(JNIEnv* env, jclass clazz, jobject tokenObj) {
- Vector<ui::DisplayMode> modes;
- if (const auto token = ibinderForJavaObject(env, tokenObj); !token ||
- SurfaceComposerClient::getDisplayModes(token, &modes) != NO_ERROR || modes.isEmpty()) {
+static jobject convertDisplayModeToJavaObject(JNIEnv* env, const ui::DisplayMode& config) {
+ jobject object = env->NewObject(gDisplayModeClassInfo.clazz, gDisplayModeClassInfo.ctor);
+ env->SetIntField(object, gDisplayModeClassInfo.id, config.id);
+ env->SetIntField(object, gDisplayModeClassInfo.width, config.resolution.getWidth());
+ env->SetIntField(object, gDisplayModeClassInfo.height, config.resolution.getHeight());
+ env->SetFloatField(object, gDisplayModeClassInfo.xDpi, config.xDpi);
+ env->SetFloatField(object, gDisplayModeClassInfo.yDpi, config.yDpi);
+
+ env->SetFloatField(object, gDisplayModeClassInfo.refreshRate, config.refreshRate);
+ env->SetLongField(object, gDisplayModeClassInfo.appVsyncOffsetNanos, config.appVsyncOffset);
+ env->SetLongField(object, gDisplayModeClassInfo.presentationDeadlineNanos,
+ config.presentationDeadline);
+ env->SetIntField(object, gDisplayModeClassInfo.group, config.group);
+ return object;
+}
+
+jobject convertDeviceProductInfoToJavaObject(JNIEnv* env, const HdrCapabilities& capabilities) {
+ const auto& types = capabilities.getSupportedHdrTypes();
+ std::vector<int32_t> intTypes;
+ for (auto type : types) {
+ intTypes.push_back(static_cast<int32_t>(type));
+ }
+ auto typesArray = env->NewIntArray(types.size());
+ env->SetIntArrayRegion(typesArray, 0, intTypes.size(), intTypes.data());
+
+ return env->NewObject(gHdrCapabilitiesClassInfo.clazz, gHdrCapabilitiesClassInfo.ctor,
+ typesArray, capabilities.getDesiredMaxLuminance(),
+ capabilities.getDesiredMaxAverageLuminance(),
+ capabilities.getDesiredMinLuminance());
+}
+
+static jobject nativeGetDynamicDisplayInfo(JNIEnv* env, jclass clazz, jobject tokenObj) {
+ ui::DynamicDisplayInfo info;
+ if (const auto token = ibinderForJavaObject(env, tokenObj);
+ !token || SurfaceComposerClient::getDynamicDisplayInfo(token, &info) != NO_ERROR) {
return nullptr;
}
- jobjectArray modesArray =
- env->NewObjectArray(modes.size(), gDisplayModeClassInfo.clazz, nullptr);
+ jobject object =
+ env->NewObject(gDynamicDisplayInfoClassInfo.clazz, gDynamicDisplayInfoClassInfo.ctor);
+ if (object == NULL) {
+ jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
+ return NULL;
+ }
- for (size_t c = 0; c < modes.size(); ++c) {
- const ui::DisplayMode& mode = modes[c];
- jobject object = env->NewObject(gDisplayModeClassInfo.clazz, gDisplayModeClassInfo.ctor);
- env->SetIntField(object, gDisplayModeClassInfo.width, mode.resolution.getWidth());
- env->SetIntField(object, gDisplayModeClassInfo.height, mode.resolution.getHeight());
- env->SetFloatField(object, gDisplayModeClassInfo.xDpi, mode.xDpi);
- env->SetFloatField(object, gDisplayModeClassInfo.yDpi, mode.yDpi);
+ const auto numModes = info.supportedDisplayModes.size();
+ jobjectArray modesArray = env->NewObjectArray(numModes, gDisplayModeClassInfo.clazz, nullptr);
+ for (size_t i = 0; i < numModes; i++) {
+ const ui::DisplayMode& mode = info.supportedDisplayModes[i];
+ jobject displayModeObj = convertDisplayModeToJavaObject(env, mode);
+ env->SetObjectArrayElement(modesArray, static_cast<jsize>(i), displayModeObj);
+ env->DeleteLocalRef(displayModeObj);
+ }
+ env->SetObjectField(object, gDynamicDisplayInfoClassInfo.supportedDisplayModes, modesArray);
+ env->SetIntField(object, gDynamicDisplayInfoClassInfo.activeDisplayModeId,
+ info.activeDisplayModeId);
- env->SetFloatField(object, gDisplayModeClassInfo.refreshRate, mode.refreshRate);
- env->SetLongField(object, gDisplayModeClassInfo.appVsyncOffsetNanos, mode.appVsyncOffset);
- env->SetLongField(object, gDisplayModeClassInfo.presentationDeadlineNanos,
- mode.presentationDeadline);
- env->SetIntField(object, gDisplayModeClassInfo.group, mode.group);
- env->SetObjectArrayElement(modesArray, static_cast<jsize>(c), object);
- env->DeleteLocalRef(object);
+ jintArray colorModesArray = env->NewIntArray(info.supportedColorModes.size());
+ if (colorModesArray == NULL) {
+ jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
+ return NULL;
}
+ jint* colorModesArrayValues = env->GetIntArrayElements(colorModesArray, 0);
+ for (size_t i = 0; i < info.supportedColorModes.size(); i++) {
+ colorModesArrayValues[i] = static_cast<jint>(info.supportedColorModes[i]);
+ }
+ env->ReleaseIntArrayElements(colorModesArray, colorModesArrayValues, 0);
+ env->SetObjectField(object, gDynamicDisplayInfoClassInfo.supportedColorModes, colorModesArray);
+
+ env->SetIntField(object, gDynamicDisplayInfoClassInfo.activeColorMode,
+ static_cast<jint>(info.activeColorMode));
- return modesArray;
+ env->SetObjectField(object, gDynamicDisplayInfoClassInfo.hdrCapabilities,
+ convertDeviceProductInfoToJavaObject(env, info.hdrCapabilities));
+
+ return object;
}
static jboolean nativeSetDesiredDisplayModeSpecs(JNIEnv* env, jclass clazz, jobject tokenObj,
@@ -1072,9 +1133,8 @@ static jboolean nativeSetDesiredDisplayModeSpecs(JNIEnv* env, jclass clazz, jobj
sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
if (token == nullptr) return JNI_FALSE;
- size_t defaultMode =
- static_cast<size_t>(env->GetIntField(DesiredDisplayModeSpecs,
- gDesiredDisplayModeSpecsClassInfo.defaultMode));
+ ui::DisplayModeId defaultMode = env->GetIntField(DesiredDisplayModeSpecs,
+ gDesiredDisplayModeSpecsClassInfo.defaultMode);
jboolean allowGroupSwitching =
env->GetBooleanField(DesiredDisplayModeSpecs,
gDesiredDisplayModeSpecsClassInfo.allowGroupSwitching);
@@ -1104,7 +1164,7 @@ static jobject nativeGetDesiredDisplayModeSpecs(JNIEnv* env, jclass clazz, jobje
sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
if (token == nullptr) return nullptr;
- size_t defaultMode;
+ ui::DisplayModeId defaultMode;
bool allowGroupSwitching;
float primaryRefreshRateMin;
float primaryRefreshRateMax;
@@ -1124,34 +1184,6 @@ static jobject nativeGetDesiredDisplayModeSpecs(JNIEnv* env, jclass clazz, jobje
appRequestRefreshRateMax);
}
-static jint nativeGetActiveDisplayMode(JNIEnv* env, jclass clazz, jobject tokenObj) {
- sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
- if (token == NULL) return -1;
- return static_cast<jint>(SurfaceComposerClient::getActiveDisplayModeId(token));
-}
-
-static jintArray nativeGetDisplayColorModes(JNIEnv* env, jclass, jobject tokenObj) {
- sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
- if (token == NULL) return NULL;
- Vector<ui::ColorMode> colorModes;
- if (SurfaceComposerClient::getDisplayColorModes(token, &colorModes) != NO_ERROR ||
- colorModes.isEmpty()) {
- return NULL;
- }
-
- jintArray colorModesArray = env->NewIntArray(colorModes.size());
- if (colorModesArray == NULL) {
- jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
- return NULL;
- }
- jint* colorModesArrayValues = env->GetIntArrayElements(colorModesArray, 0);
- for (size_t i = 0; i < colorModes.size(); i++) {
- colorModesArrayValues[i] = static_cast<jint>(colorModes[i]);
- }
- env->ReleaseIntArrayElements(colorModesArray, colorModesArrayValues, 0);
- return colorModesArray;
-}
-
static jobject nativeGetDisplayNativePrimaries(JNIEnv* env, jclass, jobject tokenObj) {
sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
if (token == NULL) return NULL;
@@ -1212,12 +1244,6 @@ static jobject nativeGetDisplayNativePrimaries(JNIEnv* env, jclass, jobject toke
return jprimaries;
}
-static jint nativeGetActiveColorMode(JNIEnv* env, jclass, jobject tokenObj) {
- sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
- if (token == NULL) return -1;
- return static_cast<jint>(SurfaceComposerClient::getActiveColorMode(token));
-}
-
static jintArray nativeGetCompositionDataspaces(JNIEnv* env, jclass) {
ui::Dataspace defaultDataspace, wcgDataspace;
ui::PixelFormat defaultPixelFormat, wcgPixelFormat;
@@ -1423,26 +1449,6 @@ static void nativeReparent(JNIEnv* env, jclass clazz, jlong transactionObj,
transaction->reparent(ctrl, newParent);
}
-static jobject nativeGetHdrCapabilities(JNIEnv* env, jclass clazz, jobject tokenObject) {
- sp<IBinder> token(ibinderForJavaObject(env, tokenObject));
- if (token == NULL) return NULL;
-
- HdrCapabilities capabilities;
- SurfaceComposerClient::getHdrCapabilities(token, &capabilities);
-
- const auto& types = capabilities.getSupportedHdrTypes();
- std::vector<int32_t> intTypes;
- for (auto type : types) {
- intTypes.push_back(static_cast<int32_t>(type));
- }
- auto typesArray = env->NewIntArray(types.size());
- env->SetIntArrayRegion(typesArray, 0, intTypes.size(), intTypes.data());
-
- return env->NewObject(gHdrCapabilitiesClassInfo.clazz, gHdrCapabilitiesClassInfo.ctor,
- typesArray, capabilities.getDesiredMaxLuminance(),
- capabilities.getDesiredMaxAverageLuminance(), capabilities.getDesiredMinLuminance());
-}
-
static jboolean nativeGetAutoLowLatencyModeSupport(JNIEnv* env, jclass clazz, jobject tokenObject) {
sp<IBinder> token(ibinderForJavaObject(env, tokenObject));
if (token == NULL) return NULL;
@@ -1787,24 +1793,21 @@ static const JNINativeMethod sSurfaceControlMethods[] = {
(void*)nativeSetDisplayProjection },
{"nativeSetDisplaySize", "(JLandroid/os/IBinder;II)V",
(void*)nativeSetDisplaySize },
- {"nativeGetDisplayInfo", "(Landroid/os/IBinder;)Landroid/view/SurfaceControl$DisplayInfo;",
- (void*)nativeGetDisplayInfo },
- {"nativeGetDisplayModes", "(Landroid/os/IBinder;)[Landroid/view/SurfaceControl$DisplayMode;",
- (void*)nativeGetDisplayModes },
- {"nativeGetActiveDisplayMode", "(Landroid/os/IBinder;)I",
- (void*)nativeGetActiveDisplayMode },
+ {"nativeGetStaticDisplayInfo",
+ "(Landroid/os/IBinder;)Landroid/view/SurfaceControl$StaticDisplayInfo;",
+ (void*)nativeGetStaticDisplayInfo },
+ {"nativeGetDynamicDisplayInfo",
+ "(Landroid/os/IBinder;)Landroid/view/SurfaceControl$DynamicDisplayInfo;",
+ (void*)nativeGetDynamicDisplayInfo },
{"nativeSetDesiredDisplayModeSpecs",
"(Landroid/os/IBinder;Landroid/view/SurfaceControl$DesiredDisplayModeSpecs;)Z",
(void*)nativeSetDesiredDisplayModeSpecs },
{"nativeGetDesiredDisplayModeSpecs",
"(Landroid/os/IBinder;)Landroid/view/SurfaceControl$DesiredDisplayModeSpecs;",
(void*)nativeGetDesiredDisplayModeSpecs },
- {"nativeGetDisplayColorModes", "(Landroid/os/IBinder;)[I",
- (void*)nativeGetDisplayColorModes},
- {"nativeGetDisplayNativePrimaries", "(Landroid/os/IBinder;)Landroid/view/SurfaceControl$DisplayPrimaries;",
+ {"nativeGetDisplayNativePrimaries",
+ "(Landroid/os/IBinder;)Landroid/view/SurfaceControl$DisplayPrimaries;",
(void*)nativeGetDisplayNativePrimaries },
- {"nativeGetActiveColorMode", "(Landroid/os/IBinder;)I",
- (void*)nativeGetActiveColorMode},
{"nativeSetActiveColorMode", "(Landroid/os/IBinder;I)Z",
(void*)nativeSetActiveColorMode},
{"nativeGetAutoLowLatencyModeSupport", "(Landroid/os/IBinder;)Z",
@@ -1817,8 +1820,6 @@ static const JNINativeMethod sSurfaceControlMethods[] = {
(void*)nativeSetGameContentType },
{"nativeGetCompositionDataspaces", "()[I",
(void*)nativeGetCompositionDataspaces},
- {"nativeGetHdrCapabilities", "(Landroid/os/IBinder;)Landroid/view/Display$HdrCapabilities;",
- (void*)nativeGetHdrCapabilities },
{"nativeClearContentFrameStats", "(J)Z",
(void*)nativeClearContentFrameStats },
{"nativeGetContentFrameStats", "(JLandroid/view/WindowContentFrameStats;)Z",
@@ -1897,19 +1898,36 @@ int register_android_view_SurfaceControl(JNIEnv* env)
gIntegerClassInfo.clazz = MakeGlobalRefOrDie(env, integerClass);
gIntegerClassInfo.ctor = GetMethodIDOrDie(env, gIntegerClassInfo.clazz, "<init>", "(I)V");
- jclass infoClazz = FindClassOrDie(env, "android/view/SurfaceControl$DisplayInfo");
- gDisplayInfoClassInfo.clazz = MakeGlobalRefOrDie(env, infoClazz);
- gDisplayInfoClassInfo.ctor = GetMethodIDOrDie(env, infoClazz, "<init>", "()V");
- gDisplayInfoClassInfo.isInternal = GetFieldIDOrDie(env, infoClazz, "isInternal", "Z");
- gDisplayInfoClassInfo.density = GetFieldIDOrDie(env, infoClazz, "density", "F");
- gDisplayInfoClassInfo.secure = GetFieldIDOrDie(env, infoClazz, "secure", "Z");
- gDisplayInfoClassInfo.deviceProductInfo =
+ jclass infoClazz = FindClassOrDie(env, "android/view/SurfaceControl$StaticDisplayInfo");
+ gStaticDisplayInfoClassInfo.clazz = MakeGlobalRefOrDie(env, infoClazz);
+ gStaticDisplayInfoClassInfo.ctor = GetMethodIDOrDie(env, infoClazz, "<init>", "()V");
+ gStaticDisplayInfoClassInfo.isInternal = GetFieldIDOrDie(env, infoClazz, "isInternal", "Z");
+ gStaticDisplayInfoClassInfo.density = GetFieldIDOrDie(env, infoClazz, "density", "F");
+ gStaticDisplayInfoClassInfo.secure = GetFieldIDOrDie(env, infoClazz, "secure", "Z");
+ gStaticDisplayInfoClassInfo.deviceProductInfo =
GetFieldIDOrDie(env, infoClazz, "deviceProductInfo",
"Landroid/hardware/display/DeviceProductInfo;");
+ jclass dynamicInfoClazz = FindClassOrDie(env, "android/view/SurfaceControl$DynamicDisplayInfo");
+ gDynamicDisplayInfoClassInfo.clazz = MakeGlobalRefOrDie(env, dynamicInfoClazz);
+ gDynamicDisplayInfoClassInfo.ctor = GetMethodIDOrDie(env, dynamicInfoClazz, "<init>", "()V");
+ gDynamicDisplayInfoClassInfo.supportedDisplayModes =
+ GetFieldIDOrDie(env, dynamicInfoClazz, "supportedDisplayModes",
+ "[Landroid/view/SurfaceControl$DisplayMode;");
+ gDynamicDisplayInfoClassInfo.activeDisplayModeId =
+ GetFieldIDOrDie(env, dynamicInfoClazz, "activeDisplayModeId", "I");
+ gDynamicDisplayInfoClassInfo.supportedColorModes =
+ GetFieldIDOrDie(env, dynamicInfoClazz, "supportedColorModes", "[I");
+ gDynamicDisplayInfoClassInfo.activeColorMode =
+ GetFieldIDOrDie(env, dynamicInfoClazz, "activeColorMode", "I");
+ gDynamicDisplayInfoClassInfo.hdrCapabilities =
+ GetFieldIDOrDie(env, dynamicInfoClazz, "hdrCapabilities",
+ "Landroid/view/Display$HdrCapabilities;");
+
jclass modeClazz = FindClassOrDie(env, "android/view/SurfaceControl$DisplayMode");
gDisplayModeClassInfo.clazz = MakeGlobalRefOrDie(env, modeClazz);
gDisplayModeClassInfo.ctor = GetMethodIDOrDie(env, modeClazz, "<init>", "()V");
+ gDisplayModeClassInfo.id = GetFieldIDOrDie(env, modeClazz, "id", "I");
gDisplayModeClassInfo.width = GetFieldIDOrDie(env, modeClazz, "width", "I");
gDisplayModeClassInfo.height = GetFieldIDOrDie(env, modeClazz, "height", "I");
gDisplayModeClassInfo.xDpi = GetFieldIDOrDie(env, modeClazz, "xDpi", "F");
diff --git a/core/tests/coretests/src/android/app/time/ExternalTimeSuggestionTest.java b/core/tests/coretests/src/android/app/time/ExternalTimeSuggestionTest.java
index 266ff3dd09f6..1c6b3cc47a45 100644
--- a/core/tests/coretests/src/android/app/time/ExternalTimeSuggestionTest.java
+++ b/core/tests/coretests/src/android/app/time/ExternalTimeSuggestionTest.java
@@ -33,17 +33,20 @@ public class ExternalTimeSuggestionTest {
@Test
public void testEquals() {
- ExternalTimeSuggestion one = new ExternalTimeSuggestion(ARBITRARY_TIME);
+ ExternalTimeSuggestion one = new ExternalTimeSuggestion(
+ ARBITRARY_TIME.getReferenceTimeMillis(),
+ ARBITRARY_TIME.getValue());
assertEquals(one, one);
- ExternalTimeSuggestion two = new ExternalTimeSuggestion(ARBITRARY_TIME);
+ ExternalTimeSuggestion two = new ExternalTimeSuggestion(
+ ARBITRARY_TIME.getReferenceTimeMillis(),
+ ARBITRARY_TIME.getValue());
assertEquals(one, two);
assertEquals(two, one);
- TimestampedValue<Long> differentTime = new TimestampedValue<>(
+ ExternalTimeSuggestion three = new ExternalTimeSuggestion(
ARBITRARY_TIME.getReferenceTimeMillis() + 1,
ARBITRARY_TIME.getValue());
- ExternalTimeSuggestion three = new ExternalTimeSuggestion(differentTime);
assertNotEquals(one, three);
assertNotEquals(three, one);
@@ -55,7 +58,9 @@ public class ExternalTimeSuggestionTest {
@Test
public void testParcelable() {
- ExternalTimeSuggestion suggestion = new ExternalTimeSuggestion(ARBITRARY_TIME);
+ ExternalTimeSuggestion suggestion = new ExternalTimeSuggestion(
+ ARBITRARY_TIME.getReferenceTimeMillis(),
+ ARBITRARY_TIME.getValue());
assertRoundTripParcelable(suggestion);
// DebugInfo should also be stored (but is not checked by equals())
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 5633de348433..cabfad44cfb9 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -1321,6 +1321,12 @@
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/DisplayRotation.java"
},
+ "-567946587": {
+ "message": "Requested redraw for orientation change: %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_ORIENTATION",
+ "at": "com\/android\/server\/wm\/WindowState.java"
+ },
"-561092364": {
"message": "onPointerDownOutsideFocusLocked called on %s",
"level": "INFO",
diff --git a/graphics/java/android/graphics/BlurShader.java b/graphics/java/android/graphics/BlurShader.java
deleted file mode 100644
index 2e4bd7d9be43..000000000000
--- a/graphics/java/android/graphics/BlurShader.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.graphics;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-
-/**
- * A subclass of shader that blurs input from another {@link android.graphics.Shader} instance
- * or all the drawing commands with the {@link android.graphics.Paint} that this shader is
- * attached to.
- */
-public final class BlurShader extends Shader {
-
- private final float mRadiusX;
- private final float mRadiusY;
- private final Shader mInputShader;
- private final TileMode mEdgeTreatment;
-
- private long mNativeInputShader = 0;
-
- /**
- * Create a {@link BlurShader} that blurs the contents of the optional input shader
- * with the specified radius along the x and y axis. If no input shader is provided
- * then all drawing commands issued with a {@link android.graphics.Paint} that this
- * shader is installed in will be blurred.
- *
- * This uses a default {@link TileMode#DECAL} for edge treatment
- *
- * @param radiusX Radius of blur along the X axis
- * @param radiusY Radius of blur along the Y axis
- * @param inputShader Input shader that provides the content to be blurred
- */
- public BlurShader(float radiusX, float radiusY, @Nullable Shader inputShader) {
- this(radiusX, radiusY, inputShader, TileMode.DECAL);
- }
-
- /**
- * Create a {@link BlurShader} that blurs the contents of the optional input shader
- * with the specified radius along the x and y axis. If no input shader is provided
- * then all drawing commands issued with a {@link android.graphics.Paint} that this
- * shader is installed in will be blurred
- * @param radiusX Radius of blur along the X axis
- * @param radiusY Radius of blur along the Y axis
- * @param inputShader Input shader that provides the content to be blurred
- * @param edgeTreatment Policy for how to blur content near edges of the blur shader
- */
- public BlurShader(float radiusX, float radiusY, @Nullable Shader inputShader,
- @NonNull TileMode edgeTreatment) {
- mRadiusX = radiusX;
- mRadiusY = radiusY;
- mInputShader = inputShader;
- mEdgeTreatment = edgeTreatment;
- }
-
- /** @hide **/
- @Override
- protected long createNativeInstance(long nativeMatrix, boolean filterFromPaint) {
- mNativeInputShader = mInputShader != null
- ? mInputShader.getNativeInstance(filterFromPaint) : 0;
- return nativeCreate(nativeMatrix, mRadiusX, mRadiusY, mNativeInputShader,
- mEdgeTreatment.nativeInt);
- }
-
- /** @hide **/
- @Override
- protected boolean shouldDiscardNativeInstance(boolean filterFromPaint) {
- long currentNativeInstance = mInputShader != null
- ? mInputShader.getNativeInstance(filterFromPaint) : 0;
- return mNativeInputShader != currentNativeInstance;
- }
-
- private static native long nativeCreate(long nativeMatrix, float radiusX, float radiusY,
- long inputShader, int edgeTreatment);
-}
diff --git a/libs/WindowManager/Shell/res/layout/size_compat_mode_hint.xml b/libs/WindowManager/Shell/res/layout/size_compat_mode_hint.xml
index 347c2b47767e..0dea87c6b7fc 100644
--- a/libs/WindowManager/Shell/res/layout/size_compat_mode_hint.xml
+++ b/libs/WindowManager/Shell/res/layout/size_compat_mode_hint.xml
@@ -14,35 +14,52 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.wm.shell.sizecompatui.SizeCompatHintPopup
+ xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:background="@android:color/background_light"
- android:orientation="vertical">
+ android:layout_height="wrap_content">
- <TextView
- android:layout_width="180dp"
- android:layout_height="wrap_content"
- android:paddingLeft="10dp"
- android:paddingRight="10dp"
- android:paddingTop="10dp"
- android:text="@string/restart_button_description"
- android:textAlignment="viewStart"
- android:textColor="@android:color/primary_text_light"
- android:textSize="16sp" />
-
- <Button
- android:id="@+id/got_it"
+ <FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:includeFontPadding="false"
- android:layout_gravity="end"
- android:minHeight="36dp"
- android:background="?android:attr/selectableItemBackground"
- android:text="@string/got_it"
- android:textAllCaps="true"
- android:textColor="#3c78d8"
- android:textSize="16sp"
- android:textStyle="bold" />
-
-</LinearLayout>
+ android:gravity="center"
+ android:clipToPadding="false"
+ android:padding="@dimen/bubble_elevation">
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:background="@android:color/background_light"
+ android:elevation="@dimen/bubble_elevation"
+ android:orientation="vertical">
+
+ <TextView
+ android:layout_width="180dp"
+ android:layout_height="wrap_content"
+ android:paddingLeft="10dp"
+ android:paddingRight="10dp"
+ android:paddingTop="10dp"
+ android:text="@string/restart_button_description"
+ android:textAlignment="viewStart"
+ android:textColor="@android:color/primary_text_light"
+ android:textSize="16sp"/>
+
+ <Button
+ android:id="@+id/got_it"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:includeFontPadding="false"
+ android:layout_gravity="end"
+ android:minHeight="36dp"
+ android:background="?android:attr/selectableItemBackground"
+ android:text="@string/got_it"
+ android:textAllCaps="true"
+ android:textColor="#3c78d8"
+ android:textSize="16sp"
+ android:textStyle="bold"/>
+
+ </LinearLayout>
+
+ </FrameLayout>
+
+</com.android.wm.shell.sizecompatui.SizeCompatHintPopup>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatHintPopup.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatHintPopup.java
new file mode 100644
index 000000000000..78af9df30e6a
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatHintPopup.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2021 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.wm.shell.sizecompatui;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.Color;
+import android.graphics.drawable.RippleDrawable;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.Button;
+import android.widget.FrameLayout;
+
+import androidx.annotation.Nullable;
+
+import com.android.wm.shell.R;
+
+/** Popup to show the hint about the {@link SizeCompatRestartButton}. */
+public class SizeCompatHintPopup extends FrameLayout implements View.OnClickListener {
+
+ private SizeCompatUILayout mLayout;
+
+ public SizeCompatHintPopup(Context context) {
+ super(context);
+ }
+
+ public SizeCompatHintPopup(Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public SizeCompatHintPopup(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ public SizeCompatHintPopup(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ void inject(SizeCompatUILayout layout) {
+ mLayout = layout;
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ final Button gotItButton = findViewById(R.id.got_it);
+ gotItButton.setBackground(new RippleDrawable(ColorStateList.valueOf(Color.LTGRAY),
+ null /* content */, null /* mask */));
+ gotItButton.setOnClickListener(this);
+ }
+
+ @Override
+ public void onClick(View v) {
+ mLayout.dismissHint();
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatRestartButton.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatRestartButton.java
index 9094d7de8d63..08a840297df1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatRestartButton.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatRestartButton.java
@@ -22,19 +22,13 @@ import android.graphics.Color;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.RippleDrawable;
import android.util.AttributeSet;
-import android.view.LayoutInflater;
import android.view.View;
-import android.view.WindowManager;
-import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ImageButton;
-import android.widget.LinearLayout;
-import android.widget.PopupWindow;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import com.android.internal.annotations.VisibleForTesting;
import com.android.wm.shell.R;
/** Button to restart the size compat activity. */
@@ -42,10 +36,6 @@ public class SizeCompatRestartButton extends FrameLayout implements View.OnClick
View.OnLongClickListener {
private SizeCompatUILayout mLayout;
- private ImageButton mRestartButton;
- @VisibleForTesting
- PopupWindow mShowingHint;
- private WindowManager.LayoutParams mWinParams;
public SizeCompatRestartButton(@NonNull Context context) {
super(context);
@@ -67,24 +57,19 @@ public class SizeCompatRestartButton extends FrameLayout implements View.OnClick
void inject(SizeCompatUILayout layout) {
mLayout = layout;
- mWinParams = layout.getWindowLayoutParams();
- }
-
- void remove() {
- dismissHint();
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- mRestartButton = findViewById(R.id.size_compat_restart_button);
+ final ImageButton restartButton = findViewById(R.id.size_compat_restart_button);
final ColorStateList color = ColorStateList.valueOf(Color.LTGRAY);
final GradientDrawable mask = new GradientDrawable();
mask.setShape(GradientDrawable.OVAL);
mask.setColor(color);
- mRestartButton.setBackground(new RippleDrawable(color, null /* content */, mask));
- mRestartButton.setOnClickListener(this);
- mRestartButton.setOnLongClickListener(this);
+ restartButton.setBackground(new RippleDrawable(color, null /* content */, mask));
+ restartButton.setOnClickListener(this);
+ restartButton.setOnLongClickListener(this);
}
@Override
@@ -94,69 +79,7 @@ public class SizeCompatRestartButton extends FrameLayout implements View.OnClick
@Override
public boolean onLongClick(View v) {
- showHint();
+ mLayout.onRestartButtonLongClicked();
return true;
}
-
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- if (mLayout.mShouldShowHint) {
- mLayout.mShouldShowHint = false;
- showHint();
- }
- }
-
- @Override
- public void setVisibility(@Visibility int visibility) {
- if (visibility == View.GONE && mShowingHint != null) {
- // Also dismiss the popup.
- dismissHint();
- }
- super.setVisibility(visibility);
- }
-
- @Override
- public void setLayoutDirection(int layoutDirection) {
- final int gravity = SizeCompatUILayout.getGravity(layoutDirection);
- if (mWinParams.gravity != gravity) {
- mWinParams.gravity = gravity;
- getContext().getSystemService(WindowManager.class).updateViewLayout(this,
- mWinParams);
- }
- super.setLayoutDirection(layoutDirection);
- }
-
- void showHint() {
- if (mShowingHint != null) {
- return;
- }
-
- // TODO: popup is not attached to the button surface. Need to handle this differently for
- // non-fullscreen task.
- final View popupView = LayoutInflater.from(getContext()).inflate(
- R.layout.size_compat_mode_hint, null);
- final PopupWindow popupWindow = new PopupWindow(popupView,
- LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
- popupWindow.setWindowLayoutType(mWinParams.type);
- popupWindow.setElevation(getResources().getDimension(R.dimen.bubble_elevation));
- popupWindow.setAnimationStyle(android.R.style.Animation_InputMethod);
- popupWindow.setClippingEnabled(false);
- popupWindow.setOnDismissListener(() -> mShowingHint = null);
- mShowingHint = popupWindow;
-
- final Button gotItButton = popupView.findViewById(R.id.got_it);
- gotItButton.setBackground(new RippleDrawable(ColorStateList.valueOf(Color.LTGRAY),
- null /* content */, null /* mask */));
- gotItButton.setOnClickListener(view -> dismissHint());
- popupWindow.showAtLocation(mRestartButton, mWinParams.gravity, mLayout.mPopupOffsetX,
- mLayout.mPopupOffsetY);
- }
-
- void dismissHint() {
- if (mShowingHint != null) {
- mShowingHint.dismiss();
- mShowingHint = null;
- }
- }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUIController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUIController.java
index a3880f497ff3..c981adee9b5c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUIController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUIController.java
@@ -50,7 +50,7 @@ public class SizeCompatUIController implements DisplayController.OnDisplaysChang
/** Whether the IME is shown on display id. */
private final Set<Integer> mDisplaysWithIme = new ArraySet<>(1);
- /** The showing buttons by task id. */
+ /** The showing UIs by task id. */
private final SparseArray<SizeCompatUILayout> mActiveLayouts = new SparseArray<>(0);
/** Avoid creating display context frequently for non-default display. */
@@ -77,12 +77,12 @@ public class SizeCompatUIController implements DisplayController.OnDisplaysChang
}
/**
- * Called when the Task info changed. Creates and updates the restart button if there is an
- * activity in size compat, or removes the restart button if there is no size compat activity.
+ * Called when the Task info changed. Creates and updates the size compat UI if there is an
+ * activity in size compat, or removes the UI if there is no size compat activity.
*
* @param displayId display the task and activity are in.
* @param taskId task the activity is in.
- * @param taskConfig task config to place the restart button with.
+ * @param taskConfig task config to place the size compat UI with.
* @param sizeCompatActivity the size compat activity in the task. Can be {@code null} if the
* top activity in this Task is not in size compat.
* @param taskListener listener to handle the Task Surface placement.
@@ -94,10 +94,10 @@ public class SizeCompatUIController implements DisplayController.OnDisplaysChang
// Null token means the current foreground activity is not in size compatibility mode.
removeLayout(taskId);
} else if (mActiveLayouts.contains(taskId)) {
- // Button already exists, update the button layout.
+ // UI already exists, update the UI layout.
updateLayout(taskId, taskConfig, sizeCompatActivity, taskListener);
} else {
- // Create a new restart button.
+ // Create a new size compat UI.
createLayout(displayId, taskId, taskConfig, sizeCompatActivity, taskListener);
}
}
@@ -106,7 +106,7 @@ public class SizeCompatUIController implements DisplayController.OnDisplaysChang
public void onDisplayRemoved(int displayId) {
mDisplayContextCache.remove(displayId);
- // Remove all buttons on the removed display.
+ // Remove all size compat UIs on the removed display.
final List<Integer> toRemoveTaskIds = new ArrayList<>();
forAllLayoutsOnDisplay(displayId, layout -> toRemoveTaskIds.add(layout.getTaskId()));
for (int i = toRemoveTaskIds.size() - 1; i >= 0; i--) {
@@ -128,7 +128,7 @@ public class SizeCompatUIController implements DisplayController.OnDisplaysChang
mDisplaysWithIme.remove(displayId);
}
- // Hide the button when input method is showing.
+ // Hide the size compat UIs when input method is showing.
forAllLayoutsOnDisplay(displayId, layout -> layout.updateImeVisibility(isShowing));
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUILayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUILayout.java
index 5924b53f822c..32f3648be19a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUILayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUILayout.java
@@ -30,7 +30,6 @@ import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.os.Binder;
import android.os.IBinder;
-import android.view.Gravity;
import android.view.SurfaceControl;
import android.view.View;
import android.view.WindowManager;
@@ -43,7 +42,7 @@ import com.android.wm.shell.common.SyncTransactionQueue;
/**
* Records and handles layout of size compat UI on a task with size compat activity. Helps to
- * calculate proper bounds when configuration or button position changes.
+ * calculate proper bounds when configuration or UI position changes.
*/
class SizeCompatUILayout {
private static final String TAG = "SizeCompatUILayout";
@@ -56,12 +55,18 @@ class SizeCompatUILayout {
private IBinder mActivityToken;
private ShellTaskOrganizer.TaskListener mTaskListener;
private DisplayLayout mDisplayLayout;
- @VisibleForTesting
- final SizeCompatUIWindowManager mWindowManager;
@VisibleForTesting
+ final SizeCompatUIWindowManager mButtonWindowManager;
+ @VisibleForTesting
+ @Nullable
+ SizeCompatUIWindowManager mHintWindowManager;
+ @VisibleForTesting
@Nullable
SizeCompatRestartButton mButton;
+ @VisibleForTesting
+ @Nullable
+ SizeCompatHintPopup mHint;
final int mButtonSize;
final int mPopupOffsetX;
final int mPopupOffsetY;
@@ -79,7 +84,7 @@ class SizeCompatUILayout {
mTaskListener = taskListener;
mDisplayLayout = displayLayout;
mShouldShowHint = !hasShownHint;
- mWindowManager = new SizeCompatUIWindowManager(mContext, taskConfig, this);
+ mButtonWindowManager = new SizeCompatUIWindowManager(mContext, taskConfig, this);
mButtonSize =
mContext.getResources().getDimensionPixelSize(R.dimen.size_compat_button_size);
@@ -87,21 +92,52 @@ class SizeCompatUILayout {
mPopupOffsetY = mButtonSize;
}
- /** Creates the button window. */
+ /** Creates the activity restart button window. */
void createSizeCompatButton(boolean isImeShowing) {
if (isImeShowing || mButton != null) {
// When ime is showing, wait until ime is dismiss to create UI.
return;
}
- mButton = mWindowManager.createSizeCompatUI();
- updateSurfacePosition();
+ mButton = mButtonWindowManager.createSizeCompatButton();
+ updateButtonSurfacePosition();
+
+ if (mShouldShowHint) {
+ // Only show by default for the first time.
+ mShouldShowHint = false;
+ createSizeCompatHint();
+ }
+ }
+
+ /** Creates the restart button hint window. */
+ private void createSizeCompatHint() {
+ if (mHint != null) {
+ // Hint already shown.
+ return;
+ }
+ mHintWindowManager = createHintWindowManager();
+ mHint = mHintWindowManager.createSizeCompatHint();
+ updateHintSurfacePosition();
}
- /** Releases the button window. */
+ @VisibleForTesting
+ SizeCompatUIWindowManager createHintWindowManager() {
+ return new SizeCompatUIWindowManager(mContext, mTaskConfig, this);
+ }
+
+ /** Dismisses the hint window. */
+ void dismissHint() {
+ mHint = null;
+ if (mHintWindowManager != null) {
+ mHintWindowManager.release();
+ mHintWindowManager = null;
+ }
+ }
+
+ /** Releases the UI windows. */
void release() {
- mButton.remove();
+ dismissHint();
mButton = null;
- mWindowManager.release();
+ mButtonWindowManager.release();
}
/** Called when size compat info changed. */
@@ -115,7 +151,10 @@ class SizeCompatUILayout {
// Update configuration.
mContext = mContext.createConfigurationContext(taskConfig);
- mWindowManager.setConfiguration(taskConfig);
+ mButtonWindowManager.setConfiguration(taskConfig);
+ if (mHintWindowManager != null) {
+ mHintWindowManager.setConfiguration(taskConfig);
+ }
if (mButton == null || prevTaskListener != taskListener) {
// TaskListener changed, recreate the button for new surface parent.
@@ -126,14 +165,19 @@ class SizeCompatUILayout {
if (!taskConfig.windowConfiguration.getBounds()
.equals(prevTaskConfig.windowConfiguration.getBounds())) {
- // Reposition the button surface.
- updateSurfacePosition();
+ // Reposition the UI surfaces.
+ updateButtonSurfacePosition();
+ updateHintSurfacePosition();
}
if (taskConfig.getLayoutDirection() != prevTaskConfig.getLayoutDirection()) {
// Update layout for RTL.
mButton.setLayoutDirection(taskConfig.getLayoutDirection());
- updateSurfacePosition();
+ updateButtonSurfacePosition();
+ if (mHint != null) {
+ mHint.setLayoutDirection(taskConfig.getLayoutDirection());
+ updateHintSurfacePosition();
+ }
}
}
@@ -149,8 +193,9 @@ class SizeCompatUILayout {
displayLayout.getStableBounds(curStableBounds);
mDisplayLayout = displayLayout;
if (!prevStableBounds.equals(curStableBounds)) {
- // Stable bounds changed, update button surface position.
- updateSurfacePosition();
+ // Stable bounds changed, update UI surface positions.
+ updateButtonSurfacePosition();
+ updateHintSurfacePosition();
}
}
@@ -162,27 +207,46 @@ class SizeCompatUILayout {
return;
}
+ // Hide size compat UIs when IME is showing.
final int newVisibility = isImeShowing ? View.GONE : View.VISIBLE;
if (mButton.getVisibility() != newVisibility) {
mButton.setVisibility(newVisibility);
}
+ if (mHint != null && mHint.getVisibility() != newVisibility) {
+ mHint.setVisibility(newVisibility);
+ }
}
/** Gets the layout params for restart button. */
- WindowManager.LayoutParams getWindowLayoutParams() {
+ WindowManager.LayoutParams getButtonWindowLayoutParams() {
final WindowManager.LayoutParams winParams = new WindowManager.LayoutParams(
+ // Cannot be wrap_content as this determines the actual window size
mButtonSize, mButtonSize,
TYPE_APPLICATION_OVERLAY,
FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL,
PixelFormat.TRANSLUCENT);
- winParams.gravity = getGravity(getLayoutDirection());
winParams.token = new Binder();
- winParams.setTitle(SizeCompatRestartButton.class.getSimpleName() + mContext.getDisplayId());
+ winParams.setTitle(SizeCompatRestartButton.class.getSimpleName() + getTaskId());
winParams.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION | PRIVATE_FLAG_TRUSTED_OVERLAY;
return winParams;
}
- /** Called when it is ready to be placed button surface button. */
+ /** Gets the layout params for hint popup. */
+ WindowManager.LayoutParams getHintWindowLayoutParams(SizeCompatHintPopup hint) {
+ final WindowManager.LayoutParams winParams = new WindowManager.LayoutParams(
+ // Cannot be wrap_content as this determines the actual window size
+ hint.getMeasuredWidth(), hint.getMeasuredHeight(),
+ TYPE_APPLICATION_OVERLAY,
+ FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL,
+ PixelFormat.TRANSLUCENT);
+ winParams.token = new Binder();
+ winParams.setTitle(SizeCompatHintPopup.class.getSimpleName() + getTaskId());
+ winParams.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION | PRIVATE_FLAG_TRUSTED_OVERLAY;
+ winParams.windowAnimations = android.R.style.Animation_InputMethod;
+ return winParams;
+ }
+
+ /** Called when it is ready to be placed size compat UI surface. */
void attachToParentSurface(SurfaceControl.Builder b) {
mTaskListener.attachChildSurfaceToTask(mTaskId, b);
}
@@ -192,13 +256,17 @@ class SizeCompatUILayout {
ActivityClient.getInstance().restartActivityProcessIfVisible(mActivityToken);
}
+ /** Called when the restart button is long clicked. */
+ void onRestartButtonLongClicked() {
+ createSizeCompatHint();
+ }
+
@VisibleForTesting
- void updateSurfacePosition() {
- if (mButton == null || mWindowManager.getSurfaceControl() == null) {
+ void updateButtonSurfacePosition() {
+ if (mButton == null || mButtonWindowManager.getSurfaceControl() == null) {
return;
}
- // The hint popup won't be at the correct position.
- mButton.dismissHint();
+ final SurfaceControl leash = mButtonWindowManager.getSurfaceControl();
// Use stable bounds to prevent the button from overlapping with system bars.
final Rect taskBounds = mTaskConfig.windowConfiguration.getBounds();
@@ -212,8 +280,30 @@ class SizeCompatUILayout {
: stableBounds.right - taskBounds.left - mButtonSize;
final int positionY = stableBounds.bottom - taskBounds.top - mButtonSize;
- mSyncQueue.runInSync(t ->
- t.setPosition(mWindowManager.getSurfaceControl(), positionX, positionY));
+ mSyncQueue.runInSync(t -> t.setPosition(leash, positionX, positionY));
+ }
+
+ void updateHintSurfacePosition() {
+ if (mHint == null || mHintWindowManager == null
+ || mHintWindowManager.getSurfaceControl() == null) {
+ return;
+ }
+ final SurfaceControl leash = mHintWindowManager.getSurfaceControl();
+
+ // Use stable bounds to prevent the hint from overlapping with system bars.
+ final Rect taskBounds = mTaskConfig.windowConfiguration.getBounds();
+ final Rect stableBounds = new Rect();
+ mDisplayLayout.getStableBounds(stableBounds);
+ stableBounds.intersect(taskBounds);
+
+ // Position of the hint in the container coordinate.
+ final int positionX = getLayoutDirection() == View.LAYOUT_DIRECTION_RTL
+ ? stableBounds.left - taskBounds.left + mPopupOffsetX
+ : stableBounds.right - taskBounds.left - mPopupOffsetX - mHint.getMeasuredWidth();
+ final int positionY =
+ stableBounds.bottom - taskBounds.top - mPopupOffsetY - mHint.getMeasuredHeight();
+
+ mSyncQueue.runInSync(t -> t.setPosition(leash, positionX, positionY));
}
int getDisplayId() {
@@ -227,9 +317,4 @@ class SizeCompatUILayout {
private int getLayoutDirection() {
return mContext.getResources().getConfiguration().getLayoutDirection();
}
-
- static int getGravity(int layoutDirection) {
- return Gravity.BOTTOM
- | (layoutDirection == View.LAYOUT_DIRECTION_RTL ? Gravity.START : Gravity.END);
- }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUIWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUIWindowManager.java
index a7ad982a4736..f634c4586e39 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUIWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUIWindowManager.java
@@ -24,12 +24,14 @@ import android.view.LayoutInflater;
import android.view.SurfaceControl;
import android.view.SurfaceControlViewHost;
import android.view.SurfaceSession;
+import android.view.View;
import android.view.WindowlessWindowManager;
import com.android.wm.shell.R;
/**
- * Holds view hierarchy of a root surface and helps to inflate {@link SizeCompatRestartButton}.
+ * Holds view hierarchy of a root surface and helps to inflate {@link SizeCompatRestartButton} or
+ * {@link SizeCompatHintPopup}.
*/
class SizeCompatUIWindowManager extends WindowlessWindowManager {
@@ -67,18 +69,39 @@ class SizeCompatUIWindowManager extends WindowlessWindowManager {
}
/** Inflates {@link SizeCompatRestartButton} on to the root surface. */
- SizeCompatRestartButton createSizeCompatUI() {
- if (mViewHost == null) {
- mViewHost = new SurfaceControlViewHost(mContext, mContext.getDisplay(), this);
+ SizeCompatRestartButton createSizeCompatButton() {
+ if (mViewHost != null) {
+ throw new IllegalStateException(
+ "A UI has already been created with this window manager.");
}
+ mViewHost = new SurfaceControlViewHost(mContext, mContext.getDisplay(), this);
+
final SizeCompatRestartButton button = (SizeCompatRestartButton)
LayoutInflater.from(mContext).inflate(R.layout.size_compat_ui, null);
button.inject(mLayout);
- mViewHost.setView(button, mLayout.getWindowLayoutParams());
+ mViewHost.setView(button, mLayout.getButtonWindowLayoutParams());
return button;
}
+ /** Inflates {@link SizeCompatHintPopup} on to the root surface. */
+ SizeCompatHintPopup createSizeCompatHint() {
+ if (mViewHost != null) {
+ throw new IllegalStateException(
+ "A UI has already been created with this window manager.");
+ }
+
+ mViewHost = new SurfaceControlViewHost(mContext, mContext.getDisplay(), this);
+
+ final SizeCompatHintPopup hint = (SizeCompatHintPopup)
+ LayoutInflater.from(mContext).inflate(R.layout.size_compat_mode_hint, null);
+ // Measure how big the hint is.
+ hint.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
+ hint.inject(mLayout);
+ mViewHost.setView(hint, mLayout.getHintWindowLayoutParams(hint));
+ return hint;
+ }
+
/** Releases the surface control and tears down the view hierarchy. */
void release() {
if (mViewHost != null) {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatHintPopupTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatHintPopupTest.java
new file mode 100644
index 000000000000..9845d4650d20
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatHintPopupTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2021 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.wm.shell.sizecompatui;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.verify;
+
+import android.content.res.Configuration;
+import android.os.IBinder;
+import android.testing.AndroidTestingRunner;
+import android.view.LayoutInflater;
+import android.widget.Button;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.wm.shell.R;
+import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.ShellTestCase;
+import com.android.wm.shell.common.DisplayLayout;
+import com.android.wm.shell.common.SyncTransactionQueue;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Tests for {@link SizeCompatHintPopup}.
+ *
+ * Build/Install/Run:
+ * atest WMShellUnitTests:SizeCompatHintPopupTest
+ */
+@RunWith(AndroidTestingRunner.class)
+@SmallTest
+public class SizeCompatHintPopupTest extends ShellTestCase {
+
+ @Mock private SyncTransactionQueue mSyncTransactionQueue;
+ @Mock private IBinder mActivityToken;
+ @Mock private ShellTaskOrganizer.TaskListener mTaskListener;
+ @Mock private DisplayLayout mDisplayLayout;
+
+ private SizeCompatUILayout mLayout;
+ private SizeCompatHintPopup mHint;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ final int taskId = 1;
+ mLayout = new SizeCompatUILayout(mSyncTransactionQueue, mContext, new Configuration(),
+ taskId, mActivityToken, mTaskListener, mDisplayLayout, false /* hasShownHint*/);
+ mHint = (SizeCompatHintPopup)
+ LayoutInflater.from(mContext).inflate(R.layout.size_compat_mode_hint, null);
+ mHint.inject(mLayout);
+
+ spyOn(mLayout);
+ }
+
+ @Test
+ public void testOnClick() {
+ doNothing().when(mLayout).dismissHint();
+
+ final Button button = mHint.findViewById(R.id.got_it);
+ button.performClick();
+
+ verify(mLayout).dismissHint();
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatRestartButtonTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatRestartButtonTest.java
index d9086a6ccdc1..5a43925a5677 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatRestartButtonTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatRestartButtonTest.java
@@ -19,13 +19,13 @@ package com.android.wm.shell.sizecompatui;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import android.content.res.Configuration;
import android.os.IBinder;
import android.testing.AndroidTestingRunner;
import android.view.LayoutInflater;
+import android.widget.ImageButton;
import androidx.test.filters.SmallTest;
@@ -71,45 +71,25 @@ public class SizeCompatRestartButtonTest extends ShellTestCase {
mButton.inject(mLayout);
spyOn(mLayout);
- spyOn(mButton);
- doNothing().when(mButton).showHint();
}
@Test
public void testOnClick() {
doNothing().when(mLayout).onRestartButtonClicked();
- mButton.onClick(mButton);
+ final ImageButton button = mButton.findViewById(R.id.size_compat_restart_button);
+ button.performClick();
verify(mLayout).onRestartButtonClicked();
}
@Test
public void testOnLongClick() {
- verify(mButton, never()).showHint();
+ doNothing().when(mLayout).onRestartButtonLongClicked();
- mButton.onLongClick(mButton);
+ final ImageButton button = mButton.findViewById(R.id.size_compat_restart_button);
+ button.performLongClick();
- verify(mButton).showHint();
- }
-
- @Test
- public void testOnAttachedToWindow_showHint() {
- mLayout.mShouldShowHint = false;
- mButton.onAttachedToWindow();
-
- verify(mButton, never()).showHint();
-
- mLayout.mShouldShowHint = true;
- mButton.onAttachedToWindow();
-
- verify(mButton).showHint();
- }
-
- @Test
- public void testRemove() {
- mButton.remove();
-
- verify(mButton).dismissHint();
+ verify(mLayout).onRestartButtonLongClicked();
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatUILayoutTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatUILayoutTest.java
index 236db44bdce0..f33cfe86224f 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatUILayoutTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatUILayoutTest.java
@@ -18,6 +18,7 @@ package com.android.wm.shell.sizecompatui;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.mockito.ArgumentMatchers.any;
@@ -27,6 +28,7 @@ import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.app.ActivityClient;
@@ -68,6 +70,7 @@ public class SizeCompatUILayoutTest extends ShellTestCase {
@Mock private ShellTaskOrganizer.TaskListener mTaskListener;
@Mock private DisplayLayout mDisplayLayout;
@Mock private SizeCompatRestartButton mButton;
+ @Mock private SizeCompatHintPopup mHint;
private Configuration mTaskConfig;
private SizeCompatUILayout mLayout;
@@ -81,8 +84,13 @@ public class SizeCompatUILayoutTest extends ShellTestCase {
TASK_ID, mActivityToken, mTaskListener, mDisplayLayout, false /* hasShownHint*/);
spyOn(mLayout);
- spyOn(mLayout.mWindowManager);
- doReturn(mButton).when(mLayout.mWindowManager).createSizeCompatUI();
+ spyOn(mLayout.mButtonWindowManager);
+ doReturn(mButton).when(mLayout.mButtonWindowManager).createSizeCompatButton();
+
+ final SizeCompatUIWindowManager hintWindowManager = mLayout.createHintWindowManager();
+ spyOn(hintWindowManager);
+ doReturn(mHint).when(hintWindowManager).createSizeCompatHint();
+ doReturn(hintWindowManager).when(mLayout).createHintWindowManager();
}
@Test
@@ -90,24 +98,45 @@ public class SizeCompatUILayoutTest extends ShellTestCase {
// Not create button if IME is showing.
mLayout.createSizeCompatButton(true /* isImeShowing */);
- verify(mLayout.mWindowManager, never()).createSizeCompatUI();
+ verify(mLayout.mButtonWindowManager, never()).createSizeCompatButton();
assertNull(mLayout.mButton);
+ assertNull(mLayout.mHintWindowManager);
+ assertNull(mLayout.mHint);
+ // Not create hint popup.
+ mLayout.mShouldShowHint = false;
mLayout.createSizeCompatButton(false /* isImeShowing */);
- verify(mLayout.mWindowManager).createSizeCompatUI();
+ verify(mLayout.mButtonWindowManager).createSizeCompatButton();
assertNotNull(mLayout.mButton);
+ assertNull(mLayout.mHintWindowManager);
+ assertNull(mLayout.mHint);
+
+ // Create hint popup.
+ mLayout.release();
+ mLayout.mShouldShowHint = true;
+ mLayout.createSizeCompatButton(false /* isImeShowing */);
+
+ verify(mLayout.mButtonWindowManager, times(2)).createSizeCompatButton();
+ assertNotNull(mLayout.mButton);
+ assertNotNull(mLayout.mHintWindowManager);
+ verify(mLayout.mHintWindowManager).createSizeCompatHint();
+ assertNotNull(mLayout.mHint);
+ assertFalse(mLayout.mShouldShowHint);
}
@Test
public void testRelease() {
mLayout.createSizeCompatButton(false /* isImeShowing */);
+ final SizeCompatUIWindowManager hintWindowManager = mLayout.mHintWindowManager;
mLayout.release();
assertNull(mLayout.mButton);
- verify(mButton).remove();
- verify(mLayout.mWindowManager).release();
+ assertNull(mLayout.mHint);
+ verify(hintWindowManager).release();
+ assertNull(mLayout.mHintWindowManager);
+ verify(mLayout.mButtonWindowManager).release();
}
@Test
@@ -119,7 +148,7 @@ public class SizeCompatUILayoutTest extends ShellTestCase {
mLayout.updateSizeCompatInfo(mTaskConfig, mActivityToken, mTaskListener,
false /* isImeShowing */);
- verify(mLayout, never()).updateSurfacePosition();
+ verify(mLayout, never()).updateButtonSurfacePosition();
verify(mLayout, never()).release();
verify(mLayout, never()).createSizeCompatButton(anyBoolean());
@@ -140,7 +169,8 @@ public class SizeCompatUILayoutTest extends ShellTestCase {
mLayout.updateSizeCompatInfo(newTaskConfiguration, mActivityToken, newTaskListener,
false /* isImeShowing */);
- verify(mLayout).updateSurfacePosition();
+ verify(mLayout).updateButtonSurfacePosition();
+ verify(mLayout).updateHintSurfacePosition();
}
@Test
@@ -152,14 +182,16 @@ public class SizeCompatUILayoutTest extends ShellTestCase {
mContext.getResources(), false, false);
mLayout.updateDisplayLayout(displayLayout1);
- verify(mLayout).updateSurfacePosition();
+ verify(mLayout).updateButtonSurfacePosition();
+ verify(mLayout).updateHintSurfacePosition();
// No update if the display bounds is the same.
clearInvocations(mLayout);
final DisplayLayout displayLayout2 = new DisplayLayout(displayInfo,
mContext.getResources(), false, false);
mLayout.updateDisplayLayout(displayLayout2);
- verify(mLayout, never()).updateSurfacePosition();
+ verify(mLayout, never()).updateButtonSurfacePosition();
+ verify(mLayout, never()).updateHintSurfacePosition();
}
@Test
@@ -203,4 +235,29 @@ public class SizeCompatUILayoutTest extends ShellTestCase {
verify(ActivityClient.getInstance()).restartActivityProcessIfVisible(mActivityToken);
}
+
+ @Test
+ public void testOnRestartButtonLongClicked_showHint() {
+ mLayout.dismissHint();
+
+ assertNull(mLayout.mHint);
+
+ mLayout.onRestartButtonLongClicked();
+
+ assertNotNull(mLayout.mHint);
+ }
+
+ @Test
+ public void testDismissHint() {
+ mLayout.onRestartButtonLongClicked();
+ final SizeCompatUIWindowManager hintWindowManager = mLayout.mHintWindowManager;
+ assertNotNull(mLayout.mHint);
+ assertNotNull(hintWindowManager);
+
+ mLayout.dismissHint();
+
+ assertNull(mLayout.mHint);
+ assertNull(mLayout.mHintWindowManager);
+ verify(hintWindowManager).release();
+ }
}
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index 64b8b711f0a8..170f73120414 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -384,10 +384,11 @@ struct DrawImageLattice final : Op {
struct DrawTextBlob final : Op {
static const auto kType = Type::DrawTextBlob;
DrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, const SkPaint& paint)
- : blob(sk_ref_sp(blob)), x(x), y(y), paint(paint) {}
+ : blob(sk_ref_sp(blob)), x(x), y(y), paint(paint), drawTextBlobMode(gDrawTextBlobMode) {}
sk_sp<const SkTextBlob> blob;
SkScalar x, y;
SkPaint paint;
+ DrawTextBlobMode drawTextBlobMode;
void draw(SkCanvas* c, const SkMatrix&) const { c->drawTextBlob(blob.get(), x, y, paint); }
};
@@ -832,6 +833,24 @@ constexpr color_transform_fn colorTransformForOp() {
}
}
+template<>
+constexpr color_transform_fn colorTransformForOp<DrawTextBlob>() {
+ return [](const void *opRaw, ColorTransform transform) {
+ const DrawTextBlob *op = reinterpret_cast<const DrawTextBlob*>(opRaw);
+ switch (op->drawTextBlobMode) {
+ case DrawTextBlobMode::HctOutline:
+ const_cast<SkPaint&>(op->paint).setColor(SK_ColorBLACK);
+ break;
+ case DrawTextBlobMode::HctInner:
+ const_cast<SkPaint&>(op->paint).setColor(SK_ColorWHITE);
+ break;
+ default:
+ transformPaint(transform, const_cast<SkPaint*>(&(op->paint)));
+ break;
+ }
+ };
+}
+
#define X(T) colorTransformForOp<T>(),
static const color_transform_fn color_transform_fns[] = {
#include "DisplayListOps.in"
diff --git a/libs/hwui/hwui/Canvas.cpp b/libs/hwui/hwui/Canvas.cpp
index 146bf283c58a..b046f45d9c57 100644
--- a/libs/hwui/hwui/Canvas.cpp
+++ b/libs/hwui/hwui/Canvas.cpp
@@ -110,16 +110,19 @@ public:
bool darken = channelSum < (128 * 3);
// outline
+ gDrawTextBlobMode = DrawTextBlobMode::HctOutline;
Paint outlinePaint(paint);
simplifyPaint(darken ? SK_ColorWHITE : SK_ColorBLACK, &outlinePaint);
outlinePaint.setStyle(SkPaint::kStrokeAndFill_Style);
canvas->drawGlyphs(glyphFunc, glyphCount, outlinePaint, x, y, totalAdvance);
// inner
+ gDrawTextBlobMode = DrawTextBlobMode::HctInner;
Paint innerPaint(paint);
simplifyPaint(darken ? SK_ColorBLACK : SK_ColorWHITE, &innerPaint);
innerPaint.setStyle(SkPaint::kFill_Style);
canvas->drawGlyphs(glyphFunc, glyphCount, innerPaint, x, y, totalAdvance);
+ gDrawTextBlobMode = DrawTextBlobMode::Normal;
} else {
// standard draw path
canvas->drawGlyphs(glyphFunc, glyphCount, paint, x, y, totalAdvance);
diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h
index fdfa2883c33f..d1bdb712e911 100644
--- a/libs/hwui/hwui/Canvas.h
+++ b/libs/hwui/hwui/Canvas.h
@@ -61,6 +61,14 @@ class Bitmap;
class Paint;
struct Typeface;
+enum class DrawTextBlobMode {
+ Normal,
+ HctOutline,
+ HctInner,
+};
+
+inline DrawTextBlobMode gDrawTextBlobMode = DrawTextBlobMode::Normal;
+
class ANDROID_API Canvas {
public:
virtual ~Canvas(){};
diff --git a/libs/hwui/tests/common/TestContext.cpp b/libs/hwui/tests/common/TestContext.cpp
index 6a9a98d6743b..898c64bd4159 100644
--- a/libs/hwui/tests/common/TestContext.cpp
+++ b/libs/hwui/tests/common/TestContext.cpp
@@ -22,16 +22,16 @@ namespace android {
namespace uirenderer {
namespace test {
-const DisplayInfo& getDisplayInfo() {
- static DisplayInfo info = [] {
- DisplayInfo info;
+const ui::StaticDisplayInfo& getDisplayInfo() {
+ static ui::StaticDisplayInfo info = [] {
+ ui::StaticDisplayInfo info;
#if HWUI_NULL_GPU
info.density = 2.f;
#else
const sp<IBinder> token = SurfaceComposerClient::getInternalDisplayToken();
LOG_ALWAYS_FATAL_IF(!token, "%s: No internal display", __FUNCTION__);
- const status_t status = SurfaceComposerClient::getDisplayInfo(token, &info);
+ const status_t status = SurfaceComposerClient::getStaticDisplayInfo(token, &info);
LOG_ALWAYS_FATAL_IF(status, "%s: Failed to get display info", __FUNCTION__);
#endif
return info;
diff --git a/libs/hwui/tests/common/TestContext.h b/libs/hwui/tests/common/TestContext.h
index 7d2f6d8ea731..9d00366daffe 100644
--- a/libs/hwui/tests/common/TestContext.h
+++ b/libs/hwui/tests/common/TestContext.h
@@ -23,8 +23,8 @@
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
#include <gui/SurfaceControl.h>
-#include <ui/DisplayInfo.h>
#include <ui/DisplayMode.h>
+#include <ui/StaticDisplayInfo.h>
#include <utils/Looper.h>
#include <atomic>
@@ -36,7 +36,7 @@ namespace android {
namespace uirenderer {
namespace test {
-const DisplayInfo& getDisplayInfo();
+const ui::StaticDisplayInfo& getDisplayInfo();
const ui::DisplayMode& getActiveDisplayMode();
inline const ui::Size& getActiveDisplayResolution() {
diff --git a/libs/input/MouseCursorController.h b/libs/input/MouseCursorController.h
index e6dfc4c6f99a..c0ab58bd2e7e 100644
--- a/libs/input/MouseCursorController.h
+++ b/libs/input/MouseCursorController.h
@@ -20,7 +20,6 @@
#include <gui/DisplayEventReceiver.h>
#include <input/DisplayViewport.h>
#include <input/Input.h>
-#include <ui/DisplayInfo.h>
#include <utils/BitSet.h>
#include <utils/Looper.h>
#include <utils/RefBase.h>
diff --git a/libs/input/PointerController.h b/libs/input/PointerController.h
index 827fcf1e1bc1..97567bab202b 100644
--- a/libs/input/PointerController.h
+++ b/libs/input/PointerController.h
@@ -21,7 +21,6 @@
#include <gui/DisplayEventReceiver.h>
#include <input/DisplayViewport.h>
#include <input/Input.h>
-#include <ui/DisplayInfo.h>
#include <utils/BitSet.h>
#include <utils/Looper.h>
#include <utils/RefBase.h>
diff --git a/libs/input/PointerControllerContext.h b/libs/input/PointerControllerContext.h
index 98073fea323e..26a65a47471d 100644
--- a/libs/input/PointerControllerContext.h
+++ b/libs/input/PointerControllerContext.h
@@ -21,7 +21,6 @@
#include <gui/DisplayEventReceiver.h>
#include <input/DisplayViewport.h>
#include <input/Input.h>
-#include <ui/DisplayInfo.h>
#include <utils/BitSet.h>
#include <utils/Looper.h>
#include <utils/RefBase.h>
diff --git a/media/java/android/media/AudioDeviceInfo.java b/media/java/android/media/AudioDeviceInfo.java
index 205c1f4b4057..383c93d7716d 100644
--- a/media/java/android/media/AudioDeviceInfo.java
+++ b/media/java/android/media/AudioDeviceInfo.java
@@ -16,8 +16,10 @@
package android.media;
+import android.Manifest;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
import android.util.SparseIntArray;
import java.lang.annotation.Retention;
@@ -161,6 +163,14 @@ public final class AudioDeviceInfo {
*/
public static final int TYPE_BLE_SPEAKER = 27;
+ /**
+ * A device type describing an Echo Canceller loopback Reference.
+ * This device is only used when capturing with MediaRecorder.AudioSource.ECHO_REFERENCE,
+ * which requires privileged permission
+ * {@link android.Manifest.permission#CAPTURE_AUDIO_OUTPUT}.
+ * @hide */
+ @RequiresPermission(Manifest.permission.CAPTURE_AUDIO_OUTPUT)
+ public static final int TYPE_ECHO_REFERENCE = 28;
/** @hide */
@IntDef(flag = false, prefix = "TYPE", value = {
@@ -188,7 +198,8 @@ public final class AudioDeviceInfo {
TYPE_FM_TUNER,
TYPE_TV_TUNER,
TYPE_BLE_HEADSET,
- TYPE_BLE_SPEAKER}
+ TYPE_BLE_SPEAKER,
+ TYPE_ECHO_REFERENCE}
)
@Retention(RetentionPolicy.SOURCE)
public @interface AudioDeviceType {}
@@ -211,7 +222,8 @@ public final class AudioDeviceInfo {
TYPE_LINE_DIGITAL,
TYPE_IP,
TYPE_BUS,
- TYPE_BLE_HEADSET}
+ TYPE_BLE_HEADSET,
+ TYPE_ECHO_REFERENCE}
)
@Retention(RetentionPolicy.SOURCE)
public @interface AudioDeviceTypeIn {}
@@ -297,6 +309,7 @@ public final class AudioDeviceInfo {
case TYPE_BUS:
case TYPE_REMOTE_SUBMIX:
case TYPE_BLE_HEADSET:
+ case TYPE_ECHO_REFERENCE:
return true;
default:
return false;
@@ -621,6 +634,8 @@ public final class AudioDeviceInfo {
INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BUS, TYPE_BUS);
INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_REMOTE_SUBMIX, TYPE_REMOTE_SUBMIX);
INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BLE_HEADSET, TYPE_BLE_HEADSET);
+ INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_ECHO_REFERENCE, TYPE_ECHO_REFERENCE);
+
// privileges mapping to output device
EXT_TO_INT_DEVICE_MAPPING = new SparseIntArray();
@@ -678,6 +693,9 @@ public final class AudioDeviceInfo {
EXT_TO_INT_INPUT_DEVICE_MAPPING.put(
TYPE_REMOTE_SUBMIX, AudioSystem.DEVICE_IN_REMOTE_SUBMIX);
EXT_TO_INT_INPUT_DEVICE_MAPPING.put(TYPE_BLE_HEADSET, AudioSystem.DEVICE_IN_BLE_HEADSET);
+ EXT_TO_INT_INPUT_DEVICE_MAPPING.put(
+ TYPE_ECHO_REFERENCE, AudioSystem.DEVICE_IN_ECHO_REFERENCE);
+
}
}
diff --git a/media/jni/tuner/DemuxClient.cpp b/media/jni/tuner/DemuxClient.cpp
index 359ef364083c..78cb5b003a38 100644
--- a/media/jni/tuner/DemuxClient.cpp
+++ b/media/jni/tuner/DemuxClient.cpp
@@ -216,7 +216,7 @@ Result DemuxClient::disconnectCiCam() {
Result DemuxClient::close() {
if (mTunerDemux != NULL) {
Status s = mTunerDemux->close();
- mDemux = NULL;
+ mTunerDemux = NULL;
return ClientHelper::getServiceSpecificErrorCode(s);
}
diff --git a/native/android/surface_control.cpp b/native/android/surface_control.cpp
index e51add276647..e8cf63f64572 100644
--- a/native/android/surface_control.cpp
+++ b/native/android/surface_control.cpp
@@ -27,14 +27,13 @@
#include <gui/SurfaceComposerClient.h>
#include <gui/SurfaceControl.h>
-#include <ui/HdrCapabilities.h>
+#include <ui/DynamicDisplayInfo.h>
#include <utils/Timers.h>
using namespace android::hardware::configstore;
using namespace android::hardware::configstore::V1_0;
using namespace android;
-using android::hardware::configstore::V1_0::ISurfaceFlingerConfigs;
using Transaction = SurfaceComposerClient::Transaction;
@@ -72,14 +71,13 @@ static bool getHdrSupport(const sp<SurfaceControl>& surfaceControl) {
return false;
}
- HdrCapabilities hdrCapabilities;
- status_t err = client->getHdrCapabilities(display, &hdrCapabilities);
- if (err) {
+ ui::DynamicDisplayInfo info;
+ if (status_t err = client->getDynamicDisplayInfo(display, &info); err != NO_ERROR) {
ALOGE("unable to get hdr capabilities");
- return false;
+ return err;
}
- return !hdrCapabilities.getSupportedHdrTypes().empty();
+ return !info.hdrCapabilities.getSupportedHdrTypes().empty();
}
static bool isDataSpaceValid(const sp<SurfaceControl>& surfaceControl, ADataSpace dataSpace) {
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 3866151982a4..79fbcc376b3c 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -1007,6 +1007,9 @@
<!-- Settings item title to select the default behavior for transcoding if an encodig is not supported by an app. [CHAR LIMIT=85] -->
<string name="transcode_default">Assume apps support modern formats</string>
+ <!-- Settings item title to select whether to show transcoding notifications. [CHAR LIMIT=85] -->
+ <string name="transcode_notification">Show transcoding notifications</string>
+
<!-- Services settings screen, setting option name for the user to go to the screen to view running services -->
<string name="runningservices_settings_title">Running services</string>
<!-- Services settings screen, setting option summary for the user to go to the screen to view running services -->
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 2faca8dbdcbf..fbe58c505662 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -334,6 +334,11 @@
</intent-filter>
</receiver>
+ <activity android:name=".screenshot.LongScreenshotActivity"
+ android:theme="@android:style/Theme.DeviceDefault.NoActionBar"
+ android:process=":screenshot"
+ android:finishOnTaskLaunch="true" />
+
<activity android:name=".screenrecord.ScreenRecordDialog"
android:theme="@style/ScreenRecord"
android:showForAllUsers="true"
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index a8ef7c346b95..23f34251b812 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -73,7 +73,7 @@
android:id="@+id/qs_edge_guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- systemui:layout_constraintGuide_percent="0.5"
+ systemui:layout_constraintGuide_percent="0.4"
android:orientation="vertical"/>
<com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout
diff --git a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
index d8ca63960b30..9686c91f2c31 100644
--- a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
@@ -473,7 +473,8 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon
@Override
public void onOpNoted(int code, int uid, String packageName,
- @AppOpsManager.OpFlags int flags, @AppOpsManager.Mode int result) {
+ String attributionTag, @AppOpsManager.OpFlags int flags,
+ @AppOpsManager.Mode int result) {
if (DEBUG) {
Log.w(TAG, "Noted op: " + code + " with result "
+ AppOpsManager.MODE_NAMES[result] + " for package " + packageName);
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java
index 2b362b94d1f5..8d2639d4cdd0 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java
@@ -22,6 +22,7 @@ import com.android.systemui.ForegroundServicesDialog;
import com.android.systemui.keyguard.WorkLockActivity;
import com.android.systemui.people.PeopleSpaceActivity;
import com.android.systemui.screenrecord.ScreenRecordDialog;
+import com.android.systemui.screenshot.LongScreenshotActivity;
import com.android.systemui.settings.brightness.BrightnessDialog;
import com.android.systemui.statusbar.tv.notifications.TvNotificationPanelActivity;
import com.android.systemui.tuner.TunerActivity;
@@ -99,4 +100,10 @@ public abstract class DefaultActivityBinder {
@IntoMap
@ClassKey(PeopleSpaceActivity.class)
public abstract Activity bindPeopleSpaceActivity(PeopleSpaceActivity activity);
+
+ /** Inject into LongScreenshotActivity. */
+ @Binds
+ @IntoMap
+ @ClassKey(LongScreenshotActivity.class)
+ public abstract Activity bindLongScreenshotActivity(LongScreenshotActivity activity);
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java b/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
new file mode 100644
index 000000000000..a6433ae94b2b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2021 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.screenshot;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.View;
+import android.widget.ImageView;
+
+import com.android.internal.logging.UiEventLogger;
+import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
+
+import java.util.concurrent.Executor;
+
+import javax.inject.Inject;
+
+/**
+ * LongScreenshotActivity acquires bitmap data for a long screenshot and lets the user trim the top
+ * and bottom before saving/sharing/editing.
+ */
+public class LongScreenshotActivity extends Activity {
+ private static final String TAG = "LongScreenshotActivity";
+
+ private final UiEventLogger mUiEventLogger;
+ private final ScrollCaptureController mScrollCaptureController;
+
+ private ImageView mPreview;
+ private View mSave;
+ private View mCancel;
+ private View mEdit;
+ private View mShare;
+ private CropView mCropView;
+ private MagnifierView mMagnifierView;
+
+ private enum PendingAction {
+ SHARE,
+ EDIT,
+ SAVE
+ }
+
+ @Inject
+ public LongScreenshotActivity(UiEventLogger uiEventLogger,
+ ImageExporter imageExporter,
+ @Main Executor mainExecutor,
+ @Background Executor bgExecutor,
+ Context context) {
+ mUiEventLogger = uiEventLogger;
+
+ mScrollCaptureController = new ScrollCaptureController(context,
+ ScreenshotController.sScrollConnection, mainExecutor, bgExecutor, imageExporter);
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.long_screenshot);
+
+ mPreview = findViewById(R.id.preview);
+ mSave = findViewById(R.id.save);
+ mCancel = findViewById(R.id.cancel);
+ mEdit = findViewById(R.id.edit);
+ mShare = findViewById(R.id.share);
+ mCropView = findViewById(R.id.crop_view);
+ mMagnifierView = findViewById(R.id.magnifier);
+ mCropView.setCropInteractionListener(mMagnifierView);
+
+ mSave.setOnClickListener(this::onClicked);
+ mCancel.setOnClickListener(this::onClicked);
+ mEdit.setOnClickListener(this::onClicked);
+ mShare.setOnClickListener(this::onClicked);
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ if (mPreview.getDrawable() == null) {
+ doCapture();
+ }
+ }
+
+ private void disableButtons() {
+ mSave.setEnabled(false);
+ mCancel.setEnabled(false);
+ mEdit.setEnabled(false);
+ mShare.setEnabled(false);
+ }
+
+ private void doEdit(Uri uri) {
+ String editorPackage = getString(R.string.config_screenshotEditor);
+ Intent intent = new Intent(Intent.ACTION_EDIT);
+ if (!TextUtils.isEmpty(editorPackage)) {
+ intent.setComponent(ComponentName.unflattenFromString(editorPackage));
+ }
+ intent.setType("image/png");
+ intent.setData(uri);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK
+ | Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+
+ startActivityAsUser(intent, UserHandle.CURRENT);
+ finishAndRemoveTask();
+ }
+
+ private void doShare(Uri uri) {
+ Intent intent = new Intent(Intent.ACTION_SEND);
+ intent.setType("image/png");
+ intent.setData(uri);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK
+ | Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ Intent sharingChooserIntent = Intent.createChooser(intent, null)
+ .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_GRANT_READ_URI_PERMISSION);
+
+ startActivityAsUser(sharingChooserIntent, UserHandle.CURRENT);
+ }
+
+ private void onClicked(View v) {
+ int id = v.getId();
+ v.setPressed(true);
+ disableButtons();
+ if (id == R.id.save) {
+ startExport(PendingAction.SAVE);
+ } else if (id == R.id.cancel) {
+ finishAndRemoveTask();
+ } else if (id == R.id.edit) {
+ mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_LONG_SCREENSHOT_EDIT);
+ startExport(PendingAction.EDIT);
+ } else if (id == R.id.share) {
+ mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_LONG_SCREENSHOT_SHARE);
+ startExport(PendingAction.SHARE);
+ }
+ }
+
+ private void startExport(PendingAction action) {
+ mScrollCaptureController.startExport(mCropView.getTopBoundary(),
+ mCropView.getBottomBoundary(), new ScrollCaptureController.ExportCallback() {
+ @Override
+ public void onError() {
+ Log.e(TAG, "Error exporting image data.");
+ }
+
+ @Override
+ public void onExportComplete(Uri outputUri) {
+ switch (action) {
+ case EDIT:
+ doEdit(outputUri);
+ break;
+ case SHARE:
+ doShare(outputUri);
+ break;
+ case SAVE:
+ // Nothing more to do
+ finishAndRemoveTask();
+ break;
+ }
+ }
+ });
+ }
+
+ private void doCapture() {
+ mScrollCaptureController.start(new ScrollCaptureController.ScrollCaptureCallback() {
+ @Override
+ public void onError() {
+ Log.e(TAG, "Error!");
+ finishAndRemoveTask();
+ }
+
+ @Override
+ public void onComplete(ImageTileSet imageTileSet) {
+ Log.i(TAG, "Got tiles " + imageTileSet.getWidth() + " x "
+ + imageTileSet.getHeight());
+ mPreview.setImageDrawable(imageTileSet.getDrawable());
+ mMagnifierView.setImageTileset(imageTileSet);
+ mCropView.animateBoundaryTo(CropView.CropBoundary.BOTTOM, 0.5f);
+ }
+ });
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
index 953b40b6e17b..31c693bdde1f 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
@@ -41,6 +41,7 @@ import android.app.Notification;
import android.app.WindowContext;
import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.graphics.Bitmap;
import android.graphics.Insets;
@@ -100,6 +101,8 @@ import javax.inject.Inject;
public class ScreenshotController {
private static final String TAG = logTag(ScreenshotController.class);
+ public static ScrollCaptureClient.Connection sScrollConnection;
+
/**
* POD used in the AsyncTask which saves an image in the background.
*/
@@ -597,21 +600,12 @@ public class ScreenshotController {
}
private void runScrollCapture(ScrollCaptureClient.Connection connection) {
- cancelTimeout();
- ScrollCaptureController controller = new ScrollCaptureController(mContext, connection,
- mMainExecutor, mBgExecutor, mImageExporter, mUiEventLogger);
- controller.attach(mWindow);
- controller.start(new TakeScreenshotService.RequestCallback() {
- @Override
- public void reportError() {
- }
+ sScrollConnection = connection; // For LongScreenshotActivity to pick up.
- @Override
- public void onFinish() {
- Log.d(TAG, "onFinish from ScrollCaptureController");
- finishDismiss();
- }
- });
+ Intent intent = new Intent(mContext, LongScreenshotActivity.class);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ mContext.startActivity(intent);
+ dismissScreenshot(false);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
index ad5e637b189e..863116a22ee4 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
@@ -16,29 +16,16 @@
package com.android.systemui.screenshot;
-import android.annotation.IdRes;
import android.annotation.UiThread;
-import android.content.ComponentName;
import android.content.Context;
-import android.content.Intent;
import android.graphics.Rect;
import android.net.Uri;
-import android.os.UserHandle;
import android.provider.Settings;
-import android.text.TextUtils;
import android.util.Log;
-import android.view.View;
-import android.view.ViewTreeObserver.InternalInsetsInfo;
-import android.view.ViewTreeObserver.OnComputeInternalInsetsListener;
-import android.view.Window;
-import android.widget.ImageView;
-
-import com.android.internal.logging.UiEventLogger;
-import com.android.systemui.R;
+
import com.android.systemui.screenshot.ScrollCaptureClient.CaptureResult;
import com.android.systemui.screenshot.ScrollCaptureClient.Connection;
import com.android.systemui.screenshot.ScrollCaptureClient.Session;
-import com.android.systemui.screenshot.TakeScreenshotService.RequestCallback;
import com.google.common.util.concurrent.ListenableFuture;
@@ -50,7 +37,7 @@ import java.util.concurrent.Executor;
/**
* Interaction controller between the UI and ScrollCaptureClient.
*/
-public class ScrollCaptureController implements OnComputeInternalInsetsListener {
+public class ScrollCaptureController {
private static final String TAG = "ScrollCaptureController";
private static final float MAX_PAGES_DEFAULT = 3f;
@@ -64,13 +51,6 @@ public class ScrollCaptureController implements OnComputeInternalInsetsListener
private boolean mAtTopEdge;
private Session mSession;
- // TODO: Support saving without additional action.
- private enum PendingAction {
- SHARE,
- EDIT,
- SAVE
- }
-
public static final int MAX_HEIGHT = 12000;
private final Connection mConnection;
@@ -80,172 +60,59 @@ public class ScrollCaptureController implements OnComputeInternalInsetsListener
private final Executor mBgExecutor;
private final ImageExporter mImageExporter;
private final ImageTileSet mImageTileSet;
- private final UiEventLogger mUiEventLogger;
private ZonedDateTime mCaptureTime;
private UUID mRequestId;
- private RequestCallback mCallback;
- private Window mWindow;
- private ImageView mPreview;
- private View mSave;
- private View mCancel;
- private View mEdit;
- private View mShare;
- private CropView mCropView;
- private MagnifierView mMagnifierView;
+ private ScrollCaptureCallback mCaptureCallback;
public ScrollCaptureController(Context context, Connection connection, Executor uiExecutor,
- Executor bgExecutor, ImageExporter exporter, UiEventLogger uiEventLogger) {
+ Executor bgExecutor, ImageExporter exporter) {
mContext = context;
mConnection = connection;
mUiExecutor = uiExecutor;
mBgExecutor = bgExecutor;
mImageExporter = exporter;
- mUiEventLogger = uiEventLogger;
mImageTileSet = new ImageTileSet(context.getMainThreadHandler());
}
/**
- * @param window the window to display the preview
- */
- public void attach(Window window) {
- mWindow = window;
- }
-
- /**
* Run scroll capture!
*
* @param callback request callback to report back to the service
*/
- public void start(RequestCallback callback) {
+ public void start(ScrollCaptureCallback callback) {
mCaptureTime = ZonedDateTime.now();
mRequestId = UUID.randomUUID();
- mCallback = callback;
-
- setContentView(R.layout.long_screenshot);
- mWindow.getDecorView().getViewTreeObserver()
- .addOnComputeInternalInsetsListener(this);
- mPreview = findViewById(R.id.preview);
-
- mSave = findViewById(R.id.save);
- mCancel = findViewById(R.id.cancel);
- mEdit = findViewById(R.id.edit);
- mShare = findViewById(R.id.share);
- mCropView = findViewById(R.id.crop_view);
- mMagnifierView = findViewById(R.id.magnifier);
- mCropView.setCropInteractionListener(mMagnifierView);
-
- mSave.setOnClickListener(this::onClicked);
- mCancel.setOnClickListener(this::onClicked);
- mEdit.setOnClickListener(this::onClicked);
- mShare.setOnClickListener(this::onClicked);
+ mCaptureCallback = callback;
float maxPages = Settings.Secure.getFloat(mContext.getContentResolver(),
SETTING_KEY_MAX_PAGES, MAX_PAGES_DEFAULT);
mConnection.start(this::startCapture, maxPages);
}
-
- /** Ensure the entire window is touchable */
- public void onComputeInternalInsets(InternalInsetsInfo inoutInfo) {
- inoutInfo.setTouchableInsets(InternalInsetsInfo.TOUCHABLE_INSETS_FRAME);
- }
-
- void disableButtons() {
- mSave.setEnabled(false);
- mCancel.setEnabled(false);
- mEdit.setEnabled(false);
- mShare.setEnabled(false);
- }
-
- private void onClicked(View v) {
- Log.d(TAG, "button clicked!");
-
- int id = v.getId();
- v.setPressed(true);
- disableButtons();
- if (id == R.id.save) {
- startExport(PendingAction.SAVE);
- } else if (id == R.id.cancel) {
- doFinish();
- } else if (id == R.id.edit) {
- mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_LONG_SCREENSHOT_EDIT);
- startExport(PendingAction.EDIT);
- } else if (id == R.id.share) {
- mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_LONG_SCREENSHOT_SHARE);
- startExport(PendingAction.SHARE);
- }
- }
-
- private void doFinish() {
- mPreview.setImageDrawable(null);
- mMagnifierView.setImageTileset(null);
- mImageTileSet.clear();
- mCallback.onFinish();
- mWindow.getDecorView().getViewTreeObserver()
- .removeOnComputeInternalInsetsListener(this);
- }
-
- private void startExport(PendingAction action) {
+ /**
+ * @param topCrop [0,1) fraction of the top of the image to be cropped out.
+ * @param bottomCrop (0, 1] fraction to be cropped out, e.g. 0.7 will crop out the bottom 30%.
+ */
+ public void startExport(float topCrop, float bottomCrop, ExportCallback callback) {
Rect croppedPortion = new Rect(
0,
- (int) (mImageTileSet.getHeight() * mCropView.getTopBoundary()),
+ (int) (mImageTileSet.getHeight() * topCrop),
mImageTileSet.getWidth(),
- (int) (mImageTileSet.getHeight() * mCropView.getBottomBoundary()));
+ (int) (mImageTileSet.getHeight() * bottomCrop));
ListenableFuture<ImageExporter.Result> exportFuture = mImageExporter.export(
mBgExecutor, mRequestId, mImageTileSet.toBitmap(croppedPortion), mCaptureTime);
exportFuture.addListener(() -> {
try {
ImageExporter.Result result = exportFuture.get();
- if (action == PendingAction.EDIT) {
- doEdit(result.uri);
- } else if (action == PendingAction.SHARE) {
- doShare(result.uri);
- }
- doFinish();
+ callback.onExportComplete(result.uri);
} catch (InterruptedException | ExecutionException e) {
Log.e(TAG, "failed to export", e);
- mCallback.onFinish();
+ callback.onError();
}
}, mUiExecutor);
}
- private void doEdit(Uri uri) {
- String editorPackage = mContext.getString(R.string.config_screenshotEditor);
- Intent intent = new Intent(Intent.ACTION_EDIT);
- if (!TextUtils.isEmpty(editorPackage)) {
- intent.setComponent(ComponentName.unflattenFromString(editorPackage));
- }
- intent.setType("image/png");
- intent.setData(uri);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK
- | Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
-
- mContext.startActivityAsUser(intent, UserHandle.CURRENT);
- }
-
- private void doShare(Uri uri) {
- Intent intent = new Intent(Intent.ACTION_SEND);
- intent.setType("image/png");
- intent.setData(uri);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK
- | Intent.FLAG_GRANT_READ_URI_PERMISSION);
- Intent sharingChooserIntent = Intent.createChooser(intent, null)
- .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_GRANT_READ_URI_PERMISSION);
-
- mContext.startActivityAsUser(sharingChooserIntent, UserHandle.CURRENT);
- }
-
- private void setContentView(@IdRes int id) {
- mWindow.setContentView(id);
- }
-
- <T extends View> T findViewById(@IdRes int res) {
- return mWindow.findViewById(res);
- }
-
-
private void onCaptureResult(CaptureResult result) {
Log.d(TAG, "onCaptureResult: " + result);
boolean emptyResult = result.captured.height() == 0;
@@ -327,11 +194,26 @@ public class ScrollCaptureController implements OnComputeInternalInsetsListener
Log.d(TAG, "afterCaptureComplete");
if (mImageTileSet.isEmpty()) {
- session.end(mCallback::onFinish);
+ mCaptureCallback.onError();
} else {
- mPreview.setImageDrawable(mImageTileSet.getDrawable());
- mMagnifierView.setImageTileset(mImageTileSet);
- mCropView.animateBoundaryTo(CropView.CropBoundary.BOTTOM, 0.5f);
+ mCaptureCallback.onComplete(mImageTileSet);
}
}
+
+ /**
+ * Callback for image capture completion or error.
+ */
+ public interface ScrollCaptureCallback {
+ void onComplete(ImageTileSet imageTileSet);
+ void onError();
+ }
+
+ /**
+ * Callback for image export completion or error.
+ */
+ public interface ExportCallback {
+ void onExportComplete(Uri outputUri);
+ void onError();
+ }
+
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java
index 73c7fd1b64a3..f21771a89c9e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java
@@ -128,15 +128,6 @@ public class NotificationFilter {
// this is a foreground-service disclosure for a user that does not need to show one
return true;
}
- if (getFsc().isSystemAlertNotification(sbn)) {
- final String[] apps = sbn.getNotification().extras.getStringArray(
- Notification.EXTRA_FOREGROUND_APPS);
- if (apps != null && apps.length >= 1) {
- if (!getFsc().isSystemAlertWarningNeeded(sbn.getUserId(), apps[0])) {
- return true;
- }
- }
- }
if (mIsMediaFlagEnabled && isMediaNotification(sbn)) {
return true;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinator.java
index 998ae9e55313..3a87f6853bcf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinator.java
@@ -95,18 +95,6 @@ public class AppOpsCoordinator implements Coordinator {
sbn.getUser().getIdentifier())) {
return true;
}
-
- // Filters out system alert notifications when unneeded
- if (mForegroundServiceController.isSystemAlertNotification(sbn)) {
- final String[] apps = sbn.getNotification().extras.getStringArray(
- Notification.EXTRA_FOREGROUND_APPS);
- if (apps != null && apps.length >= 1) {
- if (!mForegroundServiceController.isSystemAlertWarningNeeded(
- sbn.getUser().getIdentifier(), apps[0])) {
- return true;
- }
- }
- }
return false;
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index f4ffb207e665..615ff79feb1e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -868,25 +868,16 @@ public class NotificationPanelViewController extends PanelViewController {
public void updateResources() {
int qsWidth = mResources.getDimensionPixelSize(R.dimen.qs_panel_width);
- ViewGroup.LayoutParams lp = mQsFrame.getLayoutParams();
- if (lp.width != qsWidth) {
- lp.width = qsWidth;
- mQsFrame.setLayoutParams(lp);
- }
-
int panelWidth = mResources.getDimensionPixelSize(R.dimen.notification_panel_width);
- lp = mNotificationStackScrollLayoutController.getLayoutParams();
- if (lp.width != panelWidth) {
- lp.width = panelWidth;
- mNotificationStackScrollLayoutController.setLayoutParams(lp);
- }
- // In order to change the constraints at runtime, all children of the Constraint Layout
- // must have ids.
+ // To change the constraints at runtime, all children of the ConstraintLayout must have ids
ensureAllViewsHaveIds(mNotificationContainerParent);
ConstraintSet constraintSet = new ConstraintSet();
constraintSet.clone(mNotificationContainerParent);
if (Utils.shouldUseSplitNotificationShade(mFeatureFlags, mResources)) {
+ // width = 0 to take up all available space within constraints
+ qsWidth = 0;
+ panelWidth = 0;
constraintSet.connect(R.id.qs_frame, END, R.id.qs_edge_guideline, END);
constraintSet.connect(
R.id.notification_stack_scroller, START,
@@ -895,6 +886,8 @@ public class NotificationPanelViewController extends PanelViewController {
constraintSet.connect(R.id.qs_frame, END, PARENT_ID, END);
constraintSet.connect(R.id.notification_stack_scroller, START, PARENT_ID, START);
}
+ constraintSet.getConstraint(R.id.notification_stack_scroller).layout.mWidth = panelWidth;
+ constraintSet.getConstraint(R.id.qs_frame).layout.mWidth = qsWidth;
constraintSet.applyTo(mNotificationContainerParent);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
index e394ebc65a6b..0c9ed661925c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
@@ -18,14 +18,12 @@ package com.android.systemui.statusbar.phone;
import android.app.Fragment;
import android.content.Context;
-import android.content.res.Configuration;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.View;
import android.view.WindowInsets;
import android.widget.FrameLayout;
-import androidx.annotation.DimenRes;
import androidx.constraintlayout.widget.ConstraintLayout;
import com.android.systemui.R;
@@ -83,22 +81,6 @@ public class NotificationsQuickSettingsContainer extends ConstraintLayout
}
@Override
- protected void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
- reloadWidth(mQsFrame, R.dimen.qs_panel_width);
- reloadWidth(mStackScroller, R.dimen.notification_panel_width);
- }
-
- /**
- * Loads the given width resource and sets it on the given View.
- */
- private void reloadWidth(View view, @DimenRes int width) {
- LayoutParams params = (LayoutParams) view.getLayoutParams();
- params.width = getResources().getDimensionPixelSize(width);
- view.setLayoutParams(params);
- }
-
- @Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
mBottomPadding = insets.getStableInsetBottom();
setPadding(0, 0, 0, mBottomPadding);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
index 6c3b37edbd15..ba21afdfab0f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
@@ -309,17 +309,6 @@ public class ForegroundServiceControllerTest extends SysuiTestCase {
}
@Test
- public void testOverlayPredicate() {
- StatusBarNotification sbn_user1_app1 = makeMockSBN(USERID_ONE, "com.example.app1",
- 5000, "monkeys", Notification.FLAG_AUTO_CANCEL);
- StatusBarNotification sbn_user1_overlay = makeMockSBN(USERID_ONE, "android",
- 0, "AlertWindowNotification", Notification.FLAG_NO_CLEAR);
-
- assertTrue(mFsc.isSystemAlertNotification(sbn_user1_overlay));
- assertFalse(mFsc.isSystemAlertNotification(sbn_user1_app1));
- }
-
- @Test
public void testNoNotifsNorAppOps_noSystemAlertWarningRequired() {
// no notifications nor app op signals that this package/userId requires system alert
// warning
diff --git a/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
index bc322f7f18fc..97cb8736f01c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
@@ -69,6 +69,7 @@ import java.util.List;
@TestableLooper.RunWithLooper
public class AppOpsControllerTest extends SysuiTestCase {
private static final String TEST_PACKAGE_NAME = "test";
+ private static final String TEST_ATTRIBUTION_NAME = "attribution";
private static final int TEST_UID = UserHandle.getUid(0, 0);
private static final int TEST_UID_OTHER = UserHandle.getUid(1, 0);
private static final int TEST_UID_NON_USER_SENSITIVE = UserHandle.getUid(2, 0);
@@ -164,7 +165,7 @@ public class AppOpsControllerTest extends SysuiTestCase {
mController.onOpActiveChanged(
AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true);
mController.onOpNoted(AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME,
- AppOpsManager.OP_FLAG_SELF, AppOpsManager.MODE_ALLOWED);
+ TEST_ATTRIBUTION_NAME, AppOpsManager.OP_FLAG_SELF, AppOpsManager.MODE_ALLOWED);
mTestableLooper.processAllMessages();
verify(mCallback).onActiveStateChanged(AppOpsManager.OP_RECORD_AUDIO,
TEST_UID, TEST_PACKAGE_NAME, true);
@@ -218,8 +219,8 @@ public class AppOpsControllerTest extends SysuiTestCase {
mController.onOpActiveChanged(AppOpsManager.OP_CAMERA,
TEST_UID, TEST_PACKAGE_NAME, true);
mController.onOpNoted(AppOpsManager.OP_FINE_LOCATION,
- TEST_UID, TEST_PACKAGE_NAME, AppOpsManager.OP_FLAG_SELF,
- AppOpsManager.MODE_ALLOWED);
+ TEST_UID, TEST_PACKAGE_NAME, TEST_ATTRIBUTION_NAME,
+ AppOpsManager.OP_FLAG_SELF, AppOpsManager.MODE_ALLOWED);
assertEquals(3, mController.getActiveAppOps().size());
}
@@ -230,8 +231,8 @@ public class AppOpsControllerTest extends SysuiTestCase {
mController.onOpActiveChanged(AppOpsManager.OP_CAMERA,
TEST_UID_OTHER, TEST_PACKAGE_NAME, true);
mController.onOpNoted(AppOpsManager.OP_FINE_LOCATION,
- TEST_UID, TEST_PACKAGE_NAME, AppOpsManager.OP_FLAG_SELF,
- AppOpsManager.MODE_ALLOWED);
+ TEST_UID, TEST_PACKAGE_NAME, TEST_ATTRIBUTION_NAME,
+ AppOpsManager.OP_FLAG_SELF, AppOpsManager.MODE_ALLOWED);
assertEquals(2,
mController.getActiveAppOpsForUser(UserHandle.getUserId(TEST_UID)).size());
assertEquals(1,
@@ -262,7 +263,7 @@ public class AppOpsControllerTest extends SysuiTestCase {
public void opNotedScheduledForRemoval() {
mController.setBGHandler(mMockHandler);
mController.onOpNoted(AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME,
- AppOpsManager.OP_FLAG_SELF, AppOpsManager.MODE_ALLOWED);
+ TEST_ATTRIBUTION_NAME, AppOpsManager.OP_FLAG_SELF, AppOpsManager.MODE_ALLOWED);
verify(mMockHandler).scheduleRemoval(any(AppOpItem.class), anyLong());
}
@@ -274,7 +275,7 @@ public class AppOpsControllerTest extends SysuiTestCase {
mController.onOpActiveChanged(AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME,
true);
mController.onOpNoted(AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME,
- AppOpsManager.OP_FLAG_SELF, AppOpsManager.MODE_ALLOWED);
+ TEST_ATTRIBUTION_NAME, AppOpsManager.OP_FLAG_SELF, AppOpsManager.MODE_ALLOWED);
assertFalse(mController.getActiveAppOps().isEmpty());
mController.setListening(false);
@@ -288,9 +289,9 @@ public class AppOpsControllerTest extends SysuiTestCase {
mController.setBGHandler(mMockHandler);
mController.onOpNoted(AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME,
- AppOpsManager.OP_FLAG_SELF, AppOpsManager.MODE_ALLOWED);
+ TEST_ATTRIBUTION_NAME, AppOpsManager.OP_FLAG_SELF, AppOpsManager.MODE_ALLOWED);
mController.onOpNoted(AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME,
- AppOpsManager.OP_FLAG_SELF, AppOpsManager.MODE_ALLOWED);
+ TEST_ATTRIBUTION_NAME, AppOpsManager.OP_FLAG_SELF, AppOpsManager.MODE_ALLOWED);
// Only one post to notify subscribers
verify(mMockHandler, times(1)).post(any());
@@ -304,9 +305,9 @@ public class AppOpsControllerTest extends SysuiTestCase {
mController.setBGHandler(mMockHandler);
mController.onOpNoted(AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME,
- AppOpsManager.OP_FLAG_SELF, AppOpsManager.MODE_ALLOWED);
+ TEST_ATTRIBUTION_NAME, AppOpsManager.OP_FLAG_SELF, AppOpsManager.MODE_ALLOWED);
mController.onOpNoted(AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME,
- AppOpsManager.OP_FLAG_SELF, AppOpsManager.MODE_ALLOWED);
+ TEST_ATTRIBUTION_NAME, AppOpsManager.OP_FLAG_SELF, AppOpsManager.MODE_ALLOWED);
// Only one post to notify subscribers
verify(mMockHandler, times(2)).scheduleRemoval(any(), anyLong());
@@ -324,7 +325,7 @@ public class AppOpsControllerTest extends SysuiTestCase {
AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, true);
mController.onOpNoted(AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME,
- AppOpsManager.OP_FLAG_SELF, AppOpsManager.MODE_ALLOWED);
+ TEST_ATTRIBUTION_NAME, AppOpsManager.OP_FLAG_SELF, AppOpsManager.MODE_ALLOWED);
// Check that we "scheduled" the removal. Don't actually schedule until we are ready to
// process messages at a later time.
@@ -353,7 +354,7 @@ public class AppOpsControllerTest extends SysuiTestCase {
mController.addCallback(new int[]{AppOpsManager.OP_FINE_LOCATION}, mCallback);
mController.onOpNoted(AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME,
- AppOpsManager.OP_FLAG_SELF, AppOpsManager.MODE_ALLOWED);
+ TEST_ATTRIBUTION_NAME, AppOpsManager.OP_FLAG_SELF, AppOpsManager.MODE_ALLOWED);
mController.onOpActiveChanged(
AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, true);
@@ -382,7 +383,7 @@ public class AppOpsControllerTest extends SysuiTestCase {
mController.addCallback(new int[]{AppOpsManager.OP_FINE_LOCATION}, mCallback);
mController.onOpNoted(AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME,
- AppOpsManager.OP_FLAG_SELF, AppOpsManager.MODE_ALLOWED);
+ TEST_ATTRIBUTION_NAME, AppOpsManager.OP_FLAG_SELF, AppOpsManager.MODE_ALLOWED);
mController.onOpActiveChanged(
AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, true);
@@ -400,7 +401,7 @@ public class AppOpsControllerTest extends SysuiTestCase {
AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, true);
mController.onOpNoted(AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME,
- AppOpsManager.OP_FLAG_SELF, AppOpsManager.MODE_ALLOWED);
+ TEST_ATTRIBUTION_NAME, AppOpsManager.OP_FLAG_SELF, AppOpsManager.MODE_ALLOWED);
mTestableLooper.processAllMessages();
verify(mCallback).onActiveStateChanged(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java
index 05cf33a3729c..b493b9a6bd65 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java
@@ -171,62 +171,10 @@ public class NotificationFilterTest extends SysuiTestCase {
}
@Test
- public void testSuppressSystemAlertNotification() {
- when(mFsc.isSystemAlertWarningNeeded(anyInt(), anyString())).thenReturn(false);
- when(mFsc.isSystemAlertNotification(any())).thenReturn(true);
- StatusBarNotification sbn = mRow.getEntry().getSbn();
- Bundle bundle = new Bundle();
- bundle.putStringArray(Notification.EXTRA_FOREGROUND_APPS, new String[]{"something"});
- sbn.getNotification().extras = bundle;
-
- assertTrue(mNotificationFilter.shouldFilterOut(mRow.getEntry()));
- }
-
- @Test
- public void testDoNotSuppressSystemAlertNotification() {
- StatusBarNotification sbn = mRow.getEntry().getSbn();
- Bundle bundle = new Bundle();
- bundle.putStringArray(Notification.EXTRA_FOREGROUND_APPS, new String[]{"something"});
- sbn.getNotification().extras = bundle;
-
- when(mFsc.isSystemAlertWarningNeeded(anyInt(), anyString())).thenReturn(true);
- when(mFsc.isSystemAlertNotification(any())).thenReturn(true);
-
- assertFalse(mNotificationFilter.shouldFilterOut(mRow.getEntry()));
-
- when(mFsc.isSystemAlertWarningNeeded(anyInt(), anyString())).thenReturn(true);
- when(mFsc.isSystemAlertNotification(any())).thenReturn(false);
-
- assertFalse(mNotificationFilter.shouldFilterOut(mRow.getEntry()));
-
- when(mFsc.isSystemAlertWarningNeeded(anyInt(), anyString())).thenReturn(false);
- when(mFsc.isSystemAlertNotification(any())).thenReturn(false);
-
- assertFalse(mNotificationFilter.shouldFilterOut(mRow.getEntry()));
- }
-
- @Test
- public void testDoNotSuppressMalformedSystemAlertNotification() {
- when(mFsc.isSystemAlertWarningNeeded(anyInt(), anyString())).thenReturn(true);
-
- // missing extra
- assertFalse(mNotificationFilter.shouldFilterOut(mRow.getEntry()));
-
- StatusBarNotification sbn = mRow.getEntry().getSbn();
- Bundle bundle = new Bundle();
- bundle.putStringArray(Notification.EXTRA_FOREGROUND_APPS, new String[]{});
- sbn.getNotification().extras = bundle;
-
- // extra missing values
- assertFalse(mNotificationFilter.shouldFilterOut(mRow.getEntry()));
- }
-
- @Test
public void testShouldFilterHiddenNotifications() {
initStatusBarNotification(false);
// setup
when(mFsc.isSystemAlertWarningNeeded(anyInt(), anyString())).thenReturn(false);
- when(mFsc.isSystemAlertNotification(any())).thenReturn(false);
// test should filter out hidden notifications:
// hidden
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinatorTest.java
index 09546216183f..278456859735 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinatorTest.java
@@ -115,41 +115,6 @@ public class AppOpsCoordinatorTest extends SysuiTestCase {
}
@Test
- public void filterTest_systemAlertNotificationUnnecessary() {
- // GIVEN the alert notification isn't needed for this user
- final Bundle extras = new Bundle();
- extras.putStringArray(Notification.EXTRA_FOREGROUND_APPS,
- new String[]{TEST_PKG});
- mEntryBuilder.modifyNotification(mContext)
- .setExtras(extras);
- NotificationEntry entry = mEntryBuilder.build();
- StatusBarNotification sbn = entry.getSbn();
- when(mForegroundServiceController.isSystemAlertWarningNeeded(sbn.getUserId(), TEST_PKG))
- .thenReturn(false);
-
- // GIVEN the notification is a system alert notification + not a disclosure notification
- when(mForegroundServiceController.isSystemAlertNotification(sbn)).thenReturn(true);
- when(mForegroundServiceController.isDisclosureNotification(sbn)).thenReturn(false);
-
-
- // THEN filter out the notification
- assertTrue(mForegroundFilter.shouldFilterOut(entry, 0));
- }
-
- @Test
- public void filterTest_doNotFilter() {
- NotificationEntry entry = mEntryBuilder.build();
- StatusBarNotification sbn = entry.getSbn();
-
- // GIVEN the notification isn't a system alert notification nor a disclosure notification
- when(mForegroundServiceController.isSystemAlertNotification(sbn)).thenReturn(false);
- when(mForegroundServiceController.isDisclosureNotification(sbn)).thenReturn(false);
-
- // THEN don't filter out the notification
- assertFalse(mForegroundFilter.shouldFilterOut(entry, 0));
- }
-
- @Test
public void testIncludeFGSInSection_importanceDefault() {
// GIVEN the notification represents a colorized foreground service with > min importance
mEntryBuilder
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
index 8cb898443fd2..dd31f522b94d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
@@ -33,6 +33,7 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.annotation.IdRes;
import android.app.ActivityManager;
import android.app.StatusBarManager;
import android.content.res.Configuration;
@@ -269,8 +270,9 @@ public class NotificationPanelViewTest extends SysuiTestCase {
when(mView.findViewById(R.id.qs_frame)).thenReturn(mQsFrame);
when(mView.findViewById(R.id.keyguard_status_view))
.thenReturn(mock(KeyguardStatusView.class));
- when(mView.findViewById(R.id.keyguard_header)).thenReturn(mKeyguardStatusBar);
mNotificationContainerParent = new NotificationsQuickSettingsContainer(getContext(), null);
+ mNotificationContainerParent.addView(newViewWithId(R.id.qs_frame));
+ mNotificationContainerParent.addView(newViewWithId(R.id.notification_stack_scroller));
when(mView.findViewById(R.id.notification_container_parent))
.thenReturn(mNotificationContainerParent);
FlingAnimationUtils.Builder flingAnimationUtilsBuilder = new FlingAnimationUtils.Builder(
@@ -300,10 +302,6 @@ public class NotificationPanelViewTest extends SysuiTestCase {
.thenReturn(mKeyguardClockSwitchController);
when(mKeyguardStatusViewComponent.getKeyguardStatusViewController())
.thenReturn(mKeyguardStatusViewController);
- when(mQsFrame.getLayoutParams()).thenReturn(
- new ViewGroup.LayoutParams(600, 400));
- when(mNotificationStackScrollLayoutController.getLayoutParams()).thenReturn(
- new ViewGroup.LayoutParams(600, 400));
mNotificationPanelViewController = new NotificationPanelViewController(mView,
mResources,
@@ -451,7 +449,8 @@ public class NotificationPanelViewTest extends SysuiTestCase {
@Test
public void testAllChildrenOfNotificationContainer_haveIds() {
- enableDualPaneShade();
+ enableSplitShade();
+ mNotificationContainerParent.removeAllViews();
mNotificationContainerParent.addView(newViewWithId(1));
mNotificationContainerParent.addView(newViewWithId(View.NO_ID));
@@ -464,35 +463,59 @@ public class NotificationPanelViewTest extends SysuiTestCase {
@Test
public void testSinglePaneShadeLayout_isAlignedToParent() {
when(mFeatureFlags.isTwoColumnNotificationShadeEnabled()).thenReturn(false);
- mNotificationContainerParent.addView(newViewWithId(R.id.qs_frame));
- mNotificationContainerParent.addView(newViewWithId(R.id.notification_stack_scroller));
mNotificationPanelViewController.updateResources();
- ConstraintSet constraintSet = new ConstraintSet();
- constraintSet.clone(mNotificationContainerParent);
- ConstraintSet.Layout qsFrameLayout = constraintSet.getConstraint(R.id.qs_frame).layout;
- ConstraintSet.Layout stackScrollerLayout = constraintSet.getConstraint(
- R.id.notification_stack_scroller).layout;
- assertThat(qsFrameLayout.endToEnd).isEqualTo(ConstraintSet.PARENT_ID);
- assertThat(stackScrollerLayout.startToStart).isEqualTo(ConstraintSet.PARENT_ID);
+ assertThat(getConstraintSetLayout(R.id.qs_frame).endToEnd)
+ .isEqualTo(ConstraintSet.PARENT_ID);
+ assertThat(getConstraintSetLayout(R.id.notification_stack_scroller).startToStart)
+ .isEqualTo(ConstraintSet.PARENT_ID);
}
@Test
public void testSplitShadeLayout_isAlignedToGuideline() {
- enableDualPaneShade();
- mNotificationContainerParent.addView(newViewWithId(R.id.qs_frame));
- mNotificationContainerParent.addView(newViewWithId(R.id.notification_stack_scroller));
+ enableSplitShade();
mNotificationPanelViewController.updateResources();
- ConstraintSet constraintSet = new ConstraintSet();
- constraintSet.clone(mNotificationContainerParent);
- ConstraintSet.Layout qsFrameLayout = constraintSet.getConstraint(R.id.qs_frame).layout;
- ConstraintSet.Layout stackScrollerLayout = constraintSet.getConstraint(
- R.id.notification_stack_scroller).layout;
- assertThat(qsFrameLayout.endToEnd).isEqualTo(R.id.qs_edge_guideline);
- assertThat(stackScrollerLayout.startToStart).isEqualTo(R.id.qs_edge_guideline);
+ assertThat(getConstraintSetLayout(R.id.qs_frame).endToEnd)
+ .isEqualTo(R.id.qs_edge_guideline);
+ assertThat(getConstraintSetLayout(R.id.notification_stack_scroller).startToStart)
+ .isEqualTo(R.id.qs_edge_guideline);
+ }
+
+ @Test
+ public void testSinglePaneShadeLayout_childrenHaveConstantWidth() {
+ when(mFeatureFlags.isTwoColumnNotificationShadeEnabled()).thenReturn(false);
+
+ mNotificationPanelViewController.updateResources();
+
+ assertThat(getConstraintSetLayout(R.id.qs_frame).mWidth)
+ .isEqualTo(mResources.getDimensionPixelSize(R.dimen.qs_panel_width));
+ assertThat(getConstraintSetLayout(R.id.notification_stack_scroller).mWidth)
+ .isEqualTo(mResources.getDimensionPixelSize(R.dimen.notification_panel_width));
+ }
+
+ @Test
+ public void testSplitShadeLayout_childrenHaveZeroWidth() {
+ enableSplitShade();
+
+ mNotificationPanelViewController.updateResources();
+
+ assertThat(getConstraintSetLayout(R.id.qs_frame).mWidth).isEqualTo(0);
+ assertThat(getConstraintSetLayout(R.id.notification_stack_scroller).mWidth).isEqualTo(0);
+ }
+
+ @Test
+ public void testOnDragDownEvent_horizontalTranslationIsZeroForSplitShade() {
+ when(mNotificationStackScrollLayoutController.getWidth()).thenReturn(350f);
+ when(mView.getWidth()).thenReturn(800);
+ enableSplitShade();
+
+ onTouchEvent(MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN,
+ 200f /* x position */, 0f, 0));
+
+ verify(mQsFrame).setTranslationX(0);
}
@Test
@@ -538,19 +561,13 @@ public class NotificationPanelViewTest extends SysuiTestCase {
return view;
}
- @Test
- public void testOnDragDownEvent_horizontalTranslationIsZeroForDualPaneShade() {
- when(mNotificationStackScrollLayoutController.getWidth()).thenReturn(350f);
- when(mView.getWidth()).thenReturn(800);
- enableDualPaneShade();
-
- onTouchEvent(MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN,
- 200f /* x position */, 0f, 0));
-
- verify(mQsFrame).setTranslationX(0);
+ private ConstraintSet.Layout getConstraintSetLayout(@IdRes int id) {
+ ConstraintSet constraintSet = new ConstraintSet();
+ constraintSet.clone(mNotificationContainerParent);
+ return constraintSet.getConstraint(id).layout;
}
- private void enableDualPaneShade() {
+ private void enableSplitShade() {
when(mResources.getBoolean(R.bool.config_use_split_notification_shade)).thenReturn(true);
when(mFeatureFlags.isTwoColumnNotificationShadeEnabled()).thenReturn(true);
}
diff --git a/services/core/java/com/android/server/SensorPrivacyService.java b/services/core/java/com/android/server/SensorPrivacyService.java
index edaf6a90bd4a..84e429dc83e4 100644
--- a/services/core/java/com/android/server/SensorPrivacyService.java
+++ b/services/core/java/com/android/server/SensorPrivacyService.java
@@ -16,6 +16,7 @@
package com.android.server;
+import static android.Manifest.permission.MANAGE_SENSOR_PRIVACY;
import static android.app.ActivityManager.RunningServiceInfo;
import static android.app.ActivityManager.RunningTaskInfo;
import static android.app.AppOpsManager.MODE_ALLOWED;
@@ -197,18 +198,20 @@ public final class SensorPrivacyService extends SystemService {
Intent.EXTRA_USER)).getIdentifier(),
intent.getIntExtra(EXTRA_SENSOR, UNKNOWN), false);
}
- }, new IntentFilter(ACTION_DISABLE_INDIVIDUAL_SENSOR_PRIVACY));
+ }, new IntentFilter(ACTION_DISABLE_INDIVIDUAL_SENSOR_PRIVACY),
+ MANAGE_SENSOR_PRIVACY, null);
}
@Override
- public void onOpStarted(int code, int uid, String packageName,
+ public void onOpStarted(int code, int uid, String packageName, String attributionTag,
@AppOpsManager.OpFlags int flags, @AppOpsManager.Mode int result) {
- onOpNoted(code, uid, packageName, flags, result);
+ onOpNoted(code, uid, packageName, attributionTag, flags, result);
}
@Override
public void onOpNoted(int code, int uid, String packageName,
- @AppOpsManager.OpFlags int flags, @AppOpsManager.Mode int result) {
+ String attributionTag, @AppOpsManager.OpFlags int flags,
+ @AppOpsManager.Mode int result) {
if (result != MODE_ALLOWED || (flags & AppOpsManager.OP_FLAGS_ALL_TRUSTED) == 0) {
return;
}
@@ -459,12 +462,12 @@ public final class SensorPrivacyService extends SystemService {
*/
private void enforceSensorPrivacyPermission() {
if (mContext.checkCallingOrSelfPermission(
- android.Manifest.permission.MANAGE_SENSOR_PRIVACY) == PERMISSION_GRANTED) {
+ MANAGE_SENSOR_PRIVACY) == PERMISSION_GRANTED) {
return;
}
throw new SecurityException(
"Changing sensor privacy requires the following permission: "
- + android.Manifest.permission.MANAGE_SENSOR_PRIVACY);
+ + MANAGE_SENSOR_PRIVACY);
}
/**
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index a4ff230b0678..5550999b2405 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -2111,7 +2111,8 @@ public final class ActiveServices {
private final AppOpsManager.OnOpNotedListener mOpNotedCallback =
new AppOpsManager.OnOpNotedListener() {
@Override
- public void onOpNoted(int op, int uid, String pkgName, int flags, int result) {
+ public void onOpNoted(int op, int uid, String pkgName,
+ String attributionTag, int flags, int result) {
incrementOpCountIfNeeded(op, uid, result);
}
};
@@ -2119,7 +2120,8 @@ public final class ActiveServices {
private final AppOpsManager.OnOpStartedListener mOpStartedCallback =
new AppOpsManager.OnOpStartedListener() {
@Override
- public void onOpStarted(int op, int uid, String pkgName, int flags,
+ public void onOpStarted(int op, int uid, String pkgName,
+ String attributionTag, int flags,
int result) {
incrementOpCountIfNeeded(op, uid, result);
}
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index c92abd48fdc2..a776458d63c5 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -3124,7 +3124,7 @@ public class AppOpsService extends IAppOpsService.Stub {
final Ops ops = getOpsLocked(uid, packageName, attributionTag, bypass,
true /* edit */);
if (ops == null) {
- scheduleOpNotedIfNeededLocked(code, uid, packageName, flags,
+ scheduleOpNotedIfNeededLocked(code, uid, packageName, attributionTag, flags,
AppOpsManager.MODE_IGNORED);
if (DEBUG) Slog.d(TAG, "noteOperation: no op for code " + code + " uid " + uid
+ " package " + packageName);
@@ -3142,7 +3142,7 @@ public class AppOpsService extends IAppOpsService.Stub {
final UidState uidState = ops.uidState;
if (isOpRestrictedLocked(uid, code, packageName, bypass)) {
attributedOp.rejected(uidState.state, flags);
- scheduleOpNotedIfNeededLocked(code, uid, packageName, flags,
+ scheduleOpNotedIfNeededLocked(code, uid, packageName, attributionTag, flags,
AppOpsManager.MODE_IGNORED);
return AppOpsManager.MODE_IGNORED;
}
@@ -3155,7 +3155,8 @@ public class AppOpsService extends IAppOpsService.Stub {
+ switchCode + " (" + code + ") uid " + uid + " package "
+ packageName);
attributedOp.rejected(uidState.state, flags);
- scheduleOpNotedIfNeededLocked(code, uid, packageName, flags, uidMode);
+ scheduleOpNotedIfNeededLocked(code, uid, packageName, attributionTag, flags,
+ uidMode);
return uidMode;
}
} else {
@@ -3167,7 +3168,8 @@ public class AppOpsService extends IAppOpsService.Stub {
+ switchCode + " (" + code + ") uid " + uid + " package "
+ packageName);
attributedOp.rejected(uidState.state, flags);
- scheduleOpNotedIfNeededLocked(code, uid, packageName, flags, mode);
+ scheduleOpNotedIfNeededLocked(code, uid, packageName, attributionTag, flags,
+ mode);
return mode;
}
}
@@ -3177,7 +3179,7 @@ public class AppOpsService extends IAppOpsService.Stub {
+ packageName + (attributionTag == null ? ""
: "." + attributionTag));
}
- scheduleOpNotedIfNeededLocked(code, uid, packageName, flags,
+ scheduleOpNotedIfNeededLocked(code, uid, packageName, attributionTag, flags,
AppOpsManager.MODE_ALLOWED);
attributedOp.accessed(proxyUid, proxyPackageName, proxyAttributionTag, uidState.state,
flags);
@@ -3580,7 +3582,7 @@ public class AppOpsService extends IAppOpsService.Stub {
final Ops ops = getOpsLocked(uid, packageName, attributionTag, bypass, true /* edit */);
if (ops == null) {
if (!dryRun) {
- scheduleOpStartedIfNeededLocked(code, uid, packageName,
+ scheduleOpStartedIfNeededLocked(code, uid, packageName, attributionTag,
flags, AppOpsManager.MODE_IGNORED);
}
if (DEBUG) Slog.d(TAG, "startOperation: no op for code " + code + " uid " + uid
@@ -3590,7 +3592,7 @@ public class AppOpsService extends IAppOpsService.Stub {
final Op op = getOpLocked(ops, code, uid, true);
if (isOpRestrictedLocked(uid, code, packageName, bypass)) {
if (!dryRun) {
- scheduleOpStartedIfNeededLocked(code, uid, packageName,
+ scheduleOpStartedIfNeededLocked(code, uid, packageName, attributionTag,
flags, AppOpsManager.MODE_IGNORED);
}
return AppOpsManager.MODE_IGNORED;
@@ -3611,7 +3613,8 @@ public class AppOpsService extends IAppOpsService.Stub {
}
if (!dryRun) {
attributedOp.rejected(uidState.state, flags);
- scheduleOpStartedIfNeededLocked(code, uid, packageName, flags, uidMode);
+ scheduleOpStartedIfNeededLocked(code, uid, packageName, attributionTag,
+ flags, uidMode);
}
return uidMode;
}
@@ -3626,7 +3629,8 @@ public class AppOpsService extends IAppOpsService.Stub {
+ packageName);
if (!dryRun) {
attributedOp.rejected(uidState.state, flags);
- scheduleOpStartedIfNeededLocked(code, uid, packageName, flags, mode);
+ scheduleOpStartedIfNeededLocked(code, uid, packageName, attributionTag,
+ flags, mode);
}
return mode;
}
@@ -3634,7 +3638,7 @@ public class AppOpsService extends IAppOpsService.Stub {
if (DEBUG) Slog.d(TAG, "startOperation: allowing code " + code + " uid " + uid
+ " package " + packageName);
if (!dryRun) {
- scheduleOpStartedIfNeededLocked(code, uid, packageName, flags,
+ scheduleOpStartedIfNeededLocked(code, uid, packageName, attributionTag, flags,
AppOpsManager.MODE_ALLOWED);
try {
attributedOp.started(clientId, proxyUid, proxyPackageName, proxyAttributionTag,
@@ -3774,7 +3778,7 @@ public class AppOpsService extends IAppOpsService.Stub {
}
private void scheduleOpStartedIfNeededLocked(int code, int uid, String pkgName,
- @OpFlags int flags, @Mode int result) {
+ String attributionTag, @OpFlags int flags, @Mode int result) {
ArraySet<StartedCallback> dispatchedCallbacks = null;
final int callbackListCount = mStartedWatchers.size();
for (int i = 0; i < callbackListCount; i++) {
@@ -3799,18 +3803,21 @@ public class AppOpsService extends IAppOpsService.Stub {
mHandler.sendMessage(PooledLambda.obtainMessage(
AppOpsService::notifyOpStarted,
- this, dispatchedCallbacks, code, uid, pkgName, flags, result));
+ this, dispatchedCallbacks, code, uid, pkgName, attributionTag, flags,
+ result));
}
private void notifyOpStarted(ArraySet<StartedCallback> callbacks,
- int code, int uid, String packageName, @OpFlags int flags, @Mode int result) {
+ int code, int uid, String packageName, String attributionTag, @OpFlags int flags,
+ @Mode int result) {
final long identity = Binder.clearCallingIdentity();
try {
final int callbackCount = callbacks.size();
for (int i = 0; i < callbackCount; i++) {
final StartedCallback callback = callbacks.valueAt(i);
try {
- callback.mCallback.opStarted(code, uid, packageName, flags, result);
+ callback.mCallback.opStarted(code, uid, packageName, attributionTag, flags,
+ result);
} catch (RemoteException e) {
/* do nothing */
}
@@ -3821,7 +3828,7 @@ public class AppOpsService extends IAppOpsService.Stub {
}
private void scheduleOpNotedIfNeededLocked(int code, int uid, String packageName,
- @OpFlags int flags, @Mode int result) {
+ String attributionTag, @OpFlags int flags, @Mode int result) {
ArraySet<NotedCallback> dispatchedCallbacks = null;
final int callbackListCount = mNotedWatchers.size();
for (int i = 0; i < callbackListCount; i++) {
@@ -3842,11 +3849,13 @@ public class AppOpsService extends IAppOpsService.Stub {
}
mHandler.sendMessage(PooledLambda.obtainMessage(
AppOpsService::notifyOpChecked,
- this, dispatchedCallbacks, code, uid, packageName, flags, result));
+ this, dispatchedCallbacks, code, uid, packageName, attributionTag, flags,
+ result));
}
private void notifyOpChecked(ArraySet<NotedCallback> callbacks,
- int code, int uid, String packageName, @OpFlags int flags, @Mode int result) {
+ int code, int uid, String packageName, String attributionTag, @OpFlags int flags,
+ @Mode int result) {
// There are features watching for checks in our process. The callbacks in
// these features may require permissions our remote caller does not have.
final long identity = Binder.clearCallingIdentity();
@@ -3855,7 +3864,8 @@ public class AppOpsService extends IAppOpsService.Stub {
for (int i = 0; i < callbackCount; i++) {
final NotedCallback callback = callbacks.valueAt(i);
try {
- callback.mCallback.opNoted(code, uid, packageName, flags, result);
+ callback.mCallback.opNoted(code, uid, packageName, attributionTag, flags,
+ result);
} catch (RemoteException e) {
/* do nothing */
}
diff --git a/services/core/java/com/android/server/display/ColorFade.java b/services/core/java/com/android/server/display/ColorFade.java
index 5e1df27167c2..198ea3d3f66a 100644
--- a/services/core/java/com/android/server/display/ColorFade.java
+++ b/services/core/java/com/android/server/display/ColorFade.java
@@ -165,7 +165,7 @@ final class ColorFade {
"Failed to take screenshot because internal display is disconnected");
return false;
}
- boolean isWideColor = SurfaceControl.getActiveColorMode(token)
+ boolean isWideColor = SurfaceControl.getDynamicDisplayInfo(token).activeColorMode
== Display.COLOR_MODE_DISPLAY_P3;
// Set mPrepared here so if initialization fails, resources can be cleaned up.
diff --git a/services/core/java/com/android/server/display/DisplayDeviceInfo.java b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
index 501533d535d3..40cee66a6791 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceInfo.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
@@ -466,7 +466,7 @@ final class DisplayDeviceInfo {
sb.append(", supportedModes ").append(Arrays.toString(supportedModes));
sb.append(", colorMode ").append(colorMode);
sb.append(", supportedColorModes ").append(Arrays.toString(supportedColorModes));
- sb.append(", HdrCapabilities ").append(hdrCapabilities);
+ sb.append(", hdrCapabilities ").append(hdrCapabilities);
sb.append(", allmSupported ").append(allmSupported);
sb.append(", gameContentTypeSupported ").append(gameContentTypeSupported);
sb.append(", density ").append(densityDpi);
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 3b66236c9f0f..7ce4f066b058 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -100,50 +100,48 @@ final class LocalDisplayAdapter extends DisplayAdapter {
private void tryConnectDisplayLocked(long physicalDisplayId) {
final IBinder displayToken = SurfaceControl.getPhysicalDisplayToken(physicalDisplayId);
if (displayToken != null) {
- SurfaceControl.DisplayInfo info = SurfaceControl.getDisplayInfo(displayToken);
- if (info == null) {
- Slog.w(TAG, "No valid info found for display device " + physicalDisplayId);
+ SurfaceControl.StaticDisplayInfo staticInfo =
+ SurfaceControl.getStaticDisplayInfo(displayToken);
+ if (staticInfo == null) {
+ Slog.w(TAG, "No valid static info found for display device " + physicalDisplayId);
return;
}
- SurfaceControl.DisplayMode[] displayModes =
- SurfaceControl.getDisplayModes(displayToken);
- if (displayModes == null) {
+ SurfaceControl.DynamicDisplayInfo dynamicInfo =
+ SurfaceControl.getDynamicDisplayInfo(displayToken);
+ if (dynamicInfo == null) {
+ Slog.w(TAG, "No valid dynamic info found for display device " + physicalDisplayId);
+ return;
+ }
+ if (dynamicInfo.supportedDisplayModes == null) {
// There are no valid modes for this device, so we can't use it
Slog.w(TAG, "No valid modes found for display device " + physicalDisplayId);
return;
}
- int activeDisplayMode = SurfaceControl.getActiveDisplayMode(displayToken);
- if (activeDisplayMode < 0) {
+ if (dynamicInfo.activeDisplayModeId < 0) {
// There is no active mode, and for now we don't have the
// policy to set one.
- Slog.w(TAG, "No active mode found for display device " + physicalDisplayId);
+ Slog.w(TAG, "No valid active mode found for display device " + physicalDisplayId);
return;
}
- int activeColorMode = SurfaceControl.getActiveColorMode(displayToken);
- if (activeColorMode < 0) {
+ if (dynamicInfo.activeColorMode < 0) {
// We failed to get the active color mode. We don't bail out here since on the next
// configuration pass we'll go ahead and set it to whatever it was set to last (or
// COLOR_MODE_NATIVE if this is the first configuration).
- Slog.w(TAG, "Unable to get active color mode for display device " +
- physicalDisplayId);
- activeColorMode = Display.COLOR_MODE_INVALID;
+ Slog.w(TAG, "No valid active color mode for display device " + physicalDisplayId);
+ dynamicInfo.activeColorMode = Display.COLOR_MODE_INVALID;
}
- SurfaceControl.DesiredDisplayModeSpecs modeSpecsSpecs =
+ SurfaceControl.DesiredDisplayModeSpecs modeSpecs =
SurfaceControl.getDesiredDisplayModeSpecs(displayToken);
- int[] colorModes = SurfaceControl.getDisplayColorModes(displayToken);
- Display.HdrCapabilities hdrCapabilities =
- SurfaceControl.getHdrCapabilities(displayToken);
LocalDisplayDevice device = mDevices.get(physicalDisplayId);
if (device == null) {
// Display was added.
final boolean isDefaultDisplay = mDevices.size() == 0;
- device = new LocalDisplayDevice(displayToken, physicalDisplayId, info, displayModes,
- activeDisplayMode, modeSpecsSpecs, colorModes, activeColorMode,
- hdrCapabilities, isDefaultDisplay);
+ device = new LocalDisplayDevice(displayToken, physicalDisplayId, staticInfo,
+ dynamicInfo, modeSpecs, isDefaultDisplay);
mDevices.put(physicalDisplayId, device);
sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_ADDED);
- } else if (device.updateDisplayPropertiesLocked(info, displayModes, activeDisplayMode,
- modeSpecsSpecs, colorModes, activeColorMode, hdrCapabilities)) {
+ } else if (device.updateDisplayPropertiesLocked(staticInfo, dynamicInfo,
+ modeSpecs)) {
sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_CHANGED);
}
} else {
@@ -195,7 +193,6 @@ final class LocalDisplayAdapter extends DisplayAdapter {
private DisplayModeDirector.DesiredDisplayModeSpecs mDisplayModeSpecs =
new DisplayModeDirector.DesiredDisplayModeSpecs();
private boolean mDisplayModeSpecsInvalid;
- private int mActiveDisplayModeId;
private int mActiveColorMode;
private Display.HdrCapabilities mHdrCapabilities;
private boolean mAllmSupported;
@@ -204,8 +201,11 @@ final class LocalDisplayAdapter extends DisplayAdapter {
private boolean mGameContentTypeRequested;
private boolean mSidekickActive;
private SidekickInternal mSidekickInternal;
- private SurfaceControl.DisplayInfo mDisplayInfo;
- private SurfaceControl.DisplayMode[] mDisplayModes;
+ private SurfaceControl.StaticDisplayInfo mStaticDisplayInfo;
+ // The supported display modes according in SurfaceFlinger
+ private SurfaceControl.DisplayMode[] mSfDisplayModes;
+ // The active display mode in SurfaceFlinger
+ private SurfaceControl.DisplayMode mActiveSfDisplayMode;
private Spline mSystemBrightnessToNits;
private Spline mNitsToHalBrightness;
private DisplayDeviceConfig mDisplayDeviceConfig;
@@ -214,15 +214,13 @@ final class LocalDisplayAdapter extends DisplayAdapter {
new DisplayEventReceiver.FrameRateOverride[0];
LocalDisplayDevice(IBinder displayToken, long physicalDisplayId,
- SurfaceControl.DisplayInfo info, SurfaceControl.DisplayMode[] displayModes,
- int activeDisplayModeId, SurfaceControl.DesiredDisplayModeSpecs modeSpecs,
- int[] colorModes, int activeColorMode, Display.HdrCapabilities hdrCapabilities,
- boolean isDefaultDisplay) {
+ SurfaceControl.StaticDisplayInfo staticDisplayInfo,
+ SurfaceControl.DynamicDisplayInfo dynamicInfo,
+ SurfaceControl.DesiredDisplayModeSpecs modeSpecs, boolean isDefaultDisplay) {
super(LocalDisplayAdapter.this, displayToken, UNIQUE_ID_PREFIX + physicalDisplayId);
mPhysicalDisplayId = physicalDisplayId;
mIsDefaultDisplay = isDefaultDisplay;
- updateDisplayPropertiesLocked(info, displayModes, activeDisplayModeId, modeSpecs,
- colorModes, activeColorMode, hdrCapabilities);
+ updateDisplayPropertiesLocked(staticDisplayInfo, dynamicInfo, modeSpecs);
mSidekickInternal = LocalServices.getService(SidekickInternal.class);
mBacklightAdapter = new BacklightAdapter(displayToken, isDefaultDisplay);
mAllmSupported = SurfaceControl.getAutoLowLatencyModeSupport(displayToken);
@@ -241,15 +239,15 @@ final class LocalDisplayAdapter extends DisplayAdapter {
/**
* Returns true if there is a change.
**/
- public boolean updateDisplayPropertiesLocked(SurfaceControl.DisplayInfo info,
- SurfaceControl.DisplayMode[] displayModes,
- int activeDisplayModeId, SurfaceControl.DesiredDisplayModeSpecs modeSpecs,
- int[] colorModes, int activeColorMode, Display.HdrCapabilities hdrCapabilities) {
+ public boolean updateDisplayPropertiesLocked(SurfaceControl.StaticDisplayInfo staticInfo,
+ SurfaceControl.DynamicDisplayInfo dynamicInfo,
+ SurfaceControl.DesiredDisplayModeSpecs modeSpecs) {
boolean changed = updateDisplayModesLocked(
- displayModes, activeDisplayModeId, modeSpecs);
- changed |= updateDisplayInfo(info);
- changed |= updateColorModesLocked(colorModes, activeColorMode);
- changed |= updateHdrCapabilitiesLocked(hdrCapabilities);
+ dynamicInfo.supportedDisplayModes, dynamicInfo.activeDisplayModeId, modeSpecs);
+ changed |= updateStaticInfo(staticInfo);
+ changed |= updateColorModesLocked(dynamicInfo.supportedColorModes,
+ dynamicInfo.activeColorMode);
+ changed |= updateHdrCapabilitiesLocked(dynamicInfo.hdrCapabilities);
if (changed) {
mHavePendingChanges = true;
@@ -260,8 +258,9 @@ final class LocalDisplayAdapter extends DisplayAdapter {
public boolean updateDisplayModesLocked(
SurfaceControl.DisplayMode[] displayModes, int activeDisplayModeId,
SurfaceControl.DesiredDisplayModeSpecs modeSpecs) {
- mDisplayModes = Arrays.copyOf(displayModes, displayModes.length);
- mActiveDisplayModeId = activeDisplayModeId;
+ mSfDisplayModes = Arrays.copyOf(displayModes, displayModes.length);
+ mActiveSfDisplayMode = getModeById(displayModes, activeDisplayModeId);
+
// Build an updated list of all existing modes.
ArrayList<DisplayModeRecord> records = new ArrayList<>();
boolean modesAdded = false;
@@ -282,7 +281,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
// First, check to see if we've already added a matching mode. Since not all
// configuration options are exposed via Display.Mode, it's possible that we have
- // multiple DisplayModess that would generate the same Display.Mode.
+ // multiple DisplayModes that would generate the same Display.Mode.
boolean existingMode = false;
for (DisplayModeRecord record : records) {
if (record.hasMatchingMode(mode)
@@ -312,9 +311,8 @@ final class LocalDisplayAdapter extends DisplayAdapter {
// Get the currently active mode
DisplayModeRecord activeRecord = null;
- for (int i = 0; i < records.size(); i++) {
- DisplayModeRecord record = records.get(i);
- if (record.hasMatchingMode(displayModes[activeDisplayModeId])) {
+ for (DisplayModeRecord record : records) {
+ if (record.hasMatchingMode(mActiveSfDisplayMode)) {
activeRecord = record;
break;
}
@@ -370,17 +368,17 @@ final class LocalDisplayAdapter extends DisplayAdapter {
// For a new display, we need to initialize the default mode ID.
if (mDefaultModeId == NO_DISPLAY_MODE_ID) {
mDefaultModeId = activeRecord.mMode.getModeId();
- mDefaultModeGroup = displayModes[activeDisplayModeId].group;
+ mDefaultModeGroup = mActiveSfDisplayMode.group;
} else if (modesAdded && activeModeChanged) {
Slog.d(TAG, "New display modes are added and the active mode has changed, "
+ "use active mode as default mode.");
mDefaultModeId = activeRecord.mMode.getModeId();
- mDefaultModeGroup = displayModes[activeDisplayModeId].group;
+ mDefaultModeGroup = mActiveSfDisplayMode.group;
} else if (findDisplayModeIdLocked(mDefaultModeId, mDefaultModeGroup) < 0) {
Slog.w(TAG, "Default display mode no longer available, using currently"
+ " active mode as default.");
mDefaultModeId = activeRecord.mMode.getModeId();
- mDefaultModeGroup = displayModes[activeDisplayModeId].group;
+ mDefaultModeGroup = mActiveSfDisplayMode.group;
}
// Determine whether the display mode specs' base mode is still there.
@@ -454,11 +452,11 @@ final class LocalDisplayAdapter extends DisplayAdapter {
mSystemBrightnessToNits = sysToNits;
}
- private boolean updateDisplayInfo(SurfaceControl.DisplayInfo info) {
- if (Objects.equals(mDisplayInfo, info)) {
+ private boolean updateStaticInfo(SurfaceControl.StaticDisplayInfo info) {
+ if (Objects.equals(mStaticDisplayInfo, info)) {
return false;
}
- mDisplayInfo = info;
+ mStaticDisplayInfo = info;
return true;
}
@@ -520,6 +518,17 @@ final class LocalDisplayAdapter extends DisplayAdapter {
return true;
}
+ private SurfaceControl.DisplayMode getModeById(SurfaceControl.DisplayMode[] supportedModes,
+ int modeId) {
+ for (SurfaceControl.DisplayMode mode : supportedModes) {
+ if (mode.id == modeId) {
+ return mode;
+ }
+ }
+ Slog.e(TAG, "Can't find display mode with id " + modeId);
+ return null;
+ }
+
private DisplayModeRecord findDisplayModeRecord(SurfaceControl.DisplayMode mode,
List<Float> alternativeRefreshRates) {
for (int i = 0; i < mSupportedModes.size(); i++) {
@@ -556,10 +565,9 @@ final class LocalDisplayAdapter extends DisplayAdapter {
@Override
public DisplayDeviceInfo getDisplayDeviceInfoLocked() {
if (mInfo == null) {
- SurfaceControl.DisplayMode mode = mDisplayModes[mActiveDisplayModeId];
mInfo = new DisplayDeviceInfo();
- mInfo.width = mode.width;
- mInfo.height = mode.height;
+ mInfo.width = mActiveSfDisplayMode.width;
+ mInfo.height = mActiveSfDisplayMode.height;
mInfo.modeId = mActiveModeId;
mInfo.defaultModeId = mDefaultModeId;
mInfo.supportedModes = getDisplayModes(mSupportedModes);
@@ -572,21 +580,21 @@ final class LocalDisplayAdapter extends DisplayAdapter {
mInfo.supportedColorModes[i] = mSupportedColorModes.get(i);
}
mInfo.hdrCapabilities = mHdrCapabilities;
- mInfo.appVsyncOffsetNanos = mode.appVsyncOffsetNanos;
- mInfo.presentationDeadlineNanos = mode.presentationDeadlineNanos;
+ mInfo.appVsyncOffsetNanos = mActiveSfDisplayMode.appVsyncOffsetNanos;
+ mInfo.presentationDeadlineNanos = mActiveSfDisplayMode.presentationDeadlineNanos;
mInfo.state = mState;
mInfo.uniqueId = getUniqueId();
final DisplayAddress.Physical physicalAddress =
DisplayAddress.fromPhysicalDisplayId(mPhysicalDisplayId);
mInfo.address = physicalAddress;
- mInfo.densityDpi = (int) (mDisplayInfo.density * 160 + 0.5f);
- mInfo.xDpi = mode.xDpi;
- mInfo.yDpi = mode.yDpi;
- mInfo.deviceProductInfo = mDisplayInfo.deviceProductInfo;
+ mInfo.densityDpi = (int) (mStaticDisplayInfo.density * 160 + 0.5f);
+ mInfo.xDpi = mActiveSfDisplayMode.xDpi;
+ mInfo.yDpi = mActiveSfDisplayMode.yDpi;
+ mInfo.deviceProductInfo = mStaticDisplayInfo.deviceProductInfo;
// Assume that all built-in displays that have secure output (eg. HDCP) also
// support compositing from gralloc protected buffers.
- if (mDisplayInfo.secure) {
+ if (mStaticDisplayInfo.secure) {
mInfo.flags = DisplayDeviceInfo.FLAG_SECURE
| DisplayDeviceInfo.FLAG_SUPPORTS_PROTECTED_BUFFERS;
}
@@ -620,7 +628,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
}
}
- if (mDisplayInfo.isInternal) {
+ if (mStaticDisplayInfo.isInternal) {
mInfo.type = Display.TYPE_INTERNAL;
mInfo.touch = DisplayDeviceInfo.TOUCH_INTERNAL;
mInfo.flags |= DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT;
@@ -878,9 +886,10 @@ final class LocalDisplayAdapter extends DisplayAdapter {
// Do not lock when calling these SurfaceControl methods because they are sync
// operations that may block for a while when setting display power mode.
SurfaceControl.setDesiredDisplayModeSpecs(displayToken, modeSpecs);
- final int activeMode = SurfaceControl.getActiveDisplayMode(displayToken);
+ final int sfActiveModeId =
+ SurfaceControl.getDynamicDisplayInfo(displayToken).activeDisplayModeId;
synchronized (getSyncRoot()) {
- if (updateActiveModeLocked(activeMode)) {
+ if (updateActiveModeLocked(sfActiveModeId)) {
updateDeviceInfoLocked();
}
}
@@ -891,8 +900,8 @@ final class LocalDisplayAdapter extends DisplayAdapter {
updateDeviceInfoLocked();
}
- public void onActiveDisplayModeChangedLocked(int modeId) {
- if (updateActiveModeLocked(modeId)) {
+ public void onActiveDisplayModeChangedLocked(int sfModeId) {
+ if (updateActiveModeLocked(sfModeId)) {
updateDeviceInfoLocked();
}
}
@@ -904,15 +913,15 @@ final class LocalDisplayAdapter extends DisplayAdapter {
}
}
- public boolean updateActiveModeLocked(int activeModeId) {
- if (mActiveDisplayModeId == activeModeId) {
+ public boolean updateActiveModeLocked(int activeSfModeId) {
+ if (mActiveSfDisplayMode.id == activeSfModeId) {
return false;
}
- mActiveDisplayModeId = activeModeId;
- mActiveModeId = findMatchingModeIdLocked(activeModeId);
+ mActiveSfDisplayMode = getModeById(mSfDisplayModes, activeSfModeId);
+ mActiveModeId = findMatchingModeIdLocked(activeSfModeId);
if (mActiveModeId == NO_DISPLAY_MODE_ID) {
Slog.w(TAG, "In unknown mode after setting allowed modes"
- + ", activeModeId=" + mActiveDisplayModeId);
+ + ", activeModeId=" + activeSfModeId);
}
return true;
}
@@ -992,7 +1001,6 @@ final class LocalDisplayAdapter extends DisplayAdapter {
pw.println("mPhysicalDisplayId=" + mPhysicalDisplayId);
pw.println("mDisplayModeSpecs={" + mDisplayModeSpecs + "}");
pw.println("mDisplayModeSpecsInvalid=" + mDisplayModeSpecsInvalid);
- pw.println("mActiveDisplayModeId=" + mActiveDisplayModeId);
pw.println("mActiveModeId=" + mActiveModeId);
pw.println("mActiveColorMode=" + mActiveColorMode);
pw.println("mDefaultModeId=" + mDefaultModeId);
@@ -1003,11 +1011,12 @@ final class LocalDisplayAdapter extends DisplayAdapter {
pw.println("mAllmRequested=" + mAllmRequested);
pw.println("mGameContentTypeSupported=" + mGameContentTypeSupported);
pw.println("mGameContentTypeRequested=" + mGameContentTypeRequested);
- pw.println("mDisplayInfo=" + mDisplayInfo);
- pw.println("mDisplayModes=");
- for (int i = 0; i < mDisplayModes.length; i++) {
- pw.println(" " + mDisplayModes[i]);
+ pw.println("mStaticDisplayInfo=" + mStaticDisplayInfo);
+ pw.println("mSfDisplayModes=");
+ for (int i = 0; i < mSfDisplayModes.length; i++) {
+ pw.println(" " + mSfDisplayModes[i]);
}
+ pw.println("mActiveSfDisplayMode=" + mActiveSfDisplayMode);
pw.println("mSupportedModes=");
for (int i = 0; i < mSupportedModes.size(); i++) {
pw.println(" " + mSupportedModes.valueAt(i));
@@ -1020,17 +1029,16 @@ final class LocalDisplayAdapter extends DisplayAdapter {
int matchingModeId = SurfaceControl.DisplayMode.INVALID_DISPLAY_MODE_ID;
DisplayModeRecord record = mSupportedModes.get(modeId);
if (record != null) {
- for (int i = 0; i < mDisplayModes.length; i++) {
- SurfaceControl.DisplayMode mode = mDisplayModes[i];
+ for (SurfaceControl.DisplayMode mode : mSfDisplayModes) {
if (record.hasMatchingMode(mode)) {
if (matchingModeId
== SurfaceControl.DisplayMode.INVALID_DISPLAY_MODE_ID) {
- matchingModeId = i;
+ matchingModeId = mode.id;
}
// Prefer to return a mode that matches the modeGroup
if (mode.group == modeGroup) {
- return i;
+ return mode.id;
}
}
}
@@ -1038,12 +1046,12 @@ final class LocalDisplayAdapter extends DisplayAdapter {
return matchingModeId;
}
- private int findMatchingModeIdLocked(int modeId) {
- if (modeId < 0 || modeId >= mDisplayModes.length) {
- Slog.e(TAG, "Invalid display config index " + modeId);
+ private int findMatchingModeIdLocked(int sfModeId) {
+ SurfaceControl.DisplayMode mode = getModeById(mSfDisplayModes, sfModeId);
+ if (mode == null) {
+ Slog.e(TAG, "Invalid display mode ID " + sfModeId);
return NO_DISPLAY_MODE_ID;
}
- SurfaceControl.DisplayMode mode = mDisplayModes[modeId];
for (int i = 0; i < mSupportedModes.size(); i++) {
DisplayModeRecord record = mSupportedModes.valueAt(i);
if (record.hasMatchingMode(mode)) {
@@ -1229,8 +1237,6 @@ final class LocalDisplayAdapter extends DisplayAdapter {
/**
* @param displayToken Token for display associated with this backlight.
* @param isDefaultDisplay {@code true} if it is the default display.
- * @param forceSurfaceControl {@code true} if brightness should always be
- * set via SurfaceControl API.
*/
BacklightAdapter(IBinder displayToken, boolean isDefaultDisplay) {
mDisplayToken = displayToken;
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 5cb9d8ff3f31..f09f33ea95ff 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -781,7 +781,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
@GuardedBy("mLock")
private File mInheritedFilesBase;
@GuardedBy("mLock")
- private boolean mVerityFound;
+ private boolean mVerityFoundForApks;
/**
* Both flags should be guarded with mLock whenever changes need to be in lockstep.
@@ -2717,8 +2717,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
"Missing existing base package");
}
- // Default to require only if existing base has fs-verity.
- mVerityFound = PackageManagerServiceUtils.isApkVerityEnabled()
+ // Default to require only if existing base apk has fs-verity.
+ mVerityFoundForApks = PackageManagerServiceUtils.isApkVerityEnabled()
&& params.mode == SessionParams.MODE_INHERIT_EXISTING
&& VerityUtils.hasFsverity(pkgInfo.applicationInfo.getBaseCodePath());
@@ -3013,34 +3013,18 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
@GuardedBy("mLock")
- private void maybeStageFsveritySignatureLocked(File origFile, File targetFile)
- throws PackageManagerException {
+ private void maybeStageFsveritySignatureLocked(File origFile, File targetFile,
+ boolean fsVerityRequired) throws PackageManagerException {
final File originalSignature = new File(
VerityUtils.getFsveritySignatureFilePath(origFile.getPath()));
- // Make sure .fsv_sig exists when it should, then resolve and stage it.
if (originalSignature.exists()) {
- // mVerityFound can only change from false to true here during the staging loop. Since
- // all or none of files should have .fsv_sig, this should only happen in the first time
- // (or never), otherwise bail out.
- if (!mVerityFound) {
- mVerityFound = true;
- if (mResolvedStagedFiles.size() > 1) {
- throw new PackageManagerException(INSTALL_FAILED_BAD_SIGNATURE,
- "Some file is missing fs-verity signature");
- }
- }
- } else {
- if (!mVerityFound) {
- return;
- }
+ final File stagedSignature = new File(
+ VerityUtils.getFsveritySignatureFilePath(targetFile.getPath()));
+ stageFileLocked(originalSignature, stagedSignature);
+ } else if (fsVerityRequired) {
throw new PackageManagerException(INSTALL_FAILED_BAD_SIGNATURE,
"Missing corresponding fs-verity signature to " + origFile);
}
-
- final File stagedSignature = new File(
- VerityUtils.getFsveritySignatureFilePath(targetFile.getPath()));
-
- stageFileLocked(originalSignature, stagedSignature);
}
@GuardedBy("mLock")
@@ -3059,7 +3043,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
DexMetadataHelper.buildDexMetadataPathForApk(targetFile.getName()));
stageFileLocked(dexMetadataFile, targetDexMetadataFile);
- maybeStageFsveritySignatureLocked(dexMetadataFile, targetDexMetadataFile);
+
+ // Also stage .dm.fsv_sig. .dm may be required to install with fs-verity signature on
+ // supported on older devices.
+ maybeStageFsveritySignatureLocked(dexMetadataFile, targetDexMetadataFile,
+ VerityUtils.isFsVeritySupported() && DexMetadataHelper.isFsVerityRequired());
}
private void storeBytesToInstallationFile(final String localPath, final String absolutePath,
@@ -3121,13 +3109,45 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
@GuardedBy("mLock")
+ private boolean isFsVerityRequiredForApk(File origFile, File targetFile)
+ throws PackageManagerException {
+ if (mVerityFoundForApks) {
+ return true;
+ }
+
+ // We haven't seen .fsv_sig for any APKs. Treat it as not required until we see one.
+ final File originalSignature = new File(
+ VerityUtils.getFsveritySignatureFilePath(origFile.getPath()));
+ if (!originalSignature.exists()) {
+ return false;
+ }
+ mVerityFoundForApks = true;
+
+ // When a signature is found, also check any previous staged APKs since they also need to
+ // have fs-verity signature consistently.
+ for (File file : mResolvedStagedFiles) {
+ if (!file.getName().endsWith(".apk")) {
+ continue;
+ }
+ // Ignore the current targeting file.
+ if (targetFile.getName().equals(file.getName())) {
+ continue;
+ }
+ throw new PackageManagerException(INSTALL_FAILED_BAD_SIGNATURE,
+ "Previously staged apk is missing fs-verity signature");
+ }
+ return true;
+ }
+
+ @GuardedBy("mLock")
private void resolveAndStageFileLocked(File origFile, File targetFile, String splitName)
throws PackageManagerException {
stageFileLocked(origFile, targetFile);
- // Stage fsverity signature if present.
- maybeStageFsveritySignatureLocked(origFile, targetFile);
- // Stage dex metadata (.dm) if present.
+ // Stage APK's fs-verity signature if present.
+ maybeStageFsveritySignatureLocked(origFile, targetFile,
+ isFsVerityRequiredForApk(origFile, targetFile));
+ // Stage dex metadata (.dm) and corresponding fs-verity signature if present.
maybeStageDexMetadataLocked(origFile, targetFile);
// Stage checksums (.digests) if present.
maybeStageDigestsLocked(origFile, targetFile, splitName);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 14d15ac49227..4fd0bba54df8 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -8959,6 +8959,10 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public List<String> getAllPackages() {
+ // Allow iorapd to call this method.
+ if (Binder.getCallingUid() != Process.IORAPD_UID) {
+ enforceSystemOrRootOrShell("getAllPackages is limited to privileged callers");
+ }
final int callingUid = Binder.getCallingUid();
final int callingUserId = UserHandle.getUserId(callingUid);
synchronized (mLock) {
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index c0b820293649..508c73ec40c2 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -5121,7 +5121,6 @@ public final class PowerManagerService extends SystemService
@Override // Binder call
public int getPowerSaveModeTrigger() {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.POWER_SAVER, null);
final long ident = Binder.clearCallingIdentity();
try {
return Settings.Global.getInt(mContext.getContentResolver(),
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index 904bbe83e020..151895f02ac4 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -235,7 +235,10 @@ class ActivityClientController extends IActivityClientController.Stub {
public void activityRelaunched(IBinder token) {
final long origId = Binder.clearCallingIdentity();
synchronized (mGlobalLock) {
- mTaskSupervisor.activityRelaunchedLocked(token);
+ final ActivityRecord r = ActivityRecord.forTokenLocked(token);
+ if (r != null) {
+ r.finishRelaunching();
+ }
}
Binder.restoreCallingIdentity(origId);
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 8c3722dbbe76..5d3b9c197267 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -567,6 +567,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
boolean mVoiceInteraction;
private int mPendingRelaunchCount;
+ long mRelaunchStartTime;
// True if we are current in the process of removing this app token from the display
private boolean mRemovingFromDisplay = false;
@@ -3357,7 +3358,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return task.isDragResizing();
}
+ @VisibleForTesting
void startRelaunching() {
+ if (mPendingRelaunchCount == 0) {
+ mRelaunchStartTime = SystemClock.elapsedRealtime();
+ }
if (shouldFreezeBounds()) {
freezeBounds();
}
@@ -3396,6 +3401,14 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// Update keyguard flags upon finishing relaunch.
checkKeyguardFlagsChanged();
}
+
+ final Task rootTask = getRootTask();
+ if (rootTask != null && rootTask.shouldSleepOrShutDownActivities()) {
+ // Activity is always relaunched to either resumed or paused state. If it was
+ // relaunched while hidden (by keyguard or smth else), it should be stopped.
+ rootTask.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
+ false /* preserveWindows */);
+ }
}
void clearRelaunching() {
@@ -3404,6 +3417,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
unfreezeBounds();
mPendingRelaunchCount = 0;
+ mRelaunchStartTime = 0;
}
/**
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index 1264d0c53e0c..bf2aae8867ba 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -2204,19 +2204,6 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
task.mTaskId, reason, topActivity.info.applicationInfo.packageName);
}
- void activityRelaunchedLocked(IBinder token) {
- final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token);
- if (r != null) {
- r.finishRelaunching();
- if (r.getRootTask().shouldSleepOrShutDownActivities()) {
- // Activity is always relaunched to either resumed or paused state. If it was
- // relaunched while hidden (by keyguard or smth else), it should be stopped.
- r.getRootTask().ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
- false /* preserveWindows */);
- }
- }
- }
-
void logRootTaskState() {
mActivityMetricsLogger.logWindowState();
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index d33799c15e8f..0143e70f53ca 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -673,10 +673,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
// Used in updating override configurations
private final Configuration mTempConfig = new Configuration();
- // Used in performing layout, to record the insets provided by other windows above the current
- // window.
- private InsetsState mTmpAboveInsetsState = new InsetsState();
-
/**
* Used to prevent recursions when calling
* {@link #ensureActivitiesVisible(ActivityRecord, int, boolean, boolean)}
@@ -778,13 +774,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
+ " parentHidden=" + w.isParentWindowHidden());
}
- // Sets mAboveInsets for each window. Windows behind the window providing the insets can
- // receive the insets.
- if (!w.mAboveInsetsState.equals(mTmpAboveInsetsState)) {
- w.mAboveInsetsState.set(mTmpAboveInsetsState);
- mWinInsetsChanged.add(w);
- }
-
// If this view is GONE, then skip it -- keep the current frame, and let the caller know
// so they can ignore it if they want. (We do the normal layout for INVISIBLE windows,
// since that means "perform layout as normal, just don't display").
@@ -818,16 +807,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
+ " mContainingFrame=" + w.getContainingFrame()
+ " mDisplayFrame=" + w.getDisplayFrame());
}
- provideInsetsByWindow(w);
};
- private void provideInsetsByWindow(WindowState w) {
- for (int i = 0; i < w.mProvidedInsetsSources.size(); i++) {
- final InsetsSource providedSource = w.mProvidedInsetsSources.valueAt(i);
- mTmpAboveInsetsState.addSource(providedSource);
- }
- }
-
private final Consumer<WindowState> mPerformLayoutAttached = w -> {
if (w.mLayoutAttached) {
if (DEBUG_LAYOUT) Slog.v(TAG, "2ND PASS " + w + " mHaveFrame=" + w.mHaveFrame
@@ -2511,8 +2492,13 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
void onDisplayInfoChanged() {
final DisplayInfo info = mDisplayInfo;
- mDisplayFrames.onDisplayInfoUpdated(info, calculateDisplayCutoutForRotation(info.rotation),
- calculateRoundedCornersForRotation(info.rotation));
+ if (mDisplayFrames.onDisplayInfoUpdated(info,
+ calculateDisplayCutoutForRotation(info.rotation),
+ calculateRoundedCornersForRotation(info.rotation))) {
+ // TODO(b/161810301): Set notifyInsetsChange to true while the server no longer performs
+ // layout.
+ mInsetsStateController.onDisplayInfoUpdated(false /* notifyInsetsChange */);
+ }
mInputMonitor.layoutInputConsumers(info.logicalWidth, info.logicalHeight);
mDisplayPolicy.onDisplayInfoChanged(info);
}
@@ -3767,8 +3753,11 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
// 2. Assign window layers based on the IME surface parent to make sure it is on top of the
// app.
assignWindowLayers(true /* setLayoutNeeded */);
- // 3. Update the IME control target to apply any inset change and animation.
- // 4. Reparent the IME container surface to either the input target app, or the IME window
+ // 3. The z-order of IME might have been changed. Update the above insets state.
+ mInsetsStateController.updateAboveInsetsState(
+ mInputMethodWindow, true /* notifyInsetsChange */);
+ // 4. Update the IME control target to apply any inset change and animation.
+ // 5. Reparent the IME container surface to either the input target app, or the IME window
// parent.
updateImeControlTarget();
}
@@ -4341,14 +4330,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
+ " dh=" + mDisplayInfo.logicalHeight);
}
- // Used to indicate that we have processed the insets windows. This needs to be after
- // beginLayoutLw to ensure the raw insets state display related info is initialized.
- final InsetsState rawInsetsState = getInsetsStateController().getRawInsetsState();
- mTmpAboveInsetsState = new InsetsState();
- mTmpAboveInsetsState.setDisplayFrame(rawInsetsState.getDisplayFrame());
- mTmpAboveInsetsState.setDisplayCutout(rawInsetsState.getDisplayCutout());
- mTmpAboveInsetsState.mirrorAlwaysVisibleInsetsSources(rawInsetsState);
-
int seq = mLayoutSeq + 1;
if (seq < 0) seq = 0;
mLayoutSeq = seq;
diff --git a/services/core/java/com/android/server/wm/DisplayFrames.java b/services/core/java/com/android/server/wm/DisplayFrames.java
index e4230a2c8760..a37f3f254276 100644
--- a/services/core/java/com/android/server/wm/DisplayFrames.java
+++ b/services/core/java/com/android/server/wm/DisplayFrames.java
@@ -21,6 +21,7 @@ import static android.view.InsetsState.ITYPE_LEFT_DISPLAY_CUTOUT;
import static android.view.InsetsState.ITYPE_RIGHT_DISPLAY_CUTOUT;
import static android.view.InsetsState.ITYPE_TOP_DISPLAY_CUTOUT;
+import android.annotation.NonNull;
import android.graphics.Rect;
import android.util.proto.ProtoOutputStream;
import android.view.DisplayCutout;
@@ -70,25 +71,28 @@ public class DisplayFrames {
* @param info the updated {@link DisplayInfo}.
* @param displayCutout the updated {@link DisplayCutout}.
* @param roundedCorners the updated {@link RoundedCorners}.
+ * @return {@code true} if the insets state has been changed; {@code false} otherwise.
*/
- public void onDisplayInfoUpdated(DisplayInfo info, WmDisplayCutout displayCutout,
- RoundedCorners roundedCorners) {
- mDisplayWidth = info.logicalWidth;
- mDisplayHeight = info.logicalHeight;
+ public boolean onDisplayInfoUpdated(DisplayInfo info, @NonNull WmDisplayCutout displayCutout,
+ @NonNull RoundedCorners roundedCorners) {
mRotation = info.rotation;
- final WmDisplayCutout wmDisplayCutout =
- displayCutout != null ? displayCutout : WmDisplayCutout.NO_CUTOUT;
final InsetsState state = mInsetsState;
- final Rect unrestricted = mUnrestricted;
final Rect safe = mDisplayCutoutSafe;
- final DisplayCutout cutout = wmDisplayCutout.getDisplayCutout();
+ final DisplayCutout cutout = displayCutout.getDisplayCutout();
+ if (mDisplayWidth == info.logicalWidth && mDisplayHeight == info.logicalHeight
+ && state.getDisplayCutout().equals(cutout)
+ && state.getRoundedCorners().equals(roundedCorners)) {
+ return false;
+ }
+ mDisplayWidth = info.logicalWidth;
+ mDisplayHeight = info.logicalHeight;
+ final Rect unrestricted = mUnrestricted;
unrestricted.set(0, 0, mDisplayWidth, mDisplayHeight);
safe.set(Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE);
state.setDisplayFrame(unrestricted);
state.setDisplayCutout(cutout);
- state.setRoundedCorners(roundedCorners != null ? roundedCorners
- : RoundedCorners.NO_ROUNDED_CORNERS);
+ state.setRoundedCorners(roundedCorners);
if (!cutout.isEmpty()) {
if (cutout.getSafeInsetLeft() > 0) {
safe.left = unrestricted.left + cutout.getSafeInsetLeft();
@@ -116,6 +120,7 @@ public class DisplayFrames {
state.removeSource(ITYPE_RIGHT_DISPLAY_CUTOUT);
state.removeSource(ITYPE_BOTTOM_DISPLAY_CUTOUT);
}
+ return true;
}
public void dumpDebug(ProtoOutputStream proto, long fieldId) {
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index 580d3285c6a5..75176df6aaf7 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -27,6 +27,9 @@ import static android.view.InsetsState.ITYPE_IME;
import static android.view.InsetsState.ITYPE_INVALID;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
+import static android.view.WindowInsets.Type.displayCutout;
+import static android.view.WindowInsets.Type.mandatorySystemGestures;
+import static android.view.WindowInsets.Type.systemGestures;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
@@ -293,6 +296,76 @@ class InsetsStateController {
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
+ /**
+ * Updates {@link WindowState#mAboveInsetsState} for all windows in the display while the
+ * z-order of a window is changed.
+ *
+ * @param win The window whose z-order has changed.
+ * @param notifyInsetsChange {@code true} if the clients should be notified about the change.
+ */
+ void updateAboveInsetsState(WindowState win, boolean notifyInsetsChange) {
+ if (win == null || win.getDisplayContent() != mDisplayContent) {
+ return;
+ }
+ final boolean[] aboveWin = { true };
+ final InsetsState aboveInsetsState = new InsetsState();
+ aboveInsetsState.set(mState,
+ displayCutout() | systemGestures() | mandatorySystemGestures());
+ final SparseArray<InsetsSource> winProvidedSources = win.mProvidedInsetsSources;
+ final ArrayList<WindowState> insetsChangedWindows = new ArrayList<>();
+ mDisplayContent.forAllWindows(w -> {
+ if (aboveWin[0]) {
+ if (w == win) {
+ aboveWin[0] = false;
+ if (!win.mAboveInsetsState.equals(aboveInsetsState)) {
+ win.mAboveInsetsState.set(aboveInsetsState);
+ insetsChangedWindows.add(win);
+ }
+ return winProvidedSources.size() == 0;
+ } else {
+ final SparseArray<InsetsSource> providedSources = w.mProvidedInsetsSources;
+ for (int i = providedSources.size() - 1; i >= 0; i--) {
+ aboveInsetsState.addSource(providedSources.valueAt(i));
+ }
+ if (winProvidedSources.size() == 0) {
+ return false;
+ }
+ boolean changed = false;
+ for (int i = winProvidedSources.size() - 1; i >= 0; i--) {
+ changed |= w.mAboveInsetsState.removeSource(winProvidedSources.keyAt(i));
+ }
+ if (changed) {
+ insetsChangedWindows.add(w);
+ }
+ }
+ } else {
+ for (int i = winProvidedSources.size() - 1; i >= 0; i--) {
+ w.mAboveInsetsState.addSource(winProvidedSources.valueAt(i));
+ }
+ insetsChangedWindows.add(w);
+ }
+ return false;
+ }, true /* traverseTopToBottom */);
+ if (notifyInsetsChange) {
+ for (int i = insetsChangedWindows.size() - 1; i >= 0; i--) {
+ mDispatchInsetsChanged.accept(insetsChangedWindows.get(i));
+ }
+ }
+ }
+
+ void onDisplayInfoUpdated(boolean notifyInsetsChange) {
+ final ArrayList<WindowState> insetsChangedWindows = new ArrayList<>();
+ mDisplayContent.forAllWindows(w -> {
+ w.mAboveInsetsState.set(mState, displayCutout());
+ insetsChangedWindows.add(w);
+ }, true /* traverseTopToBottom */);
+ if (notifyInsetsChange) {
+ for (int i = insetsChangedWindows.size() - 1; i >= 0; i--) {
+ mDispatchInsetsChanged.accept(insetsChangedWindows.get(i));
+ }
+ }
+ }
+
void onInsetsModified(InsetsControlTarget caller) {
boolean changed = false;
for (int i = mProviders.size() - 1; i >= 0; i--) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 39b749ef54cb..89d30408fe25 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -1881,6 +1881,10 @@ public class WindowManagerService extends IWindowManager.Stub
displayContent.sendNewConfiguration();
}
+ // This window doesn't have a frame yet. Don't let this window cause the insets change.
+ displayContent.getInsetsStateController().updateAboveInsetsState(
+ win, false /* notifyInsetsChanged */);
+
getInsetsSourceControls(win, outActiveControls);
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index a94b0aa9b72f..3dfdedfec0d1 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -211,11 +211,11 @@ import android.os.Trace;
import android.os.WorkSource;
import android.provider.Settings;
import android.text.TextUtils;
-import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.DisplayMetrics;
import android.util.MergedConfiguration;
import android.util.Slog;
+import android.util.SparseArray;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
import android.view.Display;
@@ -533,6 +533,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
*/
private boolean mOrientationChanging;
+ /** The time when the window was last requested to redraw for orientation change. */
+ private long mOrientationChangeRedrawRequestTime;
+
/**
* Sometimes in addition to the mOrientationChanging
* flag we report that the orientation is changing
@@ -648,12 +651,12 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
/**
* The insets state of sources provided by windows above the current window.
*/
- InsetsState mAboveInsetsState = new InsetsState();
+ final InsetsState mAboveInsetsState = new InsetsState();
/**
* The insets sources provided by this window.
*/
- ArrayMap<Integer, InsetsSource> mProvidedInsetsSources = new ArrayMap<>();
+ final SparseArray<InsetsSource> mProvidedInsetsSources = new SparseArray<>();
/**
* Surface insets from the previous call to relayout(), used to track
@@ -1441,11 +1444,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// redrawn; to do that, we need to go through the process of getting informed by the
// application when it has finished drawing.
if (getOrientationChanging() || dragResizingChanged) {
- if (getOrientationChanging()) {
- Slog.v(TAG_WM, "Orientation start waiting for draw"
- + ", mDrawState=DRAW_PENDING in " + this
- + ", surfaceController " + winAnimator.mSurfaceController);
- }
if (dragResizingChanged) {
ProtoLog.v(WM_DEBUG_RESIZE,
"Resize start waiting for draw, "
@@ -2204,7 +2202,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
}
- @Override
+ @Override
void removeImmediately() {
super.removeImmediately();
@@ -3651,7 +3649,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
ProtoLog.v(WM_DEBUG_RESIZE, "Reporting new frame to %s: %s", this,
mWindowFrames.mCompatFrame);
- if (mWinAnimator.mDrawState == DRAW_PENDING) {
+ final boolean drawPending = mWinAnimator.mDrawState == DRAW_PENDING;
+ if (drawPending) {
ProtoLog.i(WM_DEBUG_ORIENTATION, "Resizing %s WITH DRAW PENDING", this);
}
@@ -3668,7 +3667,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
mWindowFrames.clearReportResizeHints();
final MergedConfiguration mergedConfiguration = mLastReportedConfiguration;
- final boolean reportDraw = mWinAnimator.mDrawState == DRAW_PENDING || useBLASTSync() || !mRedrawForSyncReported;
+ final boolean reportDraw = drawPending || useBLASTSync() || !mRedrawForSyncReported;
final boolean forceRelayout = reportOrientation || isDragResizeChanged() || !mRedrawForSyncReported;
final int displayId = getDisplayId();
fillClientWindowFrames(mClientWindowFrames);
@@ -3679,6 +3678,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
mClient.resized(mClientWindowFrames, reportDraw, mergedConfiguration, forceRelayout,
getDisplayContent().getDisplayPolicy().areSystemBarsForcedShownLw(this),
displayId);
+ if (drawPending && reportOrientation && mOrientationChanging) {
+ mOrientationChangeRedrawRequestTime = SystemClock.elapsedRealtime();
+ ProtoLog.v(WM_DEBUG_ORIENTATION,
+ "Requested redraw for orientation change: %s", this);
+ }
if (mWmService.mAccessibilityController != null) {
mWmService.mAccessibilityController.onSomeWindowResizedOrMoved(displayId);
@@ -5732,6 +5736,18 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
boolean finishDrawing(SurfaceControl.Transaction postDrawTransaction) {
+ if (mOrientationChangeRedrawRequestTime > 0) {
+ final long duration =
+ SystemClock.elapsedRealtime() - mOrientationChangeRedrawRequestTime;
+ Slog.i(TAG, "finishDrawing of orientation change: " + this + " " + duration + "ms");
+ mOrientationChangeRedrawRequestTime = 0;
+ } else if (mActivityRecord != null && mActivityRecord.mRelaunchStartTime != 0
+ && mActivityRecord.findMainWindow() == this) {
+ final long duration =
+ SystemClock.elapsedRealtime() - mActivityRecord.mRelaunchStartTime;
+ Slog.i(TAG, "finishDrawing of relaunch: " + this + " " + duration + "ms");
+ mActivityRecord.mRelaunchStartTime = 0;
+ }
if (!onSyncFinishedDrawing()) {
return mWinAnimator.finishDrawingLocked(postDrawTransaction);
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
index ca534927bd66..7f8784dc2599 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
@@ -223,7 +223,7 @@ public class LocalDisplayAdapterTest {
for (int i = 0; i < wrappedModes.length; i++) {
modes[i] = wrappedModes[i].mode;
}
- display.modes = modes;
+ display.dynamicInfo.supportedDisplayModes = modes;
setUpDisplay(display);
mInjector.getTransmitter().sendHotplug(display, /* connected */ true);
waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
@@ -252,53 +252,53 @@ public class LocalDisplayAdapterTest {
testAlternativeRefreshRatesCommon(display, new DisplayModeWrapper[] {
new DisplayModeWrapper(
- createFakeDisplayMode(1920, 1080, 60f, 0), new float[]{24f, 50f}),
+ createFakeDisplayMode(0, 1920, 1080, 60f, 0), new float[]{24f, 50f}),
new DisplayModeWrapper(
- createFakeDisplayMode(1920, 1080, 50f, 0), new float[]{24f, 60f}),
+ createFakeDisplayMode(1, 1920, 1080, 50f, 0), new float[]{24f, 60f}),
new DisplayModeWrapper(
- createFakeDisplayMode(1920, 1080, 24f, 0), new float[]{50f, 60f}),
+ createFakeDisplayMode(2, 1920, 1080, 24f, 0), new float[]{50f, 60f}),
new DisplayModeWrapper(
- createFakeDisplayMode(3840, 2160, 60f, 0), new float[]{24f, 50f}),
+ createFakeDisplayMode(3, 3840, 2160, 60f, 0), new float[]{24f, 50f}),
new DisplayModeWrapper(
- createFakeDisplayMode(3840, 2160, 50f, 0), new float[]{24f, 60f}),
+ createFakeDisplayMode(4, 3840, 2160, 50f, 0), new float[]{24f, 60f}),
new DisplayModeWrapper(
- createFakeDisplayMode(3840, 2160, 24f, 0), new float[]{50f, 60f}),
+ createFakeDisplayMode(5, 3840, 2160, 24f, 0), new float[]{50f, 60f}),
});
testAlternativeRefreshRatesCommon(display, new DisplayModeWrapper[] {
new DisplayModeWrapper(
- createFakeDisplayMode(1920, 1080, 60f, 0), new float[]{50f}),
+ createFakeDisplayMode(0, 1920, 1080, 60f, 0), new float[]{50f}),
new DisplayModeWrapper(
- createFakeDisplayMode(1920, 1080, 50f, 0), new float[]{60f}),
+ createFakeDisplayMode(1, 1920, 1080, 50f, 0), new float[]{60f}),
new DisplayModeWrapper(
- createFakeDisplayMode(1920, 1080, 24f, 1), new float[0]),
+ createFakeDisplayMode(2, 1920, 1080, 24f, 1), new float[0]),
new DisplayModeWrapper(
- createFakeDisplayMode(3840, 2160, 60f, 2), new float[0]),
+ createFakeDisplayMode(3, 3840, 2160, 60f, 2), new float[0]),
new DisplayModeWrapper(
- createFakeDisplayMode(3840, 2160, 50f, 3), new float[]{24f}),
+ createFakeDisplayMode(4, 3840, 2160, 50f, 3), new float[]{24f}),
new DisplayModeWrapper(
- createFakeDisplayMode(3840, 2160, 24f, 3), new float[]{50f}),
+ createFakeDisplayMode(5, 3840, 2160, 24f, 3), new float[]{50f}),
});
testAlternativeRefreshRatesCommon(display, new DisplayModeWrapper[] {
new DisplayModeWrapper(
- createFakeDisplayMode(1920, 1080, 60f, 0), new float[0]),
+ createFakeDisplayMode(0, 1920, 1080, 60f, 0), new float[0]),
new DisplayModeWrapper(
- createFakeDisplayMode(1920, 1080, 50f, 1), new float[0]),
+ createFakeDisplayMode(1, 1920, 1080, 50f, 1), new float[0]),
new DisplayModeWrapper(
- createFakeDisplayMode(1920, 1080, 24f, 2), new float[0]),
+ createFakeDisplayMode(2, 1920, 1080, 24f, 2), new float[0]),
new DisplayModeWrapper(
- createFakeDisplayMode(3840, 2160, 60f, 3), new float[0]),
+ createFakeDisplayMode(3, 3840, 2160, 60f, 3), new float[0]),
new DisplayModeWrapper(
- createFakeDisplayMode(3840, 2160, 50f, 4), new float[0]),
+ createFakeDisplayMode(4, 3840, 2160, 50f, 4), new float[0]),
new DisplayModeWrapper(
- createFakeDisplayMode(3840, 2160, 24f, 5), new float[0]),
+ createFakeDisplayMode(5, 3840, 2160, 24f, 5), new float[0]),
});
}
@Test
public void testAfterDisplayChange_DisplayModesAreUpdated() throws Exception {
- SurfaceControl.DisplayMode displayMode = createFakeDisplayMode(1920, 1080, 60f);
+ SurfaceControl.DisplayMode displayMode = createFakeDisplayMode(0, 1920, 1080, 60f);
SurfaceControl.DisplayMode[] modes =
new SurfaceControl.DisplayMode[]{displayMode};
FakeDisplay display = new FakeDisplay(PORT_A, modes, 0);
@@ -325,18 +325,14 @@ public class LocalDisplayAdapterTest {
displayMode.refreshRate)).isTrue();
// Change the display
- SurfaceControl.DisplayMode addedDisplayInfo = createFakeDisplayMode(3840, 2160,
- 60f);
+ SurfaceControl.DisplayMode addedDisplayInfo = createFakeDisplayMode(1, 3840, 2160, 60f);
modes = new SurfaceControl.DisplayMode[]{displayMode, addedDisplayInfo};
- display.modes = modes;
- display.activeMode = 1;
+ display.dynamicInfo.supportedDisplayModes = modes;
+ display.dynamicInfo.activeDisplayModeId = 1;
setUpDisplay(display);
mInjector.getTransmitter().sendHotplug(display, /* connected */ true);
waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
- assertThat(SurfaceControl.getActiveDisplayMode(display.token)).isEqualTo(1);
- assertThat(SurfaceControl.getDisplayModes(display.token).length).isEqualTo(2);
-
assertThat(mListener.addedDisplays.size()).isEqualTo(1);
assertThat(mListener.changedDisplays.size()).isEqualTo(1);
@@ -360,8 +356,8 @@ public class LocalDisplayAdapterTest {
@Test
public void testAfterDisplayChange_ActiveModeIsUpdated() throws Exception {
SurfaceControl.DisplayMode[] modes = new SurfaceControl.DisplayMode[]{
- createFakeDisplayMode(1920, 1080, 60f),
- createFakeDisplayMode(1920, 1080, 50f)
+ createFakeDisplayMode(0, 1920, 1080, 60f),
+ createFakeDisplayMode(1, 1920, 1080, 50f)
};
FakeDisplay display = new FakeDisplay(PORT_A, modes, /* activeMode */ 0);
setUpDisplay(display);
@@ -379,13 +375,11 @@ public class LocalDisplayAdapterTest {
assertThat(activeMode.matches(1920, 1080, 60f)).isTrue();
// Change the display
- display.activeMode = 1;
+ display.dynamicInfo.activeDisplayModeId = 1;
setUpDisplay(display);
mInjector.getTransmitter().sendHotplug(display, /* connected */ true);
waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
- assertThat(SurfaceControl.getActiveDisplayMode(display.token)).isEqualTo(1);
-
assertThat(mListener.addedDisplays.size()).isEqualTo(1);
assertThat(mListener.changedDisplays.size()).isEqualTo(1);
@@ -402,7 +396,7 @@ public class LocalDisplayAdapterTest {
FakeDisplay display = new FakeDisplay(PORT_A);
Display.HdrCapabilities initialHdrCapabilities = new Display.HdrCapabilities(new int[0],
1000, 1000, 0);
- display.hdrCapabilities = initialHdrCapabilities;
+ display.dynamicInfo.hdrCapabilities = initialHdrCapabilities;
setUpDisplay(display);
updateAvailableDisplays();
mAdapter.registerLocked();
@@ -419,7 +413,7 @@ public class LocalDisplayAdapterTest {
// Change the display
Display.HdrCapabilities changedHdrCapabilities = new Display.HdrCapabilities(
new int[Display.HdrCapabilities.HDR_TYPE_HDR10_PLUS], 1000, 1000, 0);
- display.hdrCapabilities = changedHdrCapabilities;
+ display.dynamicInfo.hdrCapabilities = changedHdrCapabilities;
setUpDisplay(display);
mInjector.getTransmitter().sendHotplug(display, /* connected */ true);
waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
@@ -438,7 +432,7 @@ public class LocalDisplayAdapterTest {
public void testAfterDisplayChange_ColorModesAreUpdated() throws Exception {
FakeDisplay display = new FakeDisplay(PORT_A);
final int[] initialColorModes = new int[]{Display.COLOR_MODE_BT709};
- display.colorModes = initialColorModes;
+ display.dynamicInfo.supportedColorModes = initialColorModes;
setUpDisplay(display);
updateAvailableDisplays();
mAdapter.registerLocked();
@@ -455,7 +449,7 @@ public class LocalDisplayAdapterTest {
// Change the display
final int[] changedColorModes = new int[]{Display.COLOR_MODE_DEFAULT};
- display.colorModes = changedColorModes;
+ display.dynamicInfo.supportedColorModes = changedColorModes;
setUpDisplay(display);
mInjector.getTransmitter().sendHotplug(display, /* connected */ true);
waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
@@ -474,8 +468,8 @@ public class LocalDisplayAdapterTest {
@Test
public void testDisplayChange_withStaleDesiredDisplayModeSpecs() throws Exception {
SurfaceControl.DisplayMode[] modes = new SurfaceControl.DisplayMode[]{
- createFakeDisplayMode(1920, 1080, 60f),
- createFakeDisplayMode(1920, 1080, 50f)
+ createFakeDisplayMode(0, 1920, 1080, 60f),
+ createFakeDisplayMode(1, 1920, 1080, 50f)
};
final int activeMode = 0;
FakeDisplay display = new FakeDisplay(PORT_A, modes, activeMode);
@@ -487,11 +481,11 @@ public class LocalDisplayAdapterTest {
waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
// Change the display
- display.modes = new SurfaceControl.DisplayMode[]{
- createFakeDisplayMode(1920, 1080, 60f)
+ display.dynamicInfo.supportedDisplayModes = new SurfaceControl.DisplayMode[]{
+ createFakeDisplayMode(2, 1920, 1080, 60f)
};
- // SurfaceFlinger can return a stale defaultMode. Make sure this doesn't
- // trigger ArrayOutOfBoundsException.
+ display.dynamicInfo.activeDisplayModeId = 2;
+ // SurfaceFlinger can return a stale defaultMode. Make sure this doesn't crash.
display.desiredDisplayModeSpecs.defaultMode = 1;
setUpDisplay(display);
@@ -588,12 +582,15 @@ public class LocalDisplayAdapterTest {
private static class FakeDisplay {
public final DisplayAddress.Physical address;
public final IBinder token = new Binder();
- public final SurfaceControl.DisplayInfo info;
- public SurfaceControl.DisplayMode[] modes;
- public int activeMode;
- public int[] colorModes = new int[]{ Display.COLOR_MODE_DEFAULT };
- public Display.HdrCapabilities hdrCapabilities = new Display.HdrCapabilities(new int[0],
- 1000, 1000, 0);
+ public final SurfaceControl.StaticDisplayInfo info;
+ public SurfaceControl.DynamicDisplayInfo dynamicInfo =
+ new SurfaceControl.DynamicDisplayInfo();
+ {
+ dynamicInfo.supportedColorModes = new int[]{ Display.COLOR_MODE_DEFAULT };
+ dynamicInfo.hdrCapabilities = new Display.HdrCapabilities(new int[0],
+ 1000, 1000, 0);
+ }
+
public SurfaceControl.DesiredDisplayModeSpecs desiredDisplayModeSpecs =
new SurfaceControl.DesiredDisplayModeSpecs(/* defaultMode */ 0,
/* allowGroupSwitching */ false,
@@ -603,19 +600,19 @@ public class LocalDisplayAdapterTest {
/* appRefreshRateMax */60.f);
private FakeDisplay(int port) {
- this.address = createDisplayAddress(port);
- this.info = createFakeDisplayInfo();
- this.modes = new SurfaceControl.DisplayMode[]{
- createFakeDisplayMode(800, 600, 60f)
+ address = createDisplayAddress(port);
+ info = createFakeDisplayInfo();
+ dynamicInfo.supportedDisplayModes = new SurfaceControl.DisplayMode[]{
+ createFakeDisplayMode(0, 800, 600, 60f)
};
- this.activeMode = 0;
+ dynamicInfo.activeDisplayModeId = 0;
}
private FakeDisplay(int port, SurfaceControl.DisplayMode[] modes, int activeMode) {
- this.address = createDisplayAddress(port);
- this.info = createFakeDisplayInfo();
- this.modes = modes;
- this.activeMode = activeMode;
+ address = createDisplayAddress(port);
+ info = createFakeDisplayInfo();
+ dynamicInfo.supportedDisplayModes = modes;
+ dynamicInfo.activeDisplayModeId = activeMode;
}
}
@@ -623,15 +620,9 @@ public class LocalDisplayAdapterTest {
mAddresses.add(display.address);
doReturn(display.token).when(() ->
SurfaceControl.getPhysicalDisplayToken(display.address.getPhysicalDisplayId()));
- doReturn(display.info).when(() -> SurfaceControl.getDisplayInfo(display.token));
- doReturn(display.modes).when(
- () -> SurfaceControl.getDisplayModes(display.token));
- doReturn(display.activeMode).when(() -> SurfaceControl.getActiveDisplayMode(display.token));
- doReturn(0).when(() -> SurfaceControl.getActiveColorMode(display.token));
- doReturn(display.colorModes).when(
- () -> SurfaceControl.getDisplayColorModes(display.token));
- doReturn(display.hdrCapabilities).when(
- () -> SurfaceControl.getHdrCapabilities(display.token));
+ doReturn(display.info).when(() -> SurfaceControl.getStaticDisplayInfo(display.token));
+ doReturn(display.dynamicInfo).when(
+ () -> SurfaceControl.getDynamicDisplayInfo(display.token));
doReturn(display.desiredDisplayModeSpecs)
.when(() -> SurfaceControl.getDesiredDisplayModeSpecs(display.token));
}
@@ -650,20 +641,21 @@ public class LocalDisplayAdapterTest {
return DisplayAddress.fromPortAndModel(port, DISPLAY_MODEL);
}
- private static SurfaceControl.DisplayInfo createFakeDisplayInfo() {
- final SurfaceControl.DisplayInfo info = new SurfaceControl.DisplayInfo();
+ private static SurfaceControl.StaticDisplayInfo createFakeDisplayInfo() {
+ final SurfaceControl.StaticDisplayInfo info = new SurfaceControl.StaticDisplayInfo();
info.density = 100;
return info;
}
- private static SurfaceControl.DisplayMode createFakeDisplayMode(int width, int height,
+ private static SurfaceControl.DisplayMode createFakeDisplayMode(int id, int width, int height,
float refreshRate) {
- return createFakeDisplayMode(width, height, refreshRate, 0);
+ return createFakeDisplayMode(id, width, height, refreshRate, 0);
}
- private static SurfaceControl.DisplayMode createFakeDisplayMode(int width, int height,
+ private static SurfaceControl.DisplayMode createFakeDisplayMode(int id, int width, int height,
float refreshRate, int group) {
final SurfaceControl.DisplayMode mode = new SurfaceControl.DisplayMode();
+ mode.id = id;
mode.width = width;
mode.height = height;
mode.refreshRate = refreshRate;
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java
index 6d40034c6000..91b3cb7dbdd9 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java
@@ -25,6 +25,7 @@ import static com.android.server.job.JobSchedulerService.NEVER_INDEX;
import static com.android.server.job.JobSchedulerService.RARE_INDEX;
import static com.android.server.job.JobSchedulerService.RESTRICTED_INDEX;
import static com.android.server.job.JobSchedulerService.WORKING_INDEX;
+import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
import static com.android.server.job.controllers.JobStatus.CONSTRAINT_BACKGROUND_NOT_RESTRICTED;
import static com.android.server.job.controllers.JobStatus.CONSTRAINT_BATTERY_NOT_LOW;
import static com.android.server.job.controllers.JobStatus.CONSTRAINT_CHARGING;
@@ -101,7 +102,7 @@ public class JobStatusTest {
Clock.fixed(Clock.systemUTC().instant(), ZoneOffset.UTC);
JobSchedulerService.sUptimeMillisClock =
Clock.fixed(SystemClock.uptimeClock().instant(), ZoneOffset.UTC);
- JobSchedulerService.sElapsedRealtimeClock =
+ sElapsedRealtimeClock =
Clock.fixed(SystemClock.elapsedRealtimeClock().instant(), ZoneOffset.UTC);
}
@@ -204,7 +205,7 @@ public class JobStatusTest {
@Test
public void testFraction() throws Exception {
- final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
+ final long now = sElapsedRealtimeClock.millis();
assertEquals(1, createJobStatus(0, Long.MAX_VALUE).getFractionRunTime(), DELTA);
@@ -261,15 +262,15 @@ public class JobStatusTest {
final JobStatus job = createJobStatus(jobInfo);
markImplicitConstraintsSatisfied(job, true);
- job.setChargingConstraintSatisfied(false);
+ job.setChargingConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_CHARGING));
- job.setChargingConstraintSatisfied(true);
+ job.setChargingConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_CHARGING));
markImplicitConstraintsSatisfied(job, false);
- job.setChargingConstraintSatisfied(false);
+ job.setChargingConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CHARGING));
- job.setChargingConstraintSatisfied(true);
+ job.setChargingConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CHARGING));
}
@@ -282,15 +283,15 @@ public class JobStatusTest {
final JobStatus job = createJobStatus(jobInfo);
markImplicitConstraintsSatisfied(job, true);
- job.setIdleConstraintSatisfied(false);
+ job.setIdleConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_IDLE));
- job.setIdleConstraintSatisfied(true);
+ job.setIdleConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_IDLE));
markImplicitConstraintsSatisfied(job, false);
- job.setIdleConstraintSatisfied(false);
+ job.setIdleConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_IDLE));
- job.setIdleConstraintSatisfied(true);
+ job.setIdleConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_IDLE));
}
@@ -303,15 +304,15 @@ public class JobStatusTest {
final JobStatus job = createJobStatus(jobInfo);
markImplicitConstraintsSatisfied(job, true);
- job.setBatteryNotLowConstraintSatisfied(false);
+ job.setBatteryNotLowConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_BATTERY_NOT_LOW));
- job.setBatteryNotLowConstraintSatisfied(true);
+ job.setBatteryNotLowConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_BATTERY_NOT_LOW));
markImplicitConstraintsSatisfied(job, false);
- job.setBatteryNotLowConstraintSatisfied(false);
+ job.setBatteryNotLowConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_BATTERY_NOT_LOW));
- job.setBatteryNotLowConstraintSatisfied(true);
+ job.setBatteryNotLowConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_BATTERY_NOT_LOW));
}
@@ -324,15 +325,15 @@ public class JobStatusTest {
final JobStatus job = createJobStatus(jobInfo);
markImplicitConstraintsSatisfied(job, true);
- job.setStorageNotLowConstraintSatisfied(false);
+ job.setStorageNotLowConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_STORAGE_NOT_LOW));
- job.setStorageNotLowConstraintSatisfied(true);
+ job.setStorageNotLowConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_STORAGE_NOT_LOW));
markImplicitConstraintsSatisfied(job, false);
- job.setStorageNotLowConstraintSatisfied(false);
+ job.setStorageNotLowConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_STORAGE_NOT_LOW));
- job.setStorageNotLowConstraintSatisfied(true);
+ job.setStorageNotLowConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_STORAGE_NOT_LOW));
}
@@ -345,15 +346,15 @@ public class JobStatusTest {
final JobStatus job = createJobStatus(jobInfo);
markImplicitConstraintsSatisfied(job, true);
- job.setTimingDelayConstraintSatisfied(false);
+ job.setTimingDelayConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_TIMING_DELAY));
- job.setTimingDelayConstraintSatisfied(true);
+ job.setTimingDelayConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_TIMING_DELAY));
markImplicitConstraintsSatisfied(job, false);
- job.setTimingDelayConstraintSatisfied(false);
+ job.setTimingDelayConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_TIMING_DELAY));
- job.setTimingDelayConstraintSatisfied(true);
+ job.setTimingDelayConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_TIMING_DELAY));
}
@@ -366,15 +367,15 @@ public class JobStatusTest {
final JobStatus job = createJobStatus(jobInfo);
markImplicitConstraintsSatisfied(job, true);
- job.setDeadlineConstraintSatisfied(false);
+ job.setDeadlineConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_DEADLINE));
- job.setDeadlineConstraintSatisfied(true);
+ job.setDeadlineConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_DEADLINE));
markImplicitConstraintsSatisfied(job, false);
- job.setDeadlineConstraintSatisfied(false);
+ job.setDeadlineConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_DEADLINE));
- job.setDeadlineConstraintSatisfied(true);
+ job.setDeadlineConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_DEADLINE));
}
@@ -387,15 +388,15 @@ public class JobStatusTest {
final JobStatus job = createJobStatus(jobInfo);
markImplicitConstraintsSatisfied(job, true);
- job.setConnectivityConstraintSatisfied(false);
+ job.setConnectivityConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_CONNECTIVITY));
- job.setConnectivityConstraintSatisfied(true);
+ job.setConnectivityConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_CONNECTIVITY));
markImplicitConstraintsSatisfied(job, false);
- job.setConnectivityConstraintSatisfied(false);
+ job.setConnectivityConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CONNECTIVITY));
- job.setConnectivityConstraintSatisfied(true);
+ job.setConnectivityConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CONNECTIVITY));
}
@@ -410,15 +411,15 @@ public class JobStatusTest {
final JobStatus job = createJobStatus(jobInfo);
markImplicitConstraintsSatisfied(job, true);
- job.setContentTriggerConstraintSatisfied(false);
+ job.setContentTriggerConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_CONTENT_TRIGGER));
- job.setContentTriggerConstraintSatisfied(true);
+ job.setContentTriggerConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_CONTENT_TRIGGER));
markImplicitConstraintsSatisfied(job, false);
- job.setContentTriggerConstraintSatisfied(false);
+ job.setContentTriggerConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CONTENT_TRIGGER));
- job.setContentTriggerConstraintSatisfied(true);
+ job.setContentTriggerConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CONTENT_TRIGGER));
}
@@ -436,15 +437,15 @@ public class JobStatusTest {
markImplicitConstraintsSatisfied(job, false);
- job.setChargingConstraintSatisfied(false);
- job.setConnectivityConstraintSatisfied(false);
- job.setContentTriggerConstraintSatisfied(false);
+ job.setChargingConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
+ job.setConnectivityConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
+ job.setContentTriggerConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CHARGING));
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CONNECTIVITY));
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CONTENT_TRIGGER));
- job.setChargingConstraintSatisfied(true);
- job.setConnectivityConstraintSatisfied(true);
- job.setContentTriggerConstraintSatisfied(true);
+ job.setChargingConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
+ job.setConnectivityConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
+ job.setContentTriggerConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
// Still false because implicit constraints aren't satisfied.
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CHARGING));
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CONNECTIVITY));
@@ -452,61 +453,61 @@ public class JobStatusTest {
markImplicitConstraintsSatisfied(job, true);
- job.setChargingConstraintSatisfied(false);
- job.setConnectivityConstraintSatisfied(false);
- job.setContentTriggerConstraintSatisfied(false);
+ job.setChargingConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
+ job.setConnectivityConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
+ job.setContentTriggerConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CHARGING));
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CONNECTIVITY));
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CONTENT_TRIGGER));
// Turn on constraints one at a time.
- job.setChargingConstraintSatisfied(true);
- job.setConnectivityConstraintSatisfied(false);
- job.setContentTriggerConstraintSatisfied(false);
+ job.setChargingConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
+ job.setConnectivityConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
+ job.setContentTriggerConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CHARGING));
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CONNECTIVITY));
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CONTENT_TRIGGER));
- job.setChargingConstraintSatisfied(false);
- job.setConnectivityConstraintSatisfied(false);
- job.setContentTriggerConstraintSatisfied(true);
+ job.setChargingConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
+ job.setConnectivityConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
+ job.setContentTriggerConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CHARGING));
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CONNECTIVITY));
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CONTENT_TRIGGER));
- job.setChargingConstraintSatisfied(false);
- job.setConnectivityConstraintSatisfied(true);
- job.setContentTriggerConstraintSatisfied(false);
+ job.setChargingConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
+ job.setConnectivityConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
+ job.setContentTriggerConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CHARGING));
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CONNECTIVITY));
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CONTENT_TRIGGER));
// With two of the 3 constraints satisfied (and implicit constraints also satisfied), only
// the unsatisfied constraint should return true.
- job.setChargingConstraintSatisfied(true);
- job.setConnectivityConstraintSatisfied(false);
- job.setContentTriggerConstraintSatisfied(true);
+ job.setChargingConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
+ job.setConnectivityConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
+ job.setContentTriggerConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CHARGING));
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_CONNECTIVITY));
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CONTENT_TRIGGER));
- job.setChargingConstraintSatisfied(true);
- job.setConnectivityConstraintSatisfied(true);
- job.setContentTriggerConstraintSatisfied(false);
+ job.setChargingConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
+ job.setConnectivityConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
+ job.setContentTriggerConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CHARGING));
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CONNECTIVITY));
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_CONTENT_TRIGGER));
- job.setChargingConstraintSatisfied(false);
- job.setConnectivityConstraintSatisfied(true);
- job.setContentTriggerConstraintSatisfied(true);
+ job.setChargingConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
+ job.setConnectivityConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
+ job.setContentTriggerConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_CHARGING));
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CONNECTIVITY));
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CONTENT_TRIGGER));
- job.setChargingConstraintSatisfied(true);
- job.setConnectivityConstraintSatisfied(true);
- job.setContentTriggerConstraintSatisfied(true);
+ job.setChargingConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
+ job.setConnectivityConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
+ job.setContentTriggerConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_CHARGING));
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_CONNECTIVITY));
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_CONTENT_TRIGGER));
@@ -526,15 +527,15 @@ public class JobStatusTest {
markImplicitConstraintsSatisfied(job, false);
- job.setChargingConstraintSatisfied(false);
- job.setContentTriggerConstraintSatisfied(false);
- job.setDeadlineConstraintSatisfied(false);
+ job.setChargingConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
+ job.setContentTriggerConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
+ job.setDeadlineConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CHARGING));
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CONTENT_TRIGGER));
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_DEADLINE));
- job.setChargingConstraintSatisfied(true);
- job.setContentTriggerConstraintSatisfied(true);
- job.setDeadlineConstraintSatisfied(true);
+ job.setChargingConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
+ job.setContentTriggerConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
+ job.setDeadlineConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
// Still false because implicit constraints aren't satisfied.
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CHARGING));
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CONTENT_TRIGGER));
@@ -542,18 +543,18 @@ public class JobStatusTest {
markImplicitConstraintsSatisfied(job, true);
- job.setChargingConstraintSatisfied(false);
- job.setContentTriggerConstraintSatisfied(false);
- job.setDeadlineConstraintSatisfied(false);
+ job.setChargingConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
+ job.setContentTriggerConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
+ job.setDeadlineConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CHARGING));
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CONTENT_TRIGGER));
// Once implicit constraint are satisfied, deadline constraint should always return true.
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_DEADLINE));
// Turn on constraints one at a time.
- job.setChargingConstraintSatisfied(true);
- job.setContentTriggerConstraintSatisfied(false);
- job.setDeadlineConstraintSatisfied(false);
+ job.setChargingConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
+ job.setContentTriggerConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
+ job.setDeadlineConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CHARGING));
// Deadline should force isReady to be true, but isn't needed for the job to be
// considered ready.
@@ -561,17 +562,17 @@ public class JobStatusTest {
// Once implicit constraint are satisfied, deadline constraint should always return true.
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_DEADLINE));
- job.setChargingConstraintSatisfied(false);
- job.setContentTriggerConstraintSatisfied(true);
- job.setDeadlineConstraintSatisfied(false);
+ job.setChargingConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
+ job.setContentTriggerConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
+ job.setDeadlineConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_CHARGING));
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CONTENT_TRIGGER));
// Once implicit constraint are satisfied, deadline constraint should always return true.
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_DEADLINE));
- job.setChargingConstraintSatisfied(false);
- job.setContentTriggerConstraintSatisfied(false);
- job.setDeadlineConstraintSatisfied(true);
+ job.setChargingConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
+ job.setContentTriggerConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
+ job.setDeadlineConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
// Since the deadline constraint is satisfied, none of the other explicit constraints are
// needed.
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_CHARGING));
@@ -581,33 +582,33 @@ public class JobStatusTest {
// With two of the 3 constraints satisfied (and implicit constraints also satisfied), only
// the unsatisfied constraint should return true.
- job.setChargingConstraintSatisfied(true);
- job.setContentTriggerConstraintSatisfied(true);
- job.setDeadlineConstraintSatisfied(false);
+ job.setChargingConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
+ job.setContentTriggerConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
+ job.setDeadlineConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_CHARGING));
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_CONTENT_TRIGGER));
// Once implicit constraint are satisfied, deadline constraint should always return true.
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_DEADLINE));
- job.setChargingConstraintSatisfied(true);
- job.setContentTriggerConstraintSatisfied(false);
- job.setDeadlineConstraintSatisfied(true);
+ job.setChargingConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
+ job.setContentTriggerConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
+ job.setDeadlineConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_CHARGING));
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_CONTENT_TRIGGER));
// Once implicit constraint are satisfied, deadline constraint should always return true.
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_DEADLINE));
- job.setChargingConstraintSatisfied(false);
- job.setContentTriggerConstraintSatisfied(true);
- job.setDeadlineConstraintSatisfied(true);
+ job.setChargingConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
+ job.setContentTriggerConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
+ job.setDeadlineConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_CHARGING));
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_CONTENT_TRIGGER));
// Once implicit constraint are satisfied, deadline constraint should always return true.
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_DEADLINE));
- job.setChargingConstraintSatisfied(true);
- job.setContentTriggerConstraintSatisfied(true);
- job.setDeadlineConstraintSatisfied(true);
+ job.setChargingConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
+ job.setContentTriggerConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
+ job.setDeadlineConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_CHARGING));
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_CONTENT_TRIGGER));
// Once implicit constraint are satisfied, deadline constraint should always return true.
@@ -621,15 +622,15 @@ public class JobStatusTest {
new JobInfo.Builder(101, new ComponentName("foo", "bar")).build());
markImplicitConstraintsSatisfied(job, false);
- job.setDeviceNotDozingConstraintSatisfied(false, false);
+ job.setDeviceNotDozingConstraintSatisfied(sElapsedRealtimeClock.millis(), false, false);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_DEVICE_NOT_DOZING));
- job.setDeviceNotDozingConstraintSatisfied(true, false);
+ job.setDeviceNotDozingConstraintSatisfied(sElapsedRealtimeClock.millis(), true, false);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_DEVICE_NOT_DOZING));
markImplicitConstraintsSatisfied(job, true);
- job.setDeviceNotDozingConstraintSatisfied(false, false);
+ job.setDeviceNotDozingConstraintSatisfied(sElapsedRealtimeClock.millis(), false, false);
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_DEVICE_NOT_DOZING));
- job.setDeviceNotDozingConstraintSatisfied(true, false);
+ job.setDeviceNotDozingConstraintSatisfied(sElapsedRealtimeClock.millis(), true, false);
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_DEVICE_NOT_DOZING));
}
@@ -640,15 +641,15 @@ public class JobStatusTest {
new JobInfo.Builder(101, new ComponentName("foo", "bar")).build());
markImplicitConstraintsSatisfied(job, false);
- job.setQuotaConstraintSatisfied(false);
+ job.setQuotaConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_WITHIN_QUOTA));
- job.setQuotaConstraintSatisfied(true);
+ job.setQuotaConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_WITHIN_QUOTA));
markImplicitConstraintsSatisfied(job, true);
- job.setQuotaConstraintSatisfied(false);
+ job.setQuotaConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_WITHIN_QUOTA));
- job.setQuotaConstraintSatisfied(true);
+ job.setQuotaConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_WITHIN_QUOTA));
}
@@ -659,22 +660,24 @@ public class JobStatusTest {
new JobInfo.Builder(101, new ComponentName("foo", "bar")).build());
markImplicitConstraintsSatisfied(job, false);
- job.setBackgroundNotRestrictedConstraintSatisfied(false);
+ job.setBackgroundNotRestrictedConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_BACKGROUND_NOT_RESTRICTED));
- job.setBackgroundNotRestrictedConstraintSatisfied(true);
+ job.setBackgroundNotRestrictedConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_BACKGROUND_NOT_RESTRICTED));
markImplicitConstraintsSatisfied(job, true);
- job.setBackgroundNotRestrictedConstraintSatisfied(false);
+ job.setBackgroundNotRestrictedConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_BACKGROUND_NOT_RESTRICTED));
- job.setBackgroundNotRestrictedConstraintSatisfied(true);
+ job.setBackgroundNotRestrictedConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_BACKGROUND_NOT_RESTRICTED));
}
private void markImplicitConstraintsSatisfied(JobStatus job, boolean isSatisfied) {
- job.setQuotaConstraintSatisfied(isSatisfied);
- job.setDeviceNotDozingConstraintSatisfied(isSatisfied, false);
- job.setBackgroundNotRestrictedConstraintSatisfied(isSatisfied);
+ job.setQuotaConstraintSatisfied(sElapsedRealtimeClock.millis(), isSatisfied);
+ job.setDeviceNotDozingConstraintSatisfied(
+ sElapsedRealtimeClock.millis(), isSatisfied, false);
+ job.setBackgroundNotRestrictedConstraintSatisfied(
+ sElapsedRealtimeClock.millis(), isSatisfied);
}
private static JobStatus createJobStatus(long earliestRunTimeElapsedMillis,
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
index b72121f096ba..88a691bbc209 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
@@ -359,8 +359,9 @@ public class QuotaControllerTest {
// Make sure tests aren't passing just because the default bucket is likely ACTIVE.
js.setStandbyBucket(FREQUENT_INDEX);
// Make sure Doze and background-not-restricted don't affect tests.
- js.setDeviceNotDozingConstraintSatisfied(/* state */ true, /* allowlisted */false);
- js.setBackgroundNotRestrictedConstraintSatisfied(true);
+ js.setDeviceNotDozingConstraintSatisfied(/* nowElapsed */ sElapsedRealtimeClock.millis(),
+ /* state */ true, /* allowlisted */false);
+ js.setBackgroundNotRestrictedConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
return js;
}
diff --git a/services/tests/servicestests/src/com/android/server/appop/AppOpsNotedWatcherTest.java b/services/tests/servicestests/src/com/android/server/appop/AppOpsNotedWatcherTest.java
index 41e15631d258..663017890b0c 100644
--- a/services/tests/servicestests/src/com/android/server/appop/AppOpsNotedWatcherTest.java
+++ b/services/tests/servicestests/src/com/android/server/appop/AppOpsNotedWatcherTest.java
@@ -66,11 +66,13 @@ public class AppOpsNotedWatcherTest {
inOrder.verify(listener, timeout(NOTIFICATION_TIMEOUT_MILLIS)
.times(1)).onOpNoted(eq(AppOpsManager.OP_FINE_LOCATION),
eq(Process.myUid()), eq(getContext().getPackageName()),
- eq(AppOpsManager.OP_FLAG_SELF), eq(AppOpsManager.MODE_ALLOWED));
+ eq(getContext().getAttributionTag()), eq(AppOpsManager.OP_FLAG_SELF),
+ eq(AppOpsManager.MODE_ALLOWED));
inOrder.verify(listener, timeout(NOTIFICATION_TIMEOUT_MILLIS)
.times(1)).onOpNoted(eq(AppOpsManager.OP_CAMERA),
eq(Process.myUid()), eq(getContext().getPackageName()),
- eq(AppOpsManager.OP_FLAG_SELF), eq(AppOpsManager.MODE_ALLOWED));
+ eq(getContext().getAttributionTag()), eq(AppOpsManager.OP_FLAG_SELF),
+ eq(AppOpsManager.MODE_ALLOWED));
// Stop watching
appOpsManager.stopWatchingNoted(listener);
@@ -94,7 +96,8 @@ public class AppOpsNotedWatcherTest {
verify(listener, timeout(NOTIFICATION_TIMEOUT_MILLIS)
.times(2)).onOpNoted(eq(AppOpsManager.OP_FINE_LOCATION),
eq(Process.myUid()), eq(getContext().getPackageName()),
- eq(AppOpsManager.OP_FLAG_SELF), eq(AppOpsManager.MODE_ALLOWED));
+ eq(getContext().getAttributionTag()), eq(AppOpsManager.OP_FLAG_SELF),
+ eq(AppOpsManager.MODE_ALLOWED));
// Finish up
appOpsManager.stopWatchingNoted(listener);
diff --git a/services/tests/servicestests/src/com/android/server/appop/AppOpsStartedWatcherTest.java b/services/tests/servicestests/src/com/android/server/appop/AppOpsStartedWatcherTest.java
index fec8aa9ceaff..c12eb32a9143 100644
--- a/services/tests/servicestests/src/com/android/server/appop/AppOpsStartedWatcherTest.java
+++ b/services/tests/servicestests/src/com/android/server/appop/AppOpsStartedWatcherTest.java
@@ -63,11 +63,13 @@ public class AppOpsStartedWatcherTest {
inOrder.verify(listener, timeout(NOTIFICATION_TIMEOUT_MILLIS)
.times(1)).onOpStarted(eq(AppOpsManager.OP_FINE_LOCATION),
eq(Process.myUid()), eq(getContext().getPackageName()),
- eq(AppOpsManager.OP_FLAG_SELF), eq(AppOpsManager.MODE_ALLOWED));
+ eq(getContext().getAttributionTag()), eq(AppOpsManager.OP_FLAG_SELF),
+ eq(AppOpsManager.MODE_ALLOWED));
inOrder.verify(listener, timeout(NOTIFICATION_TIMEOUT_MILLIS)
.times(1)).onOpStarted(eq(AppOpsManager.OP_CAMERA),
eq(Process.myUid()), eq(getContext().getPackageName()),
- eq(AppOpsManager.OP_FLAG_SELF), eq(AppOpsManager.MODE_ALLOWED));
+ eq(getContext().getAttributionTag()), eq(AppOpsManager.OP_FLAG_SELF),
+ eq(AppOpsManager.MODE_ALLOWED));
// Stop watching
appOpsManager.stopWatchingStarted(listener);
@@ -91,7 +93,8 @@ public class AppOpsStartedWatcherTest {
verify(listener, timeout(NOTIFICATION_TIMEOUT_MILLIS)
.times(2)).onOpStarted(eq(AppOpsManager.OP_CAMERA),
eq(Process.myUid()), eq(getContext().getPackageName()),
- eq(AppOpsManager.OP_FLAG_SELF), eq(AppOpsManager.MODE_ALLOWED));
+ eq(getContext().getAttributionTag()), eq(AppOpsManager.OP_FLAG_SELF),
+ eq(AppOpsManager.MODE_ALLOWED));
verifyNoMoreInteractions(listener);
// Finish up
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
index 55748366c1ba..5f86d282406a 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
@@ -287,8 +287,7 @@ public class TimeDetectorServiceTest {
}
private static ExternalTimeSuggestion createExternalTimeSuggestion() {
- TimestampedValue<Long> timeValue = new TimestampedValue<>(100L, 1_000_000L);
- return new ExternalTimeSuggestion(timeValue);
+ return new ExternalTimeSuggestion(100L, 1_000_000L);
}
private static class StubbedTimeDetectorStrategy implements TimeDetectorStrategy {
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
index daa1b25de22f..f7a498bc9d73 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
@@ -1483,11 +1483,8 @@ public class TimeDetectorStrategyImplTest {
* reference time.
*/
ExternalTimeSuggestion generateExternalTimeSuggestion(Instant suggestedTime) {
- TimestampedValue<Long> utcTime =
- new TimestampedValue<>(
- mFakeEnvironment.peekElapsedRealtimeMillis(),
+ return new ExternalTimeSuggestion(mFakeEnvironment.peekElapsedRealtimeMillis(),
suggestedTime.toEpochMilli());
- return new ExternalTimeSuggestion(utcTime);
}
/**
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
index b1ea4a58d0f1..5a0466afa85b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
@@ -130,7 +130,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
// insets state with the global one.
final InsetsState insetsState =
win.getDisplayContent().getInsetsStateController().getRawInsetsState();
- win.mAboveInsetsState = insetsState;
+ win.mAboveInsetsState.set(insetsState);
}
public void setRotation(int rotation, boolean includingWindows) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
index 2163661b7506..47cf53b621d3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
@@ -18,6 +18,7 @@ package com.android.server.wm;
import static android.view.InsetsState.ITYPE_IME;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
+import static android.view.RoundedCorners.NO_ROUNDED_CORNERS;
import static android.view.Surface.ROTATION_0;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
@@ -37,6 +38,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_BOTTOM;
import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_RIGHT;
+import static com.android.server.wm.utils.WmDisplayCutout.NO_CUTOUT;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -300,9 +302,9 @@ public class DisplayPolicyTests extends WindowTestsBase {
displayPolicy.addWindowLw(mNavBarWindow, mNavBarWindow.mAttrs);
mNavBarWindow.getControllableInsetProvider().setServerVisible(true);
final InsetsState state = mDisplayContent.getInsetsStateController().getRawInsetsState();
- mImeWindow.mAboveInsetsState = state;
+ mImeWindow.mAboveInsetsState.set(state);
mDisplayContent.mDisplayFrames = new DisplayFrames(mDisplayContent.getDisplayId(),
- state, displayInfo, null /* displayCutout */, null /* roundedCorners*/);
+ state, displayInfo, NO_CUTOUT, NO_ROUNDED_CORNERS);
mDisplayContent.setInputMethodWindowLocked(mImeWindow);
mImeWindow.mAttrs.setFitInsetsSides(Side.all() & ~Side.BOTTOM);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java
index 20775e84fd8f..683ed889d283 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java
@@ -117,7 +117,7 @@ public class DisplayPolicyTestsBase extends WindowTestsBase {
static Pair<DisplayInfo, WmDisplayCutout> displayInfoAndCutoutForRotation(int rotation,
boolean withDisplayCutout, boolean isLongEdgeCutout) {
final DisplayInfo info = new DisplayInfo();
- WmDisplayCutout cutout = null;
+ WmDisplayCutout cutout = WmDisplayCutout.NO_CUTOUT;
final boolean flippedDimensions = rotation == ROTATION_90 || rotation == ROTATION_270;
info.logicalWidth = flippedDimensions ? DISPLAY_HEIGHT : DISPLAY_WIDTH;
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
index ee293fcf70e6..be036034542e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
@@ -32,13 +32,14 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.server.wm.DisplayContent.IME_TARGET_INPUT;
+import static com.android.server.wm.WindowContainer.POSITION_TOP;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
@@ -208,7 +209,7 @@ public class InsetsStateControllerTest extends WindowTestsBase {
app.mAboveInsetsState.getSource(ITYPE_IME).setFrame(mImeWindow.getFrame());
// Make sure app got notified.
- verify(app, atLeast(1)).notifyInsetsChanged();
+ verify(app, atLeastOnce()).notifyInsetsChanged();
// app will get visible IME insets while below IME.
assertTrue(getController().getInsetsForWindow(app).getSource(ITYPE_IME).isVisible());
@@ -336,6 +337,92 @@ public class InsetsStateControllerTest extends WindowTestsBase {
assertFalse(app.getInsetsState().getSource(ITYPE_STATUS_BAR).isVisible());
}
+ @Test
+ public void testUpdateAboveInsetsState_provideInsets() {
+ final WindowState app = createTestWindow("app");
+ final WindowState statusBar = createTestWindow("statusBar");
+ final WindowState navBar = createTestWindow("navBar");
+
+ getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null, null);
+
+ assertNull(app.mAboveInsetsState.peekSource(ITYPE_STATUS_BAR));
+ assertNull(statusBar.mAboveInsetsState.peekSource(ITYPE_STATUS_BAR));
+ assertNull(navBar.mAboveInsetsState.peekSource(ITYPE_STATUS_BAR));
+
+ getController().updateAboveInsetsState(statusBar, true /* notifyInsetsChange */);
+
+ assertNotNull(app.mAboveInsetsState.peekSource(ITYPE_STATUS_BAR));
+ assertNull(statusBar.mAboveInsetsState.peekSource(ITYPE_STATUS_BAR));
+ assertNull(navBar.mAboveInsetsState.peekSource(ITYPE_STATUS_BAR));
+
+ verify(app, atLeastOnce()).notifyInsetsChanged();
+ }
+
+ @Test
+ public void testUpdateAboveInsetsState_receiveInsets() {
+ final WindowState app = createTestWindow("app");
+ final WindowState statusBar = createTestWindow("statusBar");
+ final WindowState navBar = createTestWindow("navBar");
+
+ getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null, null);
+ getController().getSourceProvider(ITYPE_NAVIGATION_BAR).setWindow(navBar, null, null);
+
+ assertNull(app.mAboveInsetsState.peekSource(ITYPE_STATUS_BAR));
+ assertNull(app.mAboveInsetsState.peekSource(ITYPE_NAVIGATION_BAR));
+
+ getController().updateAboveInsetsState(app, true /* notifyInsetsChange */);
+
+ assertNotNull(app.mAboveInsetsState.peekSource(ITYPE_STATUS_BAR));
+ assertNotNull(app.mAboveInsetsState.peekSource(ITYPE_NAVIGATION_BAR));
+
+ verify(app, atLeastOnce()).notifyInsetsChanged();
+ }
+
+ @Test
+ public void testUpdateAboveInsetsState_zOrderChanged() {
+ final WindowState ime = createTestWindow("ime");
+ final WindowState app = createTestWindow("app");
+ final WindowState statusBar = createTestWindow("statusBar");
+ final WindowState navBar = createTestWindow("navBar");
+
+ getController().getSourceProvider(ITYPE_IME).setWindow(ime, null, null);
+ getController().getSourceProvider(ITYPE_IME).setClientVisible(true);
+ getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null, null);
+ getController().getSourceProvider(ITYPE_NAVIGATION_BAR).setWindow(navBar, null, null);
+ getController().updateAboveInsetsState(ime, false /* notifyInsetsChange */);
+ getController().updateAboveInsetsState(statusBar, false /* notifyInsetsChange */);
+ getController().updateAboveInsetsState(navBar, false /* notifyInsetsChange */);
+
+ // ime is below others.
+ assertNull(app.mAboveInsetsState.peekSource(ITYPE_IME));
+ assertNull(statusBar.mAboveInsetsState.peekSource(ITYPE_IME));
+ assertNull(navBar.mAboveInsetsState.peekSource(ITYPE_IME));
+ assertNotNull(ime.mAboveInsetsState.peekSource(ITYPE_STATUS_BAR));
+ assertNotNull(ime.mAboveInsetsState.peekSource(ITYPE_NAVIGATION_BAR));
+
+ ime.getParent().positionChildAt(POSITION_TOP, ime, true /* includingParents */);
+ getController().updateAboveInsetsState(ime, true /* notifyInsetsChange */);
+
+ // ime is above others.
+ assertNotNull(app.mAboveInsetsState.peekSource(ITYPE_IME));
+ assertNotNull(statusBar.mAboveInsetsState.peekSource(ITYPE_IME));
+ assertNotNull(navBar.mAboveInsetsState.peekSource(ITYPE_IME));
+ assertNull(ime.mAboveInsetsState.peekSource(ITYPE_STATUS_BAR));
+ assertNull(ime.mAboveInsetsState.peekSource(ITYPE_NAVIGATION_BAR));
+
+ verify(ime, atLeastOnce()).notifyInsetsChanged();
+ verify(app, atLeastOnce()).notifyInsetsChanged();
+ verify(statusBar, atLeastOnce()).notifyInsetsChanged();
+ verify(navBar, atLeastOnce()).notifyInsetsChanged();
+ }
+
+ private WindowState createTestWindow(String name) {
+ final WindowState win = createWindow(null, TYPE_APPLICATION, name);
+ win.setHasSurface(true);
+ spyOn(win);
+ return win;
+ }
+
private InsetsStateController getController() {
return mDisplayContent.getInsetsStateController();
}
diff --git a/tests/ApkVerityTest/src/com/android/apkverity/ApkVerityTest.java b/tests/ApkVerityTest/src/com/android/apkverity/ApkVerityTest.java
index ab3572ba2173..d96005b8a71a 100644
--- a/tests/ApkVerityTest/src/com/android/apkverity/ApkVerityTest.java
+++ b/tests/ApkVerityTest/src/com/android/apkverity/ApkVerityTest.java
@@ -95,10 +95,13 @@ public class ApkVerityTest extends BaseHostJUnit4Test {
new AddFsVerityCertRule(this, CERT_PATH);
private ITestDevice mDevice;
+ private boolean mDmRequireFsVerity;
@Before
public void setUp() throws DeviceNotAvailableException {
mDevice = getDevice();
+ mDmRequireFsVerity = "true".equals(
+ mDevice.getProperty("pm.dexopt.dm.require_fsverity"));
uninstallPackage(TARGET_PACKAGE);
}
@@ -124,7 +127,7 @@ public class ApkVerityTest extends BaseHostJUnit4Test {
verifyInstalledFiles(
INSTALLED_BASE_APK,
INSTALLED_BASE_APK_FSV_SIG);
- verifyInstalledFilesHaveFsverity();
+ verifyInstalledFilesHaveFsverity(INSTALLED_BASE_APK);
}
@Test
@@ -151,7 +154,9 @@ public class ApkVerityTest extends BaseHostJUnit4Test {
INSTALLED_BASE_APK_FSV_SIG,
INSTALLED_SPLIT_APK,
INSTALLED_SPLIT_APK_FSV_SIG);
- verifyInstalledFilesHaveFsverity();
+ verifyInstalledFilesHaveFsverity(
+ INSTALLED_BASE_APK,
+ INSTALLED_SPLIT_APK);
}
@Test
@@ -167,7 +172,9 @@ public class ApkVerityTest extends BaseHostJUnit4Test {
INSTALLED_BASE_APK_FSV_SIG,
INSTALLED_BASE_DM,
INSTALLED_BASE_DM_FSV_SIG);
- verifyInstalledFilesHaveFsverity();
+ verifyInstalledFilesHaveFsverity(
+ INSTALLED_BASE_APK,
+ INSTALLED_BASE_DM);
}
@Test
@@ -189,7 +196,11 @@ public class ApkVerityTest extends BaseHostJUnit4Test {
INSTALLED_SPLIT_APK_FSV_SIG,
INSTALLED_SPLIT_DM,
INSTALLED_SPLIT_DM_FSV_SIG);
- verifyInstalledFilesHaveFsverity();
+ verifyInstalledFilesHaveFsverity(
+ INSTALLED_BASE_APK,
+ INSTALLED_BASE_DM,
+ INSTALLED_SPLIT_APK,
+ INSTALLED_SPLIT_DM);
}
@Test
@@ -213,7 +224,9 @@ public class ApkVerityTest extends BaseHostJUnit4Test {
INSTALLED_BASE_APK_FSV_SIG,
INSTALLED_SPLIT_APK,
INSTALLED_SPLIT_APK_FSV_SIG);
- verifyInstalledFilesHaveFsverity();
+ verifyInstalledFilesHaveFsverity(
+ INSTALLED_BASE_APK,
+ INSTALLED_SPLIT_APK);
}
@Test
@@ -250,39 +263,92 @@ public class ApkVerityTest extends BaseHostJUnit4Test {
INSTALLED_BASE_APK,
INSTALLED_SPLIT_APK,
INSTALLED_SPLIT_APK_FSV_SIG);
-
}
@Test
- public void testInstallOnlyBaseHasFsvSig()
+ public void testInstallOnlyDmHasFsvSig()
throws DeviceNotAvailableException, FileNotFoundException {
new InstallMultiple()
- .addFileAndSignature(BASE_APK)
+ .addFile(BASE_APK)
+ .addFileAndSignature(BASE_APK_DM)
+ .addFile(SPLIT_APK)
+ .addFileAndSignature(SPLIT_APK_DM)
+ .run();
+ verifyInstalledFiles(
+ INSTALLED_BASE_APK,
+ INSTALLED_BASE_DM,
+ INSTALLED_BASE_DM_FSV_SIG,
+ INSTALLED_SPLIT_APK,
+ INSTALLED_SPLIT_DM,
+ INSTALLED_SPLIT_DM_FSV_SIG);
+ verifyInstalledFilesHaveFsverity(
+ INSTALLED_BASE_DM,
+ INSTALLED_SPLIT_DM);
+ }
+
+ @Test
+ public void testInstallDmWithoutFsvSig_Base()
+ throws DeviceNotAvailableException, FileNotFoundException {
+ InstallMultiple installer = new InstallMultiple()
+ .addFile(BASE_APK)
.addFile(BASE_APK_DM)
.addFile(SPLIT_APK)
- .addFile(SPLIT_APK_DM)
- .runExpectingFailure();
+ .addFileAndSignature(SPLIT_APK_DM);
+ if (mDmRequireFsVerity) {
+ installer.runExpectingFailure();
+ } else {
+ installer.run();
+ verifyInstalledFiles(
+ INSTALLED_BASE_APK,
+ INSTALLED_BASE_DM,
+ INSTALLED_SPLIT_APK,
+ INSTALLED_SPLIT_DM,
+ INSTALLED_SPLIT_DM_FSV_SIG);
+ verifyInstalledFilesHaveFsverity(INSTALLED_SPLIT_DM);
+ }
}
@Test
- public void testInstallOnlyDmHasFsvSig()
+ public void testInstallDmWithoutFsvSig_Split()
throws DeviceNotAvailableException, FileNotFoundException {
- new InstallMultiple()
+ InstallMultiple installer = new InstallMultiple()
.addFile(BASE_APK)
.addFileAndSignature(BASE_APK_DM)
.addFile(SPLIT_APK)
- .addFile(SPLIT_APK_DM)
+ .addFile(SPLIT_APK_DM);
+ if (mDmRequireFsVerity) {
+ installer.runExpectingFailure();
+ } else {
+ installer.run();
+ verifyInstalledFiles(
+ INSTALLED_BASE_APK,
+ INSTALLED_BASE_DM,
+ INSTALLED_BASE_DM_FSV_SIG,
+ INSTALLED_SPLIT_APK,
+ INSTALLED_SPLIT_DM);
+ verifyInstalledFilesHaveFsverity(INSTALLED_BASE_DM);
+ }
+ }
+
+ @Test
+ public void testInstallSomeApkIsMissingFsvSig_Base()
+ throws DeviceNotAvailableException, FileNotFoundException {
+ new InstallMultiple()
+ .addFileAndSignature(BASE_APK)
+ .addFileAndSignature(BASE_APK_DM)
+ .addFile(SPLIT_APK)
+ .addFileAndSignature(SPLIT_APK_DM)
.runExpectingFailure();
}
@Test
- public void testInstallOnlySplitHasFsvSig()
+ public void testInstallSomeApkIsMissingFsvSig_Split()
throws DeviceNotAvailableException, FileNotFoundException {
new InstallMultiple()
.addFile(BASE_APK)
- .addFile(BASE_APK_DM)
+ .addFileAndSignature(BASE_APK_DM)
.addFileAndSignature(SPLIT_APK)
- .addFile(SPLIT_APK_DM)
+ .addFileAndSignature(SPLIT_APK_DM)
.runExpectingFailure();
}
@@ -383,37 +449,36 @@ public class ApkVerityTest extends BaseHostJUnit4Test {
}
}
- private void verifyInstalledFilesHaveFsverity() throws DeviceNotAvailableException {
+ private void verifyInstalledFilesHaveFsverity(String... filenames)
+ throws DeviceNotAvailableException {
// Verify that all files are protected by fs-verity
String apkPath = getApkPath(TARGET_PACKAGE);
String appDir = apkPath.substring(0, apkPath.lastIndexOf("/"));
long kTargetOffset = 0;
- for (String basename : expectRemoteCommandToSucceed("ls " + appDir).split("\n")) {
- if (basename.endsWith(".apk") || basename.endsWith(".dm")) {
- String path = appDir + "/" + basename;
- damageFileAgainstBlockDevice(path, kTargetOffset);
-
- // Retry is sometimes needed to pass the test. Package manager may have FD leaks
- // (see b/122744005 as example) that prevents the file in question to be evicted
- // from filesystem cache. Forcing GC workarounds the problem.
- int retry = 5;
- for (; retry > 0; retry--) {
- BlockDeviceWriter.dropCaches(mDevice);
- if (!BlockDeviceWriter.canReadByte(mDevice, path, kTargetOffset)) {
- break;
- }
- try {
- CLog.d("lsof: " + expectRemoteCommandToSucceed("lsof " + apkPath));
- Thread.sleep(1000);
- String pid = expectRemoteCommandToSucceed("pidof system_server");
- mDevice.executeShellV2Command("kill -10 " + pid); // force GC
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- return;
- }
+ for (String basename : filenames) {
+ String path = appDir + "/" + basename;
+ damageFileAgainstBlockDevice(path, kTargetOffset);
+
+ // Retry is sometimes needed to pass the test. Package manager may have FD leaks
+ // (see b/122744005 as example) that prevents the file in question to be evicted
+ // from filesystem cache. Forcing GC workarounds the problem.
+ int retry = 5;
+ for (; retry > 0; retry--) {
+ BlockDeviceWriter.dropCaches(mDevice);
+ if (!BlockDeviceWriter.canReadByte(mDevice, path, kTargetOffset)) {
+ break;
+ }
+ try {
+ CLog.d("lsof: " + expectRemoteCommandToSucceed("lsof " + apkPath));
+ Thread.sleep(1000);
+ String pid = expectRemoteCommandToSucceed("pidof system_server");
+ mDevice.executeShellV2Command("kill -10 " + pid); // force GC
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ return;
}
- assertTrue("Read from " + path + " should fail", retry > 0);
}
+ assertTrue("Read from " + path + " should fail", retry > 0);
}
}