summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apex/jobscheduler/framework/java/android/app/job/JobInfo.java2
-rw-r--r--apex/jobscheduler/framework/java/com/android/server/job/JobSchedulerInternal.java5
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java12
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/ContentObserverController.java2
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java37
-rw-r--r--apex/statsd/Android.bp3
-rw-r--r--api/current.txt9
-rwxr-xr-xapi/system-current.txt37
-rw-r--r--api/system-lint-baseline.txt2
-rw-r--r--cmds/statsd/Android.bp3
-rw-r--r--cmds/statsd/src/atoms.proto2
-rw-r--r--cmds/statsd/src/storage/StorageManager.cpp4
-rw-r--r--core/java/android/accessibilityservice/AccessibilityGestureEvent.java12
-rw-r--r--core/java/android/accessibilityservice/AccessibilityService.java58
-rw-r--r--core/java/android/app/AppOpsManager.java4
-rw-r--r--core/java/android/app/INotificationManager.aidl1
-rw-r--r--core/java/android/app/SystemServiceRegistry.java10
-rw-r--r--core/java/android/app/usage/UsageEvents.java44
-rw-r--r--core/java/android/content/Context.java13
-rw-r--r--core/java/android/content/pm/ApplicationInfo.java17
-rw-r--r--core/java/android/content/pm/PackageManager.java24
-rw-r--r--core/java/android/content/pm/PackageParser.java5
-rw-r--r--core/java/android/content/pm/parsing/ApkParseUtils.java3
-rw-r--r--core/java/android/content/pm/parsing/PackageImpl.java10
-rw-r--r--core/java/android/content/pm/parsing/ParsingPackage.java2
-rw-r--r--core/java/android/hardware/biometrics/BiometricPrompt.java36
-rw-r--r--core/java/android/hardware/location/ContextHubManager.java2
-rw-r--r--core/java/android/inputmethodservice/OWNERS3
-rw-r--r--core/java/android/os/incremental/V4Signature.java10
-rw-r--r--core/java/android/util/FeatureFlagUtils.java1
-rw-r--r--core/java/android/view/RenderNodeAnimator.java10
-rw-r--r--core/java/android/view/SurfaceControlViewHost.java26
-rw-r--r--core/java/android/view/SurfaceView.java143
-rw-r--r--core/java/android/view/ViewRootImpl.java11
-rw-r--r--core/java/android/view/WindowManagerImpl.java25
-rw-r--r--core/java/android/view/inputmethod/OWNERS3
-rw-r--r--core/java/android/webkit/UserPackage.java2
-rw-r--r--core/java/android/webkit/WebViewFactory.java2
-rw-r--r--core/java/android/widget/Editor.java2
-rw-r--r--core/java/com/android/internal/inputmethod/OWNERS3
-rw-r--r--core/java/com/android/internal/os/RuntimeInit.java29
-rw-r--r--core/java/com/android/internal/os/Zygote.java19
-rw-r--r--core/java/com/android/internal/os/ZygoteInit.java4
-rw-r--r--core/jni/AndroidRuntime.cpp10
-rw-r--r--core/jni/com_android_internal_os_Zygote.cpp12
-rw-r--r--core/res/res/values/attrs_manifest.xml9
-rw-r--r--core/res/res/values/public.xml1
-rw-r--r--core/tests/coretests/AndroidManifest.xml3
-rw-r--r--core/tests/coretests/src/android/view/WindowMetricsTest.java81
-rw-r--r--data/etc/privapp-permissions-platform.xml2
-rw-r--r--graphics/java/android/graphics/ColorSpace.java3
-rw-r--r--graphics/java/android/graphics/ParcelableColorSpace.java183
-rw-r--r--libs/hwui/Readback.cpp47
-rw-r--r--libs/hwui/Readback.h2
-rw-r--r--libs/hwui/renderthread/RenderProxy.cpp3
-rw-r--r--libs/hwui/renderthread/RenderProxy.h4
-rw-r--r--media/java/android/media/MediaScannerConnection.java25
-rw-r--r--media/java/android/media/tv/tuner/Tuner.java2
-rw-r--r--media/java/android/media/tv/tuner/filter/Filter.java17
-rw-r--r--media/java/android/media/tv/tuner/filter/IpFilterConfiguration.java6
-rw-r--r--media/jni/android_media_tv_Tuner.cpp383
-rw-r--r--media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java (renamed from media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java)4
-rw-r--r--media/tests/TunerTest/Android.bp18
-rw-r--r--media/tests/TunerTest/AndroidManifest.xml29
-rw-r--r--media/tests/TunerTest/AndroidTest.xml17
-rw-r--r--media/tests/TunerTest/res/values/strings.xml5
-rw-r--r--media/tests/TunerTest/src/com/android/mediatunertest/TunerTest.java61
-rw-r--r--packages/SettingsLib/Android.bp1
-rw-r--r--packages/SettingsLib/SchedulesProvider/Android.bp12
-rw-r--r--packages/SettingsLib/SchedulesProvider/AndroidManifest.xml23
-rw-r--r--packages/SettingsLib/SchedulesProvider/src/com/android/settingslib/schedulesprovider/ScheduleInfo.java167
-rw-r--r--packages/SettingsLib/SchedulesProvider/src/com/android/settingslib/schedulesprovider/SchedulesProvider.java133
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java12
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java59
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java42
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java58
-rw-r--r--packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowBluetoothAdapter.java11
-rw-r--r--packages/SettingsProvider/res/values/strings.xml9
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/WifiSoftApConfigChangedNotifier.java2
-rw-r--r--packages/Shell/AndroidManifest.xml3
-rw-r--r--packages/SystemUI/src/com/android/systemui/SysUIToast.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java45
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifBindPipeline.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifBindPipelineLogger.kt61
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindParams.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStage.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStageLogger.kt37
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifBindPipelineTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/RowContentBindStageTest.java6
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java10
-rw-r--r--services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java12
-rw-r--r--services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerMultiTap.java26
-rw-r--r--services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerMultiTapAndHold.java71
-rw-r--r--services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java126
-rw-r--r--services/appprediction/java/com/android/server/appprediction/RemoteAppPredictionService.java74
-rw-r--r--services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java5
-rw-r--r--services/core/java/android/app/usage/UsageStatsManagerInternal.java12
-rw-r--r--services/core/java/com/android/server/am/ProcessList.java19
-rw-r--r--services/core/java/com/android/server/biometrics/AuthService.java7
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiControlService.java117
-rw-r--r--services/core/java/com/android/server/inputmethod/OWNERS6
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java31
-rw-r--r--services/core/java/com/android/server/notification/NotificationRecord.java4
-rw-r--r--services/core/java/com/android/server/notification/NotificationRecordLogger.java34
-rw-r--r--services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java23
-rw-r--r--services/core/java/com/android/server/notification/SnoozeHelper.java398
-rw-r--r--services/core/java/com/android/server/pm/AppsFilter.java2
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerShellCommand.java58
-rw-r--r--services/core/java/com/android/server/pm/Settings.java1
-rw-r--r--services/core/java/com/android/server/policy/WindowManagerPolicy.java4
-rw-r--r--services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java63
-rw-r--r--services/core/java/com/android/server/wm/DisplayArea.java5
-rw-r--r--services/core/java/com/android/server/wm/DisplayAreaPolicy.java75
-rw-r--r--services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java371
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java4
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java8
-rw-r--r--services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp434
-rw-r--r--services/java/com/android/server/SystemServer.java2
-rw-r--r--services/people/java/com/android/server/people/data/UsageStatsQueryHelper.java2
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java93
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceStaticTest.java67
-rw-r--r--services/tests/servicestests/src/com/android/server/people/data/UsageStatsQueryHelperTest.java4
-rwxr-xr-xservices/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java104
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordLoggerFake.java31
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java37
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java214
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayAreaProviderTest.java4
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java14
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsService.java54
-rw-r--r--services/usage/java/com/android/server/usage/UserUsageStatsService.java24
-rw-r--r--startop/iorap/functional_tests/AndroidTest.xml9
-rw-r--r--startop/iorap/functional_tests/src/com/google/android/startop/iorap/IorapWorkFlowTest.java8
-rwxr-xr-xtelephony/java/android/telephony/CarrierConfigManager.java4
-rw-r--r--telephony/java/android/telephony/CellSignalStrengthLte.java4
-rw-r--r--telephony/java/com/android/internal/telephony/RILConstants.java1
-rw-r--r--tests/ApkVerityTest/src/com/android/apkverity/ApkVerityTest.java5
-rw-r--r--tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java2
-rw-r--r--tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java1
-rw-r--r--wifi/java/android/net/wifi/hotspot2/pps/Credential.java11
-rw-r--r--wifi/java/android/net/wifi/wificond/WifiNl80211Manager.java (renamed from wifi/java/android/net/wifi/wificond/WifiCondManager.java)19
-rw-r--r--wifi/tests/src/android/net/wifi/wificond/WifiNl80211ManagerTest.java (renamed from wifi/tests/src/android/net/wifi/wificond/WifiCondManagerTest.java)62
146 files changed, 4105 insertions, 999 deletions
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
index 088cadba89ab..8a9c774117d3 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
@@ -896,7 +896,7 @@ public class JobInfo implements Parcelable {
* @param flags Flags for the observer.
*/
public TriggerContentUri(@NonNull Uri uri, @Flags int flags) {
- mUri = uri;
+ mUri = Objects.requireNonNull(uri);
mFlags = flags;
}
diff --git a/apex/jobscheduler/framework/java/com/android/server/job/JobSchedulerInternal.java b/apex/jobscheduler/framework/java/com/android/server/job/JobSchedulerInternal.java
index 1072406d26cc..7833a037463c 100644
--- a/apex/jobscheduler/framework/java/com/android/server/job/JobSchedulerInternal.java
+++ b/apex/jobscheduler/framework/java/com/android/server/job/JobSchedulerInternal.java
@@ -16,6 +16,7 @@
package com.android.server.job;
+import android.annotation.NonNull;
import android.app.job.JobInfo;
import android.util.proto.ProtoOutputStream;
@@ -44,6 +45,10 @@ public interface JobSchedulerInternal {
void removeBackingUpUid(int uid);
void clearAllBackingUpUids();
+ /** Returns the package responsible for backing up media on the device. */
+ @NonNull
+ String getMediaBackupPackage();
+
/**
* The user has started interacting with the app. Take any appropriate action.
*/
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 e4c6b52f94bb..ff7944d07310 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -77,6 +77,7 @@ import android.util.SparseIntArray;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
+import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IBatteryStats;
import com.android.internal.util.ArrayUtils;
@@ -248,6 +249,9 @@ public class JobSchedulerService extends com.android.server.SystemService
*/
private final List<JobRestriction> mJobRestrictions;
+ @NonNull
+ private final String mSystemGalleryPackage;
+
private final CountQuotaTracker mQuotaTracker;
private static final String QUOTA_TRACKER_SCHEDULE_PERSISTED_TAG = ".schedulePersisted()";
@@ -1394,6 +1398,9 @@ public class JobSchedulerService extends com.android.server.SystemService
mJobRestrictions = new ArrayList<>();
mJobRestrictions.add(new ThermalStatusRestriction(this));
+ mSystemGalleryPackage = Objects.requireNonNull(
+ context.getString(R.string.config_systemGallery));
+
// If the job store determined that it can't yet reschedule persisted jobs,
// we need to start watching the clock.
if (!mJobs.jobTimesInflatedValid()) {
@@ -2359,6 +2366,11 @@ public class JobSchedulerService extends com.android.server.SystemService
}
@Override
+ public String getMediaBackupPackage() {
+ return mSystemGalleryPackage;
+ }
+
+ @Override
public void reportAppUsage(String packageName, int userId) {
JobSchedulerService.this.reportAppUsage(packageName, userId);
}
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 a775cf5a671c..5fcd774189ac 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
@@ -344,7 +344,7 @@ public final class ContentObserverController extends StateController {
mContext.getContentResolver().unregisterContentObserver(obs);
ArrayMap<JobInfo.TriggerContentUri, ObserverInstance> observerOfUser =
mObservers.get(obs.mUserId);
- if (observerOfUser != null) {
+ if (observerOfUser != null) {
observerOfUser.remove(obs.mUri);
}
}
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 1e89158ca4bb..cf7f3804b34d 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
@@ -19,6 +19,7 @@ package com.android.server.job.controllers;
import static com.android.server.job.JobSchedulerService.ACTIVE_INDEX;
import static com.android.server.job.JobSchedulerService.NEVER_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 android.app.AppGlobals;
@@ -30,6 +31,7 @@ import android.net.Network;
import android.net.Uri;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.provider.MediaStore;
import android.text.format.DateFormat;
import android.util.ArraySet;
import android.util.Pair;
@@ -207,6 +209,18 @@ public final class JobStatus {
*/
private int mDynamicConstraints = 0;
+ /**
+ * Indicates whether the job is responsible for backing up media, so we can be lenient in
+ * applying standby throttling.
+ *
+ * Doesn't exempt jobs with a deadline constraint, as they can be started without any content or
+ * network changes, in which case this exemption does not make sense.
+ *
+ * TODO(b/149519887): Use a more explicit signal, maybe an API flag, that the scheduling package
+ * needs to provide at the time of scheduling a job.
+ */
+ private final boolean mHasMediaBackupExemption;
+
// Set to true if doze constraint was satisfied due to app being whitelisted.
public boolean dozeWhitelisted;
@@ -415,9 +429,11 @@ public final class JobStatus {
this.mOriginalLatestRunTimeElapsedMillis = latestRunTimeElapsedMillis;
this.numFailures = numFailures;
+ boolean requiresNetwork = false;
int requiredConstraints = job.getConstraintFlags();
if (job.getRequiredNetwork() != null) {
requiredConstraints |= CONSTRAINT_CONNECTIVITY;
+ requiresNetwork = true;
}
if (earliestRunTimeElapsedMillis != NO_EARLIEST_RUNTIME) {
requiredConstraints |= CONSTRAINT_TIMING_DELAY;
@@ -425,8 +441,16 @@ public final class JobStatus {
if (latestRunTimeElapsedMillis != NO_LATEST_RUNTIME) {
requiredConstraints |= CONSTRAINT_DEADLINE;
}
+ boolean mediaOnly = false;
if (job.getTriggerContentUris() != null) {
requiredConstraints |= CONSTRAINT_CONTENT_TRIGGER;
+ mediaOnly = true;
+ for (JobInfo.TriggerContentUri uri : job.getTriggerContentUris()) {
+ if (!MediaStore.AUTHORITY.equals(uri.getUri().getAuthority())) {
+ mediaOnly = false;
+ break;
+ }
+ }
}
this.requiredConstraints = requiredConstraints;
mRequiredConstraintsOfInterest = requiredConstraints & CONSTRAINTS_OF_INTEREST;
@@ -450,6 +474,9 @@ public final class JobStatus {
// our source UID into place.
job.getRequiredNetwork().networkCapabilities.setSingleUid(this.sourceUid);
}
+ final JobSchedulerInternal jsi = LocalServices.getService(JobSchedulerInternal.class);
+ mHasMediaBackupExemption = !job.hasLateConstraint() && mediaOnly && requiresNetwork
+ && this.sourcePackageName.equals(jsi.getMediaBackupPackage());
}
/** Copy constructor: used specifically when cloning JobStatus objects for persistence,
@@ -545,7 +572,6 @@ public final class JobStatus {
int standbyBucket = JobSchedulerService.standbyBucketForPackage(jobPackage,
sourceUserId, elapsedNow);
- JobSchedulerInternal js = LocalServices.getService(JobSchedulerInternal.class);
return new JobStatus(job, callingUid, sourcePkg, sourceUserId,
standbyBucket, tag, 0,
earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis,
@@ -734,7 +760,14 @@ public final class JobStatus {
// like other ACTIVE apps.
return ACTIVE_INDEX;
}
- return getStandbyBucket();
+ final int actualBucket = getStandbyBucket();
+ if (actualBucket != RESTRICTED_INDEX && actualBucket != NEVER_INDEX
+ && mHasMediaBackupExemption) {
+ // Cap it at WORKING_INDEX as media back up jobs are important to the user, and the
+ // source package may not have been used directly in a while.
+ return Math.min(WORKING_INDEX, actualBucket);
+ }
+ return actualBucket;
}
/** Returns the real standby bucket of the job. */
diff --git a/apex/statsd/Android.bp b/apex/statsd/Android.bp
index c0f84a0ba070..baa1c251324f 100644
--- a/apex/statsd/Android.bp
+++ b/apex/statsd/Android.bp
@@ -20,6 +20,7 @@ apex {
apex_defaults {
native_shared_libs: [
+ "libstatssocket",
"libstatspull",
"libstats_jni",
],
@@ -76,4 +77,4 @@ cc_library_shared {
//TODO (b/148620413): remove platform.
"//apex_available:platform",
],
-} \ No newline at end of file
+}
diff --git a/api/current.txt b/api/current.txt
index 4887c66660bb..8394416d04d4 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -289,6 +289,7 @@ package android {
field public static final int allowBackup = 16843392; // 0x1010280
field public static final int allowClearUserData = 16842757; // 0x1010005
field public static final int allowEmbedded = 16843765; // 0x10103f5
+ field public static final int allowNativeHeapPointerTagging = 16844311; // 0x1010617
field public static final int allowParallelSyncs = 16843570; // 0x1010332
field public static final int allowSingleTap = 16843353; // 0x1010259
field public static final int allowTaskReparenting = 16843268; // 0x1010204
@@ -2876,6 +2877,7 @@ package android.accessibilityservice {
method public final void setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo);
method public boolean takeScreenshot(int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.accessibilityservice.AccessibilityService.ScreenshotResult>);
field public static final int GESTURE_2_FINGER_DOUBLE_TAP = 20; // 0x14
+ field public static final int GESTURE_2_FINGER_DOUBLE_TAP_AND_HOLD = 40; // 0x28
field public static final int GESTURE_2_FINGER_SINGLE_TAP = 19; // 0x13
field public static final int GESTURE_2_FINGER_SWIPE_DOWN = 26; // 0x1a
field public static final int GESTURE_2_FINGER_SWIPE_LEFT = 27; // 0x1b
@@ -2883,6 +2885,7 @@ package android.accessibilityservice {
field public static final int GESTURE_2_FINGER_SWIPE_UP = 25; // 0x19
field public static final int GESTURE_2_FINGER_TRIPLE_TAP = 21; // 0x15
field public static final int GESTURE_3_FINGER_DOUBLE_TAP = 23; // 0x17
+ field public static final int GESTURE_3_FINGER_DOUBLE_TAP_AND_HOLD = 41; // 0x29
field public static final int GESTURE_3_FINGER_SINGLE_TAP = 22; // 0x16
field public static final int GESTURE_3_FINGER_SWIPE_DOWN = 30; // 0x1e
field public static final int GESTURE_3_FINGER_SWIPE_LEFT = 31; // 0x1f
@@ -2890,6 +2893,7 @@ package android.accessibilityservice {
field public static final int GESTURE_3_FINGER_SWIPE_UP = 29; // 0x1d
field public static final int GESTURE_3_FINGER_TRIPLE_TAP = 24; // 0x18
field public static final int GESTURE_4_FINGER_DOUBLE_TAP = 38; // 0x26
+ field public static final int GESTURE_4_FINGER_DOUBLE_TAP_AND_HOLD = 42; // 0x2a
field public static final int GESTURE_4_FINGER_SINGLE_TAP = 37; // 0x25
field public static final int GESTURE_4_FINGER_SWIPE_DOWN = 34; // 0x22
field public static final int GESTURE_4_FINGER_SWIPE_LEFT = 35; // 0x23
@@ -2954,7 +2958,7 @@ package android.accessibilityservice {
}
public static final class AccessibilityService.ScreenshotResult {
- method @Nullable public android.graphics.ColorSpace getColorSpace();
+ method @NonNull public android.graphics.ColorSpace getColorSpace();
method @NonNull public android.hardware.HardwareBuffer getHardwareBuffer();
method public long getTimestamp();
}
@@ -10141,7 +10145,6 @@ package android.content {
field public static final String ALARM_SERVICE = "alarm";
field public static final String APPWIDGET_SERVICE = "appwidget";
field public static final String APP_OPS_SERVICE = "appops";
- field public static final String APP_SEARCH_SERVICE = "app_search";
field public static final String AUDIO_SERVICE = "audio";
field public static final String BATTERY_SERVICE = "batterymanager";
field public static final int BIND_ABOVE_CLIENT = 8; // 0x8
@@ -12068,7 +12071,7 @@ package android.content.pm {
field public static final String FEATURE_COMPANION_DEVICE_SETUP = "android.software.companion_device_setup";
field public static final String FEATURE_CONNECTION_SERVICE = "android.software.connectionservice";
field public static final String FEATURE_CONSUMER_IR = "android.hardware.consumerir";
- field public static final String FEATURE_CONTEXTHUB = "android.hardware.context_hub";
+ field public static final String FEATURE_CONTEXT_HUB = "android.hardware.context_hub";
field public static final String FEATURE_DEVICE_ADMIN = "android.software.device_admin";
field public static final String FEATURE_EMBEDDED = "android.hardware.type.embedded";
field public static final String FEATURE_ETHERNET = "android.hardware.ethernet";
diff --git a/api/system-current.txt b/api/system-current.txt
index 0fd8a20600b0..8725538f1fd8 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1809,7 +1809,7 @@ package android.content {
field public static final String TELEPHONY_REGISTRY_SERVICE = "telephony_registry";
field public static final String TETHERING_SERVICE = "tethering";
field public static final String VR_SERVICE = "vrmanager";
- field public static final String WIFI_COND_SERVICE = "wificond";
+ field public static final String WIFI_NL80211_SERVICE = "wifinl80211";
field @Deprecated public static final String WIFI_RTT_SERVICE = "rttmanager";
field public static final String WIFI_SCANNING_SERVICE = "wifiscanner";
}
@@ -2217,6 +2217,7 @@ package android.content.pm {
field public static final String FEATURE_TELEPHONY_CARRIERLOCK = "android.hardware.telephony.carrierlock";
field public static final int FLAGS_PERMISSION_RESERVED_PERMISSIONCONTROLLER = -268435456; // 0xf0000000
field public static final int FLAG_PERMISSION_APPLY_RESTRICTION = 16384; // 0x4000
+ field public static final int FLAG_PERMISSION_AUTO_REVOKED = 1048576; // 0x100000
field public static final int FLAG_PERMISSION_AUTO_REVOKE_IF_UNUSED = 131072; // 0x20000
field public static final int FLAG_PERMISSION_AUTO_REVOKE_USER_SET = 262144; // 0x40000
field public static final int FLAG_PERMISSION_GRANTED_BY_DEFAULT = 32; // 0x20
@@ -2302,7 +2303,7 @@ package android.content.pm {
method public void onPermissionsChanged(int);
}
- @IntDef(prefix={"FLAG_PERMISSION_"}, value={android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET, android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED, android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED, android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE, android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED, android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT, android.content.pm.PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED, android.content.pm.PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED, android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT, android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT, android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT, android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION, android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_ROLE, android.content.pm.PackageManager.FLAG_PERMISSION_REVOKED_COMPAT, android.content.pm.PackageManager.FLAG_PERMISSION_ONE_TIME, android.content.pm.PackageManager.FLAG_PERMISSION_AUTO_REVOKE_IF_UNUSED, android.content.pm.PackageManager.FLAG_PERMISSION_AUTO_REVOKE_USER_SET}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface PackageManager.PermissionFlags {
+ @IntDef(prefix={"FLAG_PERMISSION_"}, value={android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET, android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED, android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED, android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE, android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED, android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT, android.content.pm.PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED, android.content.pm.PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED, android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT, android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT, android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT, android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION, android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_ROLE, android.content.pm.PackageManager.FLAG_PERMISSION_REVOKED_COMPAT, android.content.pm.PackageManager.FLAG_PERMISSION_ONE_TIME, android.content.pm.PackageManager.FLAG_PERMISSION_AUTO_REVOKE_IF_UNUSED, android.content.pm.PackageManager.FLAG_PERMISSION_AUTO_REVOKE_USER_SET, android.content.pm.PackageManager.FLAG_PERMISSION_AUTO_REVOKED}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface PackageManager.PermissionFlags {
}
public class PermissionGroupInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
@@ -8329,21 +8330,21 @@ package android.net.wifi.wificond {
field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.wificond.RadioChainInfo> CREATOR;
}
- public class WifiCondManager {
+ public class WifiNl80211Manager {
method public void abortScan(@NonNull String);
method public void enableVerboseLogging(boolean);
method @NonNull public int[] getChannelsMhzForBand(int);
method @Nullable public android.net.wifi.wificond.DeviceWiphyCapabilities getDeviceWiphyCapabilities(@NonNull String);
method @NonNull public java.util.List<android.net.wifi.wificond.NativeScanResult> getScanResults(@NonNull String, int);
- method @Nullable public android.net.wifi.wificond.WifiCondManager.TxPacketCounters getTxPacketCounters(@NonNull String);
- method @Nullable public static android.net.wifi.wificond.WifiCondManager.OemSecurityType parseOemSecurityTypeElement(int, int, @NonNull byte[]);
- method public boolean registerApCallback(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.wificond.WifiCondManager.SoftApCallback);
- method public void sendMgmtFrame(@NonNull String, @NonNull byte[], int, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.wificond.WifiCondManager.SendMgmtFrameCallback);
+ method @Nullable public android.net.wifi.wificond.WifiNl80211Manager.TxPacketCounters getTxPacketCounters(@NonNull String);
+ method @Nullable public static android.net.wifi.wificond.WifiNl80211Manager.OemSecurityType parseOemSecurityTypeElement(int, int, @NonNull byte[]);
+ method public boolean registerApCallback(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.wificond.WifiNl80211Manager.SoftApCallback);
+ method public void sendMgmtFrame(@NonNull String, @NonNull byte[], int, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.wificond.WifiNl80211Manager.SendMgmtFrameCallback);
method public void setOnServiceDeadCallback(@NonNull Runnable);
- method public boolean setupInterfaceForClientMode(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.wificond.WifiCondManager.ScanEventCallback, @NonNull android.net.wifi.wificond.WifiCondManager.ScanEventCallback);
+ method public boolean setupInterfaceForClientMode(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.wificond.WifiNl80211Manager.ScanEventCallback, @NonNull android.net.wifi.wificond.WifiNl80211Manager.ScanEventCallback);
method public boolean setupInterfaceForSoftApMode(@NonNull String);
- method @Nullable public android.net.wifi.wificond.WifiCondManager.SignalPollResult signalPoll(@NonNull String);
- method public boolean startPnoScan(@NonNull String, @NonNull android.net.wifi.wificond.PnoSettings, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.wificond.WifiCondManager.PnoScanRequestCallback);
+ method @Nullable public android.net.wifi.wificond.WifiNl80211Manager.SignalPollResult signalPoll(@NonNull String);
+ method public boolean startPnoScan(@NonNull String, @NonNull android.net.wifi.wificond.PnoSettings, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.wificond.WifiNl80211Manager.PnoScanRequestCallback);
method public boolean startScan(@NonNull String, int, @Nullable java.util.Set<java.lang.Integer>, @Nullable java.util.List<byte[]>);
method public boolean stopPnoScan(@NonNull String);
method public boolean tearDownClientInterface(@NonNull String);
@@ -8358,43 +8359,43 @@ package android.net.wifi.wificond {
field public static final int SEND_MGMT_FRAME_ERROR_UNKNOWN = 1; // 0x1
}
- public static class WifiCondManager.OemSecurityType {
- ctor public WifiCondManager.OemSecurityType(int, @NonNull java.util.List<java.lang.Integer>, @NonNull java.util.List<java.lang.Integer>, int);
+ public static class WifiNl80211Manager.OemSecurityType {
+ ctor public WifiNl80211Manager.OemSecurityType(int, @NonNull java.util.List<java.lang.Integer>, @NonNull java.util.List<java.lang.Integer>, int);
field public final int groupCipher;
field @NonNull public final java.util.List<java.lang.Integer> keyManagement;
field @NonNull public final java.util.List<java.lang.Integer> pairwiseCipher;
field public final int protocol;
}
- public static interface WifiCondManager.PnoScanRequestCallback {
+ public static interface WifiNl80211Manager.PnoScanRequestCallback {
method public void onPnoRequestFailed();
method public void onPnoRequestSucceeded();
}
- public static interface WifiCondManager.ScanEventCallback {
+ public static interface WifiNl80211Manager.ScanEventCallback {
method public void onScanFailed();
method public void onScanResultReady();
}
- public static interface WifiCondManager.SendMgmtFrameCallback {
+ public static interface WifiNl80211Manager.SendMgmtFrameCallback {
method public void onAck(int);
method public void onFailure(int);
}
- public static class WifiCondManager.SignalPollResult {
+ public static class WifiNl80211Manager.SignalPollResult {
field public final int associationFrequencyMHz;
field public final int currentRssiDbm;
field public final int rxBitrateMbps;
field public final int txBitrateMbps;
}
- public static interface WifiCondManager.SoftApCallback {
+ public static interface WifiNl80211Manager.SoftApCallback {
method public void onConnectedClientsChanged(@NonNull android.net.wifi.wificond.NativeWifiClient, boolean);
method public void onFailure();
method public void onSoftApChannelSwitched(int, int);
}
- public static class WifiCondManager.TxPacketCounters {
+ public static class WifiNl80211Manager.TxPacketCounters {
field public final int txPacketFailed;
field public final int txPacketSucceeded;
}
diff --git a/api/system-lint-baseline.txt b/api/system-lint-baseline.txt
index 0caee6bebbda..dfb0d7460ca4 100644
--- a/api/system-lint-baseline.txt
+++ b/api/system-lint-baseline.txt
@@ -234,7 +234,7 @@ OnNameExpected: android.content.ContentProvider#checkUriPermission(android.net.U
If implemented by developer, should follow the on<Something> style; otherwise consider marking final
-PairedRegistration: android.net.wifi.wificond.WifiCondManager#registerApCallback(String, java.util.concurrent.Executor, android.net.wifi.wificond.WifiCondManager.SoftApCallback):
+PairedRegistration: android.net.wifi.wificond.WifiNl80211Manager#registerApCallback(String, java.util.concurrent.Executor, android.net.wifi.wificond.WifiNl80211Manager.SoftApCallback):
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index 956fd29205cb..1bcf44e03c09 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -120,13 +120,14 @@ cc_defaults {
"libstatslog",
"libstatsmetadata",
"libsysutils",
+ // TODO(b/145923087): move to shared when statsd is moved to the apex
+ "libstatssocket",
"libutils",
],
shared_libs: [
"libbinder",
"libincident",
"liblog",
- "libstatssocket",
"statsd-aidl-cpp",
],
}
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 03f97d80824d..23a4437910f7 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -381,7 +381,7 @@ message Atom {
UserspaceRebootReported userspace_reboot_reported = 243 [(module) = "framework"];
NotificationReported notification_reported = 244 [(module) = "framework"];
NotificationPanelReported notification_panel_reported = 245;
- NotificationChannelModified notification_panel_modified = 246;
+ NotificationChannelModified notification_channel_modified = 246;
IntegrityCheckResultReported integrity_check_result_reported = 247 [(module) = "framework"];
IntegrityRulesPushed integrity_rules_pushed = 248 [(module) = "framework"];
CellBroadcastMessageReported cb_message_reported =
diff --git a/cmds/statsd/src/storage/StorageManager.cpp b/cmds/statsd/src/storage/StorageManager.cpp
index 1bac19ed2c5d..4899b4a5247c 100644
--- a/cmds/statsd/src/storage/StorageManager.cpp
+++ b/cmds/statsd/src/storage/StorageManager.cpp
@@ -690,14 +690,16 @@ void StorageManager::trimToFit(const char* path, bool parseTimestampOnly) {
if (name[0] == '.') continue;
FileName output;
+ string file_name;
if (parseTimestampOnly) {
+ file_name = StringPrintf("%s/%s", path, name);
output.mTimestampSec = StrToInt64(strtok(name, "_"));
output.mIsHistory = false;
} else {
parseFileName(name, &output);
+ file_name = output.getFullFileName(path);
}
if (output.mTimestampSec == -1) continue;
- string file_name = output.getFullFileName(path);
// Check for timestamp and delete if it's too old.
long fileAge = nowSec - output.mTimestampSec;
diff --git a/core/java/android/accessibilityservice/AccessibilityGestureEvent.java b/core/java/android/accessibilityservice/AccessibilityGestureEvent.java
index ace13513e39d..25729abf9e05 100644
--- a/core/java/android/accessibilityservice/AccessibilityGestureEvent.java
+++ b/core/java/android/accessibilityservice/AccessibilityGestureEvent.java
@@ -18,6 +18,7 @@ package android.accessibilityservice;
import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_DOUBLE_TAP;
+import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_DOUBLE_TAP_AND_HOLD;
import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_SINGLE_TAP;
import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_SWIPE_DOWN;
import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_SWIPE_LEFT;
@@ -25,6 +26,7 @@ import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER
import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_SWIPE_UP;
import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_TRIPLE_TAP;
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_DOUBLE_TAP;
+import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_DOUBLE_TAP_AND_HOLD;
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SINGLE_TAP;
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SWIPE_DOWN;
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SWIPE_LEFT;
@@ -32,6 +34,7 @@ import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SWIPE_UP;
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_TRIPLE_TAP;
import static android.accessibilityservice.AccessibilityService.GESTURE_4_FINGER_DOUBLE_TAP;
+import static android.accessibilityservice.AccessibilityService.GESTURE_4_FINGER_DOUBLE_TAP_AND_HOLD;
import static android.accessibilityservice.AccessibilityService.GESTURE_4_FINGER_SINGLE_TAP;
import static android.accessibilityservice.AccessibilityService.GESTURE_4_FINGER_SWIPE_DOWN;
import static android.accessibilityservice.AccessibilityService.GESTURE_4_FINGER_SWIPE_LEFT;
@@ -83,9 +86,11 @@ public final class AccessibilityGestureEvent implements Parcelable {
@IntDef(prefix = { "GESTURE_" }, value = {
GESTURE_2_FINGER_SINGLE_TAP,
GESTURE_2_FINGER_DOUBLE_TAP,
+ GESTURE_2_FINGER_DOUBLE_TAP_AND_HOLD,
GESTURE_2_FINGER_TRIPLE_TAP,
GESTURE_3_FINGER_SINGLE_TAP,
GESTURE_3_FINGER_DOUBLE_TAP,
+ GESTURE_3_FINGER_DOUBLE_TAP_AND_HOLD,
GESTURE_3_FINGER_TRIPLE_TAP,
GESTURE_DOUBLE_TAP,
GESTURE_DOUBLE_TAP_AND_HOLD,
@@ -114,6 +119,7 @@ public final class AccessibilityGestureEvent implements Parcelable {
GESTURE_3_FINGER_SWIPE_RIGHT,
GESTURE_3_FINGER_SWIPE_UP,
GESTURE_4_FINGER_DOUBLE_TAP,
+ GESTURE_4_FINGER_DOUBLE_TAP_AND_HOLD,
GESTURE_4_FINGER_SINGLE_TAP,
GESTURE_4_FINGER_SWIPE_DOWN,
GESTURE_4_FINGER_SWIPE_LEFT,
@@ -175,12 +181,18 @@ public final class AccessibilityGestureEvent implements Parcelable {
switch (eventType) {
case GESTURE_2_FINGER_SINGLE_TAP: return "GESTURE_2_FINGER_SINGLE_TAP";
case GESTURE_2_FINGER_DOUBLE_TAP: return "GESTURE_2_FINGER_DOUBLE_TAP";
+ case GESTURE_2_FINGER_DOUBLE_TAP_AND_HOLD:
+ return "GESTURE_2_FINGER_DOUBLE_TAP_AND_HOLD";
case GESTURE_2_FINGER_TRIPLE_TAP: return "GESTURE_2_FINGER_TRIPLE_TAP";
case GESTURE_3_FINGER_SINGLE_TAP: return "GESTURE_3_FINGER_SINGLE_TAP";
case GESTURE_3_FINGER_DOUBLE_TAP: return "GESTURE_3_FINGER_DOUBLE_TAP";
+ case GESTURE_3_FINGER_DOUBLE_TAP_AND_HOLD:
+ return "GESTURE_3_FINGER_DOUBLE_TAP_AND_HOLD";
case GESTURE_3_FINGER_TRIPLE_TAP: return "GESTURE_3_FINGER_TRIPLE_TAP";
case GESTURE_4_FINGER_SINGLE_TAP: return "GESTURE_4_FINGER_SINGLE_TAP";
case GESTURE_4_FINGER_DOUBLE_TAP: return "GESTURE_4_FINGER_DOUBLE_TAP";
+ case GESTURE_4_FINGER_DOUBLE_TAP_AND_HOLD:
+ return "GESTURE_4_FINGER_DOUBLE_TAP_AND_HOLD";
case GESTURE_4_FINGER_TRIPLE_TAP: return "GESTURE_4_FINGER_TRIPLE_TAP";
case GESTURE_DOUBLE_TAP: return "GESTURE_DOUBLE_TAP";
case GESTURE_DOUBLE_TAP_AND_HOLD: return "GESTURE_DOUBLE_TAP_AND_HOLD";
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index b65f68e177ca..b7a35f7548c7 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -29,6 +29,7 @@ import android.content.Intent;
import android.content.pm.ParceledListSlice;
import android.graphics.Bitmap;
import android.graphics.ColorSpace;
+import android.graphics.ParcelableColorSpace;
import android.graphics.Region;
import android.hardware.HardwareBuffer;
import android.os.Binder;
@@ -39,6 +40,7 @@ import android.os.Looper;
import android.os.Message;
import android.os.RemoteCallback;
import android.os.RemoteException;
+import android.os.SystemClock;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Slog;
@@ -411,6 +413,15 @@ public abstract class AccessibilityService extends Service {
/** The user has performed a four-finger triple tap gesture on the touch screen. */
public static final int GESTURE_4_FINGER_TRIPLE_TAP = 39;
+ /** The user has performed a two-finger double tap and hold gesture on the touch screen. */
+ public static final int GESTURE_2_FINGER_DOUBLE_TAP_AND_HOLD = 40;
+
+ /** The user has performed a three-finger double tap and hold gesture on the touch screen. */
+ public static final int GESTURE_3_FINGER_DOUBLE_TAP_AND_HOLD = 41;
+
+ /** The user has performed a two-finger double tap and hold gesture on the touch screen. */
+ public static final int GESTURE_4_FINGER_DOUBLE_TAP_AND_HOLD = 42;
+
/**
* The {@link Intent} that must be declared as handled by the service.
*/
@@ -591,8 +602,12 @@ public abstract class AccessibilityService extends Service {
"screenshot_hardwareBuffer";
/** @hide */
- public static final String KEY_ACCESSIBILITY_SCREENSHOT_COLORSPACE_ID =
- "screenshot_colorSpaceId";
+ public static final String KEY_ACCESSIBILITY_SCREENSHOT_COLORSPACE =
+ "screenshot_colorSpace";
+
+ /** @hide */
+ public static final String KEY_ACCESSIBILITY_SCREENSHOT_TIMESTAMP =
+ "screenshot_timestamp";
/**
* Callback for {@link android.view.accessibility.AccessibilityEvent}s.
@@ -1911,6 +1926,8 @@ public abstract class AccessibilityService extends Service {
* default display.
* @param executor Executor on which to run the callback.
* @param callback The callback invoked when the taking screenshot is done.
+ * The {@link AccessibilityService.ScreenshotResult} will be null for an
+ * invalid display.
*
* @return {@code true} if the taking screenshot accepted, {@code false} if not.
*/
@@ -1932,14 +1949,11 @@ public abstract class AccessibilityService extends Service {
}
final HardwareBuffer hardwareBuffer =
result.getParcelable(KEY_ACCESSIBILITY_SCREENSHOT_HARDWAREBUFFER);
- final int colorSpaceId =
- result.getInt(KEY_ACCESSIBILITY_SCREENSHOT_COLORSPACE_ID);
- ColorSpace colorSpace = null;
- if (colorSpaceId >= 0 && colorSpaceId < ColorSpace.Named.values().length) {
- colorSpace = ColorSpace.get(ColorSpace.Named.values()[colorSpaceId]);
- }
+ final ParcelableColorSpace colorSpace =
+ result.getParcelable(KEY_ACCESSIBILITY_SCREENSHOT_COLORSPACE);
ScreenshotResult screenshot = new ScreenshotResult(hardwareBuffer,
- colorSpace, System.currentTimeMillis());
+ colorSpace.getColorSpace(),
+ result.getLong(KEY_ACCESSIBILITY_SCREENSHOT_TIMESTAMP));
sendScreenshotResult(executor, callback, screenshot);
}));
} catch (RemoteException re) {
@@ -2352,41 +2366,38 @@ public abstract class AccessibilityService extends Service {
}
/**
- * Class including hardwareBuffer, colorSpace, and timestamp to be the result for
+ * Can be used to construct a bitmap of the screenshot or any other operations for
* {@link AccessibilityService#takeScreenshot} API.
- * <p>
- * <strong>Note:</strong> colorSpace would be null if the name of this colorSpace isn't at
- * {@link ColorSpace.Named}.
- * </p>
*/
public static final class ScreenshotResult {
private final @NonNull HardwareBuffer mHardwareBuffer;
- private final @Nullable ColorSpace mColorSpace;
+ private final @NonNull ColorSpace mColorSpace;
private final long mTimestamp;
private ScreenshotResult(@NonNull HardwareBuffer hardwareBuffer,
- @Nullable ColorSpace colorSpace, long timestamp) {
+ @NonNull ColorSpace colorSpace, long timestamp) {
Preconditions.checkNotNull(hardwareBuffer, "hardwareBuffer cannot be null");
+ Preconditions.checkNotNull(colorSpace, "colorSpace cannot be null");
mHardwareBuffer = hardwareBuffer;
mColorSpace = colorSpace;
mTimestamp = timestamp;
}
/**
- * Gets the colorSpace identifying a specific organization of colors of the screenshot.
+ * Gets the {@link ColorSpace} identifying a specific organization of colors of the
+ * screenshot.
*
- * @return the colorSpace or {@code null} if the name of colorSpace isn't at
- * {@link ColorSpace.Named}
+ * @return the color space
*/
- @Nullable
+ @NonNull
public ColorSpace getColorSpace() {
return mColorSpace;
}
/**
- * Gets the hardwareBuffer representing a memory buffer of the screenshot.
+ * Gets the {@link HardwareBuffer} representing a memory buffer of the screenshot.
*
- * @return the hardwareBuffer
+ * @return the hardware buffer
*/
@NonNull
public HardwareBuffer getHardwareBuffer() {
@@ -2396,7 +2407,8 @@ public abstract class AccessibilityService extends Service {
/**
* Gets the timestamp of taking the screenshot.
*
- * @return the timestamp from {@link System#currentTimeMillis()}
+ * @return milliseconds of non-sleep uptime before screenshot since boot and it's from
+ * {@link SystemClock#uptimeMillis()}
*/
public long getTimestamp() {
return mTimestamp;
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 367c2f235f5f..1de68ba56c6a 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -7824,9 +7824,7 @@ public class AppOpsManager {
* @hide
*/
public static boolean isCollectingNotedAppOps() {
- synchronized (sLock) {
- return sNotedAppOpsCollector != null;
- }
+ return sNotedAppOpsCollector != null;
}
/**
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 9aa6b870792d..526c0b3f87ee 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -162,6 +162,7 @@ interface INotificationManager
void applyAdjustmentFromAssistant(in INotificationListener token, in Adjustment adjustment);
void applyAdjustmentsFromAssistant(in INotificationListener token, in List<Adjustment> adjustments);
void unsnoozeNotificationFromAssistant(in INotificationListener token, String key);
+ void unsnoozeNotificationFromSystemListener(in INotificationListener token, String key);
ComponentName getEffectsSuppressor();
boolean matchesCallFilter(in Bundle extras);
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 8b07418668ba..9b7306089dca 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -132,7 +132,7 @@ import android.net.lowpan.LowpanManager;
import android.net.nsd.INsdManager;
import android.net.nsd.NsdManager;
import android.net.wifi.WifiFrameworkInitializer;
-import android.net.wifi.wificond.WifiCondManager;
+import android.net.wifi.wificond.WifiNl80211Manager;
import android.nfc.NfcManager;
import android.os.BatteryManager;
import android.os.BatteryStats;
@@ -761,11 +761,11 @@ public final class SystemServiceRegistry {
return new EthernetManager(ctx.getOuterContext(), service);
}});
- registerService(Context.WIFI_COND_SERVICE, WifiCondManager.class,
- new CachedServiceFetcher<WifiCondManager>() {
+ registerService(Context.WIFI_NL80211_SERVICE, WifiNl80211Manager.class,
+ new CachedServiceFetcher<WifiNl80211Manager>() {
@Override
- public WifiCondManager createService(ContextImpl ctx) {
- return new WifiCondManager(ctx.getOuterContext());
+ public WifiNl80211Manager createService(ContextImpl ctx) {
+ return new WifiNl80211Manager(ctx.getOuterContext());
}
});
diff --git a/core/java/android/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java
index ab71e73fd58c..0f999ad68a62 100644
--- a/core/java/android/app/usage/UsageEvents.java
+++ b/core/java/android/app/usage/UsageEvents.java
@@ -41,6 +41,43 @@ public final class UsageEvents implements Parcelable {
/** @hide */
public static final String INSTANT_APP_CLASS_NAME = "android.instant_class";
+ /** @hide */
+ public static final String OBFUSCATED_NOTIFICATION_CHANNEL_ID = "unknown_channel_id";
+
+ /**
+ * Flag: indicates to not obfuscate or hide any usage event data when being queried.
+ * @hide
+ */
+ public static final int SHOW_ALL_EVENT_DATA = 0x00000000;
+
+ /**
+ * Flag: indicates to obfuscate package and class names for instant apps when querying usage
+ * events.
+ * @hide
+ */
+ public static final int OBFUSCATE_INSTANT_APPS = 0x00000001;
+
+ /**
+ * Flag: indicates to hide all {@link Event#SHORTCUT_INVOCATION} events when querying usage
+ * events.
+ * @hide
+ */
+ public static final int HIDE_SHORTCUT_EVENTS = 0x00000002;
+
+ /**
+ * Flag: indicates to obfuscate the notification channel id for all notification events,
+ * such as {@link Event#NOTIFICATION_SEEN} and {@link Event#NOTIFICATION_INTERRUPTION} events,
+ * when querying usage events.
+ * @hide
+ */
+ public static final int OBFUSCATE_NOTIFICATION_EVENTS = 0x00000004;
+
+ /**
+ * Flag: indicates to hide all {@link Event#LOCUS_ID_SET} events when querying usage events.
+ * @hide
+ */
+ public static final int HIDE_LOCUS_EVENTS = 0x00000008;
+
/**
* An event representing a state change for a component.
*/
@@ -627,6 +664,13 @@ public final class UsageEvents implements Parcelable {
return ret;
}
+ /** @hide */
+ public Event getObfuscatedNotificationEvent() {
+ final Event ret = new Event(this);
+ ret.mNotificationChannelId = OBFUSCATED_NOTIFICATION_CHANNEL_ID;
+ return ret;
+ }
+
/**
* Returns the locusId for this event if the event is of type {@link #LOCUS_ID_SET},
* otherwise it returns null.
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 49f62f407806..ae12de027e6e 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -4064,16 +4064,16 @@ public abstract class Context {
/**
* Use with {@link #getSystemService(String)} to retrieve a
- * {@link android.net.wifi.WifiCondManager} for handling management of the Wi-Fi control
- * daemon.
+ * {@link android.net.wifi.wificond.WifiNl80211Manager} for handling management of the
+ * Wi-Fi nl802.11 daemon (wificond).
*
* @see #getSystemService(String)
- * @see android.net.wifi.WifiCondManager
+ * @see android.net.wifi.wificond.WifiNl80211Manager
* @hide
*/
@SystemApi
@SuppressLint("ServiceName")
- public static final String WIFI_COND_SERVICE = "wificond";
+ public static final String WIFI_NL80211_SERVICE = "wifinl80211";
/**
* Use with {@link #getSystemService(String)} to retrieve a {@link
@@ -5098,10 +5098,11 @@ public abstract class Context {
/**
* Use with {@link #getSystemService(String)} to retrieve an
- * AppSearchManager for indexing and querying app data managed
- * by the system.
+ * {@link android.app.appsearch.AppSearchManager} for
+ * indexing and querying app data managed by the system.
*
* @see #getSystemService(String)
+ * @hide
*/
public static final String APP_SEARCH_SERVICE = "app_search";
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index d251ba9519db..9d1c677f35c6 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -702,6 +702,13 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
*/
public static final int PRIVATE_FLAG_ODM = 1 << 30;
+ /**
+ * Value for {@link #privateFlags}: If {@code true} this app allows heap tagging.
+ * {@link com.android.server.am.ProcessList#NATIVE_HEAP_POINTER_TAGGING}
+ * @hide
+ */
+ public static final int PRIVATE_FLAG_ALLOW_NATIVE_HEAP_POINTER_TAGGING = 1 << 31;
+
/** @hide */
@IntDef(flag = true, prefix = { "PRIVATE_FLAG_" }, value = {
PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE,
@@ -733,6 +740,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
PRIVATE_FLAG_ALLOW_AUDIO_PLAYBACK_CAPTURE,
PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE,
PRIVATE_FLAG_ODM,
+ PRIVATE_FLAG_ALLOW_NATIVE_HEAP_POINTER_TAGGING,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ApplicationInfoPrivateFlags {}
@@ -1878,6 +1886,15 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
return (privateFlags & PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE) != 0;
}
+ /**
+ * If {@code true} this app allows heap pointer tagging.
+ *
+ * @hide
+ */
+ public boolean allowsNativeHeapPointerTagging() {
+ return (privateFlags & PRIVATE_FLAG_ALLOW_NATIVE_HEAP_POINTER_TAGGING) != 0;
+ }
+
private boolean isAllowedToUseHiddenApis() {
if (isSignedWithPlatformKey()) {
return true;
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index c78d30dd9133..7b484b7c2c3d 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -38,7 +38,7 @@ import android.app.PackageInstallObserver;
import android.app.admin.DevicePolicyManager;
import android.app.usage.StorageStatsManager;
import android.compat.annotation.ChangeId;
-import android.compat.annotation.Disabled;
+import android.compat.annotation.EnabledAfter;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context;
@@ -1988,10 +1988,11 @@ public abstract class PackageManager {
/**
* Feature for {@link #getSystemAvailableFeatures} and
- * {@link #hasSystemFeature}: The device supports a Context Hub.
+ * {@link #hasSystemFeature}: The device supports a Context Hub, used to expose the
+ * functionalities in {@link android.hardware.location.ContextHubManager}.
*/
@SdkConstant(SdkConstantType.FEATURE)
- public static final String FEATURE_CONTEXTHUB = "android.hardware.context_hub";
+ public static final String FEATURE_CONTEXT_HUB = "android.hardware.context_hub";
/** {@hide} */
@SdkConstant(SdkConstantType.FEATURE)
@@ -3385,6 +3386,14 @@ public abstract class PackageManager {
public static final int FLAG_PERMISSION_AUTO_REVOKE_USER_SET = 1 << 18;
/**
+ * Permission flag: Whether permission was revoked by auto-revoke.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int FLAG_PERMISSION_AUTO_REVOKED = 1 << 20;
+
+ /**
* Permission flags: Reserved for use by the permission controller.
*
* @hide
@@ -3437,7 +3446,8 @@ public abstract class PackageManager {
| FLAG_PERMISSION_REVOKED_COMPAT
| FLAG_PERMISSION_ONE_TIME
| FLAG_PERMISSION_AUTO_REVOKE_IF_UNUSED
- | FLAG_PERMISSION_AUTO_REVOKE_USER_SET;
+ | FLAG_PERMISSION_AUTO_REVOKE_USER_SET
+ | FLAG_PERMISSION_AUTO_REVOKED;
/**
* Injected activity in app that forwards user to setting activity of that app.
@@ -3581,7 +3591,7 @@ public abstract class PackageManager {
* @hide
*/
@ChangeId
- @Disabled
+ @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q)
public static final long FILTER_APPLICATION_QUERY = 135549675L;
/** {@hide} */
@@ -4262,7 +4272,8 @@ public abstract class PackageManager {
FLAG_PERMISSION_REVOKED_COMPAT,
FLAG_PERMISSION_ONE_TIME,
FLAG_PERMISSION_AUTO_REVOKE_IF_UNUSED,
- FLAG_PERMISSION_AUTO_REVOKE_USER_SET
+ FLAG_PERMISSION_AUTO_REVOKE_USER_SET,
+ FLAG_PERMISSION_AUTO_REVOKED
})
@Retention(RetentionPolicy.SOURCE)
public @interface PermissionFlags {}
@@ -7401,6 +7412,7 @@ public abstract class PackageManager {
case FLAG_PERMISSION_ONE_TIME: return "ONE_TIME";
case FLAG_PERMISSION_AUTO_REVOKE_IF_UNUSED: return "AUTO_REVOKE_IF_UNUSED";
case FLAG_PERMISSION_AUTO_REVOKE_USER_SET: return "AUTO_REVOKE_USER_SET";
+ case FLAG_PERMISSION_AUTO_REVOKED: return "AUTO_REVOKED";
default: return Integer.toString(flag);
}
}
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 637e64d3d2c2..da44f70178de 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -3710,6 +3710,11 @@ public class PackageParser {
ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE;
}
+ if (sa.getBoolean(
+ R.styleable.AndroidManifestApplication_allowNativeHeapPointerTagging, true)) {
+ ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_ALLOW_NATIVE_HEAP_POINTER_TAGGING;
+ }
+
ai.maxAspectRatio = sa.getFloat(R.styleable.AndroidManifestApplication_maxAspectRatio, 0);
ai.minAspectRatio = sa.getFloat(R.styleable.AndroidManifestApplication_minAspectRatio, 0);
diff --git a/core/java/android/content/pm/parsing/ApkParseUtils.java b/core/java/android/content/pm/parsing/ApkParseUtils.java
index 548d82a6ab76..a2671136ff7b 100644
--- a/core/java/android/content/pm/parsing/ApkParseUtils.java
+++ b/core/java/android/content/pm/parsing/ApkParseUtils.java
@@ -2098,6 +2098,9 @@ public class ApkParseUtils {
R.styleable.AndroidManifestApplication_requestLegacyExternalStorage,
parsingPackage.getTargetSdkVersion() < Build.VERSION_CODES.Q));
+ parsingPackage.setAllowNativeHeapPointerTagging(sa.getBoolean(
+ R.styleable.AndroidManifestApplication_allowNativeHeapPointerTagging, true));
+
parsingPackage
.setMaxAspectRatio(
sa.getFloat(R.styleable.AndroidManifestApplication_maxAspectRatio, 0))
diff --git a/core/java/android/content/pm/parsing/PackageImpl.java b/core/java/android/content/pm/parsing/PackageImpl.java
index 0df950006f43..778d7b8b26b6 100644
--- a/core/java/android/content/pm/parsing/PackageImpl.java
+++ b/core/java/android/content/pm/parsing/PackageImpl.java
@@ -1509,6 +1509,16 @@ public final class PackageImpl implements ParsingPackage, ParsedPackage, Android
}
@Override
+ public PackageImpl setAllowNativeHeapPointerTagging(boolean allowNativeHeapPointerTagging) {
+ this.privateFlags = allowNativeHeapPointerTagging
+ ? this.privateFlags | ApplicationInfo
+ .PRIVATE_FLAG_ALLOW_NATIVE_HEAP_POINTER_TAGGING
+ : this.privateFlags & ~ApplicationInfo
+ .PRIVATE_FLAG_ALLOW_NATIVE_HEAP_POINTER_TAGGING;
+ return this;
+ }
+
+ @Override
public PackageImpl setUsesNonSdkApi(boolean usesNonSdkApi) {
this.privateFlags = usesNonSdkApi
? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_USES_NON_SDK_API
diff --git a/core/java/android/content/pm/parsing/ParsingPackage.java b/core/java/android/content/pm/parsing/ParsingPackage.java
index a2fe064b66c3..954d65c75730 100644
--- a/core/java/android/content/pm/parsing/ParsingPackage.java
+++ b/core/java/android/content/pm/parsing/ParsingPackage.java
@@ -191,6 +191,8 @@ public interface ParsingPackage extends AndroidPackage {
ParsingPackage setRequestLegacyExternalStorage(boolean requestLegacyExternalStorage);
+ ParsingPackage setAllowNativeHeapPointerTagging(boolean allowNativeHeapPointerTagging);
+
ParsingPackage setRestoreAnyVersion(boolean restoreAnyVersion);
ParsingPackage setSplitHasCode(int splitIndex, boolean splitHasCode);
diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java
index ef28e6c6db2a..ac36188ee61a 100644
--- a/core/java/android/hardware/biometrics/BiometricPrompt.java
+++ b/core/java/android/hardware/biometrics/BiometricPrompt.java
@@ -75,6 +75,18 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
/**
* @hide
*/
+ public static final String KEY_DEVICE_CREDENTIAL_TITLE = "device_credential_title";
+ /**
+ * @hide
+ */
+ public static final String KEY_DEVICE_CREDENTIAL_SUBTITLE = "device_credential_subtitle";
+ /**
+ * @hide
+ */
+ public static final String KEY_DEVICE_CREDENTIAL_DESCRIPTION = "device_credential_description";
+ /**
+ * @hide
+ */
public static final String KEY_NEGATIVE_TEXT = "negative_text";
/**
* @hide
@@ -221,6 +233,30 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
}
/**
+ * Sets an optional title, subtitle, and/or description that will override other text when
+ * the user is authenticating with PIN/pattern/password. Currently for internal use only.
+ * @return This builder.
+ * @hide
+ */
+ @RequiresPermission(USE_BIOMETRIC_INTERNAL)
+ @NonNull
+ public Builder setTextForDeviceCredential(
+ @Nullable CharSequence title,
+ @Nullable CharSequence subtitle,
+ @Nullable CharSequence description) {
+ if (title != null) {
+ mBundle.putCharSequence(KEY_DEVICE_CREDENTIAL_TITLE, title);
+ }
+ if (subtitle != null) {
+ mBundle.putCharSequence(KEY_DEVICE_CREDENTIAL_SUBTITLE, subtitle);
+ }
+ if (description != null) {
+ mBundle.putCharSequence(KEY_DEVICE_CREDENTIAL_DESCRIPTION, description);
+ }
+ return this;
+ }
+
+ /**
* Required: Sets the text, executor, and click listener for the negative button on the
* prompt. This is typically a cancel button, but may be also used to show an alternative
* method for authentication, such as a screen that asks for a backup password.
diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java
index db16d24e0af1..1ed791d66f74 100644
--- a/core/java/android/hardware/location/ContextHubManager.java
+++ b/core/java/android/hardware/location/ContextHubManager.java
@@ -54,7 +54,7 @@ import java.util.concurrent.Executor;
*/
@SystemApi
@SystemService(Context.CONTEXTHUB_SERVICE)
-@RequiresFeature(PackageManager.FEATURE_CONTEXTHUB)
+@RequiresFeature(PackageManager.FEATURE_CONTEXT_HUB)
public final class ContextHubManager {
private static final String TAG = "ContextHubManager";
diff --git a/core/java/android/inputmethodservice/OWNERS b/core/java/android/inputmethodservice/OWNERS
new file mode 100644
index 000000000000..444719701df2
--- /dev/null
+++ b/core/java/android/inputmethodservice/OWNERS
@@ -0,0 +1,3 @@
+set noparent
+
+include ../../../../services/core/java/com/android/server/inputmethod/OWNERS
diff --git a/core/java/android/os/incremental/V4Signature.java b/core/java/android/os/incremental/V4Signature.java
index 6450a67572bf..6516917afd9d 100644
--- a/core/java/android/os/incremental/V4Signature.java
+++ b/core/java/android/os/incremental/V4Signature.java
@@ -16,6 +16,7 @@
package android.os.incremental;
+import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
@@ -47,6 +48,15 @@ public class V4Signature {
}
/**
+ * Construct a V4Signature from .idsig file.
+ */
+ public static V4Signature readFrom(byte[] bytes) throws IOException {
+ try (DataInputStream stream = new DataInputStream(new ByteArrayInputStream(bytes))) {
+ return readFrom(stream);
+ }
+ }
+
+ /**
* Store the V4Signature to a byte-array.
*/
public byte[] toByteArray() {
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index afeb6c391009..44e7ae6c13c5 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -79,6 +79,7 @@ public class FeatureFlagUtils {
DEFAULT_FLAGS.put("settings_tether_all_in_one", "false");
DEFAULT_FLAGS.put(SETTINGS_SCHEDULES_FLAG, "false");
+ DEFAULT_FLAGS.put("settings_contextual_home2", "false");
}
/**
diff --git a/core/java/android/view/RenderNodeAnimator.java b/core/java/android/view/RenderNodeAnimator.java
index 06cb51927ba8..0c1edac6608c 100644
--- a/core/java/android/view/RenderNodeAnimator.java
+++ b/core/java/android/view/RenderNodeAnimator.java
@@ -19,7 +19,6 @@ package android.view;
import android.animation.Animator;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
-import android.compat.annotation.UnsupportedAppUsage;
import android.graphics.CanvasProperty;
import android.graphics.Paint;
import android.graphics.RecordingCanvas;
@@ -109,12 +108,10 @@ public class RenderNodeAnimator extends Animator {
private long mStartDelay = 0;
private long mStartTime;
- @UnsupportedAppUsage
public static int mapViewPropertyToRenderProperty(int viewProperty) {
return sViewPropertyAnimatorMap.get(viewProperty);
}
- @UnsupportedAppUsage
public RenderNodeAnimator(int property, float finalValue) {
mRenderProperty = property;
mFinalValue = finalValue;
@@ -122,7 +119,6 @@ public class RenderNodeAnimator extends Animator {
init(nCreateAnimator(property, finalValue));
}
- @UnsupportedAppUsage
public RenderNodeAnimator(CanvasProperty<Float> property, float finalValue) {
init(nCreateCanvasPropertyFloatAnimator(
property.getNativeContainer(), finalValue));
@@ -137,7 +133,6 @@ public class RenderNodeAnimator extends Animator {
* {@link #PAINT_STROKE_WIDTH}
* @param finalValue The target value for the property
*/
- @UnsupportedAppUsage
public RenderNodeAnimator(CanvasProperty<Paint> property, int paintField, float finalValue) {
init(nCreateCanvasPropertyPaintAnimator(
property.getNativeContainer(), paintField, finalValue));
@@ -289,7 +284,6 @@ public class RenderNodeAnimator extends Animator {
}
/** @hide */
- @UnsupportedAppUsage
public void setTarget(View view) {
mViewTarget = view;
setTarget(mViewTarget.mRenderNode);
@@ -301,7 +295,6 @@ public class RenderNodeAnimator extends Animator {
}
/** @hide */
- @UnsupportedAppUsage
public void setTarget(DisplayListCanvas canvas) {
setTarget((RecordingCanvas) canvas);
}
@@ -316,7 +309,6 @@ public class RenderNodeAnimator extends Animator {
mTarget.addAnimator(this);
}
- @UnsupportedAppUsage
public void setStartValue(float startValue) {
checkMutable();
nSetStartValue(mNativePtr.get(), startValue);
@@ -337,7 +329,6 @@ public class RenderNodeAnimator extends Animator {
return mUnscaledStartDelay;
}
- @UnsupportedAppUsage
@Override
public RenderNodeAnimator setDuration(long duration) {
checkMutable();
@@ -502,7 +493,6 @@ public class RenderNodeAnimator extends Animator {
}
// Called by native
- @UnsupportedAppUsage
private static void callOnFinished(RenderNodeAnimator animator) {
if (animator.mHandler != null) {
animator.mHandler.post(animator::onFinished);
diff --git a/core/java/android/view/SurfaceControlViewHost.java b/core/java/android/view/SurfaceControlViewHost.java
index bf848196454d..680a8789a6b8 100644
--- a/core/java/android/view/SurfaceControlViewHost.java
+++ b/core/java/android/view/SurfaceControlViewHost.java
@@ -24,6 +24,7 @@ import android.graphics.PixelFormat;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
+import android.view.accessibility.IAccessibilityEmbeddedConnection;
/**
* Utility class for adding a View hierarchy to a {@link SurfaceControl}. The View hierarchy
@@ -40,6 +41,7 @@ public class SurfaceControlViewHost {
private WindowlessWindowManager mWm;
private SurfaceControl mSurfaceControl;
+ private IAccessibilityEmbeddedConnection mAccessibilityEmbeddedConnection;
/**
* Package encapsulating a Surface hierarchy which contains interactive view
@@ -49,15 +51,18 @@ public class SurfaceControlViewHost {
*/
public static final class SurfacePackage implements Parcelable {
private final SurfaceControl mSurfaceControl;
- // TODO: Accessibility ID goes here
+ private final IAccessibilityEmbeddedConnection mAccessibilityEmbeddedConnection;
- SurfacePackage(SurfaceControl sc) {
+ SurfacePackage(SurfaceControl sc, IAccessibilityEmbeddedConnection connection) {
mSurfaceControl = sc;
+ mAccessibilityEmbeddedConnection = connection;
}
private SurfacePackage(Parcel in) {
mSurfaceControl = new SurfaceControl();
mSurfaceControl.readFromParcel(in);
+ mAccessibilityEmbeddedConnection = IAccessibilityEmbeddedConnection.Stub.asInterface(
+ in.readStrongBinder());
}
/**
@@ -69,6 +74,16 @@ public class SurfaceControlViewHost {
return mSurfaceControl;
}
+ /**
+ * Gets an accessibility embedded connection interface for this SurfaceControlViewHost.
+ *
+ * @return {@link IAccessibilityEmbeddedConnection} interface.
+ * @hide
+ */
+ public IAccessibilityEmbeddedConnection getAccessibilityEmbeddedConnection() {
+ return mAccessibilityEmbeddedConnection;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -77,6 +92,7 @@ public class SurfaceControlViewHost {
@Override
public void writeToParcel(@NonNull Parcel out, int flags) {
mSurfaceControl.writeToParcel(out, flags);
+ out.writeStrongBinder(mAccessibilityEmbeddedConnection.asBinder());
}
public static final @NonNull Creator<SurfacePackage> CREATOR
@@ -95,6 +111,7 @@ public class SurfaceControlViewHost {
@NonNull WindowlessWindowManager wwm) {
mWm = wwm;
mViewRoot = new ViewRootImpl(c, d, mWm);
+ mAccessibilityEmbeddedConnection = mViewRoot.getAccessibilityEmbeddedConnection();
}
/**
@@ -118,6 +135,7 @@ public class SurfaceControlViewHost {
mWm = new WindowlessWindowManager(context.getResources().getConfiguration(),
mSurfaceControl, hostToken);
mViewRoot = new ViewRootImpl(context, display, mWm);
+ mAccessibilityEmbeddedConnection = mViewRoot.getAccessibilityEmbeddedConnection();
}
/**
@@ -128,8 +146,8 @@ public class SurfaceControlViewHost {
* are linked.
*/
public @Nullable SurfacePackage getSurfacePackage() {
- if (mSurfaceControl != null) {
- return new SurfacePackage(mSurfaceControl);
+ if (mSurfaceControl != null && mAccessibilityEmbeddedConnection != null) {
+ return new SurfacePackage(mSurfaceControl, mAccessibilityEmbeddedConnection);
} else {
return null;
}
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index d5ed36b57c02..47ffd3e2714c 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -28,6 +28,7 @@ import android.content.res.CompatibilityInfo.Translator;
import android.graphics.BlendMode;
import android.graphics.Canvas;
import android.graphics.Color;
+import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.PorterDuff;
@@ -38,12 +39,14 @@ import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
+import android.os.RemoteException;
import android.os.SystemClock;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceControl.Transaction;
import android.view.SurfaceControlViewHost;
import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.IAccessibilityEmbeddedConnection;
import com.android.internal.view.SurfaceCallbackHelper;
@@ -203,8 +206,12 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
private SurfaceControl.Transaction mTmpTransaction = new SurfaceControl.Transaction();
private int mParentSurfaceGenerationId;
- // The token of embedded windowless view hierarchy.
- private IBinder mEmbeddedViewHierarchy;
+ private RemoteAccessibilityEmbeddedConnection mRemoteAccessibilityEmbeddedConnection;
+
+ private final Matrix mScreenMatrixForEmbeddedHierarchy = new Matrix();
+ private final Matrix mTmpMatrix = new Matrix();
+ private final float[] mMatrixValues = new float[9];
+
SurfaceControlViewHost.SurfacePackage mSurfacePackage;
public SurfaceView(Context context) {
@@ -923,6 +930,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
}
mTmpTransaction.apply();
+ updateScreenMatrixForEmbeddedHierarchy();
if (sizeChanged || creating) {
redrawNeeded = true;
@@ -1510,6 +1518,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
@Override
public void surfaceDestroyed() {
setWindowStopped(true);
+ setRemoteAccessibilityEmbeddedConnection(null, null);
}
/**
@@ -1568,31 +1577,133 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
private void reparentSurfacePackage(SurfaceControl.Transaction t,
SurfaceControlViewHost.SurfacePackage p) {
- // TODO: Link accessibility IDs here.
+ initEmbeddedHierarchyForAccessibility(p);
final SurfaceControl sc = p.getSurfaceControl();
t.reparent(sc, mSurfaceControl).show(sc);
}
- /**
- * Add the token of embedded view hierarchy. Set {@code null} to clear the embedded view
- * hierarchy.
- *
- * @param token IBinder token.
- * @hide
- */
- public void setEmbeddedViewHierarchy(IBinder token) {
- mEmbeddedViewHierarchy = token;
- }
-
/** @hide */
@Override
public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfoInternal(info);
- if (mEmbeddedViewHierarchy == null) {
+ final RemoteAccessibilityEmbeddedConnection wrapper =
+ getRemoteAccessibilityEmbeddedConnection();
+ if (wrapper == null) {
return;
}
// Add a leashed child when this SurfaceView embeds another view hierarchy. Getting this
// leashed child would return the root node in the embedded hierarchy
- info.addChild(mEmbeddedViewHierarchy);
+ info.addChild(wrapper.getLeashToken());
+ }
+
+ private void initEmbeddedHierarchyForAccessibility(SurfaceControlViewHost.SurfacePackage p) {
+ final IAccessibilityEmbeddedConnection connection = p.getAccessibilityEmbeddedConnection();
+ final RemoteAccessibilityEmbeddedConnection wrapper =
+ getRemoteAccessibilityEmbeddedConnection();
+
+ // Do nothing if package is embedding the same view hierarchy.
+ if (wrapper != null && wrapper.getConnection().equals(connection)) {
+ return;
+ }
+
+ // If this SurfaceView embeds a different view hierarchy, unlink the previous one first.
+ setRemoteAccessibilityEmbeddedConnection(null, null);
+
+ try {
+ final IBinder leashToken = connection.associateEmbeddedHierarchy(
+ getViewRootImpl().mLeashToken, getAccessibilityViewId());
+ setRemoteAccessibilityEmbeddedConnection(connection, leashToken);
+ } catch (RemoteException e) {
+ Log.d(TAG, "Error while associateEmbeddedHierarchy " + e);
+ }
+ updateScreenMatrixForEmbeddedHierarchy();
+ }
+
+ private void setRemoteAccessibilityEmbeddedConnection(
+ IAccessibilityEmbeddedConnection connection, IBinder leashToken) {
+ try {
+ if (mRemoteAccessibilityEmbeddedConnection != null) {
+ mRemoteAccessibilityEmbeddedConnection.getConnection()
+ .disassociateEmbeddedHierarchy();
+ mRemoteAccessibilityEmbeddedConnection.unlinkToDeath();
+ mRemoteAccessibilityEmbeddedConnection = null;
+ }
+ if (connection != null && leashToken != null) {
+ mRemoteAccessibilityEmbeddedConnection =
+ new RemoteAccessibilityEmbeddedConnection(connection, leashToken);
+ mRemoteAccessibilityEmbeddedConnection.linkToDeath();
+ }
+ } catch (RemoteException e) {
+ Log.d(TAG, "Error while setRemoteEmbeddedConnection " + e);
+ }
+ }
+
+ private RemoteAccessibilityEmbeddedConnection getRemoteAccessibilityEmbeddedConnection() {
+ return mRemoteAccessibilityEmbeddedConnection;
+ }
+
+ private void updateScreenMatrixForEmbeddedHierarchy() {
+ mTmpMatrix.reset();
+ mTmpMatrix.setTranslate(mScreenRect.left, mScreenRect.top);
+ mTmpMatrix.postScale(mScreenRect.width() / (float) mSurfaceWidth,
+ mScreenRect.height() / (float) mSurfaceHeight);
+
+ // If the screen matrix is identity or doesn't change, do nothing.
+ if (mTmpMatrix.isIdentity() || mTmpMatrix.equals(mScreenMatrixForEmbeddedHierarchy)) {
+ return;
+ }
+
+ try {
+ final RemoteAccessibilityEmbeddedConnection wrapper =
+ getRemoteAccessibilityEmbeddedConnection();
+ if (wrapper == null) {
+ return;
+ }
+ mTmpMatrix.getValues(mMatrixValues);
+ wrapper.getConnection().setScreenMatrix(mMatrixValues);
+ mScreenMatrixForEmbeddedHierarchy.set(mTmpMatrix);
+ } catch (RemoteException e) {
+ Log.d(TAG, "Error while setScreenMatrix " + e);
+ }
+ }
+
+ /**
+ * Wrapper of accessibility embedded connection for embedded view hierarchy.
+ */
+ private final class RemoteAccessibilityEmbeddedConnection implements IBinder.DeathRecipient {
+ private final IAccessibilityEmbeddedConnection mConnection;
+ private final IBinder mLeashToken;
+
+ RemoteAccessibilityEmbeddedConnection(IAccessibilityEmbeddedConnection connection,
+ IBinder leashToken) {
+ mConnection = connection;
+ mLeashToken = leashToken;
+ }
+
+ IAccessibilityEmbeddedConnection getConnection() {
+ return mConnection;
+ }
+
+ IBinder getLeashToken() {
+ return mLeashToken;
+ }
+
+ void linkToDeath() throws RemoteException {
+ mConnection.asBinder().linkToDeath(this, 0);
+ }
+
+ void unlinkToDeath() {
+ mConnection.asBinder().unlinkToDeath(this, 0);
+ }
+
+ @Override
+ public void binderDied() {
+ unlinkToDeath();
+ runOnUiThread(() -> {
+ if (mRemoteAccessibilityEmbeddedConnection == this) {
+ mRemoteAccessibilityEmbeddedConnection = null;
+ }
+ });
+ }
}
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 857bc5058d60..b971a20d11c9 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -655,7 +655,7 @@ public final class ViewRootImpl implements ViewParent,
private final GestureExclusionTracker mGestureExclusionTracker = new GestureExclusionTracker();
- private IAccessibilityEmbeddedConnection mEmbeddedConnection;
+ private IAccessibilityEmbeddedConnection mAccessibilityEmbeddedConnection;
static final class SystemUiVisibilityInfo {
int seq;
@@ -9370,11 +9370,12 @@ public final class ViewRootImpl implements ViewParent,
* Gets an accessibility embedded connection interface for this ViewRootImpl.
* @hide
*/
- public IAccessibilityEmbeddedConnection getEmbeddedConnection() {
- if (mEmbeddedConnection == null) {
- mEmbeddedConnection = new AccessibilityEmbeddedConnection(ViewRootImpl.this);
+ public IAccessibilityEmbeddedConnection getAccessibilityEmbeddedConnection() {
+ if (mAccessibilityEmbeddedConnection == null) {
+ mAccessibilityEmbeddedConnection = new AccessibilityEmbeddedConnection(
+ ViewRootImpl.this);
}
- return mEmbeddedConnection;
+ return mAccessibilityEmbeddedConnection;
}
private class SendWindowContentChangedAccessibilityEvent implements Runnable {
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index 56683dd9a5d1..3274449b95c8 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -16,6 +16,9 @@
package android.view;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
+
import android.annotation.NonNull;
import android.app.ResourcesManager;
import android.compat.annotation.UnsupportedAppUsage;
@@ -67,10 +70,6 @@ public final class WindowManagerImpl implements WindowManager {
private IBinder mDefaultToken;
- private boolean mIsViewAdded;
- private View mLastView;
- private WindowManager.LayoutParams mLastParams;
-
public WindowManagerImpl(Context context) {
this(context, null);
}
@@ -102,9 +101,6 @@ public final class WindowManagerImpl implements WindowManager {
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
- mIsViewAdded = true;
- mLastView = view;
- mLastParams = (WindowManager.LayoutParams) params;
}
@Override
@@ -250,18 +246,15 @@ public final class WindowManagerImpl implements WindowManager {
// TODO(window-context): This can only be properly implemented
// once we flip the new insets mode flag.
if (mParentWindow != null) {
- if (mParentWindow.getDecorView().isAttachedToWindow()) {
- return mParentWindow.getDecorView().getViewRootImpl()
- .getWindowInsets(true /* forceConstruct */);
- }
return getWindowInsetsFromServer(mParentWindow.getAttributes());
}
- if (mIsViewAdded) {
- return mLastView.getViewRootImpl().getWindowInsets(true /* forceConstruct */);
- } else {
- return getWindowInsetsFromServer(new WindowManager.LayoutParams());
- }
+ return getWindowInsetsFromServer(getDefaultParams());
+ }
+ private static WindowManager.LayoutParams getDefaultParams() {
+ final WindowManager.LayoutParams params = new WindowManager.LayoutParams();
+ params.flags = FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR;
+ return params;
}
private WindowInsets getWindowInsetsFromServer(WindowManager.LayoutParams attrs) {
diff --git a/core/java/android/view/inputmethod/OWNERS b/core/java/android/view/inputmethod/OWNERS
new file mode 100644
index 000000000000..244cc30e089e
--- /dev/null
+++ b/core/java/android/view/inputmethod/OWNERS
@@ -0,0 +1,3 @@
+set noparent
+
+include ../../../../../services/core/java/com/android/server/inputmethod/OWNERS
diff --git a/core/java/android/webkit/UserPackage.java b/core/java/android/webkit/UserPackage.java
index 8a1a0b5ef9b0..556b24c94b36 100644
--- a/core/java/android/webkit/UserPackage.java
+++ b/core/java/android/webkit/UserPackage.java
@@ -34,7 +34,7 @@ public class UserPackage {
private final UserInfo mUserInfo;
private final PackageInfo mPackageInfo;
- public static final int MINIMUM_SUPPORTED_SDK = Build.VERSION_CODES.Q;
+ public static final int MINIMUM_SUPPORTED_SDK = Build.VERSION_CODES.R;
public UserPackage(UserInfo user, PackageInfo packageInfo) {
this.mUserInfo = user;
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index 941af6ef1d7a..8790bbdcd8f7 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -47,7 +47,7 @@ public final class WebViewFactory {
// visible for WebViewZygoteInit to look up the class by reflection and call preloadInZygote.
/** @hide */
private static final String CHROMIUM_WEBVIEW_FACTORY =
- "com.android.webview.chromium.WebViewChromiumFactoryProviderForQ";
+ "com.android.webview.chromium.WebViewChromiumFactoryProviderForR";
private static final String CHROMIUM_WEBVIEW_FACTORY_METHOD = "create";
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 46b8b771de87..12f245e87da2 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -5271,6 +5271,8 @@ public class Editor {
if (opacity < 10 || opacity > 100) {
opacity = 50;
}
+ // Converts the opacity value from range {0..100} to {0..255}.
+ opacity = opacity * 255 / 100;
}
mDeltaHeight = deltaHeight;
mDrawableOpacity = opacity;
diff --git a/core/java/com/android/internal/inputmethod/OWNERS b/core/java/com/android/internal/inputmethod/OWNERS
new file mode 100644
index 000000000000..fc0e5d4dea2b
--- /dev/null
+++ b/core/java/com/android/internal/inputmethod/OWNERS
@@ -0,0 +1,3 @@
+set noparent
+
+include ../../../../../../services/core/java/com/android/server/inputmethod/OWNERS
diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java
index 518911e652f6..0e9c2c4dd659 100644
--- a/core/java/com/android/internal/os/RuntimeInit.java
+++ b/core/java/com/android/internal/os/RuntimeInit.java
@@ -19,8 +19,6 @@ package com.android.internal.os;
import android.app.ActivityManager;
import android.app.ActivityThread;
import android.app.ApplicationErrorReport;
-import android.compat.annotation.ChangeId;
-import android.compat.annotation.EnabledAfter;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.type.DefaultMimeMapFactory;
import android.os.Build;
@@ -36,7 +34,6 @@ import android.util.Slog;
import com.android.internal.logging.AndroidConfig;
import com.android.server.NetworkManagementSocketTagger;
-import dalvik.annotation.compat.VersionCodes;
import dalvik.system.RuntimeHooks;
import dalvik.system.ThreadPrioritySetter;
import dalvik.system.VMRuntime;
@@ -67,18 +64,8 @@ public class RuntimeInit {
private static volatile boolean mCrashing = false;
- /**
- * Native heap allocations will now have a non-zero tag in the most significant byte.
- * See
- * <a href="https://source.android.com/devices/tech/debug/tagged-pointers">https://source.android.com/devices/tech/debug/tagged-pointers</a>.
- */
- @ChangeId
- @EnabledAfter(targetSdkVersion = VersionCodes.Q)
- private static final long NATIVE_HEAP_POINTER_TAGGING = 135754954; // This is a bug id.
-
private static final native void nativeFinishInit();
private static final native void nativeSetExitWithoutCleanup(boolean exitWithoutCleanup);
- private static native void nativeDisableHeapPointerTagging();
private static int Clog_e(String tag, String msg, Throwable tr) {
return Log.printlns(Log.LOG_ID_CRASH, Log.ERROR, tag, msg, tr);
@@ -411,20 +398,6 @@ public class RuntimeInit {
if (DEBUG) Slog.d(TAG, "Leaving RuntimeInit!");
}
- private static void maybeDisableHeapPointerTagging(long[] disabledCompatChanges) {
- // Heap tagging needs to be disabled before any additional threads are created, but the
- // AppCompat framework is not initialized enough at this point.
- // Check if the change is enabled manually.
- if (disabledCompatChanges != null) {
- for (int i = 0; i < disabledCompatChanges.length; i++) {
- if (disabledCompatChanges[i] == NATIVE_HEAP_POINTER_TAGGING) {
- nativeDisableHeapPointerTagging();
- break;
- }
- }
- }
- }
-
protected static Runnable applicationInit(int targetSdkVersion, long[] disabledCompatChanges,
String[] argv, ClassLoader classLoader) {
// If the application calls System.exit(), terminate the process
@@ -437,8 +410,6 @@ public class RuntimeInit {
VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);
VMRuntime.getRuntime().setDisabledCompatChanges(disabledCompatChanges);
- maybeDisableHeapPointerTagging(disabledCompatChanges);
-
final Arguments args = new Arguments(argv);
// The end of of the RuntimeInit event (see #zygoteInit).
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index dfd700f51103..556586477218 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -122,6 +122,25 @@ public final class Zygote {
*/
public static final int DISABLE_TEST_API_ENFORCEMENT_POLICY = 1 << 18;
+ public static final int MEMORY_TAG_LEVEL_MASK = (1 << 19) | (1 << 20);
+ /**
+ * Enable pointer tagging in this process.
+ * Tags are checked during memory deallocation, but not on access.
+ * TBI stands for Top-Byte-Ignore, an ARM CPU feature.
+ * {@link https://developer.arm.com/docs/den0024/latest/the-memory-management-unit/translation-table-configuration/virtual-address-tagging}
+ */
+ public static final int MEMORY_TAG_LEVEL_TBI = 1 << 19;
+
+ /**
+ * Enable asynchronous memory tag checks in this process.
+ */
+ public static final int MEMORY_TAG_LEVEL_ASYNC = 2 << 19;
+
+ /**
+ * Enable synchronous memory tag checks in this process.
+ */
+ public static final int MEMORY_TAG_LEVEL_SYNC = 3 << 19;
+
/** No external storage should be mounted. */
public static final int MOUNT_EXTERNAL_NONE = IVold.REMOUNT_MODE_NONE;
/** Default external storage should be mounted. */
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index ae54eb210de7..e34aa9722ec2 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -788,6 +788,10 @@ public class ZygoteInit {
Zygote.applyDebuggerSystemProperty(parsedArgs);
Zygote.applyInvokeWithSystemProperty(parsedArgs);
+ /* Enable pointer tagging in the system server unconditionally. Hardware support for
+ * this is present in all ARMv8 CPUs; this flag has no effect on other platforms. */
+ parsedArgs.mRuntimeFlags |= Zygote.MEMORY_TAG_LEVEL_TBI;
+
if (shouldProfileSystemServer()) {
parsedArgs.mRuntimeFlags |= Zygote.PROFILE_SYSTEM_SERVER;
}
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 0b1c8b7f5335..19f6e2750219 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -243,14 +243,6 @@ static void com_android_internal_os_RuntimeInit_nativeSetExitWithoutCleanup(JNIE
gCurRuntime->setExitWithoutCleanup(exitWithoutCleanup);
}
-static void com_android_internal_os_RuntimeInit_nativeDisableHeapPointerTagging(
- JNIEnv* env, jobject clazz) {
- HeapTaggingLevel tag_level = M_HEAP_TAGGING_LEVEL_NONE;
- if (!android_mallopt(M_SET_HEAP_TAGGING_LEVEL, &tag_level, sizeof(tag_level))) {
- ALOGE("ERROR: could not disable heap pointer tagging\n");
- }
-}
-
/*
* JNI registration.
*/
@@ -262,8 +254,6 @@ int register_com_android_internal_os_RuntimeInit(JNIEnv* env)
(void*)com_android_internal_os_RuntimeInit_nativeFinishInit},
{"nativeSetExitWithoutCleanup", "(Z)V",
(void*)com_android_internal_os_RuntimeInit_nativeSetExitWithoutCleanup},
- {"nativeDisableHeapPointerTagging", "()V",
- (void*)com_android_internal_os_RuntimeInit_nativeDisableHeapPointerTagging},
};
return jniRegisterNativeMethods(env, "com/android/internal/os/RuntimeInit",
methods, NELEM(methods));
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 7a9a3f8643c0..9fbb8df0d079 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -349,6 +349,8 @@ static const std::array<const std::string, MOUNT_EXTERNAL_COUNT> ExternalStorage
enum RuntimeFlags : uint32_t {
DEBUG_ENABLE_JDWP = 1,
PROFILE_FROM_SHELL = 1 << 15,
+ MEMORY_TAG_LEVEL_MASK = (1 << 19) | (1 << 20),
+ MEMORY_TAG_LEVEL_TBI = 1 << 19,
};
enum UnsolicitedZygoteMessageTypes : uint32_t {
@@ -1627,6 +1629,16 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids,
}
}
+ HeapTaggingLevel heap_tagging_level;
+ switch (runtime_flags & RuntimeFlags::MEMORY_TAG_LEVEL_MASK) {
+ case RuntimeFlags::MEMORY_TAG_LEVEL_TBI:
+ heap_tagging_level = M_HEAP_TAGGING_LEVEL_TBI;
+ break;
+ default:
+ heap_tagging_level = M_HEAP_TAGGING_LEVEL_NONE;
+ }
+ android_mallopt(M_SET_HEAP_TAGGING_LEVEL, &heap_tagging_level, sizeof(heap_tagging_level));
+
if (NeedsNoRandomizeWorkaround()) {
// Work around ARM kernel ASLR lossage (http://b/5817320).
int old_personality = personality(0xffffffff);
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index c66261bb6630..e231c3a323fd 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1782,6 +1782,15 @@
The default value is {@code false}. -->
<attr name="crossProfile" format="boolean" />
+
+ <!-- If {@code true} this app will receive tagged pointers to native heap allocations
+ from functions like malloc() on compatible devices. Note that this may not always
+ be respected due to policy or backwards compatibility reasons. See the
+ <a href="https://source.android.com/devices/tech/debug/tagged-pointers">Tagged Pointers</a>
+ document for more information on this feature.
+
+ The default value is {@code true}. -->
+ <attr name="allowNativeHeapPointerTagging" format="boolean" />
</declare-styleable>
<!-- The <code>feature</code> tag declares a feature. A feature is a logical part of an app.
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 4172044dfa13..0edad3b0d9cd 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3017,6 +3017,7 @@
<public name="autofillInlineSuggestionSubtitle" />
<!-- @hide @SystemApi -->
<public name="isAutofillInlineSuggestionTheme" />
+ <public name="allowNativeHeapPointerTagging" />
</public-group>
<public-group type="drawable" first-id="0x010800b5">
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index 59335a595334..be94f02dc3e7 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -138,6 +138,9 @@
<!-- vr test permissions -->
<uses-permission android:name="android.permission.RESTRICTED_VR_ACCESS" />
+ <!-- WindowMetricsTest permissions -->
+ <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
+
<application android:theme="@style/Theme" android:supportsRtl="true">
<uses-library android:name="android.test.runner" />
<uses-library android:name="org.apache.http.legacy" android:required="false" />
diff --git a/core/tests/coretests/src/android/view/WindowMetricsTest.java b/core/tests/coretests/src/android/view/WindowMetricsTest.java
new file mode 100644
index 000000000000..d2eb8f5f5573
--- /dev/null
+++ b/core/tests/coretests/src/android/view/WindowMetricsTest.java
@@ -0,0 +1,81 @@
+/*
+ * 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.view;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+
+import android.content.Context;
+import android.hardware.display.DisplayManager;
+import android.os.Handler;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.FlakyTest;
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+/**
+ * Tests for {@link WindowManager#getCurrentWindowMetrics()} and
+ * {@link WindowManager#getMaximumWindowMetrics()}.
+ *
+ * <p>Build/Install/Run:
+ * atest FrameworksCoreTests:WindowMetricsTest
+ *
+ * <p>This test class is a part of Window Manager Service tests and specified in
+ * {@link com.android.server.wm.test.filters.FrameworksTestsFilter}.
+ */
+@FlakyTest(bugId = 148789183, detail = "Remove after confirmed it's stable.")
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Presubmit
+public class WindowMetricsTest {
+ private Context mWindowContext;
+ private WindowManager mWm;
+
+ @Before
+ public void setUp() {
+ final Context insetContext = InstrumentationRegistry.getInstrumentation()
+ .getTargetContext();
+ final Display display = insetContext.getSystemService(DisplayManager.class)
+ .getDisplay(DEFAULT_DISPLAY);
+ mWindowContext = insetContext.createDisplayContext(display)
+ .createWindowContext(TYPE_APPLICATION_OVERLAY, null /* options */);
+ mWm = mWindowContext.getSystemService(WindowManager.class);
+ }
+
+ @Test
+ public void testAddViewANdRemoveView_GetMetrics_DoNotCrash() {
+ final View view = new View(mWindowContext);
+ final WindowManager.LayoutParams params =
+ new WindowManager.LayoutParams(TYPE_APPLICATION_OVERLAY);
+ Handler.getMain().runWithScissors(() -> {
+ mWm.addView(view, params);
+ // Check get metrics do not crash.
+ mWm.getCurrentWindowMetrics();
+ mWm.getMaximumWindowMetrics();
+
+ mWm.removeViewImmediate(view);
+ // Check get metrics do not crash.
+ mWm.getCurrentWindowMetrics();
+ mWm.getMaximumWindowMetrics();
+ }, 0);
+ }
+}
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index af115b1e80c1..4b95e4d7fa6c 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -381,6 +381,8 @@ applications that come with the platform
<permission name="android.permission.REBOOT"/>
<!-- Permission required for access VIBRATOR_STATE. -->
<permission name="android.permission.ACCESS_VIBRATOR_STATE"/>
+ <!-- Permission required for UsageStatsTest CTS test. -->
+ <permission name="android.permission.MANAGE_NOTIFICATIONS"/>
</privapp-permissions>
<privapp-permissions package="com.android.statementservice">
diff --git a/graphics/java/android/graphics/ColorSpace.java b/graphics/java/android/graphics/ColorSpace.java
index 06d4fbdd85b1..ce8ff7dc38ba 100644
--- a/graphics/java/android/graphics/ColorSpace.java
+++ b/graphics/java/android/graphics/ColorSpace.java
@@ -867,7 +867,8 @@ public abstract class ColorSpace {
}
}
- private ColorSpace(
+ /** @hide */
+ ColorSpace(
@NonNull String name,
@NonNull Model model,
@IntRange(from = MIN_ID, to = MAX_ID) int id) {
diff --git a/graphics/java/android/graphics/ParcelableColorSpace.java b/graphics/java/android/graphics/ParcelableColorSpace.java
new file mode 100644
index 000000000000..f9033a53d7e6
--- /dev/null
+++ b/graphics/java/android/graphics/ParcelableColorSpace.java
@@ -0,0 +1,183 @@
+/*
+ * 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;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * A {@link Parcelable} {@link ColorSpace}. In order to enable parceling, the ColorSpace
+ * must be either a {@link ColorSpace.Named Named} ColorSpace or a {@link ColorSpace.Rgb} instance
+ * that has an ICC parametric transfer function as returned by {@link Rgb#getTransferParameters()}.
+ * TODO: Make public
+ * @hide
+ */
+public final class ParcelableColorSpace extends ColorSpace implements Parcelable {
+ private final ColorSpace mColorSpace;
+
+ /**
+ * Checks if the given ColorSpace is able to be parceled. A ColorSpace can only be
+ * parceled if it is a {@link ColorSpace.Named Named} ColorSpace or a {@link ColorSpace.Rgb}
+ * instance that has an ICC parametric transfer function as returned by
+ * {@link Rgb#getTransferParameters()}
+ */
+ public static boolean isParcelable(@NonNull ColorSpace colorSpace) {
+ if (colorSpace.getId() == ColorSpace.MIN_ID) {
+ if (!(colorSpace instanceof ColorSpace.Rgb)) {
+ return false;
+ }
+ ColorSpace.Rgb rgb = (ColorSpace.Rgb) colorSpace;
+ if (rgb.getTransferParameters() == null) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Constructs a new ParcelableColorSpace that wraps the provided ColorSpace.
+ *
+ * @param colorSpace The ColorSpace to wrap. The ColorSpace must be either named or be an
+ * RGB ColorSpace with an ICC parametric transfer function.
+ * @throws IllegalArgumentException If the provided ColorSpace does not satisfy the requirements
+ * to be parceled. See {@link #isParcelable(ColorSpace)}.
+ */
+ public ParcelableColorSpace(@NonNull ColorSpace colorSpace) {
+ super(colorSpace.getName(), colorSpace.getModel(), colorSpace.getId());
+ mColorSpace = colorSpace;
+
+ if (mColorSpace.getId() == ColorSpace.MIN_ID) {
+ if (!(mColorSpace instanceof ColorSpace.Rgb)) {
+ throw new IllegalArgumentException(
+ "Unable to parcel unknown ColorSpaces that are not ColorSpace.Rgb");
+ }
+ ColorSpace.Rgb rgb = (ColorSpace.Rgb) mColorSpace;
+ if (rgb.getTransferParameters() == null) {
+ throw new IllegalArgumentException("ColorSpace must use an ICC "
+ + "parametric transfer function to be parcelable");
+ }
+ }
+ }
+
+ public @NonNull ColorSpace getColorSpace() {
+ return mColorSpace;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ final int id = mColorSpace.getId();
+ dest.writeInt(id);
+ if (id == ColorSpace.MIN_ID) {
+ // Not a named color space. We have to actually write, like, stuff. And things. Ugh.
+ // Cast is safe because this was asserted in the constructor
+ ColorSpace.Rgb rgb = (ColorSpace.Rgb) mColorSpace;
+ dest.writeString(rgb.getName());
+ dest.writeFloatArray(rgb.getPrimaries());
+ dest.writeFloatArray(rgb.getWhitePoint());
+ ColorSpace.Rgb.TransferParameters transferParameters = rgb.getTransferParameters();
+ dest.writeDouble(transferParameters.a);
+ dest.writeDouble(transferParameters.b);
+ dest.writeDouble(transferParameters.c);
+ dest.writeDouble(transferParameters.d);
+ dest.writeDouble(transferParameters.e);
+ dest.writeDouble(transferParameters.f);
+ dest.writeDouble(transferParameters.g);
+ }
+ }
+
+ @NonNull
+ public static final Parcelable.Creator<ParcelableColorSpace> CREATOR =
+ new Parcelable.Creator<ParcelableColorSpace>() {
+
+ public @NonNull ParcelableColorSpace createFromParcel(@NonNull Parcel in) {
+ final int id = in.readInt();
+ if (id == ColorSpace.MIN_ID) {
+ String name = in.readString();
+ float[] primaries = in.createFloatArray();
+ float[] whitePoint = in.createFloatArray();
+ double a = in.readDouble();
+ double b = in.readDouble();
+ double c = in.readDouble();
+ double d = in.readDouble();
+ double e = in.readDouble();
+ double f = in.readDouble();
+ double g = in.readDouble();
+ ColorSpace.Rgb.TransferParameters function =
+ new ColorSpace.Rgb.TransferParameters(a, b, c, d, e, f, g);
+ return new ParcelableColorSpace(
+ new ColorSpace.Rgb(name, primaries, whitePoint, function));
+ } else {
+ return new ParcelableColorSpace(ColorSpace.get(id));
+ }
+ }
+
+ public ParcelableColorSpace[] newArray(int size) {
+ return new ParcelableColorSpace[size];
+ }
+ };
+
+ @Override
+ public boolean isWideGamut() {
+ return mColorSpace.isWideGamut();
+ }
+
+ @Override
+ public float getMinValue(int component) {
+ return mColorSpace.getMinValue(component);
+ }
+
+ @Override
+ public float getMaxValue(int component) {
+ return mColorSpace.getMaxValue(component);
+ }
+
+ @Override
+ public @NonNull float[] toXyz(@NonNull float[] v) {
+ return mColorSpace.toXyz(v);
+ }
+
+ @Override
+ public @NonNull float[] fromXyz(@NonNull float[] v) {
+ return mColorSpace.fromXyz(v);
+ }
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ ParcelableColorSpace other = (ParcelableColorSpace) o;
+ return mColorSpace.equals(other.mColorSpace);
+ }
+
+ @Override
+ public int hashCode() {
+ return mColorSpace.hashCode();
+ }
+
+ /** @hide */
+ @Override
+ long getNativeInstance() {
+ return mColorSpace.getNativeInstance();
+ }
+}
diff --git a/libs/hwui/Readback.cpp b/libs/hwui/Readback.cpp
index 89a9b997af97..84c07d7d9dff 100644
--- a/libs/hwui/Readback.cpp
+++ b/libs/hwui/Readback.cpp
@@ -16,16 +16,16 @@
#include "Readback.h"
-#include "pipeline/skia/LayerDrawable.h"
-#include "renderthread/EglManager.h"
-#include "renderthread/VulkanManager.h"
-
-#include <gui/Surface.h>
-#include <ui/Fence.h>
+#include <sync/sync.h>
+#include <system/window.h>
#include <ui/GraphicBuffer.h>
+
#include "DeferredLayerUpdater.h"
#include "Properties.h"
#include "hwui/Bitmap.h"
+#include "pipeline/skia/LayerDrawable.h"
+#include "renderthread/EglManager.h"
+#include "renderthread/VulkanManager.h"
#include "utils/Color.h"
#include "utils/MathUtils.h"
#include "utils/TraceUtils.h"
@@ -35,40 +35,43 @@ using namespace android::uirenderer::renderthread;
namespace android {
namespace uirenderer {
-CopyResult Readback::copySurfaceInto(Surface& surface, const Rect& srcRect, SkBitmap* bitmap) {
+CopyResult Readback::copySurfaceInto(ANativeWindow* window, const Rect& srcRect, SkBitmap* bitmap) {
ATRACE_CALL();
// Setup the source
- sp<GraphicBuffer> sourceBuffer;
- sp<Fence> sourceFence;
+ AHardwareBuffer* rawSourceBuffer;
+ int rawSourceFence;
Matrix4 texTransform;
- status_t err = surface.getLastQueuedBuffer(&sourceBuffer, &sourceFence, texTransform.data);
+ status_t err = ANativeWindow_getLastQueuedBuffer(window, &rawSourceBuffer, &rawSourceFence,
+ texTransform.data);
+ base::unique_fd sourceFence(rawSourceFence);
texTransform.invalidateType();
if (err != NO_ERROR) {
ALOGW("Failed to get last queued buffer, error = %d", err);
return CopyResult::UnknownError;
}
- if (!sourceBuffer.get()) {
+ if (rawSourceBuffer == nullptr) {
ALOGW("Surface doesn't have any previously queued frames, nothing to readback from");
return CopyResult::SourceEmpty;
}
- if (sourceBuffer->getUsage() & GRALLOC_USAGE_PROTECTED) {
+
+ std::unique_ptr<AHardwareBuffer, decltype(&AHardwareBuffer_release)> sourceBuffer(
+ rawSourceBuffer, AHardwareBuffer_release);
+ AHardwareBuffer_Desc description;
+ AHardwareBuffer_describe(sourceBuffer.get(), &description);
+ if (description.usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT) {
ALOGW("Surface is protected, unable to copy from it");
return CopyResult::SourceInvalid;
}
- err = sourceFence->wait(500 /* ms */);
- if (err != NO_ERROR) {
+
+ if (sourceFence != -1 && sync_wait(sourceFence.get(), 500 /* ms */) != NO_ERROR) {
ALOGE("Timeout (500ms) exceeded waiting for buffer fence, abandoning readback attempt");
return CopyResult::Timeout;
}
- if (!sourceBuffer.get()) {
- return CopyResult::UnknownError;
- }
- sk_sp<SkColorSpace> colorSpace =
- DataSpaceToColorSpace(static_cast<android_dataspace>(surface.getBuffersDataSpace()));
- sk_sp<SkImage> image = SkImage::MakeFromAHardwareBuffer(
- reinterpret_cast<AHardwareBuffer*>(sourceBuffer.get()),
- kPremul_SkAlphaType, colorSpace);
+ sk_sp<SkColorSpace> colorSpace = DataSpaceToColorSpace(
+ static_cast<android_dataspace>(ANativeWindow_getBuffersDataSpace(window)));
+ sk_sp<SkImage> image =
+ SkImage::MakeFromAHardwareBuffer(sourceBuffer.get(), kPremul_SkAlphaType, colorSpace);
return copyImageInto(image, texTransform, srcRect, bitmap);
}
diff --git a/libs/hwui/Readback.h b/libs/hwui/Readback.h
index e86a8136cfa3..e36f1ff6a072 100644
--- a/libs/hwui/Readback.h
+++ b/libs/hwui/Readback.h
@@ -47,7 +47,7 @@ public:
/**
* Copies the surface's most recently queued buffer into the provided bitmap.
*/
- CopyResult copySurfaceInto(Surface& surface, const Rect& srcRect, SkBitmap* bitmap);
+ CopyResult copySurfaceInto(ANativeWindow* window, const Rect& srcRect, SkBitmap* bitmap);
CopyResult copyHWBitmapInto(Bitmap* hwBitmap, SkBitmap* bitmap);
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index f9e401a2e93b..1e7fc71a7f04 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -317,8 +317,9 @@ void RenderProxy::setRenderAheadDepth(int renderAhead) {
int RenderProxy::copySurfaceInto(sp<Surface>& surface, int left, int top, int right, int bottom,
SkBitmap* bitmap) {
auto& thread = RenderThread::getInstance();
+ ANativeWindow* window = surface.get();
return static_cast<int>(thread.queue().runSync([&]() -> auto {
- return thread.readback().copySurfaceInto(*surface, Rect(left, top, right, bottom), bitmap);
+ return thread.readback().copySurfaceInto(window, Rect(left, top, right, bottom), bitmap);
}));
}
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 4683e1d69019..ab0dd2bcc8f5 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -140,6 +140,10 @@ public:
*/
ANDROID_API void setRenderAheadDepth(int renderAhead);
+ // TODO: This api will need to take in an ANativeWindow instead, but the
+ // caller, ThreadedRenderer, doesn't have access to libandroid due to a
+ // circular dependency, so it can't use the JNI ANativeWindow methods. Once
+ // that is resolved then replace the surface type here.
ANDROID_API static int copySurfaceInto(sp<Surface>& surface, int left, int top, int right,
int bottom, SkBitmap* bitmap);
ANDROID_API static void prepareToDraw(Bitmap& bitmap);
diff --git a/media/java/android/media/MediaScannerConnection.java b/media/java/android/media/MediaScannerConnection.java
index 05fa511fc81a..2bffe8ac0649 100644
--- a/media/java/android/media/MediaScannerConnection.java
+++ b/media/java/android/media/MediaScannerConnection.java
@@ -156,9 +156,7 @@ public class MediaScannerConnection implements ServiceConnection {
}
BackgroundThread.getExecutor().execute(() -> {
final Uri uri = scanFileQuietly(mProvider, new File(path));
- if (mClient != null) {
- mClient.onScanCompleted(path, uri);
- }
+ runCallBack(mContext, mClient, path, uri);
});
}
}
@@ -187,9 +185,7 @@ public class MediaScannerConnection implements ServiceConnection {
.acquireContentProviderClient(MediaStore.AUTHORITY)) {
for (String path : paths) {
final Uri uri = scanFileQuietly(client, new File(path));
- if (callback != null) {
- callback.onScanCompleted(path, uri);
- }
+ runCallBack(context, callback, path, uri);
}
}
});
@@ -206,6 +202,23 @@ public class MediaScannerConnection implements ServiceConnection {
return uri;
}
+ private static void runCallBack(Context context, OnScanCompletedListener callback,
+ String path, Uri uri) {
+ if (callback != null) {
+ // Ignore exceptions from callback to avoid calling app from crashing.
+ // Don't ignore exceptions for apps targeting 'R' or higher.
+ try {
+ callback.onScanCompleted(path, uri);
+ } catch (Throwable e) {
+ if (context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.R) {
+ throw e;
+ } else {
+ Log.w(TAG, "Ignoring exception from callback for backward compatibility", e);
+ }
+ }
+ }
+ }
+
@Deprecated
static class ClientProxy implements MediaScannerConnectionClient {
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.O)
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index 9b183a3e0e92..44142e324962 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -532,6 +532,8 @@ public class Tuner implements AutoCloseable {
Filter filter = nativeOpenFilter(
mainType, TunerUtils.getFilterSubtype(mainType, subType), bufferSize);
if (filter != null) {
+ filter.setMainType(mainType);
+ filter.setSubtype(subType);
filter.setCallback(cb);
if (mHandler == null) {
mHandler = createEventHandler();
diff --git a/media/java/android/media/tv/tuner/filter/Filter.java b/media/java/android/media/tv/tuner/filter/Filter.java
index 06de6e8a83c7..a98183bbf1a3 100644
--- a/media/java/android/media/tv/tuner/filter/Filter.java
+++ b/media/java/android/media/tv/tuner/filter/Filter.java
@@ -23,6 +23,7 @@ import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.hardware.tv.tuner.V1_0.Constants;
import android.media.tv.tuner.TunerConstants.Result;
+import android.media.tv.tuner.TunerUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -177,6 +178,8 @@ public class Filter implements AutoCloseable {
private long mNativeContext;
private FilterCallback mCallback;
private final int mId;
+ private int mMainType;
+ private int mSubtype;
private native int nativeConfigureFilter(
int type, int subType, FilterConfiguration settings);
@@ -197,6 +200,15 @@ public class Filter implements AutoCloseable {
}
/** @hide */
+ public void setMainType(@Type int mainType) {
+ mMainType = mainType;
+ }
+ /** @hide */
+ public void setSubtype(@Subtype int subtype) {
+ mSubtype = subtype;
+ }
+
+ /** @hide */
public void setCallback(FilterCallback cb) {
mCallback = cb;
}
@@ -213,10 +225,13 @@ public class Filter implements AutoCloseable {
*/
@Result
public int configure(@NonNull FilterConfiguration config) {
- int subType = -1;
+ // TODO: validate main type, subtype, config, settings
+ int subType;
Settings s = config.getSettings();
if (s != null) {
subType = s.getType();
+ } else {
+ subType = TunerUtils.getFilterSubtype(mMainType, mSubtype);
}
return nativeConfigureFilter(config.getType(), subType, config);
}
diff --git a/media/java/android/media/tv/tuner/filter/IpFilterConfiguration.java b/media/java/android/media/tv/tuner/filter/IpFilterConfiguration.java
index bf5aaeda4742..a8dbfa5b11ec 100644
--- a/media/java/android/media/tv/tuner/filter/IpFilterConfiguration.java
+++ b/media/java/android/media/tv/tuner/filter/IpFilterConfiguration.java
@@ -160,6 +160,12 @@ public class IpFilterConfiguration extends FilterConfiguration {
*/
@NonNull
public IpFilterConfiguration build() {
+ int ipAddrLength = mSrcIpAddress.length;
+ if (ipAddrLength != mDstIpAddress.length || (ipAddrLength != 4 && ipAddrLength != 16)) {
+ throw new IllegalArgumentException(
+ "The lengths of src and dst IP address must be 4 or 16 and must be the same."
+ + "srcLength=" + ipAddrLength + ", dstLength=" + mDstIpAddress.length);
+ }
return new IpFilterConfiguration(
mSettings, mSrcIpAddress, mDstIpAddress, mSrcPort, mDstPort, mPassthrough);
}
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index 08c3f988e85e..ac59003de5e6 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -27,16 +27,36 @@
#pragma GCC diagnostic ignored "-Wunused-function"
using ::android::hardware::Void;
+using ::android::hardware::hidl_bitfield;
using ::android::hardware::hidl_vec;
using ::android::hardware::tv::tuner::V1_0::DataFormat;
+using ::android::hardware::tv::tuner::V1_0::DemuxAlpFilterSettings;
+using ::android::hardware::tv::tuner::V1_0::DemuxAlpFilterType;
+using ::android::hardware::tv::tuner::V1_0::DemuxAlpLengthType;
+using ::android::hardware::tv::tuner::V1_0::DemuxFilterAvSettings;
+using ::android::hardware::tv::tuner::V1_0::DemuxFilterDownloadSettings;
using ::android::hardware::tv::tuner::V1_0::DemuxFilterMainType;
using ::android::hardware::tv::tuner::V1_0::DemuxFilterPesDataSettings;
+using ::android::hardware::tv::tuner::V1_0::DemuxFilterRecordSettings;
+using ::android::hardware::tv::tuner::V1_0::DemuxFilterSectionBits;
+using ::android::hardware::tv::tuner::V1_0::DemuxFilterSectionSettings;
using ::android::hardware::tv::tuner::V1_0::DemuxFilterSettings;
+using ::android::hardware::tv::tuner::V1_0::DemuxIpAddress;
+using ::android::hardware::tv::tuner::V1_0::DemuxIpFilterSettings;
+using ::android::hardware::tv::tuner::V1_0::DemuxIpFilterType;
+using ::android::hardware::tv::tuner::V1_0::DemuxMmtpFilterSettings;
+using ::android::hardware::tv::tuner::V1_0::DemuxMmtpFilterType;
using ::android::hardware::tv::tuner::V1_0::DemuxMmtpPid;
using ::android::hardware::tv::tuner::V1_0::DemuxQueueNotifyBits;
+using ::android::hardware::tv::tuner::V1_0::DemuxRecordScIndexType;
+using ::android::hardware::tv::tuner::V1_0::DemuxScHevcIndex;
+using ::android::hardware::tv::tuner::V1_0::DemuxScIndex;
+using ::android::hardware::tv::tuner::V1_0::DemuxTlvFilterSettings;
+using ::android::hardware::tv::tuner::V1_0::DemuxTlvFilterType;
using ::android::hardware::tv::tuner::V1_0::DemuxTpid;
using ::android::hardware::tv::tuner::V1_0::DemuxTsFilterSettings;
using ::android::hardware::tv::tuner::V1_0::DemuxTsFilterType;
+using ::android::hardware::tv::tuner::V1_0::DemuxTsIndex;
using ::android::hardware::tv::tuner::V1_0::DvrSettings;
using ::android::hardware::tv::tuner::V1_0::FrontendAnalogSettings;
using ::android::hardware::tv::tuner::V1_0::FrontendAnalogSifStandard;
@@ -111,6 +131,9 @@ struct fields_t {
static fields_t gFields;
+static int IP_V4_LENGTH = 4;
+static int IP_V6_LENGTH = 16;
+
namespace android {
/////////////// LnbCallback ///////////////////////
LnbCallback::LnbCallback(jweak tunerObj, LnbId id) : mObject(tunerObj), mId(id) {}
@@ -1367,38 +1390,352 @@ static jobject android_media_tv_Tuner_open_time_filter(JNIEnv, jobject) {
return NULL;
}
-static DemuxFilterSettings getFilterSettings(
- JNIEnv *env, int type, int subtype, jobject filterSettingsObj) {
+static DemuxFilterSectionBits getFilterSectionBits(JNIEnv *env, const jobject& settings) {
+ jclass clazz = env->FindClass("android/media/tv/tuner/filter/SectionSettingsWithSectionBits");
+ jbyteArray jfilterBytes = static_cast<jbyteArray>(
+ env->GetObjectField(settings, env->GetFieldID(clazz, "mFilter", "[B")));
+ jsize size = env->GetArrayLength(jfilterBytes);
+ std::vector<uint8_t> filterBytes(size);
+ env->GetByteArrayRegion(
+ jfilterBytes, 0, size, reinterpret_cast<jbyte*>(&filterBytes[0]));
+
+ jbyteArray jmask = static_cast<jbyteArray>(
+ env->GetObjectField(settings, env->GetFieldID(clazz, "mMask", "[B")));
+ size = env->GetArrayLength(jmask);
+ std::vector<uint8_t> mask(size);
+ env->GetByteArrayRegion(jmask, 0, size, reinterpret_cast<jbyte*>(&mask[0]));
+
+ jbyteArray jmode = static_cast<jbyteArray>(
+ env->GetObjectField(settings, env->GetFieldID(clazz, "mMode", "[B")));
+ size = env->GetArrayLength(jmode);
+ std::vector<uint8_t> mode(size);
+ env->GetByteArrayRegion(jmode, 0, size, reinterpret_cast<jbyte*>(&mode[0]));
+
+ DemuxFilterSectionBits filterSectionBits {
+ .filter = filterBytes,
+ .mask = mask,
+ .mode = mode,
+ };
+ return filterSectionBits;
+}
+
+static DemuxFilterSectionSettings::Condition::TableInfo getFilterTableInfo(
+ JNIEnv *env, const jobject& settings) {
+ jclass clazz = env->FindClass("android/media/tv/tuner/filter/SectionSettingsWithTableInfo");
+ uint16_t tableId = static_cast<uint16_t>(
+ env->GetIntField(settings, env->GetFieldID(clazz, "mTableId", "I")));
+ uint16_t version = static_cast<uint16_t>(
+ env->GetIntField(settings, env->GetFieldID(clazz, "mVersion", "I")));
+ DemuxFilterSectionSettings::Condition::TableInfo tableInfo {
+ .tableId = tableId,
+ .version = version,
+ };
+ return tableInfo;
+}
+
+static DemuxFilterSectionSettings getFilterSectionSettings(JNIEnv *env, const jobject& settings) {
+ jclass clazz = env->FindClass("android/media/tv/tuner/filter/SectionSettings");
+ bool isCheckCrc = static_cast<bool>(
+ env->GetBooleanField(settings, env->GetFieldID(clazz, "mCrcEnabled", "Z")));
+ bool isRepeat = static_cast<bool>(
+ env->GetBooleanField(settings, env->GetFieldID(clazz, "mIsRepeat", "Z")));
+ bool isRaw = static_cast<bool>(
+ env->GetBooleanField(settings, env->GetFieldID(clazz, "mIsRaw", "Z")));
+
+ DemuxFilterSectionSettings filterSectionSettings {
+ .isCheckCrc = isCheckCrc,
+ .isRepeat = isRepeat,
+ .isRaw = isRaw,
+ };
+ if (env->IsInstanceOf(
+ settings,
+ env->FindClass("android/media/tv/tuner/filter/SectionSettingsWithSectionBits"))) {
+ filterSectionSettings.condition.sectionBits(getFilterSectionBits(env, settings));
+ } else if (env->IsInstanceOf(
+ settings,
+ env->FindClass("android/media/tv/tuner/filter/SectionSettingsWithTableInfo"))) {
+ filterSectionSettings.condition.tableInfo(getFilterTableInfo(env, settings));
+ }
+ return filterSectionSettings;
+}
+
+static DemuxFilterAvSettings getFilterAvSettings(JNIEnv *env, const jobject& settings) {
+ jclass clazz = env->FindClass("android/media/tv/tuner/filter/AvSettings");
+ bool isPassthrough = static_cast<bool>(
+ env->GetBooleanField(settings, env->GetFieldID(clazz, "mIsPassthrough", "Z")));
+ DemuxFilterAvSettings filterAvSettings {
+ .isPassthrough = isPassthrough,
+ };
+ return filterAvSettings;
+}
+
+static DemuxFilterPesDataSettings getFilterPesDataSettings(JNIEnv *env, const jobject& settings) {
+ jclass clazz = env->FindClass("android/media/tv/tuner/filter/PesSettings");
+ uint16_t streamId = static_cast<uint16_t>(
+ env->GetIntField(settings, env->GetFieldID(clazz, "mStreamId", "I")));
+ bool isRaw = static_cast<bool>(
+ env->GetBooleanField(settings, env->GetFieldID(clazz, "mIsRaw", "Z")));
+ DemuxFilterPesDataSettings filterPesDataSettings {
+ .streamId = streamId,
+ .isRaw = isRaw,
+ };
+ return filterPesDataSettings;
+}
+
+static DemuxFilterRecordSettings getFilterRecordSettings(JNIEnv *env, const jobject& settings) {
+ jclass clazz = env->FindClass("android/media/tv/tuner/filter/RecordSettings");
+ hidl_bitfield<DemuxTsIndex> tsIndexMask = static_cast<hidl_bitfield<DemuxTsIndex>>(
+ env->GetIntField(settings, env->GetFieldID(clazz, "mTsIndexMask", "I")));
+ DemuxRecordScIndexType scIndexType = static_cast<DemuxRecordScIndexType>(
+ env->GetIntField(settings, env->GetFieldID(clazz, "mScIndexType", "I")));
+ jint scIndexMask = env->GetIntField(settings, env->GetFieldID(clazz, "mScIndexMask", "I"));
+
+ DemuxFilterRecordSettings filterRecordSettings {
+ .tsIndexMask = tsIndexMask,
+ .scIndexType = scIndexType,
+ };
+ if (scIndexType == DemuxRecordScIndexType::SC) {
+ filterRecordSettings.scIndexMask.sc(static_cast<hidl_bitfield<DemuxScIndex>>(scIndexMask));
+ } else if (scIndexType == DemuxRecordScIndexType::SC_HEVC) {
+ filterRecordSettings.scIndexMask.scHevc(
+ static_cast<hidl_bitfield<DemuxScHevcIndex>>(scIndexMask));
+ }
+ return filterRecordSettings;
+}
+
+static DemuxFilterDownloadSettings getFilterDownloadSettings(JNIEnv *env, const jobject& settings) {
+ jclass clazz = env->FindClass("android/media/tv/tuner/filter/DownloadSettings");
+ uint32_t downloadId = static_cast<uint32_t>(
+ env->GetIntField(settings, env->GetFieldID(clazz, "mDownloadId", "I")));
+
+ DemuxFilterDownloadSettings filterDownloadSettings {
+ .downloadId = downloadId,
+ };
+ return filterDownloadSettings;
+}
+
+static DemuxIpAddress getDemuxIpAddress(JNIEnv *env, const jobject& config) {
+ jclass clazz = env->FindClass("android/media/tv/tuner/filter/IpFilterConfiguration");
+
+ jbyteArray jsrcIpAddress = static_cast<jbyteArray>(
+ env->GetObjectField(config, env->GetFieldID(clazz, "mSrcIpAddress", "[B")));
+ jsize srcSize = env->GetArrayLength(jsrcIpAddress);
+ jbyteArray jdstIpAddress = static_cast<jbyteArray>(
+ env->GetObjectField(config, env->GetFieldID(clazz, "mDstIpAddress", "[B")));
+ jsize dstSize = env->GetArrayLength(jdstIpAddress);
+
+ DemuxIpAddress res;
+
+ if (srcSize != dstSize) {
+ // should never happen. Validated on Java size.
+ jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
+ "IP address lengths don't match. srcLength=%d, dstLength=%d", srcSize, dstSize);
+ return res;
+ }
+
+ if (srcSize == IP_V4_LENGTH) {
+ uint8_t srcAddr[IP_V4_LENGTH];
+ uint8_t dstAddr[IP_V4_LENGTH];
+ env->GetByteArrayRegion(
+ jsrcIpAddress, 0, srcSize, reinterpret_cast<jbyte*>(srcAddr));
+ env->GetByteArrayRegion(
+ jdstIpAddress, 0, dstSize, reinterpret_cast<jbyte*>(dstAddr));
+ res.srcIpAddress.v4(srcAddr);
+ res.dstIpAddress.v4(dstAddr);
+ } else if (srcSize == IP_V6_LENGTH) {
+ uint8_t srcAddr[IP_V6_LENGTH];
+ uint8_t dstAddr[IP_V6_LENGTH];
+ env->GetByteArrayRegion(
+ jsrcIpAddress, 0, srcSize, reinterpret_cast<jbyte*>(srcAddr));
+ env->GetByteArrayRegion(
+ jdstIpAddress, 0, dstSize, reinterpret_cast<jbyte*>(dstAddr));
+ res.srcIpAddress.v6(srcAddr);
+ res.dstIpAddress.v6(dstAddr);
+ } else {
+ // should never happen. Validated on Java size.
+ jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
+ "Invalid IP address length %d", srcSize);
+ return res;
+ }
+
+ uint16_t srcPort = static_cast<uint16_t>(
+ env->GetIntField(config, env->GetFieldID(clazz, "mSrcPort", "I")));
+ uint16_t dstPort = static_cast<uint16_t>(
+ env->GetIntField(config, env->GetFieldID(clazz, "mDstPort", "I")));
+
+ res.srcPort = srcPort;
+ res.dstPort = dstPort;
+
+ return res;
+}
+
+static DemuxFilterSettings getFilterConfiguration(
+ JNIEnv *env, int type, int subtype, jobject filterConfigObj) {
DemuxFilterSettings filterSettings;
- // TODO: more setting types
jobject settingsObj =
env->GetObjectField(
- filterSettingsObj,
+ filterConfigObj,
env->GetFieldID(
env->FindClass("android/media/tv/tuner/filter/FilterConfiguration"),
"mSettings",
"Landroid/media/tv/tuner/filter/Settings;"));
- if (type == (int)DemuxFilterMainType::TS) {
- // DemuxTsFilterSettings
- jclass clazz = env->FindClass("android/media/tv/tuner/filter/TsFilterConfiguration");
- int tpid = env->GetIntField(filterSettingsObj, env->GetFieldID(clazz, "mTpid", "I"));
- if (subtype == (int)DemuxTsFilterType::PES) {
- // DemuxFilterPesDataSettings
- jclass settingClazz =
- env->FindClass("android/media/tv/tuner/filter/PesSettings");
- int streamId = env->GetIntField(
- settingsObj, env->GetFieldID(settingClazz, "mStreamId", "I"));
- bool isRaw = (bool)env->GetBooleanField(
- settingsObj, env->GetFieldID(settingClazz, "mIsRaw", "Z"));
- DemuxFilterPesDataSettings filterPesDataSettings {
- .streamId = static_cast<uint16_t>(streamId),
- .isRaw = isRaw,
- };
+ DemuxFilterMainType mainType = static_cast<DemuxFilterMainType>(type);
+ switch (mainType) {
+ case DemuxFilterMainType::TS: {
+ jclass clazz = env->FindClass("android/media/tv/tuner/filter/TsFilterConfiguration");
+ uint16_t tpid = static_cast<uint16_t>(
+ env->GetIntField(filterConfigObj, env->GetFieldID(clazz, "mTpid", "I")));
DemuxTsFilterSettings tsFilterSettings {
- .tpid = static_cast<uint16_t>(tpid),
+ .tpid = tpid,
};
- tsFilterSettings.filterSettings.pesData(filterPesDataSettings);
+
+ DemuxTsFilterType tsType = static_cast<DemuxTsFilterType>(subtype);
+ switch (tsType) {
+ case DemuxTsFilterType::SECTION:
+ tsFilterSettings.filterSettings.section(
+ getFilterSectionSettings(env, settingsObj));
+ break;
+ case DemuxTsFilterType::AUDIO:
+ case DemuxTsFilterType::VIDEO:
+ tsFilterSettings.filterSettings.av(getFilterAvSettings(env, settingsObj));
+ break;
+ case DemuxTsFilterType::PES:
+ tsFilterSettings.filterSettings.pesData(
+ getFilterPesDataSettings(env, settingsObj));
+ break;
+ case DemuxTsFilterType::RECORD:
+ tsFilterSettings.filterSettings.record(
+ getFilterRecordSettings(env, settingsObj));
+ break;
+ default:
+ break;
+ }
filterSettings.ts(tsFilterSettings);
+ break;
+ }
+ case DemuxFilterMainType::MMTP: {
+ jclass clazz = env->FindClass("android/media/tv/tuner/filter/MmtpFilterConfiguration");
+ uint16_t mmtpPid = static_cast<uint16_t>(
+ env->GetIntField(filterConfigObj, env->GetFieldID(clazz, "mMmtpPid", "I")));
+ DemuxMmtpFilterSettings mmtpFilterSettings {
+ .mmtpPid = mmtpPid,
+ };
+ DemuxMmtpFilterType mmtpType = static_cast<DemuxMmtpFilterType>(subtype);
+ switch (mmtpType) {
+ case DemuxMmtpFilterType::SECTION:
+ mmtpFilterSettings.filterSettings.section(
+ getFilterSectionSettings(env, settingsObj));
+ break;
+ case DemuxMmtpFilterType::AUDIO:
+ case DemuxMmtpFilterType::VIDEO:
+ mmtpFilterSettings.filterSettings.av(getFilterAvSettings(env, settingsObj));
+ break;
+ case DemuxMmtpFilterType::PES:
+ mmtpFilterSettings.filterSettings.pesData(
+ getFilterPesDataSettings(env, settingsObj));
+ break;
+ case DemuxMmtpFilterType::RECORD:
+ mmtpFilterSettings.filterSettings.record(
+ getFilterRecordSettings(env, settingsObj));
+ break;
+ case DemuxMmtpFilterType::DOWNLOAD:
+ mmtpFilterSettings.filterSettings.download(
+ getFilterDownloadSettings(env, settingsObj));
+ break;
+ default:
+ break;
+ }
+ filterSettings.mmtp(mmtpFilterSettings);
+ break;
+ }
+ case DemuxFilterMainType::IP: {
+ DemuxIpAddress ipAddr = getDemuxIpAddress(env, filterConfigObj);
+
+ DemuxIpFilterSettings ipFilterSettings {
+ .ipAddr = ipAddr,
+ };
+ DemuxIpFilterType ipType = static_cast<DemuxIpFilterType>(subtype);
+ switch (ipType) {
+ case DemuxIpFilterType::SECTION: {
+ ipFilterSettings.filterSettings.section(
+ getFilterSectionSettings(env, settingsObj));
+ break;
+ }
+ case DemuxIpFilterType::IP: {
+ jclass clazz = env->FindClass(
+ "android/media/tv/tuner/filter/IpFilterConfiguration");
+ bool bPassthrough = static_cast<bool>(
+ env->GetBooleanField(
+ filterConfigObj, env->GetFieldID(
+ clazz, "mPassthrough", "Z")));
+ ipFilterSettings.filterSettings.bPassthrough(bPassthrough);
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ filterSettings.ip(ipFilterSettings);
+ break;
+ }
+ case DemuxFilterMainType::TLV: {
+ jclass clazz = env->FindClass("android/media/tv/tuner/filter/TlvFilterConfiguration");
+ uint8_t packetType = static_cast<uint8_t>(
+ env->GetIntField(filterConfigObj, env->GetFieldID(clazz, "mPacketType", "I")));
+ bool isCompressedIpPacket = static_cast<bool>(
+ env->GetBooleanField(
+ filterConfigObj, env->GetFieldID(clazz, "mIsCompressedIpPacket", "Z")));
+
+ DemuxTlvFilterSettings tlvFilterSettings {
+ .packetType = packetType,
+ .isCompressedIpPacket = isCompressedIpPacket,
+ };
+ DemuxTlvFilterType tlvType = static_cast<DemuxTlvFilterType>(subtype);
+ switch (tlvType) {
+ case DemuxTlvFilterType::SECTION: {
+ tlvFilterSettings.filterSettings.section(
+ getFilterSectionSettings(env, settingsObj));
+ break;
+ }
+ case DemuxTlvFilterType::TLV: {
+ bool bPassthrough = static_cast<bool>(
+ env->GetBooleanField(
+ filterConfigObj, env->GetFieldID(
+ clazz, "mPassthrough", "Z")));
+ tlvFilterSettings.filterSettings.bPassthrough(bPassthrough);
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ filterSettings.tlv(tlvFilterSettings);
+ break;
+ }
+ case DemuxFilterMainType::ALP: {
+ jclass clazz = env->FindClass("android/media/tv/tuner/filter/AlpFilterConfiguration");
+ uint8_t packetType = static_cast<uint8_t>(
+ env->GetIntField(filterConfigObj, env->GetFieldID(clazz, "mPacketType", "I")));
+ DemuxAlpLengthType lengthType = static_cast<DemuxAlpLengthType>(
+ env->GetIntField(filterConfigObj, env->GetFieldID(clazz, "mLengthType", "I")));
+ DemuxAlpFilterSettings alpFilterSettings {
+ .packetType = packetType,
+ .lengthType = lengthType,
+ };
+ DemuxAlpFilterType alpType = static_cast<DemuxAlpFilterType>(subtype);
+ switch (alpType) {
+ case DemuxAlpFilterType::SECTION:
+ alpFilterSettings.filterSettings.section(
+ getFilterSectionSettings(env, settingsObj));
+ break;
+ default:
+ break;
+ }
+ filterSettings.alp(alpFilterSettings);
+ break;
+ }
+ default: {
+ break;
}
}
return filterSettings;
@@ -1439,7 +1776,7 @@ static int android_media_tv_Tuner_configure_filter(
ALOGD("Failed to configure filter: filter not found");
return (int)Result::INVALID_STATE;
}
- DemuxFilterSettings filterSettings = getFilterSettings(env, type, subtype, settings);
+ DemuxFilterSettings filterSettings = getFilterConfiguration(env, type, subtype, settings);
Result res = iFilterSp->configure(filterSettings);
MQDescriptorSync<uint8_t> filterMQDesc;
if (res == Result::SUCCESS && filterSp->mFilterMQ == NULL) {
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
index 3ffb9514a98b..615dc48b969c 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
@@ -70,8 +70,8 @@ import java.util.function.Predicate;
@RunWith(AndroidJUnit4.class)
@SmallTest
-public class MediaRouterManagerTest {
- private static final String TAG = "MediaRouterManagerTest";
+public class MediaRouter2ManagerTest {
+ private static final String TAG = "MediaRouter2ManagerTest";
private static final int TIMEOUT_MS = 5000;
private Context mContext;
diff --git a/media/tests/TunerTest/Android.bp b/media/tests/TunerTest/Android.bp
new file mode 100644
index 000000000000..cef879112225
--- /dev/null
+++ b/media/tests/TunerTest/Android.bp
@@ -0,0 +1,18 @@
+android_test {
+ name: "mediatunertest",
+
+ srcs: ["**/*.java"],
+
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ ],
+
+ static_libs: [
+ "android-support-test",
+ "testng"
+ ],
+
+ platform_apis: true,
+ certificate: "platform",
+}
diff --git a/media/tests/TunerTest/AndroidManifest.xml b/media/tests/TunerTest/AndroidManifest.xml
new file mode 100644
index 000000000000..17e9f197b68c
--- /dev/null
+++ b/media/tests/TunerTest/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.mediatunertest">
+
+ <uses-permission android:name="android.permission.ACCESS_TV_TUNER" />
+
+ <application android:label="@string/app_name">
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.mediatunertest"
+ android:label="Media Tuner Tests"/>
+</manifest>
diff --git a/media/tests/TunerTest/AndroidTest.xml b/media/tests/TunerTest/AndroidTest.xml
new file mode 100644
index 000000000000..d9c31f45532f
--- /dev/null
+++ b/media/tests/TunerTest/AndroidTest.xml
@@ -0,0 +1,17 @@
+<configuration description="Runs Media Tuner tests.">
+ <option name="test-suite-tag" value="apct"/>
+ <option name="test-tag" value="MediaTunerTest"/>
+
+ <target_preparer class="com.android.tradefed.targetprep.TestFilePushSetup"/>
+ <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+ <option name="test-file-name" value="mediatunertest.apk"/>
+ </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"/>
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer"/>
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+ <option name="package" value="com.android.mediatunertest"/>
+ <option name="hidden-api-checks" value="false"/>
+ <option name="runner" value="android.support.test.runner.AndroidJUnitRunner"/>
+ </test>
+</configuration>
diff --git a/media/tests/TunerTest/res/values/strings.xml b/media/tests/TunerTest/res/values/strings.xml
new file mode 100644
index 000000000000..b313944ed256
--- /dev/null
+++ b/media/tests/TunerTest/res/values/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- name of the app [CHAR LIMIT=25]-->
+ <string name="app_name">MediaTunerTest</string>
+</resources> \ No newline at end of file
diff --git a/media/tests/TunerTest/src/com/android/mediatunertest/TunerTest.java b/media/tests/TunerTest/src/com/android/mediatunertest/TunerTest.java
new file mode 100644
index 000000000000..cbfbf77d11f5
--- /dev/null
+++ b/media/tests/TunerTest/src/com/android/mediatunertest/TunerTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2019 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.mediatunertest;
+
+import static org.junit.Assert.assertNotNull;
+
+import android.content.Context;
+import android.media.tv.tuner.Descrambler;
+import android.media.tv.tuner.Tuner;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class TunerTest {
+ private static final String TAG = "MediaTunerTest";
+
+ private Context mContext;
+
+ @Before
+ public void setUp() throws Exception {
+ mContext = InstrumentationRegistry.getTargetContext();
+ }
+
+ @After
+ public void tearDown() {
+ }
+
+ @Test
+ public void testTunerConstructor() throws Exception {
+ Tuner tuner = new Tuner(mContext, "123", 1, null);
+ assertNotNull(tuner);
+ }
+
+ @Test
+ public void testOpenDescrambler() throws Exception {
+ Tuner tuner = new Tuner(mContext, "123", 1, null);
+ Descrambler descrambler = tuner.openDescrambler();
+ assertNotNull(descrambler);
+ }
+}
diff --git a/packages/SettingsLib/Android.bp b/packages/SettingsLib/Android.bp
index 62124934f416..3f42ad40eb8e 100644
--- a/packages/SettingsLib/Android.bp
+++ b/packages/SettingsLib/Android.bp
@@ -27,6 +27,7 @@ android_library {
"SettingsLibRadioButtonPreference",
"WifiTrackerLib",
"SettingsLibDisplayDensityUtils",
+ "SettingsLibSchedulesProvider",
],
// ANDROIDMK TRANSLATION ERROR: unsupported assignment to LOCAL_SHARED_JAVA_LIBRARIES
diff --git a/packages/SettingsLib/SchedulesProvider/Android.bp b/packages/SettingsLib/SchedulesProvider/Android.bp
new file mode 100644
index 000000000000..ef592527ba92
--- /dev/null
+++ b/packages/SettingsLib/SchedulesProvider/Android.bp
@@ -0,0 +1,12 @@
+android_library {
+ name: "SettingsLibSchedulesProvider",
+
+ srcs: ["src/**/*.java"],
+
+ static_libs: [
+ "androidx.annotation_annotation",
+ ],
+
+ sdk_version: "system_current",
+ min_sdk_version: "21",
+}
diff --git a/packages/SettingsLib/SchedulesProvider/AndroidManifest.xml b/packages/SettingsLib/SchedulesProvider/AndroidManifest.xml
new file mode 100644
index 000000000000..1b0e4bfc1e1d
--- /dev/null
+++ b/packages/SettingsLib/SchedulesProvider/AndroidManifest.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.settingslib.schedulesprovider">
+
+ <uses-sdk android:minSdkVersion="21" />
+
+</manifest>
diff --git a/packages/SettingsLib/SchedulesProvider/src/com/android/settingslib/schedulesprovider/ScheduleInfo.java b/packages/SettingsLib/SchedulesProvider/src/com/android/settingslib/schedulesprovider/ScheduleInfo.java
new file mode 100644
index 000000000000..7d2b8e2878d6
--- /dev/null
+++ b/packages/SettingsLib/SchedulesProvider/src/com/android/settingslib/schedulesprovider/ScheduleInfo.java
@@ -0,0 +1,167 @@
+/*
+ * 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 com.android.settingslib.schedulesprovider;
+
+import android.content.Intent;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+
+import androidx.annotation.NonNull;
+
+/**
+ * This is a schedule data item. It contains the schedule title text, the summary text which
+ * displays on the summary of the Settings preference and an {@link Intent}. Intent is able to
+ * launch the editing page of the schedule data when user clicks this item (preference).
+ */
+public class ScheduleInfo implements Parcelable {
+ private static final String TAG = "ScheduleInfo";
+ private final String mTitle;
+ private final String mSummary;
+ private final Intent mIntent;
+
+ public ScheduleInfo(Builder builder) {
+ mTitle = builder.mTitle;
+ mSummary = builder.mSummary;
+ mIntent = builder.mIntent;
+ }
+
+ protected ScheduleInfo(Parcel in) {
+ mTitle = in.readString();
+ mSummary = in.readString();
+ mIntent = in.readParcelable(Intent.class.getClassLoader());
+ }
+
+ /**
+ * Returns the title text.
+ *
+ * @return The title.
+ */
+ public String getTitle() {
+ return mTitle;
+ }
+
+ /**
+ * Returns the summary text.
+ *
+ * @return The summary.
+ */
+ public String getSummary() {
+ return mSummary;
+ }
+
+ /**
+ * Returns an {@link Intent}.
+ */
+ public Intent getIntent() {
+ return mIntent;
+ }
+
+ /**
+ * Verify the member variables are valid.
+ *
+ * @return {@code true} if all member variables are valid.
+ */
+ public boolean isValid() {
+ return !TextUtils.isEmpty(mTitle) && !TextUtils.isEmpty(mSummary) && (mIntent != null);
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mTitle);
+ dest.writeString(mSummary);
+ dest.writeParcelable(mIntent, flags);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Creator<ScheduleInfo> CREATOR = new Creator<ScheduleInfo>() {
+ @Override
+ public ScheduleInfo createFromParcel(Parcel in) {
+ return new ScheduleInfo(in);
+ }
+
+ @Override
+ public ScheduleInfo[] newArray(int size) {
+ return new ScheduleInfo[size];
+ }
+ };
+
+ @NonNull
+ @Override
+ public String toString() {
+ return "title : " + mTitle + " summary : " + mSummary + (mIntent == null
+ ? " and intent is null." : ".");
+ }
+
+ /**
+ * A simple builder for {@link ScheduleInfo}.
+ */
+ public static class Builder {
+ @NonNull
+ private String mTitle;
+ @NonNull
+ private String mSummary;
+ @NonNull
+ private Intent mIntent;
+
+ /**
+ * Sets the title.
+ *
+ * @param title The title of the preference item.
+ * @return This instance.
+ */
+ public Builder setTitle(@NonNull String title) {
+ mTitle = title;
+ return this;
+ }
+
+ /**
+ * Sets the summary.
+ *
+ * @param summary The summary of the preference summary.
+ * @return This instance.
+ */
+ public Builder setSummary(@NonNull String summary) {
+ mSummary = summary;
+ return this;
+ }
+
+ /**
+ * Sets the {@link Intent}.
+ *
+ * @param intent The action when user clicks the preference.
+ * @return This instance.
+ */
+ public Builder setIntent(@NonNull Intent intent) {
+ mIntent = intent;
+ return this;
+ }
+
+ /**
+ * Creates an instance of {@link ScheduleInfo}.
+ *
+ * @return The instance of {@link ScheduleInfo}.
+ */
+ public ScheduleInfo build() {
+ return new ScheduleInfo(this);
+ }
+ }
+}
diff --git a/packages/SettingsLib/SchedulesProvider/src/com/android/settingslib/schedulesprovider/SchedulesProvider.java b/packages/SettingsLib/SchedulesProvider/src/com/android/settingslib/schedulesprovider/SchedulesProvider.java
new file mode 100644
index 000000000000..a423e475d357
--- /dev/null
+++ b/packages/SettingsLib/SchedulesProvider/src/com/android/settingslib/schedulesprovider/SchedulesProvider.java
@@ -0,0 +1,133 @@
+/*
+ * 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 com.android.settingslib.schedulesprovider;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.SystemProperties;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * This provider is a bridge for client apps to provide the schedule data.
+ * Client provider needs to implement their {@link #getScheduleInfoList()} and returns a list of
+ * {@link ScheduleInfo}.
+ */
+public abstract class SchedulesProvider extends ContentProvider {
+ public static final String METHOD_GENERATE_SCHEDULE_INFO_LIST = "generateScheduleInfoList";
+ public static final String BUNDLE_SCHEDULE_INFO_LIST = "scheduleInfoList";
+ private static final String TAG = "SchedulesProvider";
+
+ @Override
+ public boolean onCreate() {
+ return true;
+ }
+
+ @Override
+ public final Cursor query(
+ Uri uri, String[] projection, String selection, String[] selectionArgs,
+ String sortOrder) {
+ throw new UnsupportedOperationException("Query operation is not supported currently.");
+ }
+
+ @Override
+ public final String getType(Uri uri) {
+ throw new UnsupportedOperationException("GetType operation is not supported currently.");
+ }
+
+ @Override
+ public final Uri insert(Uri uri, ContentValues values) {
+ throw new UnsupportedOperationException("Insert operation is not supported currently.");
+ }
+
+ @Override
+ public final int delete(Uri uri, String selection, String[] selectionArgs) {
+ throw new UnsupportedOperationException("Delete operation not supported currently.");
+ }
+
+ @Override
+ public final int update(Uri uri, ContentValues values, String selection,
+ String[] selectionArgs) {
+ throw new UnsupportedOperationException("Update operation is not supported currently.");
+ }
+
+ /**
+ * Return the list of the schedule information.
+ *
+ * @return a list of the {@link ScheduleInfo}.
+ */
+ public abstract ArrayList<ScheduleInfo> getScheduleInfoList();
+
+ /**
+ * Returns a bundle which contains a list of {@link ScheduleInfo} and data types:
+ * scheduleInfoList : ArrayList<ScheduleInfo>
+ */
+ @Override
+ public Bundle call(@NonNull String method, @Nullable String arg, @Nullable Bundle extras) {
+ final Bundle bundle = new Bundle();
+ if (METHOD_GENERATE_SCHEDULE_INFO_LIST.equals(method)) {
+ final ArrayList<ScheduleInfo> scheduleInfoList = filterInvalidData(
+ getScheduleInfoList());
+ if (scheduleInfoList != null) {
+ bundle.putParcelableArrayList(BUNDLE_SCHEDULE_INFO_LIST, scheduleInfoList);
+ }
+ }
+ return bundle;
+ }
+
+ /**
+ * To filter the invalid schedule info.
+ *
+ * @param scheduleInfoList The list of the {@link ScheduleInfo}.
+ * @return The valid list of the {@link ScheduleInfo}.
+ */
+ private ArrayList<ScheduleInfo> filterInvalidData(ArrayList<ScheduleInfo> scheduleInfoList) {
+ if (scheduleInfoList == null) {
+ Log.d(TAG, "package : " + getContext().getPackageName() + " has no scheduling data.");
+ return null;
+ }
+ // Dump invalid data in debug mode.
+ if (SystemProperties.getInt("ro.debuggable", 0) == 1) {
+ new Thread(() -> {
+ dumpInvalidData(scheduleInfoList);
+ }).start();
+ }
+ final List<ScheduleInfo> filteredList = scheduleInfoList
+ .stream()
+ .filter(scheduleInfo -> scheduleInfo.isValid())
+ .collect(Collectors.toList());
+
+ return new ArrayList<>(filteredList);
+ }
+
+ private void dumpInvalidData(ArrayList<ScheduleInfo> scheduleInfoList) {
+ Log.d(TAG, "package : " + getContext().getPackageName()
+ + " provided some scheduling data are invalid.");
+ scheduleInfoList
+ .stream()
+ .filter(scheduleInfo -> !scheduleInfo.isValid())
+ .forEach(scheduleInfo -> Log.d(TAG, scheduleInfo.toString()));
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
index e91096760180..8e4a982fde8c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
@@ -74,13 +74,6 @@ public class InfoMediaManager extends MediaManager {
refreshDevices();
}
- @VisibleForTesting
- String getControlCategoryByPackageName(String packageName) {
- //TODO(b/117129183): Use package name to get ControlCategory.
- //Since api not ready, return fixed ControlCategory for prototype.
- return "com.google.android.gms.cast.CATEGORY_CAST";
- }
-
@Override
public void stopScan() {
mRouterManager.unregisterCallback(mMediaRouterCallback);
@@ -192,5 +185,10 @@ public class InfoMediaManager extends MediaManager {
public void onRoutesChanged(List<MediaRoute2Info> routes) {
refreshDevices();
}
+
+ @Override
+ public void onRoutesRemoved(List<MediaRoute2Info> routes) {
+ refreshDevices();
+ }
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
index 984ab11a1a71..f8db70ae0963 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
@@ -16,6 +16,8 @@
package com.android.settingslib.media;
import android.app.Notification;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.text.TextUtils;
@@ -26,13 +28,13 @@ import androidx.annotation.IntDef;
import com.android.internal.annotations.VisibleForTesting;
import com.android.settingslib.bluetooth.BluetoothCallback;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
@@ -66,9 +68,16 @@ public class LocalMediaManager implements BluetoothCallback {
@VisibleForTesting
List<MediaDevice> mMediaDevices = new ArrayList<>();
@VisibleForTesting
+ List<MediaDevice> mDisconnectedMediaDevices = new ArrayList<>();
+ @VisibleForTesting
MediaDevice mPhoneDevice;
@VisibleForTesting
MediaDevice mCurrentConnectedDevice;
+ @VisibleForTesting
+ DeviceAttributeChangeCallback mDeviceAttributeChangeCallback =
+ new DeviceAttributeChangeCallback();
+ @VisibleForTesting
+ BluetoothAdapter mBluetoothAdapter;
/**
* Register to start receiving callbacks for MediaDevice events.
@@ -89,6 +98,7 @@ public class LocalMediaManager implements BluetoothCallback {
mPackageName = packageName;
mLocalBluetoothManager =
LocalBluetoothManager.getInstance(context, /* onInitCallback= */ null);
+ mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (mLocalBluetoothManager == null) {
Log.e(TAG, "Bluetooth is not supported on this device");
return;
@@ -164,7 +174,7 @@ public class LocalMediaManager implements BluetoothCallback {
}
void dispatchDeviceListUpdate() {
- Collections.sort(mMediaDevices, COMPARATOR);
+ //TODO(b/149260820): Use new rule to rank device once device type api is ready.
for (DeviceCallback callback : getCallbacks()) {
callback.onDeviceListUpdate(new ArrayList<>(mMediaDevices));
}
@@ -278,12 +288,44 @@ public class LocalMediaManager implements BluetoothCallback {
public void onDeviceListAdded(List<MediaDevice> devices) {
mMediaDevices.clear();
mMediaDevices.addAll(devices);
+ mMediaDevices.addAll(buildDisconnectedBluetoothDevice());
+
final MediaDevice infoMediaDevice = mInfoMediaManager.getCurrentConnectedDevice();
mCurrentConnectedDevice = infoMediaDevice != null
? infoMediaDevice : updateCurrentConnectedDevice();
dispatchDeviceListUpdate();
}
+ private List<MediaDevice> buildDisconnectedBluetoothDevice() {
+ for (MediaDevice device : mDisconnectedMediaDevices) {
+ ((BluetoothMediaDevice) device).getCachedDevice()
+ .unregisterCallback(mDeviceAttributeChangeCallback);
+ }
+ mDisconnectedMediaDevices.clear();
+ final List<BluetoothDevice> bluetoothDevices =
+ mBluetoothAdapter.getMostRecentlyConnectedDevices();
+ final CachedBluetoothDeviceManager cachedDeviceManager =
+ mLocalBluetoothManager.getCachedDeviceManager();
+
+ for (BluetoothDevice device : bluetoothDevices) {
+ final CachedBluetoothDevice cachedDevice =
+ cachedDeviceManager.findDevice(device);
+ if (cachedDevice != null) {
+ if (cachedDevice.getBondState() == BluetoothDevice.BOND_BONDED
+ && !cachedDevice.isConnected()) {
+ final MediaDevice mediaDevice = new BluetoothMediaDevice(mContext,
+ cachedDevice,
+ null, null, mPackageName);
+ if (!mMediaDevices.contains(mediaDevice)) {
+ cachedDevice.registerCallback(mDeviceAttributeChangeCallback);
+ mDisconnectedMediaDevices.add(mediaDevice);
+ }
+ }
+ }
+ }
+ return new ArrayList<>(mDisconnectedMediaDevices);
+ }
+
@Override
public void onDeviceRemoved(MediaDevice device) {
if (mMediaDevices.contains(device)) {
@@ -345,4 +387,17 @@ public class LocalMediaManager implements BluetoothCallback {
*/
default void onDeviceAttributesChanged() {};
}
+
+ /**
+ * This callback is for update {@link BluetoothMediaDevice} summary when
+ * {@link CachedBluetoothDevice} connection state is changed.
+ */
+ @VisibleForTesting
+ class DeviceAttributeChangeCallback implements CachedBluetoothDevice.Callback {
+
+ @Override
+ public void onDeviceAttributesChanged() {
+ dispatchDeviceAttributesChanged();
+ }
+ }
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
index 05f5fa0afc9e..8b815bfba19d 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
@@ -203,4 +203,46 @@ public class InfoMediaManagerTest {
assertThat(mInfoMediaManager.connectDeviceWithoutPackageName(device)).isFalse();
}
+
+ @Test
+ public void onRoutesRemoved_getAvailableRoutes_shouldAddMediaDevice() {
+ final MediaRoute2Info info = mock(MediaRoute2Info.class);
+ when(info.getId()).thenReturn(TEST_ID);
+ when(info.getClientPackageName()).thenReturn(TEST_PACKAGE_NAME);
+
+ final List<MediaRoute2Info> routes = new ArrayList<>();
+ routes.add(info);
+ when(mRouterManager.getAvailableRoutes(TEST_PACKAGE_NAME)).thenReturn(routes);
+
+ final MediaDevice mediaDevice = mInfoMediaManager.findMediaDevice(TEST_ID);
+ assertThat(mediaDevice).isNull();
+
+ mInfoMediaManager.mMediaRouterCallback.onRoutesRemoved(routes);
+
+ final MediaDevice infoDevice = mInfoMediaManager.mMediaDevices.get(0);
+ assertThat(infoDevice.getId()).isEqualTo(TEST_ID);
+ assertThat(mInfoMediaManager.getCurrentConnectedDevice()).isEqualTo(infoDevice);
+ assertThat(mInfoMediaManager.mMediaDevices).hasSize(routes.size());
+ }
+
+ @Test
+ public void onRoutesRemoved_buildAllRoutes_shouldAddMediaDevice() {
+ final MediaRoute2Info info = mock(MediaRoute2Info.class);
+ when(info.getId()).thenReturn(TEST_ID);
+ when(info.getClientPackageName()).thenReturn(TEST_PACKAGE_NAME);
+
+ final List<MediaRoute2Info> routes = new ArrayList<>();
+ routes.add(info);
+ when(mRouterManager.getAllRoutes()).thenReturn(routes);
+
+ final MediaDevice mediaDevice = mInfoMediaManager.findMediaDevice(TEST_ID);
+ assertThat(mediaDevice).isNull();
+
+ mInfoMediaManager.mPackageName = "";
+ mInfoMediaManager.mMediaRouterCallback.onRoutesChanged(routes);
+
+ final MediaDevice infoDevice = mInfoMediaManager.mMediaDevices.get(0);
+ assertThat(infoDevice.getId()).isEqualTo(TEST_ID);
+ assertThat(mInfoMediaManager.mMediaDevices).hasSize(routes.size());
+ }
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
index 3d67ba053a45..3611dfefbb7f 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
@@ -25,13 +25,17 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
import android.content.Context;
import com.android.settingslib.bluetooth.A2dpProfile;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
import com.android.settingslib.bluetooth.HearingAidProfile;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
+import com.android.settingslib.testutils.shadow.ShadowBluetoothAdapter;
import org.junit.Before;
import org.junit.Test;
@@ -40,11 +44,14 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadow.api.Shadow;
import java.util.ArrayList;
import java.util.List;
@RunWith(RobolectricTestRunner.class)
+@Config(shadows = {ShadowBluetoothAdapter.class})
public class LocalMediaManagerTest {
private static final String TEST_DEVICE_ID_1 = "device_id_1";
@@ -69,11 +76,15 @@ public class LocalMediaManagerTest {
private Context mContext;
private LocalMediaManager mLocalMediaManager;
+ private ShadowBluetoothAdapter mShadowBluetoothAdapter;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
+ final List<BluetoothDevice> bluetoothDevices = new ArrayList<>();
+ mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter());
+ mShadowBluetoothAdapter.setMostRecentlyConnectedDevices(bluetoothDevices);
when(mLocalBluetoothManager.getProfileManager()).thenReturn(mLocalProfileManager);
when(mLocalProfileManager.getA2dpProfile()).thenReturn(mA2dpProfile);
@@ -81,6 +92,7 @@ public class LocalMediaManagerTest {
mLocalMediaManager = new LocalMediaManager(mContext, mLocalBluetoothManager,
mInfoMediaManager, "com.test.packagename");
+ mLocalMediaManager.mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
}
@Test
@@ -419,4 +431,50 @@ public class LocalMediaManagerTest {
MediaDevice.MediaDeviceType.TYPE_BLUETOOTH_DEVICE);
assertThat(activeDevices).containsExactly(device3);
}
+
+ @Test
+ public void onDeviceAttributesChanged_shouldBeCalled() {
+ mLocalMediaManager.registerCallback(mCallback);
+
+ mLocalMediaManager.mDeviceAttributeChangeCallback.onDeviceAttributesChanged();
+
+ verify(mCallback).onDeviceAttributesChanged();
+ }
+
+ @Test
+ public void onDeviceListAdded_haveDisconnectedDevice_addDisconnectedDevice() {
+ final List<MediaDevice> devices = new ArrayList<>();
+ final MediaDevice device1 = mock(MediaDevice.class);
+ final MediaDevice device2 = mock(MediaDevice.class);
+ final MediaDevice device3 = mock(MediaDevice.class);
+ mLocalMediaManager.mPhoneDevice = mock(PhoneMediaDevice.class);
+ devices.add(device1);
+ devices.add(device2);
+ mLocalMediaManager.mMediaDevices.add(device3);
+ mLocalMediaManager.mMediaDevices.add(mLocalMediaManager.mPhoneDevice);
+
+ final List<BluetoothDevice> bluetoothDevices = new ArrayList<>();
+ final BluetoothDevice bluetoothDevice = mock(BluetoothDevice.class);
+ final CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class);
+ final CachedBluetoothDeviceManager cachedManager = mock(CachedBluetoothDeviceManager.class);
+ bluetoothDevices.add(bluetoothDevice);
+ mShadowBluetoothAdapter.setMostRecentlyConnectedDevices(bluetoothDevices);
+
+ when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(cachedManager);
+ when(cachedManager.findDevice(bluetoothDevice)).thenReturn(cachedDevice);
+ when(cachedDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+ when(cachedDevice.isConnected()).thenReturn(false);
+
+ when(device1.getId()).thenReturn(TEST_DEVICE_ID_1);
+ when(device2.getId()).thenReturn(TEST_DEVICE_ID_2);
+ when(device3.getId()).thenReturn(TEST_DEVICE_ID_3);
+ when(mLocalMediaManager.mPhoneDevice.getId()).thenReturn("test_phone_id");
+
+ assertThat(mLocalMediaManager.mMediaDevices).hasSize(2);
+ mLocalMediaManager.registerCallback(mCallback);
+ mLocalMediaManager.mMediaDeviceCallback.onDeviceListAdded(devices);
+
+ assertThat(mLocalMediaManager.mMediaDevices).hasSize(3);
+ verify(mCallback).onDeviceListUpdate(any());
+ }
}
diff --git a/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowBluetoothAdapter.java b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowBluetoothAdapter.java
index 906dba487734..015ce149a9c4 100644
--- a/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowBluetoothAdapter.java
+++ b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowBluetoothAdapter.java
@@ -17,6 +17,7 @@
package com.android.settingslib.testutils.shadow;
import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
@@ -29,6 +30,7 @@ import java.util.List;
public class ShadowBluetoothAdapter extends org.robolectric.shadows.ShadowBluetoothAdapter {
private List<Integer> mSupportedProfiles;
+ private List<BluetoothDevice> mMostRecentlyConnectedDevices;
private BluetoothProfile.ServiceListener mServiceListener;
@Implementation
@@ -50,4 +52,13 @@ public class ShadowBluetoothAdapter extends org.robolectric.shadows.ShadowBlueto
public void setSupportedProfiles(List<Integer> supportedProfiles) {
mSupportedProfiles = supportedProfiles;
}
+
+ @Implementation
+ protected List<BluetoothDevice> getMostRecentlyConnectedDevices() {
+ return mMostRecentlyConnectedDevices;
+ }
+
+ public void setMostRecentlyConnectedDevices(List<BluetoothDevice> list) {
+ mMostRecentlyConnectedDevices = list;
+ }
}
diff --git a/packages/SettingsProvider/res/values/strings.xml b/packages/SettingsProvider/res/values/strings.xml
index 378772750194..76bea3160afe 100644
--- a/packages/SettingsProvider/res/values/strings.xml
+++ b/packages/SettingsProvider/res/values/strings.xml
@@ -23,15 +23,10 @@
<!-- A notification is shown when the user's softap config has been changed due to underlying
hardware restrictions. This is the notifications's title.
[CHAR_LIMIT=NONE] -->
- <string name="wifi_softap_config_change">Changes to your hotspot settings</string>
+ <string name="wifi_softap_config_change">Hotspot settings have changed</string>
<!-- A notification is shown when the user's softap config has been changed due to underlying
hardware restrictions. This is the notification's summary message.
[CHAR_LIMIT=NONE] -->
- <string name="wifi_softap_config_change_summary">Your hotspot band has changed.</string>
-
- <!-- A notification is shown when the user's softap config has been changed due to underlying
- hardware restrictions. This is the notification's full message.
- [CHAR_LIMIT=NONE] -->
- <string name="wifi_softap_config_change_detailed">This device doesn\u2019t support your preference for 5GHz only. Instead, this device will use the 5GHz band when available.</string>
+ <string name="wifi_softap_config_change_summary">Tap to see details</string>
</resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/WifiSoftApConfigChangedNotifier.java b/packages/SettingsProvider/src/com/android/providers/settings/WifiSoftApConfigChangedNotifier.java
index 1ee5f9093421..ca841a5cdcd6 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/WifiSoftApConfigChangedNotifier.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/WifiSoftApConfigChangedNotifier.java
@@ -57,7 +57,6 @@ public class WifiSoftApConfigChangedNotifier {
Resources resources = context.getResources();
CharSequence title = resources.getText(R.string.wifi_softap_config_change);
CharSequence contentSummary = resources.getText(R.string.wifi_softap_config_change_summary);
- CharSequence content = resources.getText(R.string.wifi_softap_config_change_detailed);
int color = resources.getColor(
android.R.color.system_notification_accent_color, context.getTheme());
@@ -73,7 +72,6 @@ public class WifiSoftApConfigChangedNotifier {
.setLocalOnly(true)
.setColor(color)
.setStyle(new Notification.BigTextStyle()
- .bigText(content)
.setBigContentTitle(title)
.setSummaryText(contentSummary))
.setAutoCancel(true)
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index cc2c92b4c7eb..d821050ac5b4 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -253,7 +253,8 @@
<!-- Permission required for CTS test - ShortcutManagerUsageTest -->
<uses-permission android:name="android.permission.ACCESS_SHORTCUTS"/>
- <!-- Permission required for CTS test - UsageStatsTest -->
+ <!-- Permissions required for CTS test - UsageStatsTest -->
+ <uses-permission android:name="android.permission.MANAGE_NOTIFICATIONS"/>
<uses-permission android:name="android.permission.ACCESS_LOCUS_ID_USAGE_STATS"/>
<!-- Permissions required to test ambient display. -->
diff --git a/packages/SystemUI/src/com/android/systemui/SysUIToast.java b/packages/SystemUI/src/com/android/systemui/SysUIToast.java
index 0f7f1bebae57..023b74b9c07e 100644
--- a/packages/SystemUI/src/com/android/systemui/SysUIToast.java
+++ b/packages/SystemUI/src/com/android/systemui/SysUIToast.java
@@ -19,7 +19,6 @@ import static android.widget.Toast.Duration;
import android.annotation.StringRes;
import android.content.Context;
-import android.view.WindowManager;
import android.widget.Toast;
public class SysUIToast {
@@ -29,10 +28,7 @@ public class SysUIToast {
}
public static Toast makeText(Context context, CharSequence text, @Duration int duration) {
- Toast toast = Toast.makeText(context, text, duration);
- toast.getWindowParams().privateFlags |=
- WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
- return toast;
+ return Toast.makeText(context, text, duration);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java
index 68b05e358786..9de10406a822 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java
@@ -16,6 +16,7 @@
package com.android.systemui.biometrics;
+import android.annotation.NonNull;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.hardware.biometrics.BiometricPrompt;
@@ -33,6 +34,8 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
+import androidx.annotation.Nullable;
+
import com.android.internal.widget.LockPatternUtils;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
@@ -126,18 +129,18 @@ public abstract class AuthCredentialView extends LinearLayout {
mHandler.postDelayed(mClearErrorRunnable, ERROR_DURATION_MS);
}
- private void setTextOrHide(TextView view, String string) {
- if (TextUtils.isEmpty(string)) {
+ private void setTextOrHide(TextView view, CharSequence text) {
+ if (TextUtils.isEmpty(text)) {
view.setVisibility(View.GONE);
} else {
- view.setText(string);
+ view.setText(text);
}
Utils.notifyAccessibilityContentChanged(mAccessibilityManager, this);
}
- private void setText(TextView view, String string) {
- view.setText(string);
+ private void setText(TextView view, CharSequence text) {
+ view.setText(text);
}
void setEffectiveUserId(int effectiveUserId) {
@@ -173,11 +176,9 @@ public abstract class AuthCredentialView extends LinearLayout {
protected void onAttachedToWindow() {
super.onAttachedToWindow();
- setText(mTitleView, mBiometricPromptBundle.getString(BiometricPrompt.KEY_TITLE));
- setTextOrHide(mSubtitleView,
- mBiometricPromptBundle.getString(BiometricPrompt.KEY_SUBTITLE));
- setTextOrHide(mDescriptionView,
- mBiometricPromptBundle.getString(BiometricPrompt.KEY_DESCRIPTION));
+ setText(mTitleView, getTitle(mBiometricPromptBundle));
+ setTextOrHide(mSubtitleView, getSubtitle(mBiometricPromptBundle));
+ setTextOrHide(mDescriptionView, getDescription(mBiometricPromptBundle));
final boolean isManagedProfile = Utils.isManagedProfile(mContext, mEffectiveUserId);
final Drawable image;
@@ -279,4 +280,28 @@ public abstract class AuthCredentialView extends LinearLayout {
}
}
}
+
+ @Nullable
+ private static CharSequence getTitle(@NonNull Bundle bundle) {
+ final CharSequence credentialTitle =
+ bundle.getCharSequence(BiometricPrompt.KEY_DEVICE_CREDENTIAL_TITLE);
+ return credentialTitle != null ? credentialTitle
+ : bundle.getCharSequence(BiometricPrompt.KEY_TITLE);
+ }
+
+ @Nullable
+ private static CharSequence getSubtitle(@NonNull Bundle bundle) {
+ final CharSequence credentialSubtitle =
+ bundle.getCharSequence(BiometricPrompt.KEY_DEVICE_CREDENTIAL_SUBTITLE);
+ return credentialSubtitle != null ? credentialSubtitle
+ : bundle.getCharSequence(BiometricPrompt.KEY_SUBTITLE);
+ }
+
+ @Nullable
+ private static CharSequence getDescription(@NonNull Bundle bundle) {
+ final CharSequence credentialDescription =
+ bundle.getCharSequence(BiometricPrompt.KEY_DEVICE_CREDENTIAL_DESCRIPTION);
+ return credentialDescription != null ? credentialDescription
+ : bundle.getCharSequence(BiometricPrompt.KEY_DESCRIPTION);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt b/packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt
index ab8de263765e..5c1d332df7a7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt
@@ -105,8 +105,8 @@ class QSLogger @Inject constructor(
fun logTileUpdated(tileSpec: String, state: QSTile.State) {
log(VERBOSE, {
str1 = tileSpec
- str2 = state.label.toString()
- str3 = state.icon.toString()
+ str2 = state.label?.toString()
+ str3 = state.icon?.toString()
int1 = state.state
if (state is QSTile.SignalState) {
bool1 = true
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 573ea4dd85de..9f64b397e9d9 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -352,6 +352,8 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
try {
Intent intent = new Intent(AccessibilityManager.ACTION_CHOOSE_ACCESSIBILITY_BUTTON);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ intent.putExtra(AccessibilityManager.EXTRA_SHORTCUT_TYPE,
+ AccessibilityManager.ACCESSIBILITY_BUTTON);
mContext.startActivityAsUser(intent, UserHandle.CURRENT);
} finally {
Binder.restoreCallingIdentity(token);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt
index 4f27c0f04c3f..5b4a927bb8f0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt
@@ -26,26 +26,23 @@ import android.content.Context
import android.content.DialogInterface
import android.graphics.Color
import android.graphics.PixelFormat
-import android.graphics.drawable.Drawable
import android.graphics.drawable.ColorDrawable
+import android.graphics.drawable.Drawable
import android.util.Log
import android.view.Gravity
import android.view.View
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
import android.view.Window
-import android.view.WindowInsets.Type
import android.view.WindowInsets.Type.statusBars
import android.view.WindowManager
import android.widget.TextView
import com.android.internal.annotations.VisibleForTesting
-
import com.android.systemui.R
-
import javax.inject.Inject
import javax.inject.Singleton
-const val TAG = "ChannelDialogController"
+private const val TAG = "ChannelDialogController"
/**
* ChannelEditorDialogController is the controller for the dialog half-shelf
@@ -149,9 +146,9 @@ class ChannelEditorDialogController @Inject constructor(
val channels = groupList
.flatMap { group ->
group.channels.asSequence().filterNot { channel ->
- channel.isImportanceLockedByOEM
- || channel.importance == IMPORTANCE_NONE
- || channel.isImportanceLockedByCriticalDeviceFunction
+ channel.isImportanceLockedByOEM ||
+ channel.importance == IMPORTANCE_NONE ||
+ channel.isImportanceLockedByCriticalDeviceFunction
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifBindPipeline.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifBindPipeline.java
index e2513dac44d8..d744fc398d7a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifBindPipeline.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifBindPipeline.java
@@ -74,11 +74,15 @@ import javax.inject.Singleton;
@Singleton
public final class NotifBindPipeline {
private final Map<NotificationEntry, BindEntry> mBindEntries = new ArrayMap<>();
+ private final NotifBindPipelineLogger mLogger;
private BindStage mStage;
@Inject
- NotifBindPipeline(CommonNotifCollection collection) {
+ NotifBindPipeline(
+ CommonNotifCollection collection,
+ NotifBindPipelineLogger logger) {
collection.addCollectionListener(mCollectionListener);
+ mLogger = logger;
}
/**
@@ -86,6 +90,8 @@ public final class NotifBindPipeline {
*/
public void setStage(
BindStage stage) {
+ mLogger.logStageSet(stage.getClass().getName());
+
mStage = stage;
mStage.setBindRequestListener(this::onBindRequested);
}
@@ -96,6 +102,8 @@ public final class NotifBindPipeline {
public void manageRow(
@NonNull NotificationEntry entry,
@NonNull ExpandableNotificationRow row) {
+ mLogger.logManagedRow(entry.getKey());
+
final BindEntry bindEntry = getBindEntry(entry);
bindEntry.row = row;
if (bindEntry.invalidated) {
@@ -130,6 +138,8 @@ public final class NotifBindPipeline {
* callbacks when the run finishes. If a run is already in progress, it is restarted.
*/
private void startPipeline(NotificationEntry entry) {
+ mLogger.logStartPipeline(entry.getKey());
+
if (mStage == null) {
throw new IllegalStateException("No stage was ever set on the pipeline");
}
@@ -147,10 +157,11 @@ public final class NotifBindPipeline {
private void onPipelineComplete(NotificationEntry entry) {
final BindEntry bindEntry = getBindEntry(entry);
+ final Set<BindCallback> callbacks = bindEntry.callbacks;
- bindEntry.invalidated = false;
+ mLogger.logFinishedPipeline(entry.getKey(), callbacks.size());
- final Set<BindCallback> callbacks = bindEntry.callbacks;
+ bindEntry.invalidated = false;
for (BindCallback cb : callbacks) {
cb.onBindFinished(entry);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifBindPipelineLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifBindPipelineLogger.kt
new file mode 100644
index 000000000000..2717d7ad143b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifBindPipelineLogger.kt
@@ -0,0 +1,61 @@
+/*
+ * 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 com.android.systemui.statusbar.notification.row
+
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel.INFO
+import com.android.systemui.log.dagger.NotificationLog
+import javax.inject.Inject
+
+class NotifBindPipelineLogger @Inject constructor(
+ @NotificationLog private val buffer: LogBuffer
+) {
+ fun logStageSet(stageName: String) {
+ buffer.log(TAG, INFO, {
+ str1 = stageName
+ }, {
+ "Stage set: $str1"
+ })
+ }
+
+ fun logManagedRow(notifKey: String) {
+ buffer.log(TAG, INFO, {
+ str1 = notifKey
+ }, {
+ "Row set for notif: $str1"
+ })
+ }
+
+ fun logStartPipeline(notifKey: String) {
+ buffer.log(TAG, INFO, {
+ str1 = notifKey
+ }, {
+ "Start pipeline for notif: $str1"
+ })
+ }
+
+ fun logFinishedPipeline(notifKey: String, numCallbacks: Int) {
+ buffer.log(TAG, INFO, {
+ str1 = notifKey
+ int1 = numCallbacks
+ }, {
+ "Finished pipeline for notif $str1 with $int1 callbacks"
+ })
+ }
+}
+
+private const val TAG = "NotifBindPipeline" \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindParams.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindParams.java
index 5170d0b85b17..88ed0bb37d0d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindParams.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindParams.java
@@ -157,6 +157,15 @@ public final class RowContentBindParams {
return mViewsNeedReinflation;
}
+ @Override
+ public String toString() {
+ return String.format("RowContentBindParams[mContentViews=%x mDirtyContentViews=%x "
+ + "mUseLowPriority=%b mUseChildInGroup=%b mUseIncreasedHeight=%b "
+ + "mUseIncreasedHeadsUpHeight=%b mViewsNeedReinflation=%b]",
+ mContentViews, mDirtyContentViews, mUseLowPriority, mUseChildInGroup,
+ mUseIncreasedHeight, mUseIncreasedHeadsUpHeight, mViewsNeedReinflation);
+ }
+
/**
* Content views that should be inflated by default for all notifications.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStage.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStage.java
index f78324596fb4..c632f3eb22a2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStage.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStage.java
@@ -38,13 +38,16 @@ import javax.inject.Singleton;
public class RowContentBindStage extends BindStage<RowContentBindParams> {
private final NotificationRowContentBinder mBinder;
private final NotifInflationErrorManager mNotifInflationErrorManager;
+ private final RowContentBindStageLogger mLogger;
@Inject
RowContentBindStage(
NotificationRowContentBinder binder,
- NotifInflationErrorManager errorManager) {
+ NotifInflationErrorManager errorManager,
+ RowContentBindStageLogger logger) {
mBinder = binder;
mNotifInflationErrorManager = errorManager;
+ mLogger = logger;
}
@Override
@@ -54,6 +57,8 @@ public class RowContentBindStage extends BindStage<RowContentBindParams> {
@NonNull StageCallback callback) {
RowContentBindParams params = getStageParams(entry);
+ mLogger.logStageParams(entry.getKey(), params.toString());
+
// Resolve content to bind/unbind.
@InflationFlag int inflationFlags = params.getContentViews();
@InflationFlag int invalidatedFlags = params.getDirtyContentViews();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStageLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStageLogger.kt
new file mode 100644
index 000000000000..29cce3375c8a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStageLogger.kt
@@ -0,0 +1,37 @@
+/*
+ * 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 com.android.systemui.statusbar.notification.row
+
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel.INFO
+import com.android.systemui.log.dagger.NotificationLog
+import javax.inject.Inject
+
+class RowContentBindStageLogger @Inject constructor(
+ @NotificationLog private val buffer: LogBuffer
+) {
+ fun logStageParams(notifKey: String, stageParams: String) {
+ buffer.log(TAG, INFO, {
+ str1 = notifKey
+ str2 = stageParams
+ }, {
+ "Invalidated notif $str1 with params: \n$str2"
+ })
+ }
+}
+
+private const val TAG = "RowContentBindStage" \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 3f5215e1a639..fd8c71b48417 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -956,6 +956,8 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
private boolean onAccessibilityLongClick(View v) {
Intent intent = new Intent(AccessibilityManager.ACTION_CHOOSE_ACCESSIBILITY_BUTTON);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ intent.putExtra(AccessibilityManager.EXTRA_SHORTCUT_TYPE,
+ AccessibilityManager.ACCESSIBILITY_BUTTON);
v.getContext().startActivityAsUser(intent, UserHandle.CURRENT);
return true;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifBindPipelineTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifBindPipelineTest.java
index 408bba48d422..6408f7a38133 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifBindPipelineTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifBindPipelineTest.java
@@ -59,7 +59,7 @@ public class NotifBindPipelineTest extends SysuiTestCase {
MockitoAnnotations.initMocks(this);
CommonNotifCollection collection = mock(CommonNotifCollection.class);
- mBindPipeline = new NotifBindPipeline(collection);
+ mBindPipeline = new NotifBindPipeline(collection, mock(NotifBindPipelineLogger.class));
mBindPipeline.setStage(mStage);
ArgumentCaptor<NotifCollectionListener> collectionListenerCaptor =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
index fd5512d62968..7a1bd052a336 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
@@ -111,11 +111,13 @@ public class NotificationTestHelper {
mock(NotifRemoteViewCache.class),
mock(NotificationRemoteInputManager.class));
contentBinder.setInflateSynchronously(true);
- mBindStage = new RowContentBindStage(contentBinder, mock(NotifInflationErrorManager.class));
+ mBindStage = new RowContentBindStage(contentBinder,
+ mock(NotifInflationErrorManager.class),
+ mock(RowContentBindStageLogger.class));
CommonNotifCollection collection = mock(CommonNotifCollection.class);
- mBindPipeline = new NotifBindPipeline(collection);
+ mBindPipeline = new NotifBindPipeline(collection, mock(NotifBindPipelineLogger.class));
mBindPipeline.setStage(mBindStage);
ArgumentCaptor<NotifCollectionListener> collectionListenerCaptor =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/RowContentBindStageTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/RowContentBindStageTest.java
index d9fe6551ba1c..0f2482ce9c4e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/RowContentBindStageTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/RowContentBindStageTest.java
@@ -60,8 +60,10 @@ public class RowContentBindStageTest extends SysuiTestCase {
public void setUp() {
MockitoAnnotations.initMocks(this);
- mRowContentBindStage = new RowContentBindStage(mBinder,
- mock(NotifInflationErrorManager.class));
+ mRowContentBindStage = new RowContentBindStage(
+ mBinder,
+ mock(NotifInflationErrorManager.class),
+ mock(RowContentBindStageLogger.class));
mRowContentBindStage.createStageParams(mEntry);
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
index 75ec4b04eeed..6c8aaf465c44 100644
--- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
@@ -16,8 +16,9 @@
package com.android.server.accessibility;
-import static android.accessibilityservice.AccessibilityService.KEY_ACCESSIBILITY_SCREENSHOT_COLORSPACE_ID;
+import static android.accessibilityservice.AccessibilityService.KEY_ACCESSIBILITY_SCREENSHOT_COLORSPACE;
import static android.accessibilityservice.AccessibilityService.KEY_ACCESSIBILITY_SCREENSHOT_HARDWAREBUFFER;
+import static android.accessibilityservice.AccessibilityService.KEY_ACCESSIBILITY_SCREENSHOT_TIMESTAMP;
import static android.accessibilityservice.AccessibilityServiceInfo.DEFAULT;
import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
import static android.view.accessibility.AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS;
@@ -39,6 +40,7 @@ import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
import android.graphics.GraphicBuffer;
+import android.graphics.ParcelableColorSpace;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Region;
@@ -1021,13 +1023,15 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
final GraphicBuffer graphicBuffer = screenshotBuffer.getGraphicBuffer();
final HardwareBuffer hardwareBuffer =
HardwareBuffer.createFromGraphicBuffer(graphicBuffer);
- final int colorSpaceId = screenshotBuffer.getColorSpace().getId();
+ final ParcelableColorSpace colorSpace =
+ new ParcelableColorSpace(screenshotBuffer.getColorSpace());
// Send back the result.
final Bundle payload = new Bundle();
payload.putParcelable(KEY_ACCESSIBILITY_SCREENSHOT_HARDWAREBUFFER,
hardwareBuffer);
- payload.putInt(KEY_ACCESSIBILITY_SCREENSHOT_COLORSPACE_ID, colorSpaceId);
+ payload.putParcelable(KEY_ACCESSIBILITY_SCREENSHOT_COLORSPACE, colorSpace);
+ payload.putLong(KEY_ACCESSIBILITY_SCREENSHOT_TIMESTAMP, SystemClock.uptimeMillis());
callback.sendResult(payload);
}, null).recycleOnUse());
} finally {
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java b/services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java
index b74be7e3f345..a3b5a3e2dcf9 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java
@@ -17,6 +17,7 @@
package com.android.server.accessibility.gestures;
import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_DOUBLE_TAP;
+import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_DOUBLE_TAP_AND_HOLD;
import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_SINGLE_TAP;
import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_SWIPE_DOWN;
import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_SWIPE_LEFT;
@@ -24,6 +25,7 @@ import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER
import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_SWIPE_UP;
import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_TRIPLE_TAP;
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_DOUBLE_TAP;
+import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_DOUBLE_TAP_AND_HOLD;
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SINGLE_TAP;
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SWIPE_DOWN;
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SWIPE_LEFT;
@@ -31,6 +33,7 @@ import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SWIPE_UP;
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_TRIPLE_TAP;
import static android.accessibilityservice.AccessibilityService.GESTURE_4_FINGER_DOUBLE_TAP;
+import static android.accessibilityservice.AccessibilityService.GESTURE_4_FINGER_DOUBLE_TAP_AND_HOLD;
import static android.accessibilityservice.AccessibilityService.GESTURE_4_FINGER_SINGLE_TAP;
import static android.accessibilityservice.AccessibilityService.GESTURE_4_FINGER_SWIPE_DOWN;
import static android.accessibilityservice.AccessibilityService.GESTURE_4_FINGER_SWIPE_LEFT;
@@ -132,6 +135,9 @@ class GestureManifold implements GestureMatcher.StateChangeListener {
mMultiFingerGestures.add(
new MultiFingerMultiTap(mContext, 2, 2, GESTURE_2_FINGER_DOUBLE_TAP, this));
mMultiFingerGestures.add(
+ new MultiFingerMultiTapAndHold(
+ mContext, 2, 2, GESTURE_2_FINGER_DOUBLE_TAP_AND_HOLD, this));
+ mMultiFingerGestures.add(
new MultiFingerMultiTap(mContext, 2, 3, GESTURE_2_FINGER_TRIPLE_TAP, this));
// Three-finger taps.
mMultiFingerGestures.add(
@@ -139,6 +145,9 @@ class GestureManifold implements GestureMatcher.StateChangeListener {
mMultiFingerGestures.add(
new MultiFingerMultiTap(mContext, 3, 2, GESTURE_3_FINGER_DOUBLE_TAP, this));
mMultiFingerGestures.add(
+ new MultiFingerMultiTapAndHold(
+ mContext, 3, 2, GESTURE_3_FINGER_DOUBLE_TAP_AND_HOLD, this));
+ mMultiFingerGestures.add(
new MultiFingerMultiTap(mContext, 3, 3, GESTURE_3_FINGER_TRIPLE_TAP, this));
// Four-finger taps.
mMultiFingerGestures.add(
@@ -146,6 +155,9 @@ class GestureManifold implements GestureMatcher.StateChangeListener {
mMultiFingerGestures.add(
new MultiFingerMultiTap(mContext, 4, 2, GESTURE_4_FINGER_DOUBLE_TAP, this));
mMultiFingerGestures.add(
+ new MultiFingerMultiTapAndHold(
+ mContext, 4, 2, GESTURE_4_FINGER_DOUBLE_TAP_AND_HOLD, this));
+ mMultiFingerGestures.add(
new MultiFingerMultiTap(mContext, 4, 3, GESTURE_4_FINGER_TRIPLE_TAP, this));
// Two-finger swipes.
mMultiFingerGestures.add(
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerMultiTap.java b/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerMultiTap.java
index 20def6154977..e5340f10dc4c 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerMultiTap.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerMultiTap.java
@@ -42,10 +42,10 @@ class MultiFingerMultiTap extends GestureMatcher {
// The acceptable distance the pointer can move and still count as a tap.
private int mTouchSlop;
// A tap counts when target number of fingers are down and up once.
- private int mCompletedTapCount;
+ protected int mCompletedTapCount;
// A flag set to true when target number of fingers have touched down at once before.
// Used to indicate what next finger action should be. Down when false and lift when true.
- private boolean mIsTargetFingerCountReached = false;
+ protected boolean mIsTargetFingerCountReached = false;
// Store initial down points for slop checking and update when next down if is inside slop.
private PointF[] mBases;
// The points in bases that already have slop checked when onDown or onPointerDown.
@@ -56,7 +56,11 @@ class MultiFingerMultiTap extends GestureMatcher {
* @throws IllegalArgumentException if <code>fingers<code/> is less than 2
* or <code>taps<code/> is not positive.
*/
- MultiFingerMultiTap(Context context, int fingers, int taps, int gestureId,
+ MultiFingerMultiTap(
+ Context context,
+ int fingers,
+ int taps,
+ int gestureId,
GestureMatcher.StateChangeListener listener) {
super(gestureId, new Handler(context.getMainLooper()), listener);
Preconditions.checkArgument(fingers >= 2);
@@ -117,8 +121,7 @@ class MultiFingerMultiTap extends GestureMatcher {
cancelAfterDoubleTapTimeout(event, rawEvent, policyFlags);
final PointF nearest = findNearestPoint(rawEvent, mTouchSlop, false);
- if ((getState() == STATE_GESTURE_STARTED || getState() == STATE_CLEAR)
- && null != nearest) {
+ if ((getState() == STATE_GESTURE_STARTED || getState() == STATE_CLEAR) && null != nearest) {
// Increase current tap count when the user have all fingers lifted
// within the tap timeout since the target number of fingers are down.
if (mIsTargetFingerCountReached) {
@@ -169,8 +172,7 @@ class MultiFingerMultiTap extends GestureMatcher {
} else {
nearest = findNearestPoint(rawEvent, mDoubleTapSlop, true);
}
- if ((getState() == STATE_GESTURE_STARTED || getState() == STATE_CLEAR)
- && nearest != null) {
+ if ((getState() == STATE_GESTURE_STARTED || getState() == STATE_CLEAR) && nearest != null) {
// The user have all fingers down within the tap timeout since first finger down,
// setting the timeout for fingers to be lifted.
if (currentFingerCount == mTargetFingerCount) {
@@ -227,11 +229,11 @@ class MultiFingerMultiTap extends GestureMatcher {
}
/**
- * Find the nearest location to the given event in the bases.
- * If no one found, it could be not inside {@code slop}, filtered or empty bases.
- * When {@code filterMatched} is true, if the location of given event matches one of the points
- * in {@link #mExcludedPointsForDownSlopChecked} it would be ignored. Otherwise, the location
- * will be added to {@link #mExcludedPointsForDownSlopChecked}.
+ * Find the nearest location to the given event in the bases. If no one found, it could be not
+ * inside {@code slop}, filtered or empty bases. When {@code filterMatched} is true, if the
+ * location of given event matches one of the points in {@link
+ * #mExcludedPointsForDownSlopChecked} it would be ignored. Otherwise, the location will be
+ * added to {@link #mExcludedPointsForDownSlopChecked}.
*
* @param event to find nearest point in bases.
* @param slop to check to the given location of the event.
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerMultiTapAndHold.java b/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerMultiTapAndHold.java
new file mode 100644
index 000000000000..7824fd902c9b
--- /dev/null
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerMultiTapAndHold.java
@@ -0,0 +1,71 @@
+/*
+ * 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 com.android.server.accessibility.gestures;
+
+import android.content.Context;
+import android.view.MotionEvent;
+
+/**
+ * This class matches gestures of the form multi-finger multi-tap and hold. The number of fingers
+ * and taps for each instance is specified in the constructor.
+ */
+class MultiFingerMultiTapAndHold extends MultiFingerMultiTap {
+
+ MultiFingerMultiTapAndHold(
+ Context context,
+ int fingers,
+ int taps,
+ int gestureId,
+ GestureMatcher.StateChangeListener listener) {
+ super(context, fingers, taps, gestureId, listener);
+ }
+
+ @Override
+ protected void onPointerDown(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+ super.onPointerDown(event, rawEvent, policyFlags);
+ if (mIsTargetFingerCountReached && mCompletedTapCount + 1 == mTargetTapCount) {
+ completeAfterLongPressTimeout(event, rawEvent, policyFlags);
+ }
+ }
+
+ @Override
+ protected void onUp(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+ if (mCompletedTapCount + 1 == mTargetFingerCount) {
+ // Calling super.onUp would complete the multi-tap version of this.
+ cancelGesture(event, rawEvent, policyFlags);
+ } else {
+ super.onUp(event, rawEvent, policyFlags);
+ cancelAfterDoubleTapTimeout(event, rawEvent, policyFlags);
+ }
+ }
+
+ @Override
+ public String getGestureName() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append(mTargetFingerCount).append("-Finger ");
+ if (mTargetTapCount == 1) {
+ builder.append("Single");
+ } else if (mTargetTapCount == 2) {
+ builder.append("Double");
+ } else if (mTargetTapCount == 3) {
+ builder.append("Triple");
+ } else if (mTargetTapCount > 3) {
+ builder.append(mTargetTapCount);
+ }
+ return builder.append(" Tap and hold").toString();
+ }
+}
diff --git a/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java b/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
index 4f49fb7578a1..0b3899d15993 100644
--- a/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
+++ b/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
@@ -16,6 +16,8 @@
package com.android.server.appprediction;
+import static android.provider.DeviceConfig.NAMESPACE_SYSTEMUI;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AppGlobals;
@@ -30,12 +32,17 @@ import android.content.pm.ParceledListSlice;
import android.content.pm.ServiceInfo;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
+import android.provider.DeviceConfig;
import android.service.appprediction.AppPredictionService;
+import android.service.appprediction.IPredictionService;
import android.util.ArrayMap;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.infra.AbstractRemoteService;
+import com.android.server.LocalServices;
import com.android.server.infra.AbstractPerUserSystemService;
+import com.android.server.people.PeopleServiceInternal;
import java.util.function.Consumer;
@@ -47,6 +54,8 @@ public class AppPredictionPerUserService extends
implements RemoteAppPredictionService.RemoteAppPredictionServiceCallbacks {
private static final String TAG = AppPredictionPerUserService.class.getSimpleName();
+ private static final String PREDICT_USING_PEOPLE_SERVICE_PREFIX =
+ "predict_using_people_service_";
@Nullable
@GuardedBy("mLock")
@@ -104,14 +113,16 @@ public class AppPredictionPerUserService extends
@GuardedBy("mLock")
public void onCreatePredictionSessionLocked(@NonNull AppPredictionContext context,
@NonNull AppPredictionSessionId sessionId) {
- final RemoteAppPredictionService service = getRemoteServiceLocked();
- if (service != null) {
- service.onCreatePredictionSession(context, sessionId);
-
- if (!mSessionInfos.containsKey(sessionId)) {
- mSessionInfos.put(sessionId, new AppPredictionSessionInfo(sessionId, context,
- this::removeAppPredictionSessionInfo));
- }
+ if (!mSessionInfos.containsKey(sessionId)) {
+ mSessionInfos.put(sessionId, new AppPredictionSessionInfo(sessionId, context,
+ DeviceConfig.getBoolean(NAMESPACE_SYSTEMUI,
+ PREDICT_USING_PEOPLE_SERVICE_PREFIX + context.getUiSurface(), false),
+ this::removeAppPredictionSessionInfo));
+ }
+ final boolean serviceExists = resolveService(sessionId, s ->
+ s.onCreatePredictionSession(context, sessionId));
+ if (!serviceExists) {
+ mSessionInfos.remove(sessionId);
}
}
@@ -121,10 +132,7 @@ public class AppPredictionPerUserService extends
@GuardedBy("mLock")
public void notifyAppTargetEventLocked(@NonNull AppPredictionSessionId sessionId,
@NonNull AppTargetEvent event) {
- final RemoteAppPredictionService service = getRemoteServiceLocked();
- if (service != null) {
- service.notifyAppTargetEvent(sessionId, event);
- }
+ resolveService(sessionId, s -> s.notifyAppTargetEvent(sessionId, event));
}
/**
@@ -133,10 +141,8 @@ public class AppPredictionPerUserService extends
@GuardedBy("mLock")
public void notifyLaunchLocationShownLocked(@NonNull AppPredictionSessionId sessionId,
@NonNull String launchLocation, @NonNull ParceledListSlice targetIds) {
- final RemoteAppPredictionService service = getRemoteServiceLocked();
- if (service != null) {
- service.notifyLaunchLocationShown(sessionId, launchLocation, targetIds);
- }
+ resolveService(sessionId, s ->
+ s.notifyLaunchLocationShown(sessionId, launchLocation, targetIds));
}
/**
@@ -145,10 +151,7 @@ public class AppPredictionPerUserService extends
@GuardedBy("mLock")
public void sortAppTargetsLocked(@NonNull AppPredictionSessionId sessionId,
@NonNull ParceledListSlice targets, @NonNull IPredictionCallback callback) {
- final RemoteAppPredictionService service = getRemoteServiceLocked();
- if (service != null) {
- service.sortAppTargets(sessionId, targets, callback);
- }
+ resolveService(sessionId, s -> s.sortAppTargets(sessionId, targets, callback));
}
/**
@@ -157,14 +160,11 @@ public class AppPredictionPerUserService extends
@GuardedBy("mLock")
public void registerPredictionUpdatesLocked(@NonNull AppPredictionSessionId sessionId,
@NonNull IPredictionCallback callback) {
- final RemoteAppPredictionService service = getRemoteServiceLocked();
- if (service != null) {
- service.registerPredictionUpdates(sessionId, callback);
-
- AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId);
- if (sessionInfo != null) {
- sessionInfo.addCallbackLocked(callback);
- }
+ final boolean serviceExists = resolveService(sessionId, s ->
+ s.registerPredictionUpdates(sessionId, callback));
+ final AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId);
+ if (serviceExists && sessionInfo != null) {
+ sessionInfo.addCallbackLocked(callback);
}
}
@@ -174,14 +174,11 @@ public class AppPredictionPerUserService extends
@GuardedBy("mLock")
public void unregisterPredictionUpdatesLocked(@NonNull AppPredictionSessionId sessionId,
@NonNull IPredictionCallback callback) {
- final RemoteAppPredictionService service = getRemoteServiceLocked();
- if (service != null) {
- service.unregisterPredictionUpdates(sessionId, callback);
-
- AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId);
- if (sessionInfo != null) {
- sessionInfo.removeCallbackLocked(callback);
- }
+ final boolean serviceExists = resolveService(sessionId, s ->
+ s.unregisterPredictionUpdates(sessionId, callback));
+ final AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId);
+ if (serviceExists && sessionInfo != null) {
+ sessionInfo.removeCallbackLocked(callback);
}
}
@@ -190,10 +187,7 @@ public class AppPredictionPerUserService extends
*/
@GuardedBy("mLock")
public void requestPredictionUpdateLocked(@NonNull AppPredictionSessionId sessionId) {
- final RemoteAppPredictionService service = getRemoteServiceLocked();
- if (service != null) {
- service.requestPredictionUpdate(sessionId);
- }
+ resolveService(sessionId, s -> s.requestPredictionUpdate(sessionId));
}
/**
@@ -201,14 +195,11 @@ public class AppPredictionPerUserService extends
*/
@GuardedBy("mLock")
public void onDestroyPredictionSessionLocked(@NonNull AppPredictionSessionId sessionId) {
- final RemoteAppPredictionService service = getRemoteServiceLocked();
- if (service != null) {
- service.onDestroyPredictionSession(sessionId);
-
- AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId);
- if (sessionInfo != null) {
- sessionInfo.destroy();
- }
+ final boolean serviceExists = resolveService(sessionId, s ->
+ s.onDestroyPredictionSession(sessionId));
+ final AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId);
+ if (serviceExists && sessionInfo != null) {
+ sessionInfo.destroy();
}
}
@@ -312,6 +303,33 @@ public class AppPredictionPerUserService extends
@GuardedBy("mLock")
@Nullable
+ protected boolean resolveService(@NonNull final AppPredictionSessionId sessionId,
+ @NonNull final AbstractRemoteService.AsyncRequest<IPredictionService> cb) {
+ final AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId);
+ if (sessionInfo == null) return false;
+ if (sessionInfo.mUsesPeopleService) {
+ final IPredictionService service =
+ LocalServices.getService(PeopleServiceInternal.class);
+ if (service != null) {
+ try {
+ cb.run(service);
+ } catch (RemoteException e) {
+ // Shouldn't happen.
+ Slog.w(TAG, "Failed to invoke service:" + service, e);
+ }
+ }
+ return service != null;
+ } else {
+ final RemoteAppPredictionService service = getRemoteServiceLocked();
+ if (service != null) {
+ service.scheduleOnResolvedService(cb);
+ }
+ return service != null;
+ }
+ }
+
+ @GuardedBy("mLock")
+ @Nullable
private RemoteAppPredictionService getRemoteServiceLocked() {
if (mRemoteService == null) {
final String serviceName = getComponentNameLocked();
@@ -334,8 +352,12 @@ public class AppPredictionPerUserService extends
private static final class AppPredictionSessionInfo {
private static final boolean DEBUG = false; // Do not submit with true
+ @NonNull
private final AppPredictionSessionId mSessionId;
+ @NonNull
private final AppPredictionContext mPredictionContext;
+ private final boolean mUsesPeopleService;
+ @NonNull
private final Consumer<AppPredictionSessionId> mRemoveSessionInfoAction;
private final RemoteCallbackList<IPredictionCallback> mCallbacks =
@@ -352,13 +374,17 @@ public class AppPredictionPerUserService extends
}
};
- AppPredictionSessionInfo(AppPredictionSessionId id, AppPredictionContext predictionContext,
- Consumer<AppPredictionSessionId> removeSessionInfoAction) {
+ AppPredictionSessionInfo(
+ @NonNull final AppPredictionSessionId id,
+ @NonNull final AppPredictionContext predictionContext,
+ final boolean usesPeopleService,
+ @NonNull final Consumer<AppPredictionSessionId> removeSessionInfoAction) {
if (DEBUG) {
Slog.d(TAG, "Creating AppPredictionSessionInfo for session Id=" + id);
}
mSessionId = id;
mPredictionContext = predictionContext;
+ mUsesPeopleService = usesPeopleService;
mRemoveSessionInfoAction = removeSessionInfoAction;
}
diff --git a/services/appprediction/java/com/android/server/appprediction/RemoteAppPredictionService.java b/services/appprediction/java/com/android/server/appprediction/RemoteAppPredictionService.java
index 04e0e7f7102f..ceb1cafcebeb 100644
--- a/services/appprediction/java/com/android/server/appprediction/RemoteAppPredictionService.java
+++ b/services/appprediction/java/com/android/server/appprediction/RemoteAppPredictionService.java
@@ -16,13 +16,8 @@
package com.android.server.appprediction;
import android.annotation.NonNull;
-import android.app.prediction.AppPredictionContext;
-import android.app.prediction.AppPredictionSessionId;
-import android.app.prediction.AppTargetEvent;
-import android.app.prediction.IPredictionCallback;
import android.content.ComponentName;
import android.content.Context;
-import android.content.pm.ParceledListSlice;
import android.os.IBinder;
import android.service.appprediction.IPredictionService;
import android.text.format.DateUtils;
@@ -71,74 +66,17 @@ public class RemoteAppPredictionService extends
}
/**
- * Notifies the service of a new prediction session.
- */
- public void onCreatePredictionSession(@NonNull AppPredictionContext context,
- @NonNull AppPredictionSessionId sessionId) {
- scheduleAsyncRequest((s) -> s.onCreatePredictionSession(context, sessionId));
- }
-
- /**
- * Records an app target event to the service.
- */
- public void notifyAppTargetEvent(@NonNull AppPredictionSessionId sessionId,
- @NonNull AppTargetEvent event) {
- scheduleAsyncRequest((s) -> s.notifyAppTargetEvent(sessionId, event));
- }
-
- /**
- * Records when a launch location is shown.
- */
- public void notifyLaunchLocationShown(@NonNull AppPredictionSessionId sessionId,
- @NonNull String launchLocation, @NonNull ParceledListSlice targetIds) {
- scheduleAsyncRequest((s)
- -> s.notifyLaunchLocationShown(sessionId, launchLocation, targetIds));
- }
-
- /**
- * Requests the service to sort a list of apps or shortcuts.
- */
- public void sortAppTargets(@NonNull AppPredictionSessionId sessionId,
- @NonNull ParceledListSlice targets, @NonNull IPredictionCallback callback) {
- scheduleAsyncRequest((s) -> s.sortAppTargets(sessionId, targets, callback));
- }
-
-
- /**
- * Registers a callback for continuous updates of predicted apps or shortcuts.
- */
- public void registerPredictionUpdates(@NonNull AppPredictionSessionId sessionId,
- @NonNull IPredictionCallback callback) {
- scheduleAsyncRequest((s) -> s.registerPredictionUpdates(sessionId, callback));
- }
-
- /**
- * Unregisters a callback for continuous updates of predicted apps or shortcuts.
- */
- public void unregisterPredictionUpdates(@NonNull AppPredictionSessionId sessionId,
- @NonNull IPredictionCallback callback) {
- scheduleAsyncRequest((s) -> s.unregisterPredictionUpdates(sessionId, callback));
- }
-
- /**
- * Requests a new set of predicted apps or shortcuts.
- */
- public void requestPredictionUpdate(@NonNull AppPredictionSessionId sessionId) {
- scheduleAsyncRequest((s) -> s.requestPredictionUpdate(sessionId));
- }
-
- /**
- * Notifies the service of the end of an existing prediction session.
+ * Schedules a request to bind to the remote service.
*/
- public void onDestroyPredictionSession(@NonNull AppPredictionSessionId sessionId) {
- scheduleAsyncRequest((s) -> s.onDestroyPredictionSession(sessionId));
+ public void reconnect() {
+ super.scheduleBind();
}
/**
- * Schedules a request to bind to the remote service.
+ * Schedule async request on remote service.
*/
- public void reconnect() {
- super.scheduleBind();
+ public void scheduleOnResolvedService(@NonNull AsyncRequest<IPredictionService> request) {
+ scheduleAsyncRequest(request);
}
/**
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
index 31ea5faa05f1..9a33fc9548a0 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
@@ -998,6 +998,11 @@ public final class ContentCaptureManagerService extends
sendErrorSignal(mClientAdapterReference, serviceAdapterReference,
ContentCaptureManager.DATA_SHARE_ERROR_UNKNOWN);
+ } finally {
+ synchronized (parentService.mLock) {
+ parentService.mPackagesWithShareRequests
+ .remove(mDataShareRequest.getPackageName());
+ }
}
});
diff --git a/services/core/java/android/app/usage/UsageStatsManagerInternal.java b/services/core/java/android/app/usage/UsageStatsManagerInternal.java
index 442c9e543b01..f688759e9f63 100644
--- a/services/core/java/android/app/usage/UsageStatsManagerInternal.java
+++ b/services/core/java/android/app/usage/UsageStatsManagerInternal.java
@@ -216,17 +216,11 @@ public abstract class UsageStatsManagerInternal {
/**
* Returns the events for the user in the given time period.
*
- * @param obfuscateInstantApps whether instant app package names need to be obfuscated in the
- * result.
- * @param hideShortcutInvocationEvents whether the {@link UsageEvents.Event#SHORTCUT_INVOCATION}
- * events need to be excluded from the result.
- * @param hideLocusIdEvents whether the {@link UsageEvents.Event#LOCUS_ID_SET}
- * events need to be excluded from the result.
- *
+ * @param flags defines the visibility of certain usage events - see flags defined in
+ * {@link UsageEvents}.
*/
public abstract UsageEvents queryEventsForUser(@UserIdInt int userId, long beginTime,
- long endTime, boolean obfuscateInstantApps, boolean hideShortcutInvocationEvents,
- boolean hideLocusIdEvents);
+ long endTime, int flags);
/**
* Used to persist the last time a job was run for this app, in order to make decisions later
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index abe0dd543deb..ffa7d9202371 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -59,6 +59,8 @@ import android.app.ApplicationExitInfo.Reason;
import android.app.ApplicationExitInfo.SubReason;
import android.app.IApplicationThread;
import android.app.IUidObserver;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledAfter;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -119,6 +121,7 @@ import com.android.server.pm.dex.DexManager;
import com.android.server.wm.ActivityServiceConnectionsHolder;
import com.android.server.wm.WindowManagerService;
+import dalvik.annotation.compat.VersionCodes;
import dalvik.system.VMRuntime;
import java.io.File;
@@ -327,6 +330,15 @@ public final class ProcessList {
*/
private static final int PROC_KILL_TIMEOUT = 2000; // 2 seconds;
+ /**
+ * Native heap allocations will now have a non-zero tag in the most significant byte.
+ * @see <a href="https://source.android.com/devices/tech/debug/tagged-pointers">Tagged
+ * Pointers</a>
+ */
+ @ChangeId
+ @EnabledAfter(targetSdkVersion = VersionCodes.Q)
+ private static final long NATIVE_HEAP_POINTER_TAGGING = 135754954; // This is a bug id.
+
ActivityManagerService mService = null;
// To kill process groups asynchronously
@@ -1768,6 +1780,13 @@ public final class ProcessList {
runtimeFlags |= Zygote.USE_APP_IMAGE_STARTUP_CACHE;
}
+ // Enable heap pointer tagging, unless disabled by the app manifest, target sdk level,
+ // or the compat feature.
+ if (app.info.allowsNativeHeapPointerTagging()
+ && mPlatformCompat.isChangeEnabled(NATIVE_HEAP_POINTER_TAGGING, app.info)) {
+ runtimeFlags |= Zygote.MEMORY_TAG_LEVEL_TBI;
+ }
+
String invokeWith = null;
if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
// Debuggable apps may include a wrapper script with their library directory.
diff --git a/services/core/java/com/android/server/biometrics/AuthService.java b/services/core/java/com/android/server/biometrics/AuthService.java
index c9c2c96a642a..204f072a72fc 100644
--- a/services/core/java/com/android/server/biometrics/AuthService.java
+++ b/services/core/java/com/android/server/biometrics/AuthService.java
@@ -153,7 +153,12 @@ public class AuthService extends SystemService {
// Only allow internal clients to enable non-public options.
if (bundle.getBoolean(BiometricPrompt.EXTRA_DISALLOW_BIOMETRICS_IF_POLICY_EXISTS)
- || bundle.getBoolean(BiometricPrompt.KEY_USE_DEFAULT_TITLE, false)) {
+ || bundle.getBoolean(BiometricPrompt.KEY_USE_DEFAULT_TITLE, false)
+ || bundle.getCharSequence(BiometricPrompt.KEY_DEVICE_CREDENTIAL_TITLE) != null
+ || bundle.getCharSequence(
+ BiometricPrompt.KEY_DEVICE_CREDENTIAL_SUBTITLE) != null
+ || bundle.getCharSequence(
+ BiometricPrompt.KEY_DEVICE_CREDENTIAL_DESCRIPTION) != null) {
checkInternalPermission();
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 7c2ec78c1cbc..d9e30250ba2d 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -105,32 +105,57 @@ import java.util.stream.Collectors;
*/
public class HdmiControlService extends SystemService {
private static final String TAG = "HdmiControlService";
- private final Locale HONG_KONG = new Locale("zh", "HK");
- private final Locale MACAU = new Locale("zh", "MO");
+ private static final Locale HONG_KONG = new Locale("zh", "HK");
+ private static final Locale MACAU = new Locale("zh", "MO");
- private static final Map<String, String> mTerminologyToBibliographicMap;
- static {
- mTerminologyToBibliographicMap = new HashMap<>();
+ private static final Map<String, String> sTerminologyToBibliographicMap =
+ createsTerminologyToBibliographicMap();
+
+ private static Map<String, String> createsTerminologyToBibliographicMap() {
+ Map<String, String> temp = new HashMap<>();
// NOTE: (TERMINOLOGY_CODE, BIBLIOGRAPHIC_CODE)
- mTerminologyToBibliographicMap.put("sqi", "alb"); // Albanian
- mTerminologyToBibliographicMap.put("hye", "arm"); // Armenian
- mTerminologyToBibliographicMap.put("eus", "baq"); // Basque
- mTerminologyToBibliographicMap.put("mya", "bur"); // Burmese
- mTerminologyToBibliographicMap.put("ces", "cze"); // Czech
- mTerminologyToBibliographicMap.put("nld", "dut"); // Dutch
- mTerminologyToBibliographicMap.put("kat", "geo"); // Georgian
- mTerminologyToBibliographicMap.put("deu", "ger"); // German
- mTerminologyToBibliographicMap.put("ell", "gre"); // Greek
- mTerminologyToBibliographicMap.put("fra", "fre"); // French
- mTerminologyToBibliographicMap.put("isl", "ice"); // Icelandic
- mTerminologyToBibliographicMap.put("mkd", "mac"); // Macedonian
- mTerminologyToBibliographicMap.put("mri", "mao"); // Maori
- mTerminologyToBibliographicMap.put("msa", "may"); // Malay
- mTerminologyToBibliographicMap.put("fas", "per"); // Persian
- mTerminologyToBibliographicMap.put("ron", "rum"); // Romanian
- mTerminologyToBibliographicMap.put("slk", "slo"); // Slovak
- mTerminologyToBibliographicMap.put("bod", "tib"); // Tibetan
- mTerminologyToBibliographicMap.put("cym", "wel"); // Welsh
+ temp.put("sqi", "alb"); // Albanian
+ temp.put("hye", "arm"); // Armenian
+ temp.put("eus", "baq"); // Basque
+ temp.put("mya", "bur"); // Burmese
+ temp.put("ces", "cze"); // Czech
+ temp.put("nld", "dut"); // Dutch
+ temp.put("kat", "geo"); // Georgian
+ temp.put("deu", "ger"); // German
+ temp.put("ell", "gre"); // Greek
+ temp.put("fra", "fre"); // French
+ temp.put("isl", "ice"); // Icelandic
+ temp.put("mkd", "mac"); // Macedonian
+ temp.put("mri", "mao"); // Maori
+ temp.put("msa", "may"); // Malay
+ temp.put("fas", "per"); // Persian
+ temp.put("ron", "rum"); // Romanian
+ temp.put("slk", "slo"); // Slovak
+ temp.put("bod", "tib"); // Tibetan
+ temp.put("cym", "wel"); // Welsh
+ return Collections.unmodifiableMap(temp);
+ }
+
+ @VisibleForTesting static String localeToMenuLanguage(Locale locale) {
+ if (locale.equals(Locale.TAIWAN) || locale.equals(HONG_KONG) || locale.equals(MACAU)) {
+ // Android always returns "zho" for all Chinese variants.
+ // Use "bibliographic" code defined in CEC639-2 for traditional
+ // Chinese used in Taiwan/Hong Kong/Macau.
+ return "chi";
+ } else {
+ String language = locale.getISO3Language();
+
+ // locale.getISO3Language() returns terminology code and need to
+ // send it as bibliographic code instead since the Bibliographic
+ // codes of ISO/FDIS 639-2 shall be used.
+ // NOTE: Chinese also has terminology/bibliographic code "zho" and "chi"
+ // But, as it depends on the locale, is not handled here.
+ if (sTerminologyToBibliographicMap.containsKey(language)) {
+ language = sTerminologyToBibliographicMap.get(language);
+ }
+
+ return language;
+ }
}
static final String PERMISSION = "android.permission.HDMI_CEC";
@@ -208,8 +233,8 @@ public class HdmiControlService extends SystemService {
}
break;
case Intent.ACTION_CONFIGURATION_CHANGED:
- String language = getMenuLanguage();
- if (!mLanguage.equals(language)) {
+ String language = HdmiControlService.localeToMenuLanguage(Locale.getDefault());
+ if (!mMenuLanguage.equals(language)) {
onLanguageChanged(language);
}
break;
@@ -221,28 +246,6 @@ public class HdmiControlService extends SystemService {
}
}
- private String getMenuLanguage() {
- Locale locale = Locale.getDefault();
- if (locale.equals(Locale.TAIWAN) || locale.equals(HONG_KONG) || locale.equals(MACAU)) {
- // Android always returns "zho" for all Chinese variants.
- // Use "bibliographic" code defined in CEC639-2 for traditional
- // Chinese used in Taiwan/Hong Kong/Macau.
- return "chi";
- } else {
- String language = locale.getISO3Language();
-
- // locale.getISO3Language() returns terminology code and need to
- // send it as bibliographic code instead since the Bibliographic
- // codes of ISO/FDIS 639-2 shall be used.
- // NOTE: Chinese also has terminology/bibliographic code "zho" and "chi"
- // But, as it depends on the locale, is not handled here.
- if (mTerminologyToBibliographicMap.containsKey(language)) {
- language = mTerminologyToBibliographicMap.get(language);
- }
-
- return language;
- }
- }
}
// A thread to handle synchronous IO of CEC and MHL control service.
@@ -339,7 +342,7 @@ public class HdmiControlService extends SystemService {
private int mPowerStatus = HdmiControlManager.POWER_STATUS_STANDBY;
@ServiceThreadOnly
- private String mLanguage = Locale.getDefault().getISO3Language();
+ private String mMenuLanguage = localeToMenuLanguage(Locale.getDefault());
@ServiceThreadOnly
private boolean mStandbyMessageReceived = false;
@@ -759,7 +762,7 @@ public class HdmiControlService extends SystemService {
private void initializeCec(int initiatedBy) {
mAddressAllocated = false;
mCecController.setOption(OptionKey.SYSTEM_CEC_CONTROL, true);
- mCecController.setLanguage(mLanguage);
+ mCecController.setLanguage(mMenuLanguage);
initializeLocalDevices(initiatedBy);
}
@@ -2818,7 +2821,7 @@ public class HdmiControlService extends SystemService {
@ServiceThreadOnly
private void onLanguageChanged(String language) {
assertRunOnServiceThread();
- mLanguage = language;
+ mMenuLanguage = language;
if (isTvDeviceEnabled()) {
tv().broadcastMenuLanguage(language);
@@ -2826,10 +2829,19 @@ public class HdmiControlService extends SystemService {
}
}
+ /**
+ * Gets the CEC menu language.
+ *
+ * <p>This is the ISO/FDIS 639-2 3 letter language code sent in the CEC message @{code <Set Menu
+ * Language>}.
+ * See HDMI 1.4b section CEC 13.6.2
+ *
+ * @see {@link Locale#getISO3Language()}
+ */
@ServiceThreadOnly
String getLanguage() {
assertRunOnServiceThread();
- return mLanguage;
+ return mMenuLanguage;
}
private void disableDevices(PendingActionClearedCallback callback) {
@@ -2838,7 +2850,6 @@ public class HdmiControlService extends SystemService {
device.disableDevice(mStandbyMessageReceived, callback);
}
}
-
mMhlController.clearAllLocalDevices();
}
diff --git a/services/core/java/com/android/server/inputmethod/OWNERS b/services/core/java/com/android/server/inputmethod/OWNERS
new file mode 100644
index 000000000000..25ef9facb216
--- /dev/null
+++ b/services/core/java/com/android/server/inputmethod/OWNERS
@@ -0,0 +1,6 @@
+set noparent
+
+ogunwale@google.com
+yukawa@google.com
+tarandeep@google.com
+lumark@google.com
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index a570502dee10..d0d0f5a3a233 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1055,7 +1055,7 @@ public class NotificationManagerService extends SystemService {
if (DBG) Slog.d(TAG, "Marking notification as visible " + nv.key);
reportSeen(r);
}
- r.setVisibility(true, nv.rank, nv.count);
+ r.setVisibility(true, nv.rank, nv.count, mNotificationRecordLogger);
mAssistants.notifyAssistantVisibilityChangedLocked(r.getSbn(), true);
boolean isHun = (nv.location
== NotificationVisibility.NotificationLocation.LOCATION_FIRST_HEADS_UP);
@@ -1074,7 +1074,7 @@ public class NotificationManagerService extends SystemService {
for (NotificationVisibility nv : noLongerVisibleKeys) {
NotificationRecord r = mNotificationsByKey.get(nv.key);
if (r == null) continue;
- r.setVisibility(false, nv.rank, nv.count);
+ r.setVisibility(false, nv.rank, nv.count, mNotificationRecordLogger);
mAssistants.notifyAssistantVisibilityChangedLocked(r.getSbn(), false);
nv.recycle();
}
@@ -3979,6 +3979,29 @@ public class NotificationManagerService extends SystemService {
}
/**
+ * Allows the notification assistant to un-snooze a single notification.
+ *
+ * @param token The binder for the listener, to check that the caller is allowed
+ */
+ @Override
+ public void unsnoozeNotificationFromSystemListener(INotificationListener token,
+ String key) {
+ long identity = Binder.clearCallingIdentity();
+ try {
+ synchronized (mNotificationLock) {
+ final ManagedServiceInfo info =
+ mListeners.checkServiceTokenLocked(token);
+ if (!info.isSystem) {
+ throw new SecurityException("Not allowed to unsnooze before deadline");
+ }
+ unsnoozeNotificationInt(key, info);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ /**
* Allow an INotificationListener to simulate clearing (dismissing) a single notification.
*
* {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
@@ -6468,7 +6491,7 @@ public class NotificationManagerService extends SystemService {
mUsageStats.registerPostedByApp(r);
r.setInterruptive(isVisuallyInterruptive(null, r));
} else {
- old = mNotificationList.get(index);
+ old = mNotificationList.get(index); // Potentially *changes* old
mNotificationList.set(index, r);
mUsageStats.registerUpdatedByApp(r, old);
// Make sure we don't lose the foreground service state.
@@ -6537,7 +6560,7 @@ public class NotificationManagerService extends SystemService {
maybeRecordInterruptionLocked(r);
// Log event to statsd
- mNotificationRecordLogger.logNotificationReported(r, old, position,
+ mNotificationRecordLogger.maybeLogNotificationPosted(r, old, position,
buzzBeepBlinkLoggingCode);
} finally {
int N = mEnqueuedNotifications.size();
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 4785da9a5922..0ada58e1ce16 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -909,7 +909,8 @@ public final class NotificationRecord {
/**
* Set the visibility of the notification.
*/
- public void setVisibility(boolean visible, int rank, int count) {
+ public void setVisibility(boolean visible, int rank, int count,
+ NotificationRecordLogger notificationRecordLogger) {
final long now = System.currentTimeMillis();
mVisibleSinceMs = visible ? now : mVisibleSinceMs;
stats.onVisibilityChanged(visible);
@@ -927,6 +928,7 @@ public final class NotificationRecord {
getFreshnessMs(now),
0, // exposure time
rank);
+ notificationRecordLogger.logNotificationVisibility(this, visible);
}
/**
diff --git a/services/core/java/com/android/server/notification/NotificationRecordLogger.java b/services/core/java/com/android/server/notification/NotificationRecordLogger.java
index 2f7854226c5c..eaca066f026f 100644
--- a/services/core/java/com/android/server/notification/NotificationRecordLogger.java
+++ b/services/core/java/com/android/server/notification/NotificationRecordLogger.java
@@ -41,13 +41,14 @@ import java.util.Objects;
public interface NotificationRecordLogger {
/**
- * Logs a NotificationReported atom reflecting the posting or update of a notification.
+ * May log a NotificationReported atom reflecting the posting or update of a notification.
* @param r The new NotificationRecord. If null, no action is taken.
* @param old The previous NotificationRecord. Null if there was no previous record.
* @param position The position at which this notification is ranked.
* @param buzzBeepBlink Logging code reflecting whether this notification alerted the user.
*/
- void logNotificationReported(@Nullable NotificationRecord r, @Nullable NotificationRecord old,
+ void maybeLogNotificationPosted(@Nullable NotificationRecord r,
+ @Nullable NotificationRecord old,
int position, int buzzBeepBlink);
/**
@@ -62,6 +63,14 @@ public interface NotificationRecordLogger {
@NotificationStats.DismissalSurface int dismissalSurface);
/**
+ * Logs a notification visibility change event using UiEventReported (event ids from the
+ * NotificationEvents enum).
+ * @param r The NotificationRecord. If null, no action is taken.
+ * @param visible True if the notification became visible.
+ */
+ void logNotificationVisibility(@Nullable NotificationRecord r, boolean visible);
+
+ /**
* The UiEvent enums that this class can log.
*/
enum NotificationReportedEvent implements UiEventLogger.UiEventEnum {
@@ -145,6 +154,7 @@ public interface NotificationRecordLogger {
@Override public int getId() {
return mId;
}
+
public static NotificationCancelledEvent fromCancelReason(
@NotificationListenerService.NotificationCancelReason int reason,
@NotificationStats.DismissalSurface int surface) {
@@ -191,6 +201,24 @@ public interface NotificationRecordLogger {
}
}
+ enum NotificationEvent implements UiEventLogger.UiEventEnum {
+ @UiEvent(doc = "Notification became visible.")
+ NOTIFICATION_OPEN(197),
+ @UiEvent(doc = "Notification stopped being visible.")
+ NOTIFICATION_CLOSE(198);
+
+ private final int mId;
+ NotificationEvent(int id) {
+ mId = id;
+ }
+ @Override public int getId() {
+ return mId;
+ }
+
+ public static NotificationEvent fromVisibility(boolean visible) {
+ return visible ? NOTIFICATION_OPEN : NOTIFICATION_CLOSE;
+ }
+ }
/**
* A helper for extracting logging information from one or two NotificationRecords.
*/
@@ -209,7 +237,7 @@ public interface NotificationRecordLogger {
/**
* @return True if old is null, alerted, or important logged fields have changed.
*/
- boolean shouldLog(int buzzBeepBlink) {
+ boolean shouldLogReported(int buzzBeepBlink) {
if (r == null) {
return false;
}
diff --git a/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java b/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java
index bb23d1e876dc..9fcac257d328 100644
--- a/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java
+++ b/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java
@@ -26,13 +26,13 @@ import com.android.internal.util.FrameworkStatsLog;
*/
public class NotificationRecordLoggerImpl implements NotificationRecordLogger {
- UiEventLogger mUiEventLogger = new UiEventLoggerImpl();
+ private UiEventLogger mUiEventLogger = new UiEventLoggerImpl();
@Override
- public void logNotificationReported(NotificationRecord r, NotificationRecord old,
+ public void maybeLogNotificationPosted(NotificationRecord r, NotificationRecord old,
int position, int buzzBeepBlink) {
NotificationRecordPair p = new NotificationRecordPair(r, old);
- if (!p.shouldLog(buzzBeepBlink)) {
+ if (!p.shouldLogReported(buzzBeepBlink)) {
return;
}
FrameworkStatsLog.write(FrameworkStatsLog.NOTIFICATION_REPORTED,
@@ -66,8 +66,19 @@ public class NotificationRecordLoggerImpl implements NotificationRecordLogger {
@Override
public void logNotificationCancelled(NotificationRecord r, int reason, int dismissalSurface) {
- mUiEventLogger.logWithInstanceId(
- NotificationCancelledEvent.fromCancelReason(reason, dismissalSurface),
- r.getUid(), r.getSbn().getPackageName(), r.getSbn().getInstanceId());
+ log(NotificationCancelledEvent.fromCancelReason(reason, dismissalSurface), r);
+ }
+
+ @Override
+ public void logNotificationVisibility(NotificationRecord r, boolean visible) {
+ log(NotificationEvent.fromVisibility(visible), r);
+ }
+
+ void log(UiEventLogger.UiEventEnum event, NotificationRecord r) {
+ if (r == null) {
+ return;
+ }
+ mUiEventLogger.logWithInstanceId(event, r.getUid(), r.getSbn().getPackageName(),
+ r.getSbn().getInstanceId());
}
}
diff --git a/services/core/java/com/android/server/notification/SnoozeHelper.java b/services/core/java/com/android/server/notification/SnoozeHelper.java
index 661297a7346e..bae1dd3c6cb6 100644
--- a/services/core/java/com/android/server/notification/SnoozeHelper.java
+++ b/services/core/java/com/android/server/notification/SnoozeHelper.java
@@ -16,6 +16,7 @@
package com.android.server.notification;
import android.annotation.NonNull;
+import android.annotation.UserIdInt;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
@@ -42,7 +43,9 @@ import org.xmlpull.v1.XmlSerializer;
import java.io.IOException;
import java.io.PrintWriter;
+import java.sql.Array;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
@@ -77,26 +80,26 @@ public class SnoozeHelper {
private static final String REPOST_ACTION = SnoozeHelper.class.getSimpleName() + ".EVALUATE";
private static final int REQUEST_CODE_REPOST = 1;
private static final String REPOST_SCHEME = "repost";
- private static final String EXTRA_KEY = "key";
+ static final String EXTRA_KEY = "key";
private static final String EXTRA_USER_ID = "userId";
private final Context mContext;
private AlarmManager mAm;
private final ManagedServices.UserProfiles mUserProfiles;
- // User id : package name : notification key : record.
- private ArrayMap<Integer, ArrayMap<String, ArrayMap<String, NotificationRecord>>>
+ // User id | package name : notification key : record.
+ private ArrayMap<String, ArrayMap<String, NotificationRecord>>
mSnoozedNotifications = new ArrayMap<>();
- // User id : package name : notification key : time-milliseconds .
+ // User id | package name : notification key : time-milliseconds .
// This member stores persisted snoozed notification trigger times. it persists through reboots
// It should have the notifications that haven't expired or re-posted yet
- private ArrayMap<Integer, ArrayMap<String, ArrayMap<String, Long>>>
+ private final ArrayMap<String, ArrayMap<String, Long>>
mPersistedSnoozedNotifications = new ArrayMap<>();
- // User id : package name : notification key : creation ID .
+ // User id | package name : notification key : creation ID .
// This member stores persisted snoozed notification trigger context for the assistant
// it persists through reboots.
// It should have the notifications that haven't expired or re-posted yet
- private ArrayMap<Integer, ArrayMap<String, ArrayMap<String, String>>>
+ private final ArrayMap<String, ArrayMap<String, String>>
mPersistedSnoozedNotificationsWithContext = new ArrayMap<>();
// notification key : package.
private ArrayMap<String, String> mPackages = new ArrayMap<>();
@@ -115,6 +118,10 @@ public class SnoozeHelper {
mUserProfiles = userProfiles;
}
+ private String getPkgKey(@UserIdInt int userId, String pkg) {
+ return userId + "|" + pkg;
+ }
+
void cleanupPersistedContext(String key){
int userId = mUsers.get(key);
String pkg = mPackages.get(key);
@@ -144,15 +151,13 @@ public class SnoozeHelper {
}
protected boolean isSnoozed(int userId, String pkg, String key) {
- return mSnoozedNotifications.containsKey(userId)
- && mSnoozedNotifications.get(userId).containsKey(pkg)
- && mSnoozedNotifications.get(userId).get(pkg).containsKey(key);
+ return mSnoozedNotifications.containsKey(getPkgKey(userId, pkg))
+ && mSnoozedNotifications.get(getPkgKey(userId, pkg)).containsKey(key);
}
protected Collection<NotificationRecord> getSnoozed(int userId, String pkg) {
- if (mSnoozedNotifications.containsKey(userId)
- && mSnoozedNotifications.get(userId).containsKey(pkg)) {
- return mSnoozedNotifications.get(userId).get(pkg).values();
+ if (mSnoozedNotifications.containsKey(getPkgKey(userId, pkg))) {
+ return mSnoozedNotifications.get(getPkgKey(userId, pkg)).values();
}
return Collections.EMPTY_LIST;
}
@@ -161,14 +166,14 @@ public class SnoozeHelper {
ArrayList<NotificationRecord> getNotifications(String pkg,
String groupKey, Integer userId) {
ArrayList<NotificationRecord> records = new ArrayList<>();
- if (mSnoozedNotifications.containsKey(userId)
- && mSnoozedNotifications.get(userId).containsKey(pkg)) {
- ArrayMap<String, NotificationRecord> packages =
- mSnoozedNotifications.get(userId).get(pkg);
- for (int i = 0; i < packages.size(); i++) {
- String currentGroupKey = packages.valueAt(i).getSbn().getGroup();
+ ArrayMap<String, NotificationRecord> allRecords =
+ mSnoozedNotifications.get(getPkgKey(userId, pkg));
+ if (allRecords != null) {
+ for (int i = 0; i < allRecords.size(); i++) {
+ NotificationRecord r = allRecords.valueAt(i);
+ String currentGroupKey = r.getSbn().getGroup();
if (currentGroupKey.equals(groupKey)) {
- records.add(packages.valueAt(i));
+ records.add(r);
}
}
}
@@ -176,47 +181,30 @@ public class SnoozeHelper {
}
protected NotificationRecord getNotification(String key) {
- List<NotificationRecord> snoozedForUser = new ArrayList<>();
- IntArray userIds = mUserProfiles.getCurrentProfileIds();
- if (userIds != null) {
- final int userIdsSize = userIds.size();
- for (int i = 0; i < userIdsSize; i++) {
- final ArrayMap<String, ArrayMap<String, NotificationRecord>> snoozedPkgs =
- mSnoozedNotifications.get(userIds.get(i));
- if (snoozedPkgs != null) {
- final int snoozedPkgsSize = snoozedPkgs.size();
- for (int j = 0; j < snoozedPkgsSize; j++) {
- final ArrayMap<String, NotificationRecord> records = snoozedPkgs.valueAt(j);
- if (records != null) {
- return records.get(key);
- }
- }
- }
- }
+ if (!mUsers.containsKey(key) || !mPackages.containsKey(key)) {
+ Slog.w(TAG, "Snoozed data sets no longer agree for " + key);
+ return null;
+ }
+ int userId = mUsers.get(key);
+ String pkg = mPackages.get(key);
+ ArrayMap<String, NotificationRecord> snoozed =
+ mSnoozedNotifications.get(getPkgKey(userId, pkg));
+ if (snoozed == null) {
+ return null;
}
- return null;
+ return snoozed.get(key);
}
protected @NonNull List<NotificationRecord> getSnoozed() {
- List<NotificationRecord> snoozedForUser = new ArrayList<>();
- IntArray userIds = mUserProfiles.getCurrentProfileIds();
- if (userIds != null) {
- final int N = userIds.size();
- for (int i = 0; i < N; i++) {
- final ArrayMap<String, ArrayMap<String, NotificationRecord>> snoozedPkgs =
- mSnoozedNotifications.get(userIds.get(i));
- if (snoozedPkgs != null) {
- final int M = snoozedPkgs.size();
- for (int j = 0; j < M; j++) {
- final ArrayMap<String, NotificationRecord> records = snoozedPkgs.valueAt(j);
- if (records != null) {
- snoozedForUser.addAll(records.values());
- }
- }
- }
- }
- }
- return snoozedForUser;
+ // caller filters records based on the current user profiles and listener access, so just
+ // return everything
+ List<NotificationRecord> snoozed= new ArrayList<>();
+ for (String userPkgKey : mSnoozedNotifications.keySet()) {
+ ArrayMap<String, NotificationRecord> snoozedRecords =
+ mSnoozedNotifications.get(userPkgKey);
+ snoozed.addAll(snoozedRecords.values());
+ }
+ return snoozed;
}
/**
@@ -261,120 +249,88 @@ public class SnoozeHelper {
}
private <T> void storeRecord(String pkg, String key, Integer userId,
- ArrayMap<Integer, ArrayMap<String, ArrayMap<String, T>>> targets, T object) {
+ ArrayMap<String, ArrayMap<String, T>> targets, T object) {
- ArrayMap<String, ArrayMap<String, T>> records =
- targets.get(userId);
- if (records == null) {
- records = new ArrayMap<>();
- }
- ArrayMap<String, T> pkgRecords = records.get(pkg);
- if (pkgRecords == null) {
- pkgRecords = new ArrayMap<>();
+ ArrayMap<String, T> keyToValue = targets.get(getPkgKey(userId, pkg));
+ if (keyToValue == null) {
+ keyToValue = new ArrayMap<>();
}
- pkgRecords.put(key, object);
- records.put(pkg, pkgRecords);
- targets.put(userId, records);
+ keyToValue.put(key, object);
+ targets.put(getPkgKey(userId, pkg), keyToValue);
}
private <T> T removeRecord(String pkg, String key, Integer userId,
- ArrayMap<Integer, ArrayMap<String, ArrayMap<String, T>>> targets) {
+ ArrayMap<String, ArrayMap<String, T>> targets) {
T object = null;
-
- ArrayMap<String, ArrayMap<String, T>> records =
- targets.get(userId);
- if (records == null) {
+ ArrayMap<String, T> keyToValue = targets.get(getPkgKey(userId, pkg));
+ if (keyToValue == null) {
return null;
}
- ArrayMap<String, T> pkgRecords = records.get(pkg);
- if (pkgRecords == null) {
- return null;
- }
- object = pkgRecords.remove(key);
- if (pkgRecords.size() == 0) {
- records.remove(pkg);
- }
- if (records.size() == 0) {
- targets.remove(userId);
+ object = keyToValue.remove(key);
+ if (keyToValue.size() == 0) {
+ targets.remove(getPkgKey(userId, pkg));
}
return object;
}
protected boolean cancel(int userId, String pkg, String tag, int id) {
- if (mSnoozedNotifications.containsKey(userId)) {
- ArrayMap<String, NotificationRecord> recordsForPkg =
- mSnoozedNotifications.get(userId).get(pkg);
- if (recordsForPkg != null) {
- final Set<Map.Entry<String, NotificationRecord>> records = recordsForPkg.entrySet();
- for (Map.Entry<String, NotificationRecord> record : records) {
- final StatusBarNotification sbn = record.getValue().getSbn();
- if (Objects.equals(sbn.getTag(), tag) && sbn.getId() == id) {
- record.getValue().isCanceled = true;
- return true;
- }
+ ArrayMap<String, NotificationRecord> recordsForPkg =
+ mSnoozedNotifications.get(getPkgKey(userId, pkg));
+ if (recordsForPkg != null) {
+ final Set<Map.Entry<String, NotificationRecord>> records = recordsForPkg.entrySet();
+ for (Map.Entry<String, NotificationRecord> record : records) {
+ final StatusBarNotification sbn = record.getValue().getSbn();
+ if (Objects.equals(sbn.getTag(), tag) && sbn.getId() == id) {
+ record.getValue().isCanceled = true;
+ return true;
}
}
}
return false;
}
- protected boolean cancel(int userId, boolean includeCurrentProfiles) {
- int[] userIds = {userId};
+ protected void cancel(int userId, boolean includeCurrentProfiles) {
+ if (mSnoozedNotifications.size() == 0) {
+ return;
+ }
+ IntArray userIds = new IntArray();
+ userIds.add(userId);
if (includeCurrentProfiles) {
- userIds = mUserProfiles.getCurrentProfileIds().toArray();
+ userIds = mUserProfiles.getCurrentProfileIds();
}
- final int N = userIds.length;
- for (int i = 0; i < N; i++) {
- final ArrayMap<String, ArrayMap<String, NotificationRecord>> snoozedPkgs =
- mSnoozedNotifications.get(userIds[i]);
- if (snoozedPkgs != null) {
- final int M = snoozedPkgs.size();
- for (int j = 0; j < M; j++) {
- final ArrayMap<String, NotificationRecord> records = snoozedPkgs.valueAt(j);
- if (records != null) {
- int P = records.size();
- for (int k = 0; k < P; k++) {
- records.valueAt(k).isCanceled = true;
- }
- }
+ for (ArrayMap<String, NotificationRecord> snoozedRecords : mSnoozedNotifications.values()) {
+ for (NotificationRecord r : snoozedRecords.values()) {
+ if (userIds.binarySearch(r.getUserId()) >= 0) {
+ r.isCanceled = true;
}
- return true;
}
}
- return false;
}
protected boolean cancel(int userId, String pkg) {
- if (mSnoozedNotifications.containsKey(userId)) {
- if (mSnoozedNotifications.get(userId).containsKey(pkg)) {
- ArrayMap<String, NotificationRecord> records =
- mSnoozedNotifications.get(userId).get(pkg);
- int N = records.size();
- for (int i = 0; i < N; i++) {
- records.valueAt(i).isCanceled = true;
- }
- return true;
- }
+ ArrayMap<String, NotificationRecord> records =
+ mSnoozedNotifications.get(getPkgKey(userId, pkg));
+ if (records == null) {
+ return false;
}
- return false;
+ int N = records.size();
+ for (int i = 0; i < N; i++) {
+ records.valueAt(i).isCanceled = true;
+ }
+ return true;
}
/**
* Updates the notification record so the most up to date information is shown on re-post.
*/
protected void update(int userId, NotificationRecord record) {
- ArrayMap<String, ArrayMap<String, NotificationRecord>> records =
- mSnoozedNotifications.get(userId);
+ ArrayMap<String, NotificationRecord> records =
+ mSnoozedNotifications.get(getPkgKey(userId, record.getSbn().getPackageName()));
if (records == null) {
return;
}
- ArrayMap<String, NotificationRecord> pkgRecords = records.get(record.getSbn().getPackageName());
- if (pkgRecords == null) {
- return;
- }
- NotificationRecord existing = pkgRecords.get(record.getKey());
- pkgRecords.put(record.getKey(), record);
+ records.put(record.getKey(), record);
}
protected void repost(String key) {
@@ -386,20 +342,18 @@ public class SnoozeHelper {
protected void repost(String key, int userId) {
final String pkg = mPackages.remove(key);
- ArrayMap<String, ArrayMap<String, NotificationRecord>> records =
- mSnoozedNotifications.get(userId);
+ ArrayMap<String, NotificationRecord> records =
+ mSnoozedNotifications.get(getPkgKey(userId, pkg));
if (records == null) {
return;
}
- ArrayMap<String, NotificationRecord> pkgRecords = records.get(pkg);
- if (pkgRecords == null) {
- return;
- }
- final NotificationRecord record = pkgRecords.remove(key);
+ final NotificationRecord record = records.remove(key);
mPackages.remove(key);
mUsers.remove(key);
if (record != null && !record.isCanceled) {
+ final PendingIntent pi = createPendingIntent(pkg, record.getKey(), userId);
+ mAm.cancel(pi);
MetricsLogger.action(record.getLogMaker()
.setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED)
.setType(MetricsProto.MetricsEvent.TYPE_OPEN));
@@ -408,55 +362,46 @@ public class SnoozeHelper {
}
protected void repostGroupSummary(String pkg, int userId, String groupKey) {
- if (mSnoozedNotifications.containsKey(userId)) {
- ArrayMap<String, ArrayMap<String, NotificationRecord>> keysByPackage
- = mSnoozedNotifications.get(userId);
-
- if (keysByPackage != null && keysByPackage.containsKey(pkg)) {
- ArrayMap<String, NotificationRecord> recordsByKey = keysByPackage.get(pkg);
-
- if (recordsByKey != null) {
- String groupSummaryKey = null;
- int N = recordsByKey.size();
- for (int i = 0; i < N; i++) {
- final NotificationRecord potentialGroupSummary = recordsByKey.valueAt(i);
- if (potentialGroupSummary.getSbn().isGroup()
- && potentialGroupSummary.getNotification().isGroupSummary()
- && groupKey.equals(potentialGroupSummary.getGroupKey())) {
- groupSummaryKey = potentialGroupSummary.getKey();
- break;
- }
- }
+ ArrayMap<String, NotificationRecord> recordsByKey
+ = mSnoozedNotifications.get(getPkgKey(userId, pkg));
+ if (recordsByKey == null) {
+ return;
+ }
- if (groupSummaryKey != null) {
- NotificationRecord record = recordsByKey.remove(groupSummaryKey);
- mPackages.remove(groupSummaryKey);
- mUsers.remove(groupSummaryKey);
+ String groupSummaryKey = null;
+ int N = recordsByKey.size();
+ for (int i = 0; i < N; i++) {
+ final NotificationRecord potentialGroupSummary = recordsByKey.valueAt(i);
+ if (potentialGroupSummary.getSbn().isGroup()
+ && potentialGroupSummary.getNotification().isGroupSummary()
+ && groupKey.equals(potentialGroupSummary.getGroupKey())) {
+ groupSummaryKey = potentialGroupSummary.getKey();
+ break;
+ }
+ }
- if (record != null && !record.isCanceled) {
- MetricsLogger.action(record.getLogMaker()
- .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED)
- .setType(MetricsProto.MetricsEvent.TYPE_OPEN));
- mCallback.repost(userId, record);
- }
- }
- }
+ if (groupSummaryKey != null) {
+ NotificationRecord record = recordsByKey.remove(groupSummaryKey);
+ mPackages.remove(groupSummaryKey);
+ mUsers.remove(groupSummaryKey);
+
+ if (record != null && !record.isCanceled) {
+ MetricsLogger.action(record.getLogMaker()
+ .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED)
+ .setType(MetricsProto.MetricsEvent.TYPE_OPEN));
+ mCallback.repost(userId, record);
}
}
}
protected void clearData(int userId, String pkg) {
- ArrayMap<String, ArrayMap<String, NotificationRecord>> records =
- mSnoozedNotifications.get(userId);
+ ArrayMap<String, NotificationRecord> records =
+ mSnoozedNotifications.get(getPkgKey(userId, pkg));
if (records == null) {
return;
}
- ArrayMap<String, NotificationRecord> pkgRecords = records.get(pkg);
- if (pkgRecords == null) {
- return;
- }
- for (int i = pkgRecords.size() - 1; i >= 0; i--) {
- final NotificationRecord r = pkgRecords.removeAt(i);
+ for (int i = records.size() - 1; i >= 0; i--) {
+ final NotificationRecord r = records.removeAt(i);
if (r != null) {
mPackages.remove(r.getKey());
mUsers.remove(r.getKey());
@@ -495,22 +440,36 @@ public class SnoozeHelper {
public void dump(PrintWriter pw, NotificationManagerService.DumpFilter filter) {
pw.println("\n Snoozed notifications:");
- for (int userId : mSnoozedNotifications.keySet()) {
+ for (String userPkgKey : mSnoozedNotifications.keySet()) {
pw.print(INDENT);
- pw.println("user: " + userId);
- ArrayMap<String, ArrayMap<String, NotificationRecord>> snoozedPkgs =
- mSnoozedNotifications.get(userId);
- for (String pkg : snoozedPkgs.keySet()) {
+ pw.println("key: " + userPkgKey);
+ ArrayMap<String, NotificationRecord> snoozedRecords =
+ mSnoozedNotifications.get(userPkgKey);
+ Set<String> snoozedKeys = snoozedRecords.keySet();
+ for (String key : snoozedKeys) {
pw.print(INDENT);
pw.print(INDENT);
- pw.println("package: " + pkg);
- Set<String> snoozedKeys = snoozedPkgs.get(pkg).keySet();
- for (String key : snoozedKeys) {
- pw.print(INDENT);
- pw.print(INDENT);
- pw.print(INDENT);
- pw.println(key);
- }
+ pw.print(INDENT);
+ pw.println(key);
+ }
+ }
+ pw.println("\n Pending snoozed notifications");
+ for (String userPkgKey : mPersistedSnoozedNotifications.keySet()) {
+ pw.print(INDENT);
+ pw.println("key: " + userPkgKey);
+ ArrayMap<String, Long> snoozedRecords =
+ mPersistedSnoozedNotifications.get(userPkgKey);
+ if (snoozedRecords == null) {
+ continue;
+ }
+ Set<String> snoozedKeys = snoozedRecords.keySet();
+ for (String key : snoozedKeys) {
+ pw.print(INDENT);
+ pw.print(INDENT);
+ pw.print(INDENT);
+ pw.print(key);
+ pw.print(INDENT);
+ pw.println(snoozedRecords.get(key));
}
}
}
@@ -538,41 +497,34 @@ public class SnoozeHelper {
void insert(T t) throws IOException;
}
private <T> void writeXml(XmlSerializer out,
- ArrayMap<Integer, ArrayMap<String, ArrayMap<String, T>>> targets, String tag,
+ ArrayMap<String, ArrayMap<String, T>> targets, String tag,
Inserter<T> attributeInserter)
throws IOException {
synchronized (targets) {
final int M = targets.size();
for (int i = 0; i < M; i++) {
- final ArrayMap<String, ArrayMap<String, T>> packages =
- targets.valueAt(i);
- if (packages == null) {
- continue;
- }
- final int N = packages.size();
- for (int j = 0; j < N; j++) {
- final ArrayMap<String, T> keyToValue = packages.valueAt(j);
- if (keyToValue == null) {
- continue;
- }
- final int O = keyToValue.size();
- for (int k = 0; k < O; k++) {
- T value = keyToValue.valueAt(k);
+ String userIdPkgKey = targets.keyAt(i);
+ // T is a String (snoozed until context) or Long (snoozed until time)
+ ArrayMap<String, T> keyToValue = targets.valueAt(i);
+ for (int j = 0; j < keyToValue.size(); j++) {
+ String key = keyToValue.keyAt(j);
+ T value = keyToValue.valueAt(j);
- out.startTag(null, tag);
+ out.startTag(null, tag);
- attributeInserter.insert(value);
+ attributeInserter.insert(value);
- out.attribute(null, XML_SNOOZED_NOTIFICATION_VERSION_LABEL,
- XML_SNOOZED_NOTIFICATION_VERSION);
- out.attribute(null, XML_SNOOZED_NOTIFICATION_KEY, keyToValue.keyAt(k));
- out.attribute(null, XML_SNOOZED_NOTIFICATION_PKG, packages.keyAt(j));
- out.attribute(null, XML_SNOOZED_NOTIFICATION_USER_ID,
- targets.keyAt(i).toString());
+ out.attribute(null, XML_SNOOZED_NOTIFICATION_VERSION_LABEL,
+ XML_SNOOZED_NOTIFICATION_VERSION);
+ out.attribute(null, XML_SNOOZED_NOTIFICATION_KEY, key);
- out.endTag(null, tag);
+ String pkg = mPackages.get(key);
+ int userId = mUsers.get(key);
+ out.attribute(null, XML_SNOOZED_NOTIFICATION_PKG, pkg);
+ out.attribute(null, XML_SNOOZED_NOTIFICATION_USER_ID,
+ String.valueOf(userId));
- }
+ out.endTag(null, tag);
}
}
}
@@ -606,7 +558,6 @@ public class SnoozeHelper {
}
scheduleRepost(pkg, key, userId, time - System.currentTimeMillis());
}
- continue;
}
if (tag.equals(XML_SNOOZED_NOTIFICATION_CONTEXT)) {
final String creationId = parser.getAttributeValue(
@@ -615,18 +566,9 @@ public class SnoozeHelper {
storeRecord(pkg, key, userId, mPersistedSnoozedNotificationsWithContext,
creationId);
}
- continue;
}
-
-
} catch (Exception e) {
- //we dont cre if it is a number format exception or a null pointer exception.
- //we just want to debug it and continue with our lives
- if (DEBUG) {
- Slog.d(TAG,
- "Exception in reading snooze data from policy xml: "
- + e.getMessage());
- }
+ Slog.e(TAG, "Exception in reading snooze data from policy xml", e);
}
}
}
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index d629b547992b..0fb889c8da22 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -69,7 +69,7 @@ public class AppsFilter {
// Logs all filtering instead of enforcing
private static final boolean DEBUG_ALLOW_ALL = false;
private static final boolean DEBUG_LOGGING = false;
- private static final boolean FEATURE_ENABLED_BY_DEFAULT = false;
+ private static final boolean FEATURE_ENABLED_BY_DEFAULT = true;
/**
* This contains a list of app UIDs that are implicitly queryable because another app explicitly
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index c267cea163d5..f1e403b1bc63 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -119,6 +119,7 @@ import java.io.PrintWriter;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
+import java.util.Base64;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
@@ -135,7 +136,6 @@ import java.util.concurrent.TimeUnit;
class PackageManagerShellCommand extends ShellCommand {
/** Path for streaming APK content */
private static final String STDIN_PATH = "-";
- private static final byte[] STDIN_PATH_BYTES = "-".getBytes(StandardCharsets.UTF_8);
/** Path where ART profiles snapshots are dumped for the shell user */
private final static String ART_PROFILE_SNAPSHOT_DEBUG_LOCATION = "/data/misc/profman/";
private static final int DEFAULT_WAIT_MS = 60 * 1000;
@@ -2988,8 +2988,10 @@ class PackageManagerShellCommand extends ShellCommand {
try {
// 1. Single file from stdin.
if (args.isEmpty() || STDIN_PATH.equals(args.get(0))) {
- String name = "base." + (isApex ? "apex" : "apk");
- session.addFile(LOCATION_DATA_APP, name, sessionSizeBytes, STDIN_PATH_BYTES, null);
+ final String name = "base." + (isApex ? "apex" : "apk");
+ final String metadata = "-" + name;
+ session.addFile(LOCATION_DATA_APP, name, sessionSizeBytes,
+ metadata.getBytes(StandardCharsets.UTF_8), null);
return 0;
}
@@ -2998,24 +3000,58 @@ class PackageManagerShellCommand extends ShellCommand {
// 2. File with specified size read from stdin.
if (delimLocation != -1) {
- String name = arg.substring(0, delimLocation);
- String sizeStr = arg.substring(delimLocation + 1);
- long sizeBytes;
+ final String[] fileDesc = arg.split(":");
+ String name = null;
+ long sizeBytes = -1;
+ String metadata;
+ byte[] signature = null;
+
+ try {
+ if (fileDesc.length > 0) {
+ name = fileDesc[0];
+ }
+ if (fileDesc.length > 1) {
+ sizeBytes = Long.parseUnsignedLong(fileDesc[1]);
+ }
+ if (fileDesc.length > 2 && !TextUtils.isEmpty(fileDesc[2])) {
+ metadata = fileDesc[2];
+ } else {
+ metadata = name;
+ }
+ if (fileDesc.length > 3) {
+ signature = Base64.getDecoder().decode(fileDesc[3]);
+ }
+ } catch (IllegalArgumentException e) {
+ getErrPrintWriter().println(
+ "Unable to parse file parameters: " + arg + ", reason: " + e);
+ return 1;
+ }
if (TextUtils.isEmpty(name)) {
getErrPrintWriter().println("Empty file name in: " + arg);
return 1;
}
+
+ if (signature != null) {
+ // Streaming/adb mode.
+ metadata = "+" + metadata;
+ } else {
+ // Singleshot read from stdin.
+ metadata = "-" + metadata;
+ }
+
try {
- sizeBytes = Long.parseUnsignedLong(sizeStr);
- } catch (NumberFormatException e) {
- getErrPrintWriter().println("Unable to parse size from: " + arg);
+ if (V4Signature.readFrom(signature) == null) {
+ getErrPrintWriter().println("V4 signature is invalid in: " + arg);
+ return 1;
+ }
+ } catch (Exception e) {
+ getErrPrintWriter().println("V4 signature is invalid: " + e + " in " + arg);
return 1;
}
- // Incremental requires unique metadatas, let's add a name to the dash.
session.addFile(LOCATION_DATA_APP, name, sizeBytes,
- ("-" + name).getBytes(StandardCharsets.UTF_8), null);
+ metadata.getBytes(StandardCharsets.UTF_8), signature);
continue;
}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 0fb4cb036282..832c9b788b0b 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -4393,6 +4393,7 @@ public final class Settings {
ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT, "SYSTEM_EXT",
ApplicationInfo.PRIVATE_FLAG_VIRTUAL_PRELOAD, "VIRTUAL_PRELOAD",
ApplicationInfo.PRIVATE_FLAG_ODM, "ODM",
+ ApplicationInfo.PRIVATE_FLAG_ALLOW_NATIVE_HEAP_POINTER_TAGGING, "PRIVATE_FLAG_ALLOW_NATIVE_HEAP_POINTER_TAGGING",
};
void dumpVersionLPr(IndentingPrintWriter pw) {
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index 67a22d3e477c..39093aec07c0 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -866,6 +866,10 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
}
}
+ default int getMaxWindowLayer() {
+ return 35;
+ }
+
/**
* Return how to Z-order sub-windows in relation to the window they are attached to.
* Return positive to have them ordered in front, negative for behind.
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index 9e150fd6a8b3..f9981d0d9c96 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -802,7 +802,6 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
newRollback = getRollbackForSessionLocked(packageSession.getSessionId());
if (newRollback == null) {
newRollback = createNewRollbackLocked(parentSession);
- mRollbacks.add(newRollback);
}
}
newRollback.addToken(token);
@@ -1002,11 +1001,10 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
}
}
- Rollback rollback = completeEnableRollback(newRollback);
- if (rollback == null) {
+ if (!completeEnableRollback(newRollback)) {
result.offer(-1);
} else {
- result.offer(rollback.info.getRollbackId());
+ result.offer(newRollback.info.getRollbackId());
}
});
@@ -1158,19 +1156,10 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
Rollback rollback;
synchronized (mLock) {
rollback = getRollbackForSessionLocked(sessionId);
- if (rollback == null || rollback.isStaged() || !rollback.isEnabling()
- || !rollback.notifySessionWithSuccess()) {
- return;
- }
- // All child sessions finished with success. We can enable this rollback now.
- // TODO: refactor #completeEnableRollback so we won't remove 'rollback' from
- // mRollbacks here and add it back in #completeEnableRollback later.
- mRollbacks.remove(rollback);
}
- // TODO: Now #completeEnableRollback returns the same rollback object as the
- // parameter on success. It would be more readable to return a boolean to indicate
- // success or failure.
- if (completeEnableRollback(rollback) != null) {
+ if (rollback != null && !rollback.isStaged() && rollback.isEnabling()
+ && rollback.notifySessionWithSuccess()
+ && completeEnableRollback(rollback)) {
makeRollbackAvailable(rollback);
}
} else {
@@ -1188,13 +1177,14 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
}
/**
- * Add a rollback to the list of rollbacks. It does not make the rollback available yet.
+ * Persist a rollback as enable-completed. It does not make the rollback available yet.
+ * This rollback will be deleted and removed from {@link #mRollbacks} should any error happens.
*
- * @return the Rollback instance for a successfully enable-completed rollback,
- * or null on error.
+ * @return {code true} if {code rollback} is successfully enable-completed,
+ * or {code false} otherwise.
*/
@WorkerThread
- private Rollback completeEnableRollback(Rollback rollback) {
+ private boolean completeEnableRollback(Rollback rollback) {
if (LOCAL_LOGV) {
Slog.v(TAG, "completeEnableRollback id=" + rollback.info.getRollbackId());
}
@@ -1205,26 +1195,24 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
// rollback for the embedded apk-in-apex, if any.
if (!rollback.allPackagesEnabled()) {
Slog.e(TAG, "Failed to enable rollback for all packages in session.");
+ mRollbacks.remove(rollback);
rollback.delete(mAppDataRollbackHelper);
- return null;
+ return false;
}
+ // Note: There is a small window of time between when
+ // the session has been committed by the package
+ // manager and when we make the rollback available
+ // here. Presumably the window is small enough that
+ // nobody will want to roll back the newly installed
+ // package before we make the rollback available.
+ // TODO: We'll lose the rollback if the
+ // device reboots between when the session is
+ // committed and this point. Revisit this after
+ // adding support for rollback of staged installs.
rollback.saveRollback();
- synchronized (mLock) {
- // Note: There is a small window of time between when
- // the session has been committed by the package
- // manager and when we make the rollback available
- // here. Presumably the window is small enough that
- // nobody will want to roll back the newly installed
- // package before we make the rollback available.
- // TODO: We'll lose the rollback if the
- // device reboots between when the session is
- // committed and this point. Revisit this after
- // adding support for rollback of staged installs.
- mRollbacks.add(rollback);
- }
- return rollback;
+ return true;
}
@WorkerThread
@@ -1304,6 +1292,10 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
}
}
+ /**
+ * Creates and returns a Rollback according to the given SessionInfo
+ * and adds it to {@link #mRollbacks}.
+ */
@WorkerThread
@GuardedBy("mLock")
private Rollback createNewRollbackLocked(PackageInstaller.SessionInfo parentSession) {
@@ -1338,6 +1330,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
installerPackageName, packageSessionIds);
}
+ mRollbacks.add(rollback);
return rollback;
}
diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java
index b3edc91a4129..0d365b16e228 100644
--- a/services/core/java/com/android/server/wm/DisplayArea.java
+++ b/services/core/java/com/android/server/wm/DisplayArea.java
@@ -102,6 +102,11 @@ public class DisplayArea<T extends WindowContainer> extends WindowContainer<T> {
}
@Override
+ public String toString() {
+ return mName + "@" + System.identityHashCode(this);
+ }
+
+ @Override
public final void dumpDebug(ProtoOutputStream proto, long fieldId, int logLevel) {
final long token = proto.start(fieldId);
super.dumpDebug(proto, WINDOW_CONTAINER, logLevel);
diff --git a/services/core/java/com/android/server/wm/DisplayAreaPolicy.java b/services/core/java/com/android/server/wm/DisplayAreaPolicy.java
index 9e93e1455f2c..0ec0c7b53875 100644
--- a/services/core/java/com/android/server/wm/DisplayAreaPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayAreaPolicy.java
@@ -16,8 +16,6 @@
package com.android.server.wm;
-import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
-
import android.content.res.Resources;
import android.text.TextUtils;
@@ -43,7 +41,7 @@ public abstract class DisplayAreaPolicy {
/**
* The Tasks container. Tasks etc. are automatically added to this container.
*/
- protected final TaskContainers mTaskContainers;
+ protected final DisplayArea<? extends ActivityStack> mTaskContainers;
/**
* Construct a new {@link DisplayAreaPolicy}
@@ -58,7 +56,8 @@ public abstract class DisplayAreaPolicy {
*/
protected DisplayAreaPolicy(WindowManagerService wmService,
DisplayContent content, DisplayArea.Root root,
- DisplayArea<? extends WindowContainer> imeContainer, TaskContainers taskContainers) {
+ DisplayArea<? extends WindowContainer> imeContainer,
+ DisplayArea<? extends ActivityStack> taskContainers) {
mWmService = wmService;
mContent = content;
mRoot = root;
@@ -83,67 +82,15 @@ public abstract class DisplayAreaPolicy {
*/
public abstract void addWindow(WindowToken token);
- /**
- * Default policy that has no special features.
- */
- public static class Default extends DisplayAreaPolicy {
-
- public Default(WindowManagerService wmService, DisplayContent content,
- DisplayArea.Root root,
+ /** Provider for platform-default display area policy. */
+ static final class DefaultProvider implements DisplayAreaPolicy.Provider {
+ @Override
+ public DisplayAreaPolicy instantiate(WindowManagerService wmService,
+ DisplayContent content, DisplayArea.Root root,
DisplayArea<? extends WindowContainer> imeContainer,
TaskContainers taskContainers) {
- super(wmService, content, root, imeContainer, taskContainers);
- }
-
- private final DisplayArea.Tokens mBelow = new DisplayArea.Tokens(mWmService,
- DisplayArea.Type.BELOW_TASKS, "BelowTasks");
- private final DisplayArea<DisplayArea> mAbove = new DisplayArea<>(mWmService,
- DisplayArea.Type.ABOVE_TASKS, "AboveTasks");
- private final DisplayArea.Tokens mAboveBelowIme = new DisplayArea.Tokens(mWmService,
- DisplayArea.Type.ABOVE_TASKS, "AboveTasksBelowIme");
- private final DisplayArea.Tokens mAboveAboveIme = new DisplayArea.Tokens(mWmService,
- DisplayArea.Type.ABOVE_TASKS, "AboveTasksAboveIme");
-
- @Override
- public void attachDisplayAreas() {
- mRoot.addChild(mBelow, 0);
- mRoot.addChild(mTaskContainers, 1);
- mRoot.addChild(mAbove, 2);
-
- mAbove.addChild(mAboveBelowIme, 0);
- mAbove.addChild(mImeContainer, 1);
- mAbove.addChild(mAboveAboveIme, 2);
- }
-
- @Override
- public void addWindow(WindowToken token) {
- switch (DisplayArea.Type.typeOf(token)) {
- case ABOVE_TASKS:
- if (token.getWindowLayerFromType()
- < mWmService.mPolicy.getWindowLayerFromTypeLw(TYPE_INPUT_METHOD)) {
- mAboveBelowIme.addChild(token);
- } else {
- mAboveAboveIme.addChild(token);
- }
- break;
- case BELOW_TASKS:
- mBelow.addChild(token);
- break;
- default:
- throw new IllegalArgumentException("don't know how to sort " + token);
- }
- }
-
- /** Provider for {@link DisplayAreaPolicy.Default platform-default display area policy}. */
- static class Provider implements DisplayAreaPolicy.Provider {
- @Override
- public DisplayAreaPolicy instantiate(WindowManagerService wmService,
- DisplayContent content, DisplayArea.Root root,
- DisplayArea<? extends WindowContainer> imeContainer,
- TaskContainers taskContainers) {
- return new DisplayAreaPolicy.Default(wmService, content, root, imeContainer,
- taskContainers);
- }
+ return new DisplayAreaPolicyBuilder()
+ .build(wmService, content, root, imeContainer, taskContainers);
}
}
@@ -172,7 +119,7 @@ public abstract class DisplayAreaPolicy {
String name = res.getString(
com.android.internal.R.string.config_deviceSpecificDisplayAreaPolicyProvider);
if (TextUtils.isEmpty(name)) {
- return new DisplayAreaPolicy.Default.Provider();
+ return new DisplayAreaPolicy.DefaultProvider();
}
try {
return (Provider) Class.forName(name).newInstance();
diff --git a/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java b/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java
new file mode 100644
index 000000000000..885456a8488c
--- /dev/null
+++ b/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java
@@ -0,0 +1,371 @@
+/*
+ * 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 com.android.server.wm;
+
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
+import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
+import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
+import static android.view.WindowManagerPolicyConstants.APPLICATION_LAYER;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.policy.WindowManagerPolicy;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A builder for instantiating a complex {@link DisplayAreaPolicy}
+ *
+ * <p>Given a set of features (that each target a set of window types), it builds the necessary
+ * DisplayArea hierarchy.
+ *
+ * <p>Example: <br />
+ *
+ * <pre>
+ * // Feature for targeting everything below the magnification overlay:
+ * new DisplayAreaPolicyBuilder(...)
+ * .addFeature(new Feature.Builder(..., "Magnification")
+ * .upTo(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY)
+ * .build())
+ * .build(...)
+ *
+ * // Builds a policy with the following hierarchy:
+ * - DisplayArea.Root
+ * - Magnification
+ * - DisplayArea.Tokens (Wallpapers are attached here)
+ * - TaskContainers
+ * - DisplayArea.Tokens (windows above Tasks up to IME are attached here)
+ * - ImeContainers
+ * - DisplayArea.Tokens (windows above IME up to TYPE_ACCESSIBILITY_OVERLAY attached here)
+ * - DisplayArea.Tokens (TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY and up are attached here)
+ *
+ * </pre>
+ *
+ * // TODO(display-area): document more complex scenarios where we need multiple areas per feature.
+ */
+class DisplayAreaPolicyBuilder {
+
+ private final ArrayList<Feature> mFeatures = new ArrayList<>();
+
+ /**
+ * A feature that requires {@link DisplayArea DisplayArea(s)}.
+ */
+ static class Feature {
+ private final String mName;
+ private final boolean[] mWindowLayers;
+
+ private Feature(String name, boolean[] windowLayers) {
+ mName = name;
+ mWindowLayers = windowLayers;
+ }
+
+ static class Builder {
+ private final WindowManagerPolicy mPolicy;
+ private final String mName;
+ private final boolean[] mLayers;
+
+ /**
+ * Build a new feature that applies to a set of window types as specified by the builder
+ * methods.
+ *
+ * <p>The set of types is updated iteratively in the order of the method invocations.
+ * For example, {@code all().except(TYPE_STATUS_BAR)} expresses that a feature should
+ * apply to all types except TYPE_STATUS_BAR.
+ *
+ * The builder starts out with the feature not applying to any types.
+ *
+ * @param name the name of the feature.
+ */
+ Builder(WindowManagerPolicy policy, String name) {
+ mPolicy = policy;
+ mName = name;
+ mLayers = new boolean[mPolicy.getMaxWindowLayer()];
+ }
+
+ /**
+ * Set that the feature applies to all window types.
+ */
+ Builder all() {
+ Arrays.fill(mLayers, true);
+ return this;
+ }
+
+ /**
+ * Set that the feature applies to the given window types.
+ */
+ Builder and(int... types) {
+ for (int i = 0; i < types.length; i++) {
+ int type = types[i];
+ set(type, true);
+ }
+ return this;
+ }
+
+ /**
+ * Set that the feature does not apply to the given window types.
+ */
+ Builder except(int... types) {
+ for (int i = 0; i < types.length; i++) {
+ int type = types[i];
+ set(type, false);
+ }
+ return this;
+ }
+
+ /**
+ * Set that the feature applies window types that are layerd at or below the layer of
+ * the given window type.
+ */
+ Builder upTo(int typeInclusive) {
+ final int max = layerFromType(typeInclusive, false);
+ for (int i = 0; i < max; i++) {
+ mLayers[i] = true;
+ }
+ set(typeInclusive, true);
+ return this;
+ }
+
+ Feature build() {
+ return new Feature(mName, mLayers.clone());
+ }
+
+ private void set(int type, boolean value) {
+ mLayers[layerFromType(type, true)] = value;
+ if (type == TYPE_APPLICATION_OVERLAY) {
+ mLayers[layerFromType(type, true)] = value;
+ mLayers[layerFromType(TYPE_SYSTEM_ALERT, false)] = value;
+ mLayers[layerFromType(TYPE_SYSTEM_OVERLAY, false)] = value;
+ mLayers[layerFromType(TYPE_SYSTEM_ERROR, false)] = value;
+ }
+ }
+
+ private int layerFromType(int type, boolean internalWindows) {
+ return mPolicy.getWindowLayerFromTypeLw(type, internalWindows);
+ }
+ }
+ }
+
+ static class Result extends DisplayAreaPolicy {
+ private static final int LEAF_TYPE_TASK_CONTAINERS = 1;
+ private static final int LEAF_TYPE_IME_CONTAINERS = 2;
+ private static final int LEAF_TYPE_TOKENS = 0;
+
+ private final int mMaxWindowLayer = mWmService.mPolicy.getMaxWindowLayer();
+
+ private final ArrayList<Feature> mFeatures;
+ private final Map<Feature, List<DisplayArea<? extends WindowContainer>>> mAreas;
+ private final DisplayArea.Tokens[] mAreaForLayer = new DisplayArea.Tokens[mMaxWindowLayer];
+
+ Result(WindowManagerService wmService, DisplayContent content, DisplayArea.Root root,
+ DisplayArea<? extends WindowContainer> imeContainer,
+ DisplayArea<? extends ActivityStack> taskStacks, ArrayList<Feature> features) {
+ super(wmService, content, root, imeContainer, taskStacks);
+ mFeatures = features;
+ mAreas = new HashMap<>(features.size());
+ for (int i = 0; i < mFeatures.size(); i++) {
+ mAreas.put(mFeatures.get(i), new ArrayList<>());
+ }
+ }
+
+ @Override
+ public void attachDisplayAreas() {
+ // This method constructs the layer hierarchy with the following properties:
+ // (1) Every feature maps to a set of DisplayAreas
+ // (2) After adding a window, for every feature the window's type belongs to,
+ // it is a descendant of one of the corresponding DisplayAreas of the feature.
+ // (3) Z-order is maintained, i.e. if z-range(area) denotes the set of layers of windows
+ // within a DisplayArea:
+ // for every pair of DisplayArea siblings (a,b), where a is below b, it holds that
+ // max(z-range(a)) <= min(z-range(b))
+ //
+ // The algorithm below iteratively creates such a hierarchy:
+ // - Initially, all windows are attached to the root.
+ // - For each feature we create a set of DisplayAreas, by looping over the layers
+ // - if the feature does apply to the current layer, we need to find a DisplayArea
+ // for it to satisfy (2)
+ // - we can re-use the previous layer's area if:
+ // the current feature also applies to the previous layer, (to satisfy (3))
+ // and the last feature that applied to the previous layer is the same as
+ // the last feature that applied to the current layer (to satisfy (2))
+ // - otherwise we create a new DisplayArea below the last feature that applied
+ // to the current layer
+
+
+ PendingArea[] areaForLayer = new PendingArea[mMaxWindowLayer];
+ final PendingArea root = new PendingArea(null, 0, null);
+ Arrays.fill(areaForLayer, root);
+
+ final int size = mFeatures.size();
+ for (int i = 0; i < size; i++) {
+ PendingArea featureArea = null;
+ for (int layer = 0; layer < mMaxWindowLayer; layer++) {
+ final Feature feature = mFeatures.get(i);
+ if (feature.mWindowLayers[layer]) {
+ if (featureArea == null || featureArea.mParent != areaForLayer[layer]) {
+ // No suitable DisplayArea - create a new one under the previous area
+ // for this layer.
+ featureArea = new PendingArea(feature, layer, areaForLayer[layer]);
+ areaForLayer[layer].mChildren.add(featureArea);
+ }
+ areaForLayer[layer] = featureArea;
+ } else {
+ featureArea = null;
+ }
+ }
+ }
+
+ PendingArea leafArea = null;
+ int leafType = LEAF_TYPE_TOKENS;
+ for (int layer = 0; layer < mMaxWindowLayer; layer++) {
+ int type = typeOfLayer(mWmService.mPolicy, layer);
+ if (leafArea == null || leafArea.mParent != areaForLayer[layer]
+ || type != leafType) {
+ leafArea = new PendingArea(null, layer, areaForLayer[layer]);
+ areaForLayer[layer].mChildren.add(leafArea);
+ leafType = type;
+ if (leafType == LEAF_TYPE_TASK_CONTAINERS) {
+ leafArea.mExisting = mTaskContainers;
+ } else if (leafType == LEAF_TYPE_IME_CONTAINERS) {
+ leafArea.mExisting = mImeContainer;
+ }
+ }
+ leafArea.mMaxLayer = layer;
+ }
+ root.computeMaxLayer();
+ root.instantiateChildren(mRoot, mAreaForLayer, 0, mAreas);
+ }
+
+ @Override
+ public void addWindow(WindowToken token) {
+ DisplayArea.Tokens area = findAreaForToken(token);
+ area.addChild(token);
+ }
+
+ @VisibleForTesting
+ DisplayArea.Tokens findAreaForToken(WindowToken token) {
+ int windowLayerFromType = token.getWindowLayerFromType();
+ if (windowLayerFromType == APPLICATION_LAYER) {
+ // TODO(display-area): Better handle AboveAppWindows in APPLICATION_LAYER
+ windowLayerFromType += 1;
+ } else if (token.mRoundedCornerOverlay) {
+ windowLayerFromType = mMaxWindowLayer - 1;
+ }
+ return mAreaForLayer[windowLayerFromType];
+ }
+
+ public List<DisplayArea<? extends WindowContainer>> getDisplayAreas(Feature feature) {
+ return mAreas.get(feature);
+ }
+
+ private static int typeOfLayer(WindowManagerPolicy policy, int layer) {
+ if (layer == APPLICATION_LAYER) {
+ return LEAF_TYPE_TASK_CONTAINERS;
+ } else if (layer == policy.getWindowLayerFromTypeLw(TYPE_INPUT_METHOD)
+ || layer == policy.getWindowLayerFromTypeLw(TYPE_INPUT_METHOD_DIALOG)) {
+ return LEAF_TYPE_IME_CONTAINERS;
+ } else {
+ return LEAF_TYPE_TOKENS;
+ }
+ }
+ }
+
+ DisplayAreaPolicyBuilder addFeature(Feature feature) {
+ mFeatures.add(feature);
+ return this;
+ }
+
+ Result build(WindowManagerService wmService,
+ DisplayContent content, DisplayArea.Root root,
+ DisplayArea<? extends WindowContainer> imeContainer,
+ DisplayArea<? extends ActivityStack> taskContainers) {
+
+ return new Result(wmService, content, root, imeContainer, taskContainers, new ArrayList<>(
+ mFeatures));
+ }
+
+ static class PendingArea {
+ final int mMinLayer;
+ final ArrayList<PendingArea> mChildren = new ArrayList<>();
+ final Feature mFeature;
+ final PendingArea mParent;
+ int mMaxLayer;
+ DisplayArea mExisting;
+
+ PendingArea(Feature feature,
+ int minLayer,
+ PendingArea parent) {
+ mMinLayer = minLayer;
+ mFeature = feature;
+ mParent = parent;
+ }
+
+ int computeMaxLayer() {
+ for (int i = 0; i < mChildren.size(); i++) {
+ mMaxLayer = Math.max(mMaxLayer, mChildren.get(i).computeMaxLayer());
+ }
+ return mMaxLayer;
+ }
+
+ void instantiateChildren(DisplayArea<DisplayArea> parent,
+ DisplayArea.Tokens[] areaForLayer, int level, Map<Feature, List<DisplayArea<?
+ extends WindowContainer>>> areas) {
+ mChildren.sort(Comparator.comparingInt(pendingArea -> pendingArea.mMinLayer));
+ for (int i = 0; i < mChildren.size(); i++) {
+ final PendingArea child = mChildren.get(i);
+ final DisplayArea area = child.createArea(parent, areaForLayer);
+ parent.addChild(area, WindowContainer.POSITION_TOP);
+ if (mFeature != null) {
+ areas.get(mFeature).add(area);
+ }
+ child.instantiateChildren(area, areaForLayer, level + 1, areas);
+ }
+ }
+
+ private DisplayArea createArea(DisplayArea<DisplayArea> parent,
+ DisplayArea.Tokens[] areaForLayer) {
+ if (mExisting != null) {
+ return mExisting;
+ }
+ DisplayArea.Type type;
+ if (mMinLayer > APPLICATION_LAYER) {
+ type = DisplayArea.Type.ABOVE_TASKS;
+ } else if (mMaxLayer < APPLICATION_LAYER) {
+ type = DisplayArea.Type.BELOW_TASKS;
+ } else {
+ type = DisplayArea.Type.ANY;
+ }
+ if (mFeature == null) {
+ final DisplayArea.Tokens leaf = new DisplayArea.Tokens(parent.mWmService, type,
+ "Leaf:" + mMinLayer + ":" + mMaxLayer);
+ for (int i = mMinLayer; i <= mMaxLayer; i++) {
+ areaForLayer[i] = leaf;
+ }
+ return leaf;
+ } else {
+ return new DisplayArea(parent.mWmService, type, mFeature.mName + ":"
+ + mMinLayer + ":" + mMaxLayer);
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 2196d899406d..e3d85c84b50c 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -2008,10 +2008,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = display.getStackAt(stackNdx);
stack.switchUser(userId);
- Task task = stack.getTopMostTask();
- if (task != null && task != stack) {
- stack.positionChildAtTop(task);
- }
}
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 8f9caea26534..2bb67035f44b 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -7317,9 +7317,11 @@ public class WindowManagerService extends IWindowManager.Stub
Slog.w(TAG_WM, "updateInputMethodTargetWindow: imeToken=" + imeToken
+ " imeTargetWindowToken=" + imeTargetWindowToken);
}
- final WindowState imeTarget = mWindowMap.get(imeTargetWindowToken);
- if (imeTarget != null) {
- imeTarget.getDisplayContent().updateImeControlTarget(imeTarget);
+ synchronized (mGlobalLock) {
+ final WindowState imeTarget = mWindowMap.get(imeTargetWindowToken);
+ if (imeTarget != null) {
+ imeTarget.getDisplayContent().updateImeControlTarget(imeTarget);
+ }
}
}
diff --git a/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp b/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp
index 7e6f79f0d407..70a9c09c815d 100644
--- a/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp
+++ b/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp
@@ -18,18 +18,27 @@
#define LOG_TAG "PackageManagerShellCommandDataLoader-jni"
#include <android-base/logging.h>
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
#include <android-base/unique_fd.h>
-#include <nativehelper/JNIHelp.h>
-#include "android-base/file.h"
+#include <cutils/trace.h>
+#include <sys/eventfd.h>
+#include <sys/poll.h>
-#include <endian.h>
+#include <nativehelper/JNIHelp.h>
#include <core_jni_helpers.h>
+#include <endian.h>
#include "dataloader.h"
+#include <charconv>
#include <chrono>
+#include <span>
+#include <string>
#include <thread>
+#include <unordered_map>
+#include <unordered_set>
namespace android {
@@ -39,9 +48,26 @@ using android::base::borrowed_fd;
using android::base::ReadFully;
using android::base::unique_fd;
+using namespace std::literals;
+
+using BlockSize = int16_t;
+using FileIdx = int16_t;
+using BlockIdx = int32_t;
+using NumBlocks = int32_t;
+using CompressionType = int16_t;
+using RequestType = int16_t;
+using MagicType = uint32_t;
+
static constexpr int BUFFER_SIZE = 256 * 1024;
static constexpr int BLOCKS_COUNT = BUFFER_SIZE / INCFS_DATA_FILE_BLOCK_SIZE;
+static constexpr int COMMAND_SIZE = 4 + 2 + 2 + 4; // bytes
+static constexpr int HEADER_SIZE = 2 + 2 + 4 + 2; // bytes
+static constexpr std::string_view OKAY = "OKAY"sv;
+static constexpr MagicType INCR = 0x52434e49; // BE INCR
+
+static constexpr auto PollTimeoutMs = 5000;
+
struct JniIds {
jclass packageManagerShellCommandDataLoader;
jmethodID pmscdLookupShellCommand;
@@ -85,6 +111,70 @@ const JniIds& jniIds(JNIEnv* env) {
return ids;
}
+struct BlockHeader {
+ FileIdx fileIdx = -1;
+ CompressionType compressionType = -1;
+ BlockIdx blockIdx = -1;
+ BlockSize blockSize = -1;
+} __attribute__((packed));
+
+static_assert(sizeof(BlockHeader) == HEADER_SIZE);
+
+static constexpr RequestType EXIT = 0;
+static constexpr RequestType BLOCK_MISSING = 1;
+static constexpr RequestType PREFETCH = 2;
+
+struct RequestCommand {
+ MagicType magic;
+ RequestType requestType;
+ FileIdx fileIdx;
+ BlockIdx blockIdx;
+} __attribute__((packed));
+
+static_assert(COMMAND_SIZE == sizeof(RequestCommand));
+
+static bool sendRequest(int fd, RequestType requestType, FileIdx fileIdx = -1,
+ BlockIdx blockIdx = -1) {
+ const RequestCommand command{.magic = INCR,
+ .requestType = static_cast<int16_t>(be16toh(requestType)),
+ .fileIdx = static_cast<int16_t>(be16toh(fileIdx)),
+ .blockIdx = static_cast<int32_t>(be32toh(blockIdx))};
+ return android::base::WriteFully(fd, &command, sizeof(command));
+}
+
+static int waitForDataOrSignal(int fd, int event_fd) {
+ struct pollfd pfds[2] = {{fd, POLLIN, 0}, {event_fd, POLLIN, 0}};
+ // Wait indefinitely until either data is ready or stop signal is received
+ int res = poll(pfds, 2, PollTimeoutMs);
+ if (res <= 0) {
+ return res;
+ }
+ // First check if there is a stop signal
+ if (pfds[1].revents == POLLIN) {
+ return event_fd;
+ }
+ // Otherwise check if incoming data is ready
+ if (pfds[0].revents == POLLIN) {
+ return fd;
+ }
+ return -1;
+}
+
+static bool readChunk(int fd, std::vector<uint8_t>& data) {
+ int32_t size;
+ if (!android::base::ReadFully(fd, &size, sizeof(size))) {
+ return false;
+ }
+ size = int32_t(be32toh(size));
+ if (size <= 0) {
+ return false;
+ }
+ data.resize(size);
+ return android::base::ReadFully(fd, data.data(), data.size());
+}
+
+BlockHeader readHeader(std::span<uint8_t>& data);
+
static inline int32_t readBEInt32(borrowed_fd fd) {
int32_t result;
ReadFully(fd, &result, sizeof(result));
@@ -106,6 +196,22 @@ static inline int32_t skipIdSigHeaders(borrowed_fd fd) {
return readBEInt32(fd); // size of the verity tree
}
+static inline IncFsSize verityTreeSizeForFile(IncFsSize fileSize) {
+ constexpr int SHA256_DIGEST_SIZE = 32;
+ constexpr int digest_size = SHA256_DIGEST_SIZE;
+ constexpr int hash_per_block = INCFS_DATA_FILE_BLOCK_SIZE / digest_size;
+
+ IncFsSize total_tree_block_count = 0;
+
+ auto block_count = 1 + (fileSize - 1) / INCFS_DATA_FILE_BLOCK_SIZE;
+ auto hash_block_count = block_count;
+ for (auto i = 0; hash_block_count > 1; i++) {
+ hash_block_count = (hash_block_count + hash_per_block - 1) / hash_per_block;
+ total_tree_block_count += hash_block_count;
+ }
+ return total_tree_block_count * INCFS_DATA_FILE_BLOCK_SIZE;
+}
+
static inline unique_fd convertPfdToFdAndDup(JNIEnv* env, const JniIds& jni, jobject pfd) {
if (!pfd) {
ALOGE("Missing In ParcelFileDescriptor.");
@@ -125,8 +231,9 @@ static inline unique_fd convertPfdToFdAndDup(JNIEnv* env, const JniIds& jni, job
struct InputDesc {
unique_fd fd;
IncFsSize size;
- IncFsBlockKind kind;
- bool waitOnEof;
+ IncFsBlockKind kind = INCFS_BLOCK_KIND_DATA;
+ bool waitOnEof = false;
+ bool streaming = false;
};
using InputDescs = std::vector<InputDesc>;
@@ -135,8 +242,7 @@ static inline InputDescs openInputs(JNIEnv* env, const JniIds& jni, jobject shel
InputDescs result;
result.reserve(2);
- const bool fromStdin = (metadata.size == 0 || *metadata.data == '-');
- if (fromStdin) {
+ if (metadata.size == 0 || *metadata.data == '-') {
// stdin
auto fd = convertPfdToFdAndDup(
env, jni,
@@ -146,12 +252,29 @@ static inline InputDescs openInputs(JNIEnv* env, const JniIds& jni, jobject shel
result.push_back(InputDesc{
.fd = std::move(fd),
.size = size,
- .kind = INCFS_BLOCK_KIND_DATA,
.waitOnEof = true,
});
}
return result;
}
+ if (*metadata.data == '+') {
+ // verity tree from stdin, rest is streaming
+ auto fd = convertPfdToFdAndDup(
+ env, jni,
+ env->CallStaticObjectMethod(jni.packageManagerShellCommandDataLoader,
+ jni.pmscdGetStdInPFD, shellCommand));
+ if (fd.ok()) {
+ auto treeSize = verityTreeSizeForFile(size);
+ result.push_back(InputDesc{
+ .fd = std::move(fd),
+ .size = treeSize,
+ .kind = INCFS_BLOCK_KIND_HASH,
+ .waitOnEof = true,
+ .streaming = true,
+ });
+ }
+ return result;
+ }
// local file and possibly signature
const std::string filePath(metadata.data, metadata.size);
@@ -163,13 +286,17 @@ static inline InputDescs openInputs(JNIEnv* env, const JniIds& jni, jobject shel
jni.pmscdGetLocalFile, shellCommand,
env->NewStringUTF(idsigPath.c_str())));
if (idsigFd.ok()) {
- ALOGE("idsig found, skipping to the tree");
- auto treeSize = skipIdSigHeaders(idsigFd);
+ auto treeSize = verityTreeSizeForFile(size);
+ auto actualTreeSize = skipIdSigHeaders(idsigFd);
+ if (treeSize != actualTreeSize) {
+ ALOGE("Verity tree size mismatch: %d vs .idsig: %d.", int(treeSize),
+ int(actualTreeSize));
+ return {};
+ }
result.push_back(InputDesc{
.fd = std::move(idsigFd),
.size = treeSize,
.kind = INCFS_BLOCK_KIND_HASH,
- .waitOnEof = false,
});
}
@@ -182,8 +309,6 @@ static inline InputDescs openInputs(JNIEnv* env, const JniIds& jni, jobject shel
result.push_back(InputDesc{
.fd = std::move(fileFd),
.size = size,
- .kind = INCFS_BLOCK_KIND_DATA,
- .waitOnEof = false,
});
}
@@ -226,19 +351,32 @@ private:
android::dataloader::StatusListenerPtr statusListener,
android::dataloader::ServiceConnectorPtr,
android::dataloader::ServiceParamsPtr) final {
+ CHECK(ifs) << "ifs can't be null";
+ CHECK(statusListener) << "statusListener can't be null";
mArgs = params.arguments();
mIfs = ifs;
+ mStatusListener = statusListener;
return true;
}
bool onStart() final { return true; }
- void onStop() final {}
- void onDestroy() final {}
-
- // IFS callbacks.
- void onPendingReads(const dataloader::PendingReads& pendingReads) final {}
- void onPageReads(const dataloader::PageReads& pageReads) final {}
+ void onStop() final {
+ mStopReceiving = true;
+ eventfd_write(mEventFd, 1);
+ if (mReceiverThread.joinable()) {
+ mReceiverThread.join();
+ }
+ }
+ void onDestroy() final {
+ ALOGE("Sending EXIT to server.");
+ sendRequest(mOutFd, EXIT);
+ // Make sure the receiver thread stopped.
+ CHECK(!mReceiverThread.joinable());
+
+ mInFd.reset();
+ mOutFd.reset();
+ }
- // FS callbacks.
+ // Installation.
bool onPrepareImage(const dataloader::DataLoaderInstallationFiles& addedFiles) final {
JNIEnv* env = GetOrAttachJNIEnvironment(mJvm);
const auto& jni = jniIds(env);
@@ -257,6 +395,7 @@ private:
std::vector<IncFsDataBlock> blocks;
blocks.reserve(BLOCKS_COUNT);
+ unique_fd streamingFd;
for (auto&& file : addedFiles) {
auto inputs = openInputs(env, jni, shellCommand, file.size, file.metadata);
if (inputs.empty()) {
@@ -267,7 +406,6 @@ private:
}
const auto fileId = IncFs_FileIdFromMetadata(file.metadata);
-
const auto incfsFd(mIfs->openWrite(fileId));
if (incfsFd < 0) {
ALOGE("Failed to open an IncFS file for metadata: %.*s, final file name is: %s. "
@@ -277,6 +415,9 @@ private:
}
for (auto&& input : inputs) {
+ if (input.streaming && !streamingFd.ok()) {
+ streamingFd.reset(dup(input.fd));
+ }
if (!copyToIncFs(incfsFd, input.size, input.kind, input.fd, input.waitOnEof,
&buffer, &blocks)) {
ALOGE("Failed to copy data to IncFS file for metadata: %.*s, final file name "
@@ -288,7 +429,12 @@ private:
}
}
- ALOGE("All done.");
+ if (streamingFd.ok()) {
+ ALOGE("onPrepareImage: done, proceeding to streaming.");
+ return initStreaming(std::move(streamingFd));
+ }
+
+ ALOGE("onPrepareImage: done.");
return true;
}
@@ -378,11 +524,253 @@ private:
return true;
}
+ // Read tracing.
+ struct TracedRead {
+ uint64_t timestampUs;
+ android::dataloader::FileId fileId;
+ uint32_t firstBlockIdx;
+ uint32_t count;
+ };
+
+ void onPageReads(const android::dataloader::PageReads& pageReads) final {
+ auto trace = atrace_is_tag_enabled(ATRACE_TAG);
+ if (CC_LIKELY(!trace)) {
+ return;
+ }
+
+ TracedRead last = {};
+ for (auto&& read : pageReads) {
+ if (read.id != last.fileId || read.block != last.firstBlockIdx + last.count) {
+ traceRead(last);
+ last = TracedRead{
+ .timestampUs = read.bootClockTsUs,
+ .fileId = read.id,
+ .firstBlockIdx = (uint32_t)read.block,
+ .count = 1,
+ };
+ } else {
+ ++last.count;
+ }
+ }
+ traceRead(last);
+ }
+
+ void traceRead(const TracedRead& read) {
+ if (!read.count) {
+ return;
+ }
+
+ FileIdx fileIdx = convertFileIdToFileIndex(read.fileId);
+ auto str = android::base::StringPrintf("page_read: index=%lld count=%lld file=%d",
+ static_cast<long long>(read.firstBlockIdx),
+ static_cast<long long>(read.count),
+ static_cast<int>(fileIdx));
+ ATRACE_BEGIN(str.c_str());
+ ATRACE_END();
+ }
+
+ // Streaming.
+ bool initStreaming(unique_fd inout) {
+ mInFd.reset(dup(inout));
+ mOutFd.reset(dup(inout));
+ if (mInFd < 0 || mOutFd < 0) {
+ ALOGE("Failed to dup FDs.");
+ return false;
+ }
+
+ mEventFd.reset(eventfd(0, EFD_CLOEXEC));
+ if (mEventFd < 0) {
+ ALOGE("Failed to create eventfd.");
+ return false;
+ }
+
+ // Awaiting adb handshake.
+ char okay_buf[OKAY.size()];
+ if (!android::base::ReadFully(mInFd, okay_buf, OKAY.size())) {
+ ALOGE("Failed to receive OKAY. Abort.");
+ return false;
+ }
+ if (std::string_view(okay_buf, OKAY.size()) != OKAY) {
+ ALOGE("Received '%.*s', expecting '%.*s'", (int)OKAY.size(), okay_buf, (int)OKAY.size(),
+ OKAY.data());
+ return false;
+ }
+
+ mReceiverThread = std::thread([this]() { receiver(); });
+ ALOGI("Started streaming...");
+ return true;
+ }
+
+ // IFS callbacks.
+ void onPendingReads(const dataloader::PendingReads& pendingReads) final {
+ CHECK(mIfs);
+ for (auto&& pendingRead : pendingReads) {
+ const android::dataloader::FileId& fileId = pendingRead.id;
+ const auto blockIdx = static_cast<BlockIdx>(pendingRead.block);
+ /*
+ ALOGI("Missing: %d", (int) blockIdx);
+ */
+ FileIdx fileIdx = convertFileIdToFileIndex(fileId);
+ if (fileIdx < 0) {
+ ALOGE("Failed to handle event for fileid=%s. Ignore.",
+ android::incfs::toString(fileId).c_str());
+ continue;
+ }
+ if (mRequestedFiles.insert(fileIdx).second) {
+ if (!sendRequest(mOutFd, PREFETCH, fileIdx, blockIdx)) {
+ ALOGE("Failed to request prefetch for fileid=%s. Ignore.",
+ android::incfs::toString(fileId).c_str());
+ mRequestedFiles.erase(fileIdx);
+ mStatusListener->reportStatus(DATA_LOADER_NO_CONNECTION);
+ }
+ }
+ sendRequest(mOutFd, BLOCK_MISSING, fileIdx, blockIdx);
+ }
+ }
+
+ void receiver() {
+ std::vector<uint8_t> data;
+ std::vector<IncFsDataBlock> instructions;
+ std::unordered_map<FileIdx, unique_fd> writeFds;
+ while (!mStopReceiving) {
+ const int res = waitForDataOrSignal(mInFd, mEventFd);
+ if (res == 0) {
+ continue;
+ }
+ if (res < 0) {
+ ALOGE("Failed to poll. Abort.");
+ mStatusListener->reportStatus(DATA_LOADER_NO_CONNECTION);
+ break;
+ }
+ if (res == mEventFd) {
+ ALOGE("Received stop signal. Exit.");
+ break;
+ }
+ if (!readChunk(mInFd, data)) {
+ ALOGE("Failed to read a message. Abort.");
+ mStatusListener->reportStatus(DATA_LOADER_NO_CONNECTION);
+ break;
+ }
+ auto remainingData = std::span(data);
+ while (!remainingData.empty()) {
+ auto header = readHeader(remainingData);
+ if (header.fileIdx == -1 && header.compressionType == 0 && header.blockIdx == 0 &&
+ header.blockSize == 0) {
+ ALOGI("Stop signal received. Sending exit command (remaining bytes: %d).",
+ int(remainingData.size()));
+
+ sendRequest(mOutFd, EXIT);
+ mStopReceiving = true;
+ break;
+ }
+ if (header.fileIdx < 0 || header.blockSize <= 0 || header.compressionType < 0 ||
+ header.blockIdx < 0) {
+ ALOGE("invalid header received. Abort.");
+ mStopReceiving = true;
+ break;
+ }
+ const FileIdx fileIdx = header.fileIdx;
+ const android::dataloader::FileId fileId = convertFileIndexToFileId(fileIdx);
+ if (!android::incfs::isValidFileId(fileId)) {
+ ALOGE("Unknown data destination for file ID %d. "
+ "Ignore.",
+ header.fileIdx);
+ continue;
+ }
+
+ auto& writeFd = writeFds[fileIdx];
+ if (writeFd < 0) {
+ writeFd = this->mIfs->openWrite(fileId);
+ if (writeFd < 0) {
+ ALOGE("Failed to open file %d for writing (%d). Aboring.", header.fileIdx,
+ -writeFd);
+ break;
+ }
+ }
+
+ const auto inst = IncFsDataBlock{
+ .fileFd = writeFd,
+ .pageIndex = static_cast<IncFsBlockIndex>(header.blockIdx),
+ .compression = static_cast<IncFsCompressionKind>(header.compressionType),
+ .kind = INCFS_BLOCK_KIND_DATA,
+ .dataSize = static_cast<uint16_t>(header.blockSize),
+ .data = (const char*)remainingData.data(),
+ };
+ instructions.push_back(inst);
+ remainingData = remainingData.subspan(header.blockSize);
+ }
+ writeInstructions(instructions);
+ }
+ writeInstructions(instructions);
+ }
+
+ void writeInstructions(std::vector<IncFsDataBlock>& instructions) {
+ auto res = this->mIfs->writeBlocks(instructions);
+ if (res != instructions.size()) {
+ ALOGE("Dailed to write data to Incfs (res=%d when expecting %d)", res,
+ int(instructions.size()));
+ }
+ instructions.clear();
+ }
+
+ FileIdx convertFileIdToFileIndex(android::dataloader::FileId fileId) {
+ // FileId is a string in format '+FileIdx\0'.
+ const char* meta = (const char*)&fileId;
+ if (*meta != '+') {
+ return -1;
+ }
+
+ int fileIdx;
+ auto res = std::from_chars(meta + 1, meta + sizeof(fileId), fileIdx);
+ if (res.ec != std::errc{} || fileIdx < std::numeric_limits<FileIdx>::min() ||
+ fileIdx > std::numeric_limits<FileIdx>::max()) {
+ return -1;
+ }
+
+ return FileIdx(fileIdx);
+ }
+
+ android::dataloader::FileId convertFileIndexToFileId(FileIdx fileIdx) {
+ IncFsFileId fileId = {};
+ char* meta = (char*)&fileId;
+ *meta = '+';
+ if (auto [p, ec] = std::to_chars(meta + 1, meta + sizeof(fileId), fileIdx);
+ ec != std::errc()) {
+ return {};
+ }
+ return fileId;
+ }
+
JavaVM* const mJvm;
std::string mArgs;
- android::dataloader::FilesystemConnectorPtr mIfs;
+ android::dataloader::FilesystemConnectorPtr mIfs = nullptr;
+ android::dataloader::StatusListenerPtr mStatusListener = nullptr;
+ android::base::unique_fd mInFd;
+ android::base::unique_fd mOutFd;
+ android::base::unique_fd mEventFd;
+ std::thread mReceiverThread;
+ std::atomic<bool> mStopReceiving = false;
+ /** Tracks which files have been requested */
+ std::unordered_set<FileIdx> mRequestedFiles;
};
+BlockHeader readHeader(std::span<uint8_t>& data) {
+ BlockHeader header;
+ if (data.size() < sizeof(header)) {
+ return header;
+ }
+
+ header.fileIdx = static_cast<FileIdx>(be16toh(*reinterpret_cast<const uint16_t*>(&data[0])));
+ header.compressionType =
+ static_cast<CompressionType>(be16toh(*reinterpret_cast<const uint16_t*>(&data[2])));
+ header.blockIdx = static_cast<BlockIdx>(be32toh(*reinterpret_cast<const uint32_t*>(&data[4])));
+ header.blockSize =
+ static_cast<BlockSize>(be16toh(*reinterpret_cast<const uint16_t*>(&data[8])));
+ data = data.subspan(sizeof(header));
+
+ return header;
+}
+
static void nativeInitialize(JNIEnv* env, jclass klass) {
jniIds(env);
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 93662c91af90..1936f13ca6e1 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1741,7 +1741,7 @@ public final class SystemServer {
mSystemServiceManager.startService(SensorNotificationService.class);
t.traceEnd();
- if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_CONTEXTHUB)) {
+ if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_CONTEXT_HUB)) {
t.traceBegin("StartContextHubSystemService");
mSystemServiceManager.startService(ContextHubSystemService.class);
t.traceEnd();
diff --git a/services/people/java/com/android/server/people/data/UsageStatsQueryHelper.java b/services/people/java/com/android/server/people/data/UsageStatsQueryHelper.java
index bf09681e7027..6dcfaa00dfd5 100644
--- a/services/people/java/com/android/server/people/data/UsageStatsQueryHelper.java
+++ b/services/people/java/com/android/server/people/data/UsageStatsQueryHelper.java
@@ -59,7 +59,7 @@ class UsageStatsQueryHelper {
*/
boolean querySince(long sinceTime) {
UsageEvents usageEvents = mUsageStatsManagerInternal.queryEventsForUser(
- mUserId, sinceTime, System.currentTimeMillis(), false, false, false);
+ mUserId, sinceTime, System.currentTimeMillis(), UsageEvents.SHOW_ALL_EVENT_DATA);
if (usageEvents == null) {
return false;
}
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 64da6f6b8590..d7a3cfd8aeca 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
@@ -19,6 +19,12 @@ package com.android.server.job.controllers;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+import static com.android.server.job.JobSchedulerService.ACTIVE_INDEX;
+import static com.android.server.job.JobSchedulerService.FREQUENT_INDEX;
+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.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;
@@ -34,13 +40,16 @@ import static com.android.server.job.controllers.JobStatus.CONSTRAINT_WITHIN_QUO
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.when;
import android.app.job.JobInfo;
import android.app.usage.UsageStatsManagerInternal;
import android.content.ComponentName;
import android.content.pm.PackageManagerInternal;
+import android.net.Uri;
import android.os.SystemClock;
import android.provider.MediaStore;
+import android.util.SparseIntArray;
import androidx.test.runner.AndroidJUnit4;
@@ -52,6 +61,7 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
import org.mockito.MockitoSession;
import org.mockito.quality.Strictness;
@@ -61,7 +71,12 @@ import java.time.ZoneOffset;
@RunWith(AndroidJUnit4.class)
public class JobStatusTest {
private static final double DELTA = 0.00001;
+ private static final String TEST_PACKAGE = "job.test.package";
+ private static final ComponentName TEST_JOB_COMPONENT = new ComponentName(TEST_PACKAGE, "test");
+ private static final Uri TEST_MEDIA_URI = Uri.parse("content://media/path/to/media");
+ @Mock
+ private JobSchedulerInternal mJobSchedulerInternal;
private MockitoSession mMockingSession;
@Before
@@ -71,7 +86,7 @@ public class JobStatusTest {
.strictness(Strictness.LENIENT)
.mockStatic(LocalServices.class)
.startMocking();
- doReturn(mock(JobSchedulerInternal.class))
+ doReturn(mJobSchedulerInternal)
.when(() -> LocalServices.getService(JobSchedulerInternal.class));
doReturn(mock(PackageManagerInternal.class))
.when(() -> LocalServices.getService(PackageManagerInternal.class));
@@ -94,6 +109,82 @@ public class JobStatusTest {
}
}
+ private static void assertEffectiveBucketForMediaExemption(JobStatus jobStatus,
+ boolean exemptionGranted) {
+ final SparseIntArray effectiveBucket = new SparseIntArray();
+ effectiveBucket.put(ACTIVE_INDEX, ACTIVE_INDEX);
+ effectiveBucket.put(WORKING_INDEX, WORKING_INDEX);
+ effectiveBucket.put(FREQUENT_INDEX, exemptionGranted ? WORKING_INDEX : FREQUENT_INDEX);
+ effectiveBucket.put(RARE_INDEX, exemptionGranted ? WORKING_INDEX : RARE_INDEX);
+ effectiveBucket.put(NEVER_INDEX, NEVER_INDEX);
+ effectiveBucket.put(RESTRICTED_INDEX, RESTRICTED_INDEX);
+ for (int i = 0; i < effectiveBucket.size(); i++) {
+ jobStatus.setStandbyBucket(effectiveBucket.keyAt(i));
+ assertEquals(effectiveBucket.valueAt(i), jobStatus.getEffectiveStandbyBucket());
+ }
+ }
+
+ @Test
+ public void testMediaBackupExemption_lateConstraint() {
+ final JobInfo triggerContentJob = new JobInfo.Builder(42, TEST_JOB_COMPONENT)
+ .addTriggerContentUri(new JobInfo.TriggerContentUri(TEST_MEDIA_URI, 0))
+ .setOverrideDeadline(12)
+ .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
+ .build();
+ when(mJobSchedulerInternal.getMediaBackupPackage()).thenReturn(TEST_PACKAGE);
+ assertEffectiveBucketForMediaExemption(createJobStatus(triggerContentJob), false);
+ }
+
+ @Test
+ public void testMediaBackupExemption_noConnectivityConstraint() {
+ final JobInfo triggerContentJob = new JobInfo.Builder(42, TEST_JOB_COMPONENT)
+ .addTriggerContentUri(new JobInfo.TriggerContentUri(TEST_MEDIA_URI, 0))
+ .build();
+ when(mJobSchedulerInternal.getMediaBackupPackage()).thenReturn(TEST_PACKAGE);
+ assertEffectiveBucketForMediaExemption(createJobStatus(triggerContentJob), false);
+ }
+
+ @Test
+ public void testMediaBackupExemption_noContentTriggerConstraint() {
+ final JobInfo networkJob = new JobInfo.Builder(42, TEST_JOB_COMPONENT)
+ .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
+ .build();
+ when(mJobSchedulerInternal.getMediaBackupPackage()).thenReturn(TEST_PACKAGE);
+ assertEffectiveBucketForMediaExemption(createJobStatus(networkJob), false);
+ }
+
+ @Test
+ public void testMediaBackupExemption_wrongSourcePackage() {
+ final JobInfo networkContentJob = new JobInfo.Builder(42, TEST_JOB_COMPONENT)
+ .addTriggerContentUri(new JobInfo.TriggerContentUri(TEST_MEDIA_URI, 0))
+ .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
+ .build();
+ when(mJobSchedulerInternal.getMediaBackupPackage()).thenReturn("not.test.package");
+ assertEffectiveBucketForMediaExemption(createJobStatus(networkContentJob), false);
+ }
+
+ @Test
+ public void testMediaBackupExemption_nonMediaUri() {
+ final Uri nonMediaUri = Uri.parse("content://not-media/any/path");
+ final JobInfo networkContentJob = new JobInfo.Builder(42, TEST_JOB_COMPONENT)
+ .addTriggerContentUri(new JobInfo.TriggerContentUri(TEST_MEDIA_URI, 0))
+ .addTriggerContentUri(new JobInfo.TriggerContentUri(nonMediaUri, 0))
+ .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
+ .build();
+ when(mJobSchedulerInternal.getMediaBackupPackage()).thenReturn(TEST_PACKAGE);
+ assertEffectiveBucketForMediaExemption(createJobStatus(networkContentJob), false);
+ }
+
+ @Test
+ public void testMediaBackupExemptionGranted() {
+ final JobInfo networkContentJob = new JobInfo.Builder(42, TEST_JOB_COMPONENT)
+ .addTriggerContentUri(new JobInfo.TriggerContentUri(TEST_MEDIA_URI, 0))
+ .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
+ .build();
+ when(mJobSchedulerInternal.getMediaBackupPackage()).thenReturn(TEST_PACKAGE);
+ assertEffectiveBucketForMediaExemption(createJobStatus(networkContentJob), true);
+ }
+
@Test
public void testFraction() throws Exception {
final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceStaticTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceStaticTest.java
new file mode 100644
index 000000000000..607cd816d7dd
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceStaticTest.java
@@ -0,0 +1,67 @@
+/*
+ * 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 com.android.server.hdmi;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.Locale;
+
+/**
+ * Tests for static methods of {@link HdmiControlService} class.
+ */
+@SmallTest
+@RunWith(JUnit4.class)
+public class HdmiControlServiceStaticTest {
+
+ @Test
+ public void localToMenuLanguage_english() {
+ assertThat(HdmiControlService.localeToMenuLanguage(Locale.ENGLISH)).isEqualTo("eng");
+ }
+
+ @Test
+ public void localToMenuLanguage_german() {
+ assertThat(HdmiControlService.localeToMenuLanguage(Locale.GERMAN)).isEqualTo("ger");
+ }
+
+ @Test
+ public void localToMenuLanguage_taiwan() {
+ assertThat(HdmiControlService.localeToMenuLanguage(Locale.TAIWAN)).isEqualTo("chi");
+ }
+
+ @Test
+ public void localToMenuLanguage_macau() {
+ assertThat(HdmiControlService.localeToMenuLanguage(new Locale("zh", "MO"))).isEqualTo(
+ "chi");
+ }
+
+ @Test
+ public void localToMenuLanguage_hongkong() {
+ assertThat(HdmiControlService.localeToMenuLanguage(new Locale("zh", "HK"))).isEqualTo(
+ "chi");
+ }
+
+ @Test
+ public void localToMenuLanguage_chinese() {
+ assertThat(HdmiControlService.localeToMenuLanguage(Locale.CHINESE)).isEqualTo("zho");
+ }
+
+}
diff --git a/services/tests/servicestests/src/com/android/server/people/data/UsageStatsQueryHelperTest.java b/services/tests/servicestests/src/com/android/server/people/data/UsageStatsQueryHelperTest.java
index b1cdea2060b8..dc4876b665f7 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/UsageStatsQueryHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/UsageStatsQueryHelperTest.java
@@ -19,9 +19,9 @@ package com.android.server.people.data;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;
import android.annotation.NonNull;
@@ -189,7 +189,7 @@ public final class UsageStatsQueryHelperTest {
private void addUsageEvents(UsageEvents.Event... events) {
UsageEvents usageEvents = new UsageEvents(Arrays.asList(events), new String[]{});
when(mUsageStatsManagerInternal.queryEventsForUser(anyInt(), anyLong(), anyLong(),
- anyBoolean(), anyBoolean(), anyBoolean())).thenReturn(usageEvents);
+ eq(UsageEvents.SHOW_ALL_EVENT_DATA))).thenReturn(usageEvents);
}
private static <T> void addLocalServiceMock(Class<T> clazz, T mock) {
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 75efdd717d02..bc33f0824214 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -51,8 +51,6 @@ import static android.os.Build.VERSION_CODES.P;
import static android.os.UserHandle.USER_SYSTEM;
import static android.service.notification.Adjustment.KEY_IMPORTANCE;
import static android.service.notification.Adjustment.KEY_USER_SENTIMENT;
-import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
-import static android.service.notification.NotificationListenerService.REASON_CANCEL;
import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE;
import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL;
@@ -1144,14 +1142,15 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
- public void testEnqueueNotificationWithTag_WritesExpectedLog() throws Exception {
+ public void testEnqueueNotificationWithTag_WritesExpectedLogs() throws Exception {
final String tag = "testEnqueueNotificationWithTag_WritesExpectedLog";
mBinderService.enqueueNotificationWithTag(PKG, PKG, tag, 0,
generateNotificationRecord(null).getNotification(), 0);
waitForIdle();
assertEquals(1, mNotificationRecordLogger.getCalls().size());
+
NotificationRecordLoggerFake.CallRecord call = mNotificationRecordLogger.get(0);
- assertTrue(call.shouldLog);
+ assertTrue(call.shouldLogReported);
assertEquals(NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_POSTED,
call.event);
assertNotNull(call.r);
@@ -1161,7 +1160,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
assertEquals(PKG, call.r.getSbn().getPackageName());
assertEquals(0, call.r.getSbn().getId());
assertEquals(tag, call.r.getSbn().getTag());
- assertNotNull(call.r.getSbn().getInstanceId());
assertEquals(0, call.getInstanceId()); // Fake instance IDs are assigned in order
}
@@ -1180,13 +1178,13 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
waitForIdle();
assertEquals(2, mNotificationRecordLogger.getCalls().size());
- assertTrue(mNotificationRecordLogger.get(0).shouldLog);
+ assertTrue(mNotificationRecordLogger.get(0).shouldLogReported);
assertEquals(
NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_POSTED,
mNotificationRecordLogger.get(0).event);
assertEquals(0, mNotificationRecordLogger.get(0).getInstanceId());
- assertTrue(mNotificationRecordLogger.get(1).shouldLog);
+ assertTrue(mNotificationRecordLogger.get(1).shouldLogReported);
assertEquals(
NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_UPDATED,
mNotificationRecordLogger.get(1).event);
@@ -1195,16 +1193,37 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
- public void testEnqueueNotificationWithTag_DoesNotLogOnMinorUpdates() throws Exception {
- final String tag = "testEnqueueNotificationWithTag_DoesNotLogOnMinorUpdates";
+ public void testEnqueueNotificationWithTag_DoesNotLogOnMinorUpdate() throws Exception {
+ final String tag = "testEnqueueNotificationWithTag_DoesNotLogOnMinorUpdate";
mBinderService.enqueueNotificationWithTag(PKG, PKG, tag, 0,
generateNotificationRecord(null).getNotification(), 0);
mBinderService.enqueueNotificationWithTag(PKG, PKG, tag, 0,
generateNotificationRecord(null).getNotification(), 0);
waitForIdle();
assertEquals(2, mNotificationRecordLogger.getCalls().size());
- assertTrue(mNotificationRecordLogger.get(0).shouldLog);
- assertFalse(mNotificationRecordLogger.get(1).shouldLog);
+ assertTrue(mNotificationRecordLogger.get(0).shouldLogReported);
+ assertEquals(
+ NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_POSTED,
+ mNotificationRecordLogger.get(0).event);
+ assertFalse(mNotificationRecordLogger.get(1).shouldLogReported);
+ assertNull(mNotificationRecordLogger.get(1).event);
+ }
+
+ @Test
+ public void testEnqueueNotificationWithTag_DoesNotLogOnTitleUpdate() throws Exception {
+ final String tag = "testEnqueueNotificationWithTag_DoesNotLogOnTitleUpdate";
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, tag, 0,
+ generateNotificationRecord(null).getNotification(),
+ 0);
+ final Notification notif = generateNotificationRecord(null).getNotification();
+ notif.extras.putString(Notification.EXTRA_TITLE, "Changed title");
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, tag, 0, notif, 0);
+ waitForIdle();
+ assertEquals(2, mNotificationRecordLogger.getCalls().size());
+ assertEquals(
+ NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_POSTED,
+ mNotificationRecordLogger.get(0).event);
+ assertNull(mNotificationRecordLogger.get(1).event);
}
@Test
@@ -1224,20 +1243,18 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
assertEquals(
NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_POSTED,
mNotificationRecordLogger.get(0).event);
- assertTrue(mNotificationRecordLogger.get(0).shouldLog);
+ assertTrue(mNotificationRecordLogger.get(0).shouldLogReported);
assertEquals(0, mNotificationRecordLogger.get(0).getInstanceId());
- assertEquals(REASON_APP_CANCEL, mNotificationRecordLogger.get(1).reason);
assertEquals(
NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_APP_CANCEL,
mNotificationRecordLogger.get(1).event);
- assertTrue(mNotificationRecordLogger.get(1).shouldLog);
assertEquals(0, mNotificationRecordLogger.get(1).getInstanceId());
assertEquals(
NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_POSTED,
mNotificationRecordLogger.get(2).event);
- assertTrue(mNotificationRecordLogger.get(2).shouldLog);
+ assertTrue(mNotificationRecordLogger.get(2).shouldLogReported);
// New instance ID because notification was canceled before re-post
assertEquals(1, mNotificationRecordLogger.get(2).getInstanceId());
}
@@ -2605,6 +2622,33 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
+ public void testSystemNotificationListenerCanUnsnooze() throws Exception {
+ final NotificationRecord nr = generateNotificationRecord(
+ mTestNotificationChannel, 2, "group", false);
+
+ mBinderService.enqueueNotificationWithTag(PKG, PKG,
+ "testSystemNotificationListenerCanUnsnooze",
+ nr.getSbn().getId(), nr.getSbn().getNotification(),
+ nr.getSbn().getUserId());
+ waitForIdle();
+ NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
+ mService.new SnoozeNotificationRunnable(
+ nr.getKey(), 100, null);
+ snoozeNotificationRunnable.run();
+
+ ManagedServices.ManagedServiceInfo listener = mListeners.new ManagedServiceInfo(
+ null, new ComponentName(PKG, "test_class"), mUid, true, null, 0);
+ listener.isSystem = true;
+ when(mListeners.checkServiceTokenLocked(any())).thenReturn(listener);
+
+ mBinderService.unsnoozeNotificationFromSystemListener(null, nr.getKey());
+ waitForIdle();
+ StatusBarNotification[] notifs = mBinderService.getActiveNotifications(PKG);
+ assertEquals(1, notifs.length);
+ assertNotNull(notifs[0].getKey());//mService.getNotificationRecord(nr.getSbn().getKey()));
+ }
+
+ @Test
public void testSetListenerAccessForUser() throws Exception {
UserHandle user = UserHandle.of(10);
ComponentName c = ComponentName.unflattenFromString("package/Component");
@@ -3396,11 +3440,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
// so we only get the cancel notification.
assertEquals(1, mNotificationRecordLogger.getCalls().size());
- assertEquals(REASON_CANCEL, mNotificationRecordLogger.get(0).reason);
assertEquals(
NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_USER_AOD,
mNotificationRecordLogger.get(0).event);
- assertTrue(mNotificationRecordLogger.get(0).shouldLog);
assertEquals(0, mNotificationRecordLogger.get(0).getInstanceId());
}
@@ -4326,6 +4368,34 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
+ public void testOnNotificationVisibilityChanged_triggersVisibilityLog() {
+ final NotificationRecord r = generateNotificationRecord(
+ mTestNotificationChannel, 1, null, true);
+ r.setTextChanged(true);
+ mService.addNotification(r);
+
+ mService.mNotificationDelegate.onNotificationVisibilityChanged(new NotificationVisibility[]
+ {NotificationVisibility.obtain(r.getKey(), 1, 1, true)},
+ new NotificationVisibility[]{});
+
+ assertEquals(1, mNotificationRecordLogger.getCalls().size());
+ assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_OPEN,
+ mNotificationRecordLogger.get(0).event);
+ assertEquals(0, mNotificationRecordLogger.get(0).getInstanceId());
+
+ mService.mNotificationDelegate.onNotificationVisibilityChanged(
+ new NotificationVisibility[]{},
+ new NotificationVisibility[]
+ {NotificationVisibility.obtain(r.getKey(), 1, 1, true)}
+ );
+
+ assertEquals(2, mNotificationRecordLogger.getCalls().size());
+ assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_CLOSE,
+ mNotificationRecordLogger.get(1).event);
+ assertEquals(0, mNotificationRecordLogger.get(1).getInstanceId());
+ }
+
+ @Test
public void testSetNotificationsShownFromListener_triggersInterruptionUsageStat()
throws RemoteException {
final NotificationRecord r = generateNotificationRecord(
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordLoggerFake.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordLoggerFake.java
index b120dbee03c5..2a17bae57c8e 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordLoggerFake.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordLoggerFake.java
@@ -26,24 +26,26 @@ import java.util.List;
*/
class NotificationRecordLoggerFake implements NotificationRecordLogger {
static class CallRecord extends NotificationRecordPair {
- static final int INVALID = -1;
- public int position = INVALID, buzzBeepBlink = INVALID, reason = INVALID;
- public boolean shouldLog;
public UiEventLogger.UiEventEnum event;
+
+ // The following fields are only relevant to maybeLogNotificationPosted() calls.
+ static final int INVALID = -1;
+ public int position = INVALID, buzzBeepBlink = INVALID;
+ public boolean shouldLogReported;
+
CallRecord(NotificationRecord r, NotificationRecord old, int position,
int buzzBeepBlink) {
super(r, old);
-
this.position = position;
this.buzzBeepBlink = buzzBeepBlink;
- shouldLog = shouldLog(buzzBeepBlink);
- event = NotificationReportedEvent.fromRecordPair(this);
+ shouldLogReported = shouldLogReported(buzzBeepBlink);
+ event = shouldLogReported ? NotificationReportedEvent.fromRecordPair(this) : null;
}
- CallRecord(NotificationRecord r, int reason, int dismissalSurface) {
+
+ CallRecord(NotificationRecord r, UiEventLogger.UiEventEnum event) {
super(r, null);
- this.reason = reason;
- shouldLog = true;
- event = NotificationCancelledEvent.fromCancelReason(reason, dismissalSurface);
+ shouldLogReported = false;
+ this.event = event;
}
}
private List<CallRecord> mCalls = new ArrayList<>();
@@ -57,14 +59,19 @@ class NotificationRecordLoggerFake implements NotificationRecordLogger {
}
@Override
- public void logNotificationReported(NotificationRecord r, NotificationRecord old,
+ public void maybeLogNotificationPosted(NotificationRecord r, NotificationRecord old,
int position, int buzzBeepBlink) {
mCalls.add(new CallRecord(r, old, position, buzzBeepBlink));
}
@Override
public void logNotificationCancelled(NotificationRecord r, int reason, int dismissalSurface) {
- mCalls.add(new CallRecord(r, reason, dismissalSurface));
+ mCalls.add(new CallRecord(r,
+ NotificationCancelledEvent.fromCancelReason(reason, dismissalSurface)));
}
+ @Override
+ public void logNotificationVisibility(NotificationRecord r, boolean visible) {
+ mCalls.add(new CallRecord(r, NotificationEvent.fromVisibility(visible)));
+ }
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
index 3186d539b817..1dd0b1a6f359 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
@@ -15,15 +15,18 @@
*/
package com.android.server.notification;
+import static com.android.server.notification.SnoozeHelper.EXTRA_KEY;
+
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.assertNull;
+import static junit.framework.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyLong;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -322,8 +325,12 @@ public class SnoozeHelperTest extends UiServiceTestCase {
mSnoozeHelper.snooze(r, 1000);
NotificationRecord r2 = getNotificationRecord("pkg", 2, "one", UserHandle.ALL);
mSnoozeHelper.snooze(r2, 1000);
+ reset(mAm);
mSnoozeHelper.repost(r.getKey(), UserHandle.USER_SYSTEM);
verify(mCallback, times(1)).repost(UserHandle.USER_SYSTEM, r);
+ ArgumentCaptor<PendingIntent> captor = ArgumentCaptor.forClass(PendingIntent.class);
+ verify(mAm).cancel(captor.capture());
+ assertEquals(r.getKey(), captor.getValue().getIntent().getStringExtra(EXTRA_KEY));
}
@Test
@@ -332,8 +339,10 @@ public class SnoozeHelperTest extends UiServiceTestCase {
mSnoozeHelper.snooze(r, 1000);
NotificationRecord r2 = getNotificationRecord("pkg", 2, "one", UserHandle.ALL);
mSnoozeHelper.snooze(r2, 1000);
+ reset(mAm);
mSnoozeHelper.repost(r.getKey());
verify(mCallback, times(1)).repost(UserHandle.USER_SYSTEM, r);
+ verify(mAm).cancel(any(PendingIntent.class));
}
@Test
@@ -370,31 +379,7 @@ public class SnoozeHelperTest extends UiServiceTestCase {
}
@Test
- public void testGetSnoozedByUser() throws Exception {
- NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
- NotificationRecord r2 = getNotificationRecord("pkg", 2, "two", UserHandle.SYSTEM);
- NotificationRecord r3 = getNotificationRecord("pkg2", 3, "three", UserHandle.SYSTEM);
- NotificationRecord r4 = getNotificationRecord("pkg2", 3, "three", UserHandle.CURRENT);
- mSnoozeHelper.snooze(r, 1000);
- mSnoozeHelper.snooze(r2, 1000);
- mSnoozeHelper.snooze(r3, 1000);
- mSnoozeHelper.snooze(r4, 1000);
- IntArray profileIds = new IntArray();
- profileIds.add(UserHandle.USER_SYSTEM);
- when(mUserProfiles.getCurrentProfileIds()).thenReturn(profileIds);
- assertEquals(3, mSnoozeHelper.getSnoozed().size());
- profileIds = new IntArray();
- profileIds.add(UserHandle.USER_CURRENT);
- when(mUserProfiles.getCurrentProfileIds()).thenReturn(profileIds);
- assertEquals(1, mSnoozeHelper.getSnoozed().size());
- }
-
- @Test
- public void testGetSnoozedByUser_managedProfiles() throws Exception {
- IntArray profileIds = new IntArray();
- profileIds.add(UserHandle.USER_CURRENT);
- profileIds.add(UserHandle.USER_SYSTEM);
- when(mUserProfiles.getCurrentProfileIds()).thenReturn(profileIds);
+ public void testGetSnoozedBy() throws Exception {
NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
NotificationRecord r2 = getNotificationRecord("pkg", 2, "two", UserHandle.SYSTEM);
NotificationRecord r3 = getNotificationRecord("pkg2", 3, "three", UserHandle.SYSTEM);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java
new file mode 100644
index 000000000000..8ac1d24333be
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java
@@ -0,0 +1,214 @@
+/*
+ * 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 com.android.server.wm;
+
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+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_PRESENTATION;
+import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
+import static android.view.WindowManagerPolicyConstants.APPLICATION_LAYER;
+
+import static com.android.server.wm.DisplayArea.Type.ABOVE_TASKS;
+import static com.android.server.wm.DisplayArea.Type.ANY;
+import static com.android.server.wm.DisplayAreaPolicyBuilder.Feature;
+
+import static org.hamcrest.Matchers.empty;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.not;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import static java.util.stream.Collectors.toList;
+
+import android.platform.test.annotations.Presubmit;
+import android.view.SurfaceControl;
+
+import org.hamcrest.CustomTypeSafeMatcher;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.junit.Rule;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+@Presubmit
+public class DisplayAreaPolicyBuilderTest {
+
+ @Rule
+ public final SystemServicesTestRule mSystemServices = new SystemServicesTestRule();
+
+ private TestWindowManagerPolicy mPolicy = new TestWindowManagerPolicy(null, null);
+
+ @Test
+ public void testBuilder() {
+ WindowManagerService wms = mSystemServices.getWindowManagerService();
+ DisplayArea.Root root = new SurfacelessDisplayAreaRoot(wms);
+ DisplayArea<WindowContainer> ime = new DisplayArea<>(wms, ABOVE_TASKS, "Ime");
+ DisplayArea<ActivityStack> tasks = new DisplayArea<>(wms, ANY, "Tasks");
+
+ final Feature foo;
+ final Feature bar;
+
+ DisplayAreaPolicyBuilder.Result policy = new DisplayAreaPolicyBuilder()
+ .addFeature(foo = new Feature.Builder(mPolicy, "Foo")
+ .upTo(TYPE_STATUS_BAR)
+ .and(TYPE_NAVIGATION_BAR)
+ .build())
+ .addFeature(bar = new Feature.Builder(mPolicy, "Bar")
+ .all()
+ .except(TYPE_STATUS_BAR)
+ .build())
+ .build(wms, mock(DisplayContent.class), root, ime, tasks);
+
+ policy.attachDisplayAreas();
+
+ assertThat(policy.getDisplayAreas(foo), is(not(empty())));
+ assertThat(policy.getDisplayAreas(bar), is(not(empty())));
+
+ assertThat(policy.findAreaForToken(tokenOfType(TYPE_STATUS_BAR)),
+ is(decendantOfOneOf(policy.getDisplayAreas(foo))));
+ assertThat(policy.findAreaForToken(tokenOfType(TYPE_STATUS_BAR)),
+ is(not(decendantOfOneOf(policy.getDisplayAreas(bar)))));
+
+ assertThat(tasks,
+ is(decendantOfOneOf(policy.getDisplayAreas(foo))));
+ assertThat(tasks,
+ is(decendantOfOneOf(policy.getDisplayAreas(bar))));
+
+ assertThat(ime,
+ is(decendantOfOneOf(policy.getDisplayAreas(foo))));
+ assertThat(ime,
+ is(decendantOfOneOf(policy.getDisplayAreas(bar))));
+
+ List<DisplayArea<?>> actualOrder = collectLeafAreas(root);
+ Map<DisplayArea<?>, Set<Integer>> zSets = calculateZSets(policy, root, ime, tasks);
+ actualOrder = actualOrder.stream().filter(zSets::containsKey).collect(toList());
+
+ Map<DisplayArea<?>, Integer> expectedByMinLayer = mapValues(zSets,
+ v -> v.stream().min(Integer::compareTo).get());
+ Map<DisplayArea<?>, Integer> expectedByMaxLayer = mapValues(zSets,
+ v -> v.stream().max(Integer::compareTo).get());
+
+ assertThat(expectedByMinLayer, is(equalTo(expectedByMaxLayer)));
+ assertThat(actualOrder, is(equalTo(expectedByMaxLayer)));
+ }
+
+ private <K, V, R> Map<K, R> mapValues(Map<K, V> zSets, Function<V, R> f) {
+ return zSets.entrySet().stream().collect(Collectors.toMap(
+ Map.Entry::getKey,
+ e -> f.apply(e.getValue())));
+ }
+
+ private List<DisplayArea<?>> collectLeafAreas(DisplayArea<?> root) {
+ ArrayList<DisplayArea<?>> leafs = new ArrayList<>();
+ traverseLeafAreas(root, leafs::add);
+ return leafs;
+ }
+
+ private Map<DisplayArea<?>, Set<Integer>> calculateZSets(
+ DisplayAreaPolicyBuilder.Result policy, DisplayArea.Root root,
+ DisplayArea<WindowContainer> ime,
+ DisplayArea<ActivityStack> tasks) {
+ Map<DisplayArea<?>, Set<Integer>> zSets = new HashMap<>();
+ int[] types = {TYPE_STATUS_BAR, TYPE_NAVIGATION_BAR, TYPE_PRESENTATION,
+ TYPE_APPLICATION_OVERLAY};
+ for (int type : types) {
+ WindowToken token = tokenOfType(type);
+ recordLayer(policy.findAreaForToken(token), token.getWindowLayerFromType(), zSets);
+ }
+ recordLayer(tasks, APPLICATION_LAYER, zSets);
+ recordLayer(ime, mPolicy.getWindowLayerFromTypeLw(TYPE_INPUT_METHOD), zSets);
+ return zSets;
+ }
+
+ private void recordLayer(DisplayArea<?> area, int layer,
+ Map<DisplayArea<?>, Set<Integer>> zSets) {
+ zSets.computeIfAbsent(area, k -> new HashSet<>()).add(layer);
+ }
+
+ private Matcher<WindowContainer> decendantOfOneOf(List<? extends WindowContainer> expected) {
+ return new CustomTypeSafeMatcher<WindowContainer>("descendant of one of " + expected) {
+ @Override
+ protected boolean matchesSafely(WindowContainer actual) {
+ for (WindowContainer expected : expected) {
+ WindowContainer candidate = actual;
+ while (candidate != null && candidate.getParent() != candidate) {
+ if (candidate.getParent() == expected) {
+ return true;
+ }
+ candidate = candidate.getParent();
+ }
+ }
+ return false;
+ }
+
+ @Override
+ protected void describeMismatchSafely(WindowContainer item,
+ Description description) {
+ description.appendText("was ").appendValue(item);
+ while (item != null && item.getParent() != item) {
+ item = item.getParent();
+ description.appendText(", child of ").appendValue(item);
+ }
+ }
+ };
+ }
+
+ private WindowToken tokenOfType(int type) {
+ WindowToken m = mock(WindowToken.class);
+ when(m.getWindowLayerFromType()).thenReturn(mPolicy.getWindowLayerFromTypeLw(type));
+ return m;
+ }
+
+ private static void traverseLeafAreas(DisplayArea<?> root, Consumer<DisplayArea<?>> consumer) {
+ boolean leaf = true;
+ for (int i = 0; i < root.getChildCount(); i++) {
+ WindowContainer child = root.getChildAt(i);
+ if (child instanceof DisplayArea<?>) {
+ traverseLeafAreas((DisplayArea<?>) child, consumer);
+ leaf = false;
+ }
+ }
+ if (leaf) {
+ consumer.accept(root);
+ }
+ }
+
+ private static class SurfacelessDisplayAreaRoot extends DisplayArea.Root {
+
+ SurfacelessDisplayAreaRoot(WindowManagerService wms) {
+ super(wms);
+ }
+
+ @Override
+ SurfaceControl.Builder makeChildSurface(WindowContainer child) {
+ return new MockSurfaceControlBuilder();
+ }
+ }
+
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaProviderTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaProviderTest.java
index c1a1d5ecd3c8..31206315618e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaProviderTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaProviderTest.java
@@ -34,13 +34,13 @@ public class DisplayAreaProviderTest {
@Test
public void testFromResources_emptyProvider() {
Assert.assertThat(DisplayAreaPolicy.Provider.fromResources(resourcesWithProvider("")),
- Matchers.instanceOf(DisplayAreaPolicy.Default.Provider.class));
+ Matchers.instanceOf(DisplayAreaPolicy.DefaultProvider.class));
}
@Test
public void testFromResources_nullProvider() {
Assert.assertThat(DisplayAreaPolicy.Provider.fromResources(resourcesWithProvider(null)),
- Matchers.instanceOf(DisplayAreaPolicy.Default.Provider.class));
+ Matchers.instanceOf(DisplayAreaPolicy.DefaultProvider.class));
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index f517881d835b..8ad75053060f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -56,6 +56,7 @@ import android.os.PowerManagerInternal;
import android.os.PowerSaveState;
import android.os.StrictMode;
import android.os.UserHandle;
+import android.util.Log;
import android.view.InputChannel;
import android.view.Surface;
import android.view.SurfaceControl;
@@ -120,11 +121,22 @@ public class SystemServicesTestRule implements TestRule {
return new Statement() {
@Override
public void evaluate() throws Throwable {
+ Throwable throwable = null;
try {
runWithDexmakerShareClassLoader(SystemServicesTestRule.this::setUp);
base.evaluate();
+ } catch (Throwable t) {
+ throwable = t;
} finally {
- tearDown();
+ try {
+ tearDown();
+ } catch (Throwable t) {
+ if (throwable != null) {
+ Log.e("SystemServicesTestRule", "Suppressed: ", throwable);
+ t.addSuppressed(throwable);
+ }
+ throw t;
+ }
}
}
};
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 420695dc51e4..df5b311bbab1 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -500,6 +500,19 @@ public class UsageStatsService extends SystemService implements
== PackageManager.PERMISSION_GRANTED);
}
+ /**
+ * Obfuscate both {@link UsageEvents.Event#NOTIFICATION_SEEN} and
+ * {@link UsageEvents.Event#NOTIFICATION_INTERRUPTION} events if the provided calling uid does
+ * not hold the {@link android.Manifest.permission.MANAGE_NOTIFICATIONS} permission.
+ */
+ private boolean shouldObfuscateNotificationEvents(int callingPid, int callingUid) {
+ if (callingUid == Process.SYSTEM_UID) {
+ return false;
+ }
+ return !(getContext().checkPermission(android.Manifest.permission.MANAGE_NOTIFICATIONS,
+ callingPid, callingUid) == PackageManager.PERMISSION_GRANTED);
+ }
+
private static void deleteRecursively(File f) {
File[] files = f.listFiles();
if (files != null) {
@@ -1038,9 +1051,7 @@ public class UsageStatsService extends SystemService implements
/**
* Called by the Binder stub.
*/
- UsageEvents queryEvents(int userId, long beginTime, long endTime,
- boolean shouldObfuscateInstantApps, boolean shouldHideShortcutInvocationEvents,
- boolean shouldHideLocusIdEvents) {
+ UsageEvents queryEvents(int userId, long beginTime, long endTime, int flags) {
synchronized (mLock) {
if (!mUserUnlockedStates.get(userId)) {
Slog.w(TAG, "Failed to query events for locked user " + userId);
@@ -1051,8 +1062,7 @@ public class UsageStatsService extends SystemService implements
if (service == null) {
return null; // user was stopped or removed
}
- return service.queryEvents(beginTime, endTime, shouldObfuscateInstantApps,
- shouldHideShortcutInvocationEvents, shouldHideLocusIdEvents);
+ return service.queryEvents(beginTime, endTime, flags);
}
}
@@ -1475,10 +1485,15 @@ public class UsageStatsService extends SystemService implements
try {
final boolean hideShortcutInvocationEvents = shouldHideShortcutInvocationEvents(
userId, callingPackage, callingPid, callingUid);
- boolean shouldHideLocusIdEvents = shouldHideLocusIdEvents(callingPid, callingUid);
- return UsageStatsService.this.queryEvents(userId, beginTime, endTime,
- obfuscateInstantApps, hideShortcutInvocationEvents,
- shouldHideLocusIdEvents);
+ final boolean hideLocusIdEvents = shouldHideLocusIdEvents(callingPid, callingUid);
+ final boolean obfuscateNotificationEvents = shouldObfuscateNotificationEvents(
+ callingPid, callingUid);
+ int flags = UsageEvents.SHOW_ALL_EVENT_DATA;
+ if (obfuscateInstantApps) flags |= UsageEvents.OBFUSCATE_INSTANT_APPS;
+ if (hideShortcutInvocationEvents) flags |= UsageEvents.HIDE_SHORTCUT_EVENTS;
+ if (hideLocusIdEvents) flags |= UsageEvents.HIDE_LOCUS_EVENTS;
+ if (obfuscateNotificationEvents) flags |= UsageEvents.OBFUSCATE_NOTIFICATION_EVENTS;
+ return UsageStatsService.this.queryEvents(userId, beginTime, endTime, flags);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -1525,10 +1540,15 @@ public class UsageStatsService extends SystemService implements
try {
final boolean hideShortcutInvocationEvents = shouldHideShortcutInvocationEvents(
userId, callingPackage, callingPid, callingUid);
- boolean shouldHideLocusIdEvents = shouldHideLocusIdEvents(callingPid, callingUid);
- return UsageStatsService.this.queryEvents(userId, beginTime, endTime,
- obfuscateInstantApps, hideShortcutInvocationEvents,
- shouldHideLocusIdEvents);
+ final boolean obfuscateNotificationEvents = shouldObfuscateNotificationEvents(
+ callingPid, callingUid);
+ boolean hideLocusIdEvents = shouldHideLocusIdEvents(callingPid, callingUid);
+ int flags = UsageEvents.SHOW_ALL_EVENT_DATA;
+ if (obfuscateInstantApps) flags |= UsageEvents.OBFUSCATE_INSTANT_APPS;
+ if (hideShortcutInvocationEvents) flags |= UsageEvents.HIDE_SHORTCUT_EVENTS;
+ if (hideLocusIdEvents) flags |= UsageEvents.HIDE_LOCUS_EVENTS;
+ if (obfuscateNotificationEvents) flags |= UsageEvents.OBFUSCATE_NOTIFICATION_EVENTS;
+ return UsageStatsService.this.queryEvents(userId, beginTime, endTime, flags);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -2144,12 +2164,8 @@ public class UsageStatsService extends SystemService implements
}
@Override
- public UsageEvents queryEventsForUser(int userId, long beginTime, long endTime,
- boolean obfuscateInstantApps, boolean shouldHideShortcutInvocationEvents,
- boolean shouldHideLocusIdEvents) {
- return UsageStatsService.this.queryEvents(
- userId, beginTime, endTime, obfuscateInstantApps,
- shouldHideShortcutInvocationEvents, shouldHideLocusIdEvents);
+ public UsageEvents queryEventsForUser(int userId, long beginTime, long endTime, int flags) {
+ return UsageStatsService.this.queryEvents(userId, beginTime, endTime, flags);
}
@Override
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index d9317ace6e24..db26d88dbfbb 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -18,6 +18,10 @@ package com.android.server.usage;
import static android.app.usage.UsageEvents.Event.DEVICE_SHUTDOWN;
import static android.app.usage.UsageEvents.Event.DEVICE_STARTUP;
+import static android.app.usage.UsageEvents.HIDE_LOCUS_EVENTS;
+import static android.app.usage.UsageEvents.HIDE_SHORTCUT_EVENTS;
+import static android.app.usage.UsageEvents.OBFUSCATE_INSTANT_APPS;
+import static android.app.usage.UsageEvents.OBFUSCATE_NOTIFICATION_EVENTS;
import static android.app.usage.UsageStatsManager.INTERVAL_BEST;
import static android.app.usage.UsageStatsManager.INTERVAL_COUNT;
import static android.app.usage.UsageStatsManager.INTERVAL_DAILY;
@@ -481,8 +485,7 @@ class UserUsageStatsService {
return queryStats(bucketType, beginTime, endTime, sEventStatsCombiner);
}
- UsageEvents queryEvents(final long beginTime, final long endTime, boolean obfuscateInstantApps,
- boolean hideShortcutInvocationEvents, boolean hideLocusIdEvents) {
+ UsageEvents queryEvents(final long beginTime, final long endTime, int flags) {
if (!validRange(checkAndGetTimeLocked(), beginTime, endTime)) {
return null;
}
@@ -500,15 +503,22 @@ class UserUsageStatsService {
}
Event event = stats.events.get(i);
- if (hideShortcutInvocationEvents
- && event.mEventType == Event.SHORTCUT_INVOCATION) {
+ final int eventType = event.mEventType;
+ if (eventType == Event.SHORTCUT_INVOCATION
+ && (flags & HIDE_SHORTCUT_EVENTS) == HIDE_SHORTCUT_EVENTS) {
continue;
}
- if (hideLocusIdEvents
- && event.mEventType == Event.LOCUS_ID_SET) {
+ if (eventType == Event.LOCUS_ID_SET
+ && (flags & HIDE_LOCUS_EVENTS) == HIDE_LOCUS_EVENTS) {
continue;
}
- if (obfuscateInstantApps) {
+ if ((eventType == Event.NOTIFICATION_SEEN
+ || eventType == Event.NOTIFICATION_INTERRUPTION)
+ && (flags & OBFUSCATE_NOTIFICATION_EVENTS)
+ == OBFUSCATE_NOTIFICATION_EVENTS) {
+ event = event.getObfuscatedNotificationEvent();
+ }
+ if ((flags & OBFUSCATE_INSTANT_APPS) == OBFUSCATE_INSTANT_APPS) {
event = event.getObfuscatedIfInstantApp();
}
if (event.mPackage != null) {
diff --git a/startop/iorap/functional_tests/AndroidTest.xml b/startop/iorap/functional_tests/AndroidTest.xml
index 41109b43ab82..ef56fc827420 100644
--- a/startop/iorap/functional_tests/AndroidTest.xml
+++ b/startop/iorap/functional_tests/AndroidTest.xml
@@ -34,6 +34,11 @@
<option name="run-command" value="rm -r /data/misc/iorapd/*" />
<option name="run-command" value="sleep 1" />
+ <!-- Set system properties to enable perfetto tracing, readahead and detailed logging. -->
+ <option name="run-command" value="setprop iorapd.perfetto.enable true" />
+ <option name="run-command" value="setprop iorapd.readahead.enable true" />
+ <option name="run-command" value="setprop iorapd.log.verbose true" />
+
<option name="run-command" value="start iorapd" />
<!-- give it some time to restart the service; otherwise the first unit test might fail -->
@@ -45,9 +50,5 @@
<option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
</test>
- <!-- using DeviceSetup again does not work. we simply leave the device in a semi-bad
- state. there is no way to clean this up as far as I know.
- -->
-
</configuration>
diff --git a/startop/iorap/functional_tests/src/com/google/android/startop/iorap/IorapWorkFlowTest.java b/startop/iorap/functional_tests/src/com/google/android/startop/iorap/IorapWorkFlowTest.java
index bd8a45c2ca00..40023878af19 100644
--- a/startop/iorap/functional_tests/src/com/google/android/startop/iorap/IorapWorkFlowTest.java
+++ b/startop/iorap/functional_tests/src/com/google/android/startop/iorap/IorapWorkFlowTest.java
@@ -67,7 +67,7 @@ public class IorapWorkFlowTest {
private static final String TEST_ACTIVITY_NAME = "com.android.settings.Settings";
private static final String DB_PATH = "/data/misc/iorapd/sqlite.db";
- private static final Duration TIMEOUT = Duration.ofSeconds(20L);
+ private static final Duration TIMEOUT = Duration.ofSeconds(300L);
private static final String READAHEAD_INDICATOR =
"Description = /data/misc/iorapd/com.android.settings/none/com.android.settings.Settings/compiled_traces/compiled_trace.pb";
@@ -88,7 +88,7 @@ public class IorapWorkFlowTest {
mDevice.wait(Until.hasObject(By.pkg(launcherPackage).depth(0)), TIMEOUT.getSeconds());
}
- @Test
+ @Test (timeout = 300000)
public void testApp() throws Exception {
assertThat(mDevice, notNullValue());
@@ -247,7 +247,7 @@ public class IorapWorkFlowTest {
if (supplier.getAsBoolean()) {
return true;
}
- TimeUnit.SECONDS.sleep(totalSleepTimeSeconds);
+ TimeUnit.SECONDS.sleep(sleepIntervalSeconds);
totalSleepTimeSeconds += sleepIntervalSeconds;
if (totalSleepTimeSeconds > timeout.getSeconds()) {
return false;
@@ -367,7 +367,7 @@ public class IorapWorkFlowTest {
*
* <p> This should be run as root.</p>
*/
- private String executeShellCommand(String cmd) throws Exception {
+ private static String executeShellCommand(String cmd) throws Exception {
Log.i(TAG, "Execute: " + cmd);
return UiDevice.getInstance(
InstrumentationRegistry.getInstrumentation()).executeShellCommand(cmd);
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 51b4a31ea8b2..c51a8520ad3b 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -2377,7 +2377,7 @@ public class CarrierConfigManager {
* {@link CellSignalStrengthLte#USE_RSRQ}, {@link CellSignalStrengthLte#USE_RSSNR}.
*
* For example, if both RSRP and RSRQ are used, the value of key is 3 (1 << 0 | 1 << 1).
- * If the key is invalid or not configured, a default value (RSRP | RSSNR = 1 << 0 | 1 << 2)
+ * If the key is invalid or not configured, a default value (RSRP = 1 << 0)
* will apply.
*
* @hide
@@ -4334,7 +4334,7 @@ public class CarrierConfigManager {
sDefaults.putBoolean(KEY_PREVENT_CLIR_ACTIVATION_AND_DEACTIVATION_CODE_BOOL, false);
sDefaults.putLong(KEY_DATA_SWITCH_VALIDATION_TIMEOUT_LONG, 2000);
sDefaults.putInt(KEY_PARAMETERS_USED_FOR_LTE_SIGNAL_BAR_INT,
- CellSignalStrengthLte.USE_RSRP | CellSignalStrengthLte.USE_RSSNR);
+ CellSignalStrengthLte.USE_RSRP);
// Default wifi configurations.
sDefaults.putAll(Wifi.getDefaults());
sDefaults.putBoolean(ENABLE_EAP_METHOD_PREFIX_BOOL, false);
diff --git a/telephony/java/android/telephony/CellSignalStrengthLte.java b/telephony/java/android/telephony/CellSignalStrengthLte.java
index 1cd45e93a52a..2529387b19b3 100644
--- a/telephony/java/android/telephony/CellSignalStrengthLte.java
+++ b/telephony/java/android/telephony/CellSignalStrengthLte.java
@@ -181,7 +181,7 @@ public final class CellSignalStrengthLte extends CellSignalStrength implements P
mCqi = CellInfo.UNAVAILABLE;
mTimingAdvance = CellInfo.UNAVAILABLE;
mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
- mParametersUseForLevel = USE_RSRP | USE_RSSNR;
+ mParametersUseForLevel = USE_RSRP;
}
/** {@inheritDoc} */
@@ -236,7 +236,7 @@ public final class CellSignalStrengthLte extends CellSignalStrength implements P
int[] rsrpThresholds, rsrqThresholds, rssnrThresholds;
boolean rsrpOnly;
if (cc == null) {
- mParametersUseForLevel = USE_RSRP | USE_RSSNR;
+ mParametersUseForLevel = USE_RSRP;
rsrpThresholds = sRsrpThresholds;
rsrqThresholds = sRsrqThresholds;
rssnrThresholds = sRssnrThresholds;
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index c40573b25068..6fdc13e6a31b 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -492,6 +492,7 @@ public interface RILConstants {
int RIL_REQUEST_ENABLE_UICC_APPLICATIONS = 208;
int RIL_REQUEST_GET_UICC_APPLICATIONS_ENABLEMENT = 209;
int RIL_REQUEST_SET_SYSTEM_SELECTION_CHANNELS = 210;
+ int RIL_REQUEST_GET_BARRING_INFO = 211;
/* Responses begin */
int RIL_RESPONSE_ACKNOWLEDGEMENT = 800;
diff --git a/tests/ApkVerityTest/src/com/android/apkverity/ApkVerityTest.java b/tests/ApkVerityTest/src/com/android/apkverity/ApkVerityTest.java
index 20d0e9690e8e..ae20cae36839 100644
--- a/tests/ApkVerityTest/src/com/android/apkverity/ApkVerityTest.java
+++ b/tests/ApkVerityTest/src/com/android/apkverity/ApkVerityTest.java
@@ -430,10 +430,9 @@ public class ApkVerityTest extends BaseHostJUnit4Test {
private void verifyInstalledFiles(String... filenames) throws DeviceNotAvailableException {
String apkPath = getApkPath(TARGET_PACKAGE);
String appDir = apkPath.substring(0, apkPath.lastIndexOf("/"));
+ // Exclude directories since we only care about files.
HashSet<String> actualFiles = new HashSet<>(Arrays.asList(
- expectRemoteCommandToSucceed("ls " + appDir).split("\n")));
- assertTrue(actualFiles.remove("lib"));
- assertTrue(actualFiles.remove("oat"));
+ expectRemoteCommandToSucceed("ls -p " + appDir + " | grep -v '/'").split("\n")));
HashSet<String> expectedFiles = new HashSet<>(Arrays.asList(filenames));
assertEquals(expectedFiles, actualFiles);
diff --git a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
index 95b8f6700c76..da45d9a258bd 100644
--- a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
+++ b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
@@ -296,6 +296,8 @@ public class AppLaunch extends InstrumentationTestCase {
AppLaunchResult launchResults = null;
if (hasFailureOnFirstLaunch(launch)) {
// skip if the app has failures while launched first
+ Log.w(TAG, "Has failures on first launch: " + launch.getApp());
+ forceStopApp(launch.getApp());
continue;
}
AtraceLogger atraceLogger = null;
diff --git a/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java b/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java
index 957216e17925..37842de92e79 100644
--- a/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java
+++ b/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java
@@ -45,6 +45,7 @@ public final class FrameworksTestsFilter extends SelectTest {
"android.view.InsetsSourceTest",
"android.view.InsetsSourceConsumerTest",
"android.view.InsetsStateTest",
+ "android.view.WindowMetricsTest"
};
public FrameworksTestsFilter(Bundle testArgs) {
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/Credential.java b/wifi/java/android/net/wifi/hotspot2/pps/Credential.java
index 99901808ec3e..9c01d3643c19 100644
--- a/wifi/java/android/net/wifi/hotspot2/pps/Credential.java
+++ b/wifi/java/android/net/wifi/hotspot2/pps/Credential.java
@@ -738,7 +738,16 @@ public final class Credential implements Parcelable {
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
- builder.append("IMSI: ").append(mImsi).append("\n");
+ String imsi;
+ if (mImsi != null) {
+ if (mImsi.length() > 6 && mImsi.charAt(6) != '*') {
+ // Truncate the full IMSI from the log
+ imsi = mImsi.substring(0, 6) + "****";
+ } else {
+ imsi = mImsi;
+ }
+ builder.append("IMSI: ").append(imsi).append("\n");
+ }
builder.append("EAPType: ").append(mEapType).append("\n");
return builder.toString();
}
diff --git a/wifi/java/android/net/wifi/wificond/WifiCondManager.java b/wifi/java/android/net/wifi/wificond/WifiNl80211Manager.java
index 61f18e0b7191..89f642fdbb66 100644
--- a/wifi/java/android/net/wifi/wificond/WifiCondManager.java
+++ b/wifi/java/android/net/wifi/wificond/WifiNl80211Manager.java
@@ -49,15 +49,16 @@ import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
/**
- * This class encapsulates the interface the wificond daemon presents to the Wi-Fi framework. The
+ * This class encapsulates the interface the wificond daemon presents to the Wi-Fi framework - used
+ * to encapsulate the Wi-Fi 80211nl management interface. The
* interface is only for use by the Wi-Fi framework and access is protected by SELinux permissions.
*
* @hide
*/
@SystemApi
-@SystemService(Context.WIFI_COND_SERVICE)
-public class WifiCondManager {
- private static final String TAG = "WifiCondManager";
+@SystemService(Context.WIFI_NL80211_SERVICE)
+public class WifiNl80211Manager {
+ private static final String TAG = "WifiNl80211Manager";
private boolean mVerboseLoggingEnabled = false;
/**
@@ -316,14 +317,14 @@ public class WifiCondManager {
public static final int SEND_MGMT_FRAME_ERROR_ALREADY_STARTED = 5;
/** @hide */
- public WifiCondManager(Context context) {
+ public WifiNl80211Manager(Context context) {
mAlarmManager = context.getSystemService(AlarmManager.class);
mEventHandler = new Handler(context.getMainLooper());
}
/** @hide */
@VisibleForTesting
- public WifiCondManager(Context context, IWificond wificond) {
+ public WifiNl80211Manager(Context context, IWificond wificond) {
this(context);
mWificond = wificond;
}
@@ -485,7 +486,7 @@ public class WifiCondManager {
}
/**
- * Enable or disable verbose logging of the WifiCondManager module.
+ * Enable or disable verbose logging of the WifiNl80211Manager module.
* @param enable True to enable verbose logging. False to disable verbose logging.
*/
public void enableVerboseLogging(boolean enable) {
@@ -493,7 +494,7 @@ public class WifiCondManager {
}
/**
- * Register a death notification for the WifiCondManager which acts as a proxy for the
+ * Register a death notification for the WifiNl80211Manager which acts as a proxy for the
* wificond daemon (i.e. the death listener will be called when and if the wificond daemon
* dies).
*
@@ -518,7 +519,7 @@ public class WifiCondManager {
// We already have a wificond handle.
return true;
}
- IBinder binder = ServiceManager.getService(Context.WIFI_COND_SERVICE);
+ IBinder binder = ServiceManager.getService(Context.WIFI_NL80211_SERVICE);
mWificond = IWificond.Stub.asInterface(binder);
if (mWificond == null) {
Log.e(TAG, "Failed to get reference to wificond");
diff --git a/wifi/tests/src/android/net/wifi/wificond/WifiCondManagerTest.java b/wifi/tests/src/android/net/wifi/wificond/WifiNl80211ManagerTest.java
index b745a341b459..a8184068ff5a 100644
--- a/wifi/tests/src/android/net/wifi/wificond/WifiCondManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/wificond/WifiNl80211ManagerTest.java
@@ -71,10 +71,10 @@ import java.util.List;
import java.util.Set;
/**
- * Unit tests for {@link android.net.wifi.WifiCondManager}.
+ * Unit tests for {@link android.net.wifi.wificond.WifiNl80211Manager}.
*/
@SmallTest
-public class WifiCondManagerTest {
+public class WifiNl80211ManagerTest {
@Mock
private IWificond mWificond;
@Mock
@@ -86,21 +86,21 @@ public class WifiCondManagerTest {
@Mock
private IApInterface mApInterface;
@Mock
- private WifiCondManager.SoftApCallback mSoftApListener;
+ private WifiNl80211Manager.SoftApCallback mSoftApListener;
@Mock
- private WifiCondManager.SendMgmtFrameCallback mSendMgmtFrameCallback;
+ private WifiNl80211Manager.SendMgmtFrameCallback mSendMgmtFrameCallback;
@Mock
- private WifiCondManager.ScanEventCallback mNormalScanCallback;
+ private WifiNl80211Manager.ScanEventCallback mNormalScanCallback;
@Mock
- private WifiCondManager.ScanEventCallback mPnoScanCallback;
+ private WifiNl80211Manager.ScanEventCallback mPnoScanCallback;
@Mock
- private WifiCondManager.PnoScanRequestCallback mPnoScanRequestCallback;
+ private WifiNl80211Manager.PnoScanRequestCallback mPnoScanRequestCallback;
@Mock
private Context mContext;
private TestLooper mLooper;
private TestAlarmManager mTestAlarmManager;
private AlarmManager mAlarmManager;
- private WifiCondManager mWificondControl;
+ private WifiNl80211Manager mWificondControl;
private static final String TEST_INTERFACE_NAME = "test_wlan_if";
private static final String TEST_INTERFACE_NAME1 = "test_wlan_if1";
private static final String TEST_INVALID_INTERFACE_NAME = "asdf";
@@ -180,7 +180,7 @@ public class WifiCondManagerTest {
when(mWificond.tearDownApInterface(any())).thenReturn(true);
when(mClientInterface.getWifiScannerImpl()).thenReturn(mWifiScannerImpl);
when(mClientInterface.getInterfaceName()).thenReturn(TEST_INTERFACE_NAME);
- mWificondControl = new WifiCondManager(mContext, mWificond);
+ mWificondControl = new WifiNl80211Manager(mContext, mWificond);
assertEquals(true,
mWificondControl.setupInterfaceForClientMode(TEST_INTERFACE_NAME, Runnable::run,
mNormalScanCallback, mPnoScanCallback));
@@ -492,7 +492,7 @@ public class WifiCondManagerTest {
// getScanResults should fail.
assertEquals(0,
mWificondControl.getScanResults(TEST_INTERFACE_NAME,
- WifiCondManager.SCAN_TYPE_SINGLE_SCAN).size());
+ WifiNl80211Manager.SCAN_TYPE_SINGLE_SCAN).size());
}
/**
@@ -786,10 +786,10 @@ public class WifiCondManagerTest {
*/
@Test
public void testSendMgmtFrameCalledTwiceBeforeFinished() throws Exception {
- WifiCondManager.SendMgmtFrameCallback cb1 = mock(
- WifiCondManager.SendMgmtFrameCallback.class);
- WifiCondManager.SendMgmtFrameCallback cb2 = mock(
- WifiCondManager.SendMgmtFrameCallback.class);
+ WifiNl80211Manager.SendMgmtFrameCallback cb1 = mock(
+ WifiNl80211Manager.SendMgmtFrameCallback.class);
+ WifiNl80211Manager.SendMgmtFrameCallback cb2 = mock(
+ WifiNl80211Manager.SendMgmtFrameCallback.class);
mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, TEST_PROBE_FRAME, TEST_MCS_RATE,
Runnable::run, cb1);
@@ -800,7 +800,7 @@ public class WifiCondManagerTest {
mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, TEST_PROBE_FRAME, TEST_MCS_RATE,
Runnable::run, cb2);
- verify(cb2).onFailure(WifiCondManager.SEND_MGMT_FRAME_ERROR_ALREADY_STARTED);
+ verify(cb2).onFailure(WifiNl80211Manager.SEND_MGMT_FRAME_ERROR_ALREADY_STARTED);
// verify SendMgmtFrame() still was only called once i.e. not called again
verify(mClientInterface, times(1))
.SendMgmtFrame(any(), any(), anyInt());
@@ -811,8 +811,8 @@ public class WifiCondManagerTest {
*/
@Test
public void testSendMgmtFrameThrowsException() throws Exception {
- WifiCondManager.SendMgmtFrameCallback cb = mock(
- WifiCondManager.SendMgmtFrameCallback.class);
+ WifiNl80211Manager.SendMgmtFrameCallback cb = mock(
+ WifiNl80211Manager.SendMgmtFrameCallback.class);
final ArgumentCaptor<ISendMgmtFrameEvent> sendMgmtFrameEventCaptor =
ArgumentCaptor.forClass(ISendMgmtFrameEvent.class);
@@ -834,7 +834,7 @@ public class WifiCondManagerTest {
verify(mAlarmManager).cancel(eq(alarmListenerCaptor.getValue()));
sendMgmtFrameEventCaptor.getValue().OnFailure(
- WifiCondManager.SEND_MGMT_FRAME_ERROR_UNKNOWN);
+ WifiNl80211Manager.SEND_MGMT_FRAME_ERROR_UNKNOWN);
mLooper.dispatchAll();
handlerCaptor.getValue().post(() -> alarmListenerCaptor.getValue().onAlarm());
@@ -848,8 +848,8 @@ public class WifiCondManagerTest {
*/
@Test
public void testSendMgmtFrameSuccess() throws Exception {
- WifiCondManager.SendMgmtFrameCallback cb = mock(
- WifiCondManager.SendMgmtFrameCallback.class);
+ WifiNl80211Manager.SendMgmtFrameCallback cb = mock(
+ WifiNl80211Manager.SendMgmtFrameCallback.class);
final ArgumentCaptor<ISendMgmtFrameEvent> sendMgmtFrameEventCaptor =
ArgumentCaptor.forClass(ISendMgmtFrameEvent.class);
@@ -882,8 +882,8 @@ public class WifiCondManagerTest {
*/
@Test
public void testSendMgmtFrameFailure() throws Exception {
- WifiCondManager.SendMgmtFrameCallback cb = mock(
- WifiCondManager.SendMgmtFrameCallback.class);
+ WifiNl80211Manager.SendMgmtFrameCallback cb = mock(
+ WifiNl80211Manager.SendMgmtFrameCallback.class);
final ArgumentCaptor<ISendMgmtFrameEvent> sendMgmtFrameEventCaptor =
ArgumentCaptor.forClass(ISendMgmtFrameEvent.class);
@@ -898,10 +898,10 @@ public class WifiCondManagerTest {
Runnable::run, cb);
sendMgmtFrameEventCaptor.getValue().OnFailure(
- WifiCondManager.SEND_MGMT_FRAME_ERROR_UNKNOWN);
+ WifiNl80211Manager.SEND_MGMT_FRAME_ERROR_UNKNOWN);
mLooper.dispatchAll();
verify(cb, never()).onAck(anyInt());
- verify(cb).onFailure(WifiCondManager.SEND_MGMT_FRAME_ERROR_UNKNOWN);
+ verify(cb).onFailure(WifiNl80211Manager.SEND_MGMT_FRAME_ERROR_UNKNOWN);
verify(mAlarmManager).cancel(eq(alarmListenerCaptor.getValue()));
// verify that even if timeout is triggered afterwards, SendMgmtFrameCallback is not
@@ -917,8 +917,8 @@ public class WifiCondManagerTest {
*/
@Test
public void testSendMgmtFrameTimeout() throws Exception {
- WifiCondManager.SendMgmtFrameCallback cb = mock(
- WifiCondManager.SendMgmtFrameCallback.class);
+ WifiNl80211Manager.SendMgmtFrameCallback cb = mock(
+ WifiNl80211Manager.SendMgmtFrameCallback.class);
final ArgumentCaptor<ISendMgmtFrameEvent> sendMgmtFrameEventCaptor =
ArgumentCaptor.forClass(ISendMgmtFrameEvent.class);
@@ -935,7 +935,7 @@ public class WifiCondManagerTest {
handlerCaptor.getValue().post(() -> alarmListenerCaptor.getValue().onAlarm());
mLooper.dispatchAll();
verify(cb, never()).onAck(anyInt());
- verify(cb).onFailure(WifiCondManager.SEND_MGMT_FRAME_ERROR_TIMEOUT);
+ verify(cb).onFailure(WifiNl80211Manager.SEND_MGMT_FRAME_ERROR_TIMEOUT);
// verify that even if onAck() callback is triggered after timeout,
// SendMgmtFrameCallback is not triggered again
@@ -1006,7 +1006,8 @@ public class WifiCondManagerTest {
sendMgmtFrameEventCaptor.getValue().OnAck(TEST_SEND_MGMT_FRAME_ELAPSED_TIME_MS);
mLooper.dispatchAll();
verify(mSendMgmtFrameCallback, never()).onAck(anyInt());
- verify(mSendMgmtFrameCallback).onFailure(WifiCondManager.SEND_MGMT_FRAME_ERROR_TIMEOUT);
+ verify(mSendMgmtFrameCallback).onFailure(
+ WifiNl80211Manager.SEND_MGMT_FRAME_ERROR_TIMEOUT);
}
/**
@@ -1032,9 +1033,10 @@ public class WifiCondManagerTest {
handlerCaptor.getValue().post(() -> alarmListenerCaptor.getValue().onAlarm());
// OnFailure posts to the handler
sendMgmtFrameEventCaptor.getValue().OnFailure(
- WifiCondManager.SEND_MGMT_FRAME_ERROR_UNKNOWN);
+ WifiNl80211Manager.SEND_MGMT_FRAME_ERROR_UNKNOWN);
mLooper.dispatchAll();
- verify(mSendMgmtFrameCallback).onFailure(WifiCondManager.SEND_MGMT_FRAME_ERROR_TIMEOUT);
+ verify(mSendMgmtFrameCallback).onFailure(
+ WifiNl80211Manager.SEND_MGMT_FRAME_ERROR_TIMEOUT);
}
/**