summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/hardware/CameraSessionStats.java9
-rw-r--r--core/java/android/view/contentcapture/ContentCaptureManager.java20
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java17
-rw-r--r--libs/WindowManager/Shell/tests/flicker/Android.bp31
-rw-r--r--libs/WindowManager/Shell/tests/flicker/csuiteDefaultTemplate.xml121
-rw-r--r--native/android/system_fonts.cpp18
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt47
-rw-r--r--services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java179
-rw-r--r--services/contentcapture/java/com/android/server/contentprotection/ContentProtectionAllowlistManager.java135
-rw-r--r--services/contentcapture/java/com/android/server/contentprotection/ContentProtectionConsentManager.java21
-rw-r--r--services/core/java/com/android/server/camera/CameraServiceProxy.java18
-rw-r--r--services/core/java/com/android/server/wm/BackgroundActivityStartController.java22
-rw-r--r--services/tests/servicestests/src/com/android/server/contentcapture/ContentCaptureManagerServiceTest.java180
-rw-r--r--services/tests/servicestests/src/com/android/server/contentprotection/ContentProtectionAllowlistManagerTest.java326
-rw-r--r--services/tests/servicestests/src/com/android/server/contentprotection/ContentProtectionConsentManagerTest.java84
16 files changed, 1068 insertions, 164 deletions
diff --git a/core/java/android/hardware/CameraSessionStats.java b/core/java/android/hardware/CameraSessionStats.java
index b1d6ac4b4cd2..32938ffae63d 100644
--- a/core/java/android/hardware/CameraSessionStats.java
+++ b/core/java/android/hardware/CameraSessionStats.java
@@ -65,6 +65,7 @@ public class CameraSessionStats implements Parcelable {
private String mUserTag;
private int mVideoStabilizationMode;
private boolean mUsedUltraWide;
+ private boolean mUsedZoomOverride;
private int mSessionIndex;
private CameraExtensionSessionStats mCameraExtensionSessionStats;
@@ -84,6 +85,7 @@ public class CameraSessionStats implements Parcelable {
mStreamStats = new ArrayList<CameraStreamStats>();
mVideoStabilizationMode = -1;
mUsedUltraWide = false;
+ mUsedZoomOverride = false;
mSessionIndex = 0;
mCameraExtensionSessionStats = new CameraExtensionSessionStats();
}
@@ -106,6 +108,7 @@ public class CameraSessionStats implements Parcelable {
mStreamStats = new ArrayList<CameraStreamStats>();
mVideoStabilizationMode = -1;
mUsedUltraWide = false;
+ mUsedZoomOverride = false;
mSessionIndex = sessionIdx;
mCameraExtensionSessionStats = new CameraExtensionSessionStats();
}
@@ -152,6 +155,7 @@ public class CameraSessionStats implements Parcelable {
dest.writeString(mUserTag);
dest.writeInt(mVideoStabilizationMode);
dest.writeBoolean(mUsedUltraWide);
+ dest.writeBoolean(mUsedZoomOverride);
dest.writeInt(mSessionIndex);
mCameraExtensionSessionStats.writeToParcel(dest, 0);
}
@@ -180,6 +184,7 @@ public class CameraSessionStats implements Parcelable {
mVideoStabilizationMode = in.readInt();
mUsedUltraWide = in.readBoolean();
+ mUsedZoomOverride = in.readBoolean();
mSessionIndex = in.readInt();
mCameraExtensionSessionStats = CameraExtensionSessionStats.CREATOR.createFromParcel(in);
@@ -257,6 +262,10 @@ public class CameraSessionStats implements Parcelable {
return mUsedUltraWide;
}
+ public boolean getUsedZoomOverride() {
+ return mUsedZoomOverride;
+ }
+
public int getSessionIndex() {
return mSessionIndex;
}
diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java
index 57011e879454..5f612d6b0009 100644
--- a/core/java/android/view/contentcapture/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -395,6 +395,22 @@ public final class ContentCaptureManager {
public static final String DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_OPTIONAL_GROUPS_THRESHOLD =
"content_protection_optional_groups_threshold";
+ /**
+ * Sets the initial delay for fetching content protection allowlist in milliseconds.
+ *
+ * @hide
+ */
+ public static final String DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_ALLOWLIST_DELAY_MS =
+ "content_protection_allowlist_delay_ms";
+
+ /**
+ * Sets the timeout for fetching content protection allowlist in milliseconds.
+ *
+ * @hide
+ */
+ public static final String DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_ALLOWLIST_TIMEOUT_MS =
+ "content_protection_allowlist_timeout_ms";
+
/** @hide */
@TestApi
public static final int LOGGING_LEVEL_OFF = 0;
@@ -445,6 +461,10 @@ public final class ContentCaptureManager {
public static final String DEFAULT_CONTENT_PROTECTION_OPTIONAL_GROUPS_CONFIG = "";
/** @hide */
public static final int DEFAULT_CONTENT_PROTECTION_OPTIONAL_GROUPS_THRESHOLD = 0;
+ /** @hide */
+ public static final long DEFAULT_CONTENT_PROTECTION_ALLOWLIST_DELAY_MS = 30000;
+ /** @hide */
+ public static final long DEFAULT_CONTENT_PROTECTION_ALLOWLIST_TIMEOUT_MS = 250;
private final Object mLock = new Object();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
index 37bcf1ddeac5..0568edaa7ab6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
@@ -949,7 +949,9 @@ public class BubbleExpandedView extends LinearLayout {
if (mTaskView != null
&& mTaskView.getVisibility() == VISIBLE
&& mTaskView.isAttachedToWindow()) {
- mTaskView.onLocationChanged();
+ // post this to the looper, because if the device orientation just changed, we need to
+ // let the current shell transition complete before updating the task view bounds.
+ post(() -> mTaskView.onLocationChanged());
}
if (mIsOverflow) {
// post this to the looper so that the view has a chance to be laid out before it can
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index 3660fa29e9e4..9402d028ecc4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -1012,15 +1012,15 @@ public class BubbleStackView extends FrameLayout
}
if (mIsExpanded) {
- // Re-draw bubble row and pointer for new orientation.
- beforeExpandedViewAnimation();
+ // update the expanded view and pointer location for the new orientation.
+ hideFlyoutImmediate();
+ mExpandedViewContainer.setAlpha(0f);
+ updateExpandedView();
updateOverflowVisibility();
- updatePointerPosition(false /* forIme */);
- mExpandedAnimationController.expandFromStack(() -> {
- afterExpandedViewAnimation();
- mExpandedViewContainer.setVisibility(VISIBLE);
- showManageMenu(mShowingManage);
- } /* after */);
+ updatePointerPosition(false);
+ requestUpdate();
+ showManageMenu(mShowingManage);
+
PointF p = mPositioner.getExpandedBubbleXY(getBubbleIndex(mExpandedBubble),
getState());
final float translationY = mPositioner.getExpandedViewY(mExpandedBubble,
@@ -1029,6 +1029,7 @@ public class BubbleStackView extends FrameLayout
mExpandedViewContainer.setTranslationY(translationY);
mExpandedViewContainer.setAlpha(1f);
}
+
removeOnLayoutChangeListener(mOrientationChangedListener);
};
final float maxDismissSize = getResources().getDimensionPixelSize(
diff --git a/libs/WindowManager/Shell/tests/flicker/Android.bp b/libs/WindowManager/Shell/tests/flicker/Android.bp
index acfb259d7359..bd2eb5b4a8ae 100644
--- a/libs/WindowManager/Shell/tests/flicker/Android.bp
+++ b/libs/WindowManager/Shell/tests/flicker/Android.bp
@@ -153,9 +153,8 @@ java_library {
}
java_defaults {
- name: "WMShellFlickerTestsDefault",
+ name: "WMShellFlickerTestsDefaultWithoutTemplate",
manifest: "manifests/AndroidManifest.xml",
- test_config_template: "AndroidTestTemplate.xml",
platform_apis: true,
certificate: "platform",
optimize: {
@@ -182,6 +181,12 @@ java_defaults {
],
}
+java_defaults {
+ name: "WMShellFlickerTestsDefault",
+ defaults: ["WMShellFlickerTestsDefaultWithoutTemplate"],
+ test_config_template: "AndroidTestTemplate.xml",
+}
+
android_test {
name: "WMShellFlickerTestsOther",
defaults: ["WMShellFlickerTestsDefault"],
@@ -276,6 +281,23 @@ android_test {
}
android_test {
+ name: "WMShellFlickerTestsPipAppsCSuite",
+ defaults: ["WMShellFlickerTestsDefaultWithoutTemplate"],
+ additional_manifests: ["manifests/AndroidManifestPip.xml"],
+ package_name: "com.android.wm.shell.flicker.pip.apps",
+ instrumentation_target_package: "com.android.wm.shell.flicker.pip.apps",
+ srcs: [
+ ":WMShellFlickerTestsBase-src",
+ ":WMShellFlickerTestsPipApps-src",
+ ":WMShellFlickerTestsPipCommon-src",
+ ],
+ test_suites: [
+ "device-tests",
+ "csuite",
+ ],
+}
+
+android_test {
name: "WMShellFlickerTestsSplitScreenGroup1",
defaults: ["WMShellFlickerTestsDefault"],
additional_manifests: ["manifests/AndroidManifestSplitScreen.xml"],
@@ -327,3 +349,8 @@ android_test {
":WMShellFlickerServicePlatinumTests-src",
],
}
+
+csuite_test {
+ name: "csuite-1p3p-pip-flickers",
+ test_config_template: "csuiteDefaultTemplate.xml",
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/csuiteDefaultTemplate.xml b/libs/WindowManager/Shell/tests/flicker/csuiteDefaultTemplate.xml
new file mode 100644
index 000000000000..ca182fa5a266
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/csuiteDefaultTemplate.xml
@@ -0,0 +1,121 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<configuration description="Runs WindowManager Shell Flicker Tests WMShellFlickerTestsPipAppsCSuite">
+ <option name="test-tag" value="FlickerTests"/>
+ <!-- Needed for storing the perfetto trace files in the sdcard/test_results-->
+ <option name="isolated-storage" value="false"/>
+
+ <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
+ <!-- keeps the screen on during tests -->
+ <option name="screen-always-on" value="on"/>
+ <!-- prevents the phone from restarting -->
+ <option name="force-skip-system-props" value="true"/>
+ <!-- set WM tracing verbose level to all -->
+ <option name="run-command" value="cmd window tracing level all"/>
+ <!-- set WM tracing to frame (avoid incomplete states) -->
+ <option name="run-command" value="cmd window tracing frame"/>
+ <!-- disable betterbug as it's log collection dialogues cause flakes in e2e tests -->
+ <option name="run-command" value="pm disable com.google.android.internal.betterbug"/>
+ <!-- ensure lock screen mode is swipe -->
+ <option name="run-command" value="locksettings set-disabled false"/>
+ <!-- restart launcher to activate TAPL -->
+ <option name="run-command"
+ value="setprop ro.test_harness 1 ; am force-stop com.google.android.apps.nexuslauncher"/>
+ <!-- Increase trace size: 20mb for WM and 80mb for SF -->
+ <option name="run-command" value="cmd window tracing size 20480"/>
+ <option name="run-command" value="su root service call SurfaceFlinger 1029 i32 81920"/>
+ </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="test-user-token" value="%TEST_USER%"/>
+ <option name="run-command" value="rm -rf /data/user/%TEST_USER%/files/*"/>
+ <option name="run-command" value="settings put secure show_ime_with_hard_keyboard 1"/>
+ <option name="run-command" value="settings put system show_touches 1"/>
+ <option name="run-command" value="settings put system pointer_location 1"/>
+ <option name="teardown-command"
+ value="settings delete secure show_ime_with_hard_keyboard"/>
+ <option name="teardown-command" value="settings delete system show_touches"/>
+ <option name="teardown-command" value="settings delete system pointer_location"/>
+ <option name="teardown-command"
+ value="cmd overlay enable com.android.internal.systemui.navbar.gestural"/>
+ </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true"/>
+ <option name="test-file-name" value="WMShellFlickerTestsPipAppsCSuite.apk"/>
+ <option name="test-file-name" value="FlickerTestApp.apk"/>
+ </target_preparer>
+ <!-- Enable mocking GPS location by the test app -->
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="run-command"
+ value="appops set com.android.wm.shell.flicker.pip.apps android:mock_location allow"/>
+ <option name="teardown-command"
+ value="appops set com.android.wm.shell.flicker.pip.apps android:mock_location deny"/>
+ </target_preparer>
+
+ <!-- Needed for pushing the trace config file -->
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="push-file"
+ key="trace_config.textproto"
+ value="/data/misc/perfetto-traces/trace_config.textproto"
+ />
+ <!--Install the content provider automatically when we push some file in sdcard folder.-->
+ <!--Needed to avoid the installation during the test suite.-->
+ <option name="push-file" key="trace_config.textproto" value="/sdcard/sample.textproto"/>
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+ <option name="package" value="com.android.wm.shell.flicker.pip.apps"/>
+ <option name="shell-timeout" value="6600s"/>
+ <option name="test-timeout" value="6000s"/>
+ <option name="hidden-api-checks" value="false"/>
+ <option name="device-listeners" value="android.device.collectors.PerfettoListener"/>
+ <!-- PerfettoListener related arguments -->
+ <option name="instrumentation-arg" key="perfetto_config_text_proto" value="true"/>
+ <option name="instrumentation-arg"
+ key="perfetto_config_file"
+ value="trace_config.textproto"
+ />
+ <option name="instrumentation-arg" key="per_run" value="true"/>
+ </test>
+ <!-- Needed for pulling the collected trace config on to the host -->
+ <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+ <option name="pull-pattern-keys" value="perfetto_file_path"/>
+ <option name="directory-keys"
+ value="/data/user/0/com.android.wm.shell.flicker/files"/>
+ <option name="directory-keys"
+ value="/data/user/0/com.android.wm.shell.flicker.bubbles/files"/>
+ <option name="directory-keys"
+ value="/data/user/0/com.android.wm.shell.flicker.pip/files"/>
+ <option name="directory-keys"
+ value="/data/user/0/com.android.wm.shell.flicker.pip.apps/files"/>
+ <option name="directory-keys"
+ value="/data/user/0/com.android.wm.shell.flicker.splitscreen/files"/>
+ <option name="directory-keys"
+ value="/data/user/0/com.android.wm.shell.flicker.service/files"/>
+ <option name="collect-on-run-ended-only" value="true"/>
+ <option name="clean-up" value="true"/>
+ </metrics_collector>
+
+ <!-- Needed for installing apk's from Play Store -->
+ <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+ <option name="aapt-version" value="AAPT2"/>
+ <option name="throw-if-not-found" value="false"/>
+ <option name="install-arg" value="-d"/>
+ <option name="install-arg" value="-g"/>
+ <option name="install-arg" value="-r"/>
+ <option name="test-file-name" value="pstash://com.netflix.mediaclient"/>
+ </target_preparer>
+</configuration>
diff --git a/native/android/system_fonts.cpp b/native/android/system_fonts.cpp
index de7ea701b26d..91f78ce6f950 100644
--- a/native/android/system_fonts.cpp
+++ b/native/android/system_fonts.cpp
@@ -21,22 +21,20 @@
#include <android/font.h>
#include <android/font_matcher.h>
#include <android/system_fonts.h>
-
-#include <memory>
-#include <string>
-#include <vector>
-
#include <errno.h>
#include <fcntl.h>
-#include <libxml/tree.h>
-#include <log/log.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
#include <hwui/MinikinSkia.h>
+#include <libxml/parser.h>
+#include <log/log.h>
#include <minikin/FontCollection.h>
#include <minikin/LocaleList.h>
#include <minikin/SystemFonts.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <memory>
+#include <string>
+#include <vector>
struct XmlCharDeleter {
void operator()(xmlChar* b) { xmlFree(b); }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt
index 95b467fdad40..5c590870981d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt
@@ -45,30 +45,61 @@ object NotificationListViewBinder {
iconAreaController: NotificationIconAreaController,
shelfIconViewStore: ShelfNotificationIconViewStore,
) {
+ bindShelf(
+ view,
+ viewModel,
+ configuration,
+ configurationController,
+ falsingManager,
+ iconAreaController,
+ shelfIconViewStore
+ )
+
+ bindFooter(view, viewModel, configuration)
+ }
+
+ private fun bindShelf(
+ parentView: NotificationStackScrollLayout,
+ parentViewModel: NotificationListViewModel,
+ configuration: ConfigurationState,
+ configurationController: ConfigurationController,
+ falsingManager: FalsingManager,
+ iconAreaController: NotificationIconAreaController,
+ shelfIconViewStore: ShelfNotificationIconViewStore
+ ) {
val shelf =
- LayoutInflater.from(view.context)
- .inflate(R.layout.status_bar_notification_shelf, view, false) as NotificationShelf
+ LayoutInflater.from(parentView.context)
+ .inflate(R.layout.status_bar_notification_shelf, parentView, false)
+ as NotificationShelf
NotificationShelfViewBinder.bind(
shelf,
- viewModel.shelf,
+ parentViewModel.shelf,
configuration,
configurationController,
falsingManager,
iconAreaController,
shelfIconViewStore,
)
- view.setShelf(shelf)
+ parentView.setShelf(shelf)
+ }
- viewModel.footer.ifPresent { footerViewModel ->
+ private fun bindFooter(
+ parentView: NotificationStackScrollLayout,
+ parentViewModel: NotificationListViewModel,
+ configuration: ConfigurationState
+ ) {
+ parentViewModel.footer.ifPresent { footerViewModel ->
// The footer needs to be re-inflated every time the theme or the font size changes.
- view.repeatWhenAttached {
+ parentView.repeatWhenAttached {
configuration.reinflateAndBindLatest(
R.layout.status_bar_notification_footer,
- view,
+ parentView,
attachToRoot = false,
) { footerView: FooterView ->
traceSection("bind FooterView") {
- FooterViewBinder.bind(footerView, footerViewModel)
+ val disposableHandle = FooterViewBinder.bind(footerView, footerViewModel)
+ parentView.setFooterView(footerView)
+ return@reinflateAndBindLatest disposableHandle
}
}
}
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
index 76ebdf4d4c1c..9f4528b113e7 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
@@ -20,6 +20,8 @@ import static android.Manifest.permission.MANAGE_CONTENT_CAPTURE;
import static android.content.Context.CONTENT_CAPTURE_MANAGER_SERVICE;
import static android.service.contentcapture.ContentCaptureService.setClientState;
import static android.view.contentcapture.ContentCaptureHelper.toList;
+import static android.view.contentcapture.ContentCaptureManager.DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_ALLOWLIST_DELAY_MS;
+import static android.view.contentcapture.ContentCaptureManager.DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_ALLOWLIST_TIMEOUT_MS;
import static android.view.contentcapture.ContentCaptureManager.DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_OPTIONAL_GROUPS_CONFIG;
import static android.view.contentcapture.ContentCaptureManager.DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_OPTIONAL_GROUPS_THRESHOLD;
import static android.view.contentcapture.ContentCaptureManager.DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_REQUIRED_GROUPS_CONFIG;
@@ -219,6 +221,12 @@ public class ContentCaptureManagerService extends
@GuardedBy("mLock")
int mDevCfgContentProtectionOptionalGroupsThreshold;
+ @GuardedBy("mLock")
+ long mDevCfgContentProtectionAllowlistDelayMs;
+
+ @GuardedBy("mLock")
+ long mDevCfgContentProtectionAllowlistTimeoutMs;
+
private final Executor mDataShareExecutor = Executors.newCachedThreadPool();
private final Handler mHandler = new Handler(Looper.getMainLooper());
@@ -231,11 +239,17 @@ public class ContentCaptureManagerService extends
final GlobalContentCaptureOptions mGlobalContentCaptureOptions =
new GlobalContentCaptureOptions();
- @Nullable private final ComponentName mContentProtectionServiceComponentName;
+ @GuardedBy("mLock")
+ @Nullable
+ private ComponentName mContentProtectionServiceComponentName;
- @Nullable private final ContentProtectionAllowlistManager mContentProtectionAllowlistManager;
+ @GuardedBy("mLock")
+ @Nullable
+ private ContentProtectionAllowlistManager mContentProtectionAllowlistManager;
- @Nullable private final ContentProtectionConsentManager mContentProtectionConsentManager;
+ @GuardedBy("mLock")
+ @Nullable
+ private ContentProtectionConsentManager mContentProtectionConsentManager;
public ContentCaptureManagerService(@NonNull Context context) {
super(context, new FrameworkResourcesServiceNameResolver(context,
@@ -279,21 +293,6 @@ public class ContentCaptureManagerService extends
mServiceNameResolver.getServiceName(userId),
mServiceNameResolver.isTemporary(userId));
}
-
- if (getEnableContentProtectionReceiverLocked()) {
- mContentProtectionServiceComponentName = getContentProtectionServiceComponentName();
- if (mContentProtectionServiceComponentName != null) {
- mContentProtectionAllowlistManager = createContentProtectionAllowlistManager();
- mContentProtectionConsentManager = createContentProtectionConsentManager();
- } else {
- mContentProtectionAllowlistManager = null;
- mContentProtectionConsentManager = null;
- }
- } else {
- mContentProtectionServiceComponentName = null;
- mContentProtectionAllowlistManager = null;
- mContentProtectionConsentManager = null;
- }
}
@Override // from AbstractMasterSystemService
@@ -442,6 +441,8 @@ public class ContentCaptureManagerService extends
case DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_REQUIRED_GROUPS_CONFIG:
case DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_OPTIONAL_GROUPS_CONFIG:
case DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_OPTIONAL_GROUPS_THRESHOLD:
+ case DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_ALLOWLIST_DELAY_MS:
+ case DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_ALLOWLIST_TIMEOUT_MS:
setFineTuneParamsFromDeviceConfig();
return;
default:
@@ -453,8 +454,15 @@ public class ContentCaptureManagerService extends
/** @hide */
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
protected void setFineTuneParamsFromDeviceConfig() {
+ boolean enableContentProtectionReceiverOld;
+ boolean enableContentProtectionReceiverNew;
String contentProtectionRequiredGroupsConfig;
String contentProtectionOptionalGroupsConfig;
+ int contentProtectionOptionalGroupsThreshold;
+ long contentProtectionAllowlistDelayMs;
+ long contentProtectionAllowlistTimeoutMs;
+ ContentProtectionAllowlistManager contentProtectionAllowlistManagerOld;
+
synchronized (mLock) {
mDevCfgMaxBufferSize =
DeviceConfig.getInt(
@@ -488,12 +496,9 @@ public class ContentCaptureManagerService extends
ContentCaptureManager
.DEVICE_CONFIG_PROPERTY_DISABLE_FLUSH_FOR_VIEW_TREE_APPEARING,
false);
- mDevCfgEnableContentProtectionReceiver =
- DeviceConfig.getBoolean(
- DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
- ContentCaptureManager
- .DEVICE_CONFIG_PROPERTY_ENABLE_CONTENT_PROTECTION_RECEIVER,
- ContentCaptureManager.DEFAULT_ENABLE_CONTENT_PROTECTION_RECEIVER);
+
+ enableContentProtectionReceiverOld = mDevCfgEnableContentProtectionReceiver;
+ enableContentProtectionReceiverNew = getDeviceConfigEnableContentProtectionReceiver();
mDevCfgContentProtectionBufferSize =
DeviceConfig.getInt(
DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
@@ -512,12 +517,25 @@ public class ContentCaptureManagerService extends
DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_OPTIONAL_GROUPS_CONFIG,
ContentCaptureManager
.DEFAULT_CONTENT_PROTECTION_OPTIONAL_GROUPS_CONFIG);
- mDevCfgContentProtectionOptionalGroupsThreshold =
+ contentProtectionOptionalGroupsThreshold =
DeviceConfig.getInt(
DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_OPTIONAL_GROUPS_THRESHOLD,
ContentCaptureManager
.DEFAULT_CONTENT_PROTECTION_OPTIONAL_GROUPS_THRESHOLD);
+ contentProtectionAllowlistDelayMs =
+ DeviceConfig.getLong(
+ DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
+ DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_ALLOWLIST_DELAY_MS,
+ ContentCaptureManager.DEFAULT_CONTENT_PROTECTION_ALLOWLIST_DELAY_MS);
+ contentProtectionAllowlistTimeoutMs =
+ DeviceConfig.getLong(
+ DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
+ DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_ALLOWLIST_TIMEOUT_MS,
+ ContentCaptureManager.DEFAULT_CONTENT_PROTECTION_ALLOWLIST_TIMEOUT_MS);
+
+ contentProtectionAllowlistManagerOld = mContentProtectionAllowlistManager;
+
if (verbose) {
Slog.v(
TAG,
@@ -535,7 +553,7 @@ public class ContentCaptureManagerService extends
+ ", disableFlushForViewTreeAppearing="
+ mDevCfgDisableFlushForViewTreeAppearing
+ ", enableContentProtectionReceiver="
- + mDevCfgEnableContentProtectionReceiver
+ + enableContentProtectionReceiverNew
+ ", contentProtectionBufferSize="
+ mDevCfgContentProtectionBufferSize
+ ", contentProtectionRequiredGroupsConfig="
@@ -543,7 +561,11 @@ public class ContentCaptureManagerService extends
+ ", contentProtectionOptionalGroupsConfig="
+ contentProtectionOptionalGroupsConfig
+ ", contentProtectionOptionalGroupsThreshold="
- + mDevCfgContentProtectionOptionalGroupsThreshold);
+ + contentProtectionOptionalGroupsThreshold
+ + ", contentProtectionAllowlistDelayMs="
+ + contentProtectionAllowlistDelayMs
+ + ", contentProtectionAllowlistTimeoutMs="
+ + contentProtectionAllowlistTimeoutMs);
}
}
@@ -551,9 +573,37 @@ public class ContentCaptureManagerService extends
parseContentProtectionGroupsConfig(contentProtectionRequiredGroupsConfig);
List<List<String>> contentProtectionOptionalGroups =
parseContentProtectionGroupsConfig(contentProtectionOptionalGroupsConfig);
+ ComponentName contentProtectionServiceComponentNameNew = null;
+ ContentProtectionAllowlistManager contentProtectionAllowlistManagerNew = null;
+ ContentProtectionConsentManager contentProtectionConsentManagerNew = null;
+
+ if (contentProtectionAllowlistManagerOld != null && !enableContentProtectionReceiverNew) {
+ contentProtectionAllowlistManagerOld.stop();
+ }
+ if (!enableContentProtectionReceiverOld && enableContentProtectionReceiverNew) {
+ contentProtectionServiceComponentNameNew = getContentProtectionServiceComponentName();
+ if (contentProtectionServiceComponentNameNew != null) {
+ contentProtectionAllowlistManagerNew =
+ createContentProtectionAllowlistManager(
+ contentProtectionAllowlistTimeoutMs);
+ contentProtectionAllowlistManagerNew.start(contentProtectionAllowlistDelayMs);
+ contentProtectionConsentManagerNew = createContentProtectionConsentManager();
+ }
+ }
+
synchronized (mLock) {
+ mDevCfgEnableContentProtectionReceiver = enableContentProtectionReceiverNew;
mDevCfgContentProtectionRequiredGroups = contentProtectionRequiredGroups;
mDevCfgContentProtectionOptionalGroups = contentProtectionOptionalGroups;
+ mDevCfgContentProtectionOptionalGroupsThreshold =
+ contentProtectionOptionalGroupsThreshold;
+ mDevCfgContentProtectionAllowlistDelayMs = contentProtectionAllowlistDelayMs;
+
+ if (enableContentProtectionReceiverOld ^ enableContentProtectionReceiverNew) {
+ mContentProtectionServiceComponentName = contentProtectionServiceComponentNameNew;
+ mContentProtectionAllowlistManager = contentProtectionAllowlistManagerNew;
+ mContentProtectionConsentManager = contentProtectionConsentManagerNew;
+ }
}
}
@@ -837,27 +887,34 @@ public class ContentCaptureManagerService extends
pw.print(prefix2);
pw.print("contentProtectionOptionalGroupsThreshold: ");
pw.println(mDevCfgContentProtectionOptionalGroupsThreshold);
+ pw.print(prefix2);
+ pw.print("contentProtectionAllowlistDelayMs: ");
+ pw.println(mDevCfgContentProtectionAllowlistDelayMs);
+ pw.print(prefix2);
+ pw.print("contentProtectionAllowlistTimeoutMs: ");
+ pw.println(mDevCfgContentProtectionAllowlistTimeoutMs);
pw.print(prefix);
pw.println("Global Options:");
mGlobalContentCaptureOptions.dump(prefix2, pw);
}
- /**
- * Used by the constructor in order to be able to override the value in the tests.
- *
- * @hide
- */
+ /** @hide */
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
- @GuardedBy("mLock")
- protected boolean getEnableContentProtectionReceiverLocked() {
- return mDevCfgEnableContentProtectionReceiver;
+ protected boolean getDeviceConfigEnableContentProtectionReceiver() {
+ return DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
+ ContentCaptureManager.DEVICE_CONFIG_PROPERTY_ENABLE_CONTENT_PROTECTION_RECEIVER,
+ ContentCaptureManager.DEFAULT_ENABLE_CONTENT_PROTECTION_RECEIVER);
}
/** @hide */
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
@NonNull
- protected ContentProtectionAllowlistManager createContentProtectionAllowlistManager() {
- return new ContentProtectionAllowlistManager();
+ protected ContentProtectionAllowlistManager createContentProtectionAllowlistManager(
+ long timeoutMs) {
+ // Same handler as used by AbstractMasterSystemService
+ return new ContentProtectionAllowlistManager(
+ this, BackgroundThread.getHandler(), timeoutMs);
}
/** @hide */
@@ -874,6 +931,9 @@ public class ContentCaptureManagerService extends
@Nullable
private ComponentName getContentProtectionServiceComponentName() {
String flatComponentName = getContentProtectionServiceFlatComponentName();
+ if (flatComponentName == null) {
+ return null;
+ }
return ComponentName.unflattenFromString(flatComponentName);
}
@@ -898,27 +958,27 @@ public class ContentCaptureManagerService extends
getContext(), componentName, /* isTemp= */ false, UserHandle.getCallingUserId());
}
+ /** @hide */
@Nullable
- private RemoteContentProtectionService createRemoteContentProtectionService() {
- if (mContentProtectionServiceComponentName == null) {
- // This case should not be possible but make sure
- return null;
- }
+ public RemoteContentProtectionService createRemoteContentProtectionService() {
+ ComponentName componentName;
synchronized (mLock) {
- if (!mDevCfgEnableContentProtectionReceiver) {
+ if (!mDevCfgEnableContentProtectionReceiver
+ || mContentProtectionServiceComponentName == null) {
return null;
}
+ componentName = mContentProtectionServiceComponentName;
}
// Check permissions by trying to construct {@link ContentCaptureServiceInfo}
try {
- createContentProtectionServiceInfo(mContentProtectionServiceComponentName);
+ createContentProtectionServiceInfo(componentName);
} catch (Exception ex) {
// Swallow, exception was already logged
return null;
}
- return createRemoteContentProtectionService(mContentProtectionServiceComponentName);
+ return createRemoteContentProtectionService(componentName);
}
/** @hide */
@@ -976,6 +1036,16 @@ public class ContentCaptureManagerService extends
.toList();
}
+ @GuardedBy("mLock")
+ private boolean isContentProtectionEnabledLocked() {
+ return mDevCfgEnableContentProtectionReceiver
+ && mContentProtectionServiceComponentName != null
+ && mContentProtectionAllowlistManager != null
+ && mContentProtectionConsentManager != null
+ && !(mDevCfgContentProtectionRequiredGroups.isEmpty()
+ && mDevCfgContentProtectionOptionalGroups.isEmpty());
+ }
+
final class ContentCaptureManagerServiceStub extends IContentCaptureManager.Stub {
@Override
@@ -1406,22 +1476,17 @@ public class ContentCaptureManagerService extends
private boolean isContentProtectionReceiverEnabled(
@UserIdInt int userId, @NonNull String packageName) {
- if (mContentProtectionServiceComponentName == null
- || mContentProtectionAllowlistManager == null
- || mContentProtectionConsentManager == null) {
- return false;
- }
+ ContentProtectionConsentManager consentManager;
+ ContentProtectionAllowlistManager allowlistManager;
synchronized (mLock) {
- if (!mDevCfgEnableContentProtectionReceiver) {
- return false;
- }
- if (mDevCfgContentProtectionRequiredGroups.isEmpty()
- && mDevCfgContentProtectionOptionalGroups.isEmpty()) {
+ if (!isContentProtectionEnabledLocked()) {
return false;
}
+ consentManager = mContentProtectionConsentManager;
+ allowlistManager = mContentProtectionAllowlistManager;
}
- return mContentProtectionConsentManager.isConsentGranted(userId)
- && mContentProtectionAllowlistManager.isAllowed(packageName);
+ return consentManager.isConsentGranted(userId)
+ && allowlistManager.isAllowed(packageName);
}
}
diff --git a/services/contentcapture/java/com/android/server/contentprotection/ContentProtectionAllowlistManager.java b/services/contentcapture/java/com/android/server/contentprotection/ContentProtectionAllowlistManager.java
index 59af5263fa9e..f77430dae26b 100644
--- a/services/contentcapture/java/com/android/server/contentprotection/ContentProtectionAllowlistManager.java
+++ b/services/contentcapture/java/com/android/server/contentprotection/ContentProtectionAllowlistManager.java
@@ -16,8 +16,22 @@
package com.android.server.contentprotection;
+import static android.view.contentprotection.flags.Flags.blocklistUpdateEnabled;
+
import android.annotation.NonNull;
-import android.util.Slog;
+import android.annotation.Nullable;
+import android.os.Handler;
+import android.os.UserHandle;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.content.PackageMonitor;
+import com.android.server.contentcapture.ContentCaptureManagerService;
+
+import java.time.Instant;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
/**
* Manages whether the content protection is enabled for an app using a allowlist.
@@ -28,11 +42,124 @@ public class ContentProtectionAllowlistManager {
private static final String TAG = "ContentProtectionAllowlistManager";
- public ContentProtectionAllowlistManager() {}
+ @NonNull private final ContentCaptureManagerService mContentCaptureManagerService;
+
+ @NonNull private final Handler mHandler;
+
+ private final long mTimeoutMs;
+
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+ @NonNull
+ final PackageMonitor mPackageMonitor;
+
+ private final Object mHandlerToken = new Object();
+
+ private final Object mLock = new Object();
+
+ // Used outside of the handler
+ private boolean mStarted;
+
+ // Used inside the handler
+ @Nullable private Instant mUpdatePendingUntil;
+
+ @NonNull
+ @GuardedBy("mLock")
+ private Set<String> mAllowedPackages = Set.of();
+
+ public ContentProtectionAllowlistManager(
+ @NonNull ContentCaptureManagerService contentCaptureManagerService,
+ @NonNull Handler handler,
+ long timeoutMs) {
+ mContentCaptureManagerService = contentCaptureManagerService;
+ mHandler = handler;
+ mTimeoutMs = timeoutMs;
+ mPackageMonitor = createPackageMonitor();
+ }
+
+ /** Starts the manager. */
+ public void start(long delayMs) {
+ if (mStarted) {
+ return;
+ }
+ mStarted = true;
+ mHandler.postDelayed(this::handleInitialUpdate, mHandlerToken, delayMs);
+ // PackageMonitor will be registered inside handleInitialUpdate to respect the initial delay
+ }
+
+ /** Stops the manager. */
+ public void stop() {
+ try {
+ mPackageMonitor.unregister();
+ } catch (IllegalStateException ex) {
+ // Swallow, throws if not registered
+ }
+ mHandler.removeCallbacksAndMessages(mHandlerToken);
+ mUpdatePendingUntil = null;
+ mStarted = false;
+ }
/** Returns true if the package is allowed. */
public boolean isAllowed(@NonNull String packageName) {
- Slog.v(TAG, packageName);
- return false;
+ Set<String> allowedPackages;
+ synchronized (mLock) {
+ allowedPackages = mAllowedPackages;
+ }
+ return allowedPackages.contains(packageName);
+ }
+
+ private void setAllowlist(@NonNull List<String> packages) {
+ synchronized (mLock) {
+ mAllowedPackages = packages.stream().collect(Collectors.toUnmodifiableSet());
+ }
+ mUpdatePendingUntil = null;
+ }
+
+ private void handleInitialUpdate() {
+ handleUpdate();
+
+ // Initial update done, start listening to package updates now
+ mPackageMonitor.register(
+ mContentCaptureManagerService.getContext(), UserHandle.ALL, mHandler);
+ }
+
+ private void handleUpdate() {
+ if (!blocklistUpdateEnabled()) {
+ return;
+ }
+
+ /**
+ * PackageMonitor callback can be invoked more than once in a matter of milliseconds on the
+ * same monitor instance for the same package (eg: b/295969873). This check acts both as a
+ * simple generic rate limit and as a mitigation for this quirk.
+ */
+ if (mUpdatePendingUntil != null && Instant.now().isBefore(mUpdatePendingUntil)) {
+ return;
+ }
+
+ RemoteContentProtectionService remoteContentProtectionService =
+ mContentCaptureManagerService.createRemoteContentProtectionService();
+ if (remoteContentProtectionService == null) {
+ return;
+ }
+
+ // If there are any pending updates queued already, they can be removed immediately
+ mHandler.removeCallbacksAndMessages(mHandlerToken);
+ mUpdatePendingUntil = Instant.now().plusMillis(mTimeoutMs);
+ }
+
+ /** @hide */
+ @NonNull
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+ protected PackageMonitor createPackageMonitor() {
+ return new ContentProtectionPackageMonitor();
+ }
+
+ private final class ContentProtectionPackageMonitor extends PackageMonitor {
+
+ // This callback might be invoked multiple times, for more info refer to the comment above
+ @Override
+ public void onSomePackagesChanged() {
+ handleUpdate();
+ }
}
}
diff --git a/services/contentcapture/java/com/android/server/contentprotection/ContentProtectionConsentManager.java b/services/contentcapture/java/com/android/server/contentprotection/ContentProtectionConsentManager.java
index 2eb758cd5a13..488a51a56fee 100644
--- a/services/contentcapture/java/com/android/server/contentprotection/ContentProtectionConsentManager.java
+++ b/services/contentcapture/java/com/android/server/contentprotection/ContentProtectionConsentManager.java
@@ -40,6 +40,9 @@ public class ContentProtectionConsentManager {
private static final String KEY_PACKAGE_VERIFIER_USER_CONSENT = "package_verifier_user_consent";
+ private static final String KEY_CONTENT_PROTECTION_USER_CONSENT =
+ "content_protection_user_consent";
+
@NonNull private final ContentResolver mContentResolver;
@NonNull private final DevicePolicyManagerInternal mDevicePolicyManagerInternal;
@@ -50,6 +53,8 @@ public class ContentProtectionConsentManager {
private volatile boolean mCachedPackageVerifierConsent;
+ private volatile boolean mCachedContentProtectionConsent;
+
public ContentProtectionConsentManager(
@NonNull Handler handler,
@NonNull ContentResolver contentResolver,
@@ -63,14 +68,18 @@ public class ContentProtectionConsentManager {
/* notifyForDescendants= */ false,
mContentObserver,
UserHandle.USER_ALL);
+
mCachedPackageVerifierConsent = isPackageVerifierConsentGranted();
+ mCachedContentProtectionConsent = isContentProtectionConsentGranted();
}
/**
* Returns true if all the consents are granted
*/
public boolean isConsentGranted(@UserIdInt int userId) {
- return mCachedPackageVerifierConsent && !isUserOrganizationManaged(userId);
+ return mCachedPackageVerifierConsent
+ && mCachedContentProtectionConsent
+ && !isUserOrganizationManaged(userId);
}
private boolean isPackageVerifierConsentGranted() {
@@ -80,6 +89,13 @@ public class ContentProtectionConsentManager {
>= 1;
}
+ private boolean isContentProtectionConsentGranted() {
+ // Not always cached internally
+ return Settings.Global.getInt(
+ mContentResolver, KEY_CONTENT_PROTECTION_USER_CONSENT, /* def= */ 0)
+ >= 0;
+ }
+
private boolean isUserOrganizationManaged(@UserIdInt int userId) {
// Cached internally
return mDevicePolicyManagerInternal.isUserOrganizationManaged(userId);
@@ -101,6 +117,9 @@ public class ContentProtectionConsentManager {
case KEY_PACKAGE_VERIFIER_USER_CONSENT:
mCachedPackageVerifierConsent = isPackageVerifierConsentGranted();
return;
+ case KEY_CONTENT_PROTECTION_USER_CONSENT:
+ mCachedContentProtectionConsent = isContentProtectionConsentGranted();
+ return;
default:
Slog.w(TAG, "Ignoring unexpected property: " + property);
}
diff --git a/services/core/java/com/android/server/camera/CameraServiceProxy.java b/services/core/java/com/android/server/camera/CameraServiceProxy.java
index f9bc8dcc7d0b..5bb5c53f6d5e 100644
--- a/services/core/java/com/android/server/camera/CameraServiceProxy.java
+++ b/services/core/java/com/android/server/camera/CameraServiceProxy.java
@@ -243,6 +243,7 @@ public class CameraServiceProxy extends SystemService
public String mUserTag;
public int mVideoStabilizationMode;
public boolean mUsedUltraWide;
+ public boolean mUsedZoomOverride;
public final long mLogId;
public final int mSessionIndex;
@@ -271,7 +272,7 @@ public class CameraServiceProxy extends SystemService
long resultErrorCount, boolean deviceError,
List<CameraStreamStats> streamStats, String userTag,
int videoStabilizationMode, boolean usedUltraWide,
- CameraExtensionSessionStats extStats) {
+ boolean usedZoomOverride, CameraExtensionSessionStats extStats) {
if (mCompleted) {
return;
}
@@ -285,6 +286,7 @@ public class CameraServiceProxy extends SystemService
mUserTag = userTag;
mVideoStabilizationMode = videoStabilizationMode;
mUsedUltraWide = usedUltraWide;
+ mUsedZoomOverride = usedZoomOverride;
mExtSessionStats = extStats;
if (CameraServiceProxy.DEBUG) {
Slog.v(TAG, "A camera facing " + cameraFacingToString(mCameraFacing) +
@@ -877,6 +879,9 @@ public class CameraServiceProxy extends SystemService
String ultrawideDebug = Flags.logUltrawideUsage()
? ", wideAngleUsage " + e.mUsedUltraWide
: "";
+ String zoomOverrideDebug = Flags.logZoomOverrideUsage()
+ ? ", zoomOverrideUsage " + e.mUsedZoomOverride
+ : "";
Slog.v(TAG, "CAMERA_ACTION_EVENT: action " + e.mAction
+ " clientName " + e.mClientName
@@ -895,6 +900,7 @@ public class CameraServiceProxy extends SystemService
+ ", userTag is " + e.mUserTag
+ ", videoStabilizationMode " + e.mVideoStabilizationMode
+ ultrawideDebug
+ + zoomOverrideDebug
+ ", logId " + e.mLogId
+ ", sessionIndex " + e.mSessionIndex
+ ", mExtSessionStats {type " + extensionType
@@ -960,7 +966,8 @@ public class CameraServiceProxy extends SystemService
MessageNano.toByteArray(streamProtos[4]),
e.mUserTag, e.mVideoStabilizationMode,
e.mLogId, e.mSessionIndex,
- extensionType, extensionIsAdvanced, e.mUsedUltraWide);
+ extensionType, extensionIsAdvanced, e.mUsedUltraWide,
+ e.mUsedZoomOverride);
}
}
@@ -1158,6 +1165,8 @@ public class CameraServiceProxy extends SystemService
String userTag = cameraState.getUserTag();
int videoStabilizationMode = cameraState.getVideoStabilizationMode();
boolean usedUltraWide = Flags.logUltrawideUsage() ? cameraState.getUsedUltraWide() : false;
+ boolean usedZoomOverride =
+ Flags.logZoomOverrideUsage() ? cameraState.getUsedZoomOverride() : false;
long logId = cameraState.getLogId();
int sessionIdx = cameraState.getSessionIndex();
CameraExtensionSessionStats extSessionStats = cameraState.getExtensionSessionStats();
@@ -1216,7 +1225,7 @@ public class CameraServiceProxy extends SystemService
oldEvent.markCompleted(/*internalReconfigure*/0, /*requestCount*/0,
/*resultErrorCount*/0, /*deviceError*/false, streamStats,
/*userTag*/"", /*videoStabilizationMode*/-1, /*usedUltraWide*/false,
- new CameraExtensionSessionStats());
+ /*usedZoomOverride*/false, new CameraExtensionSessionStats());
mCameraUsageHistory.add(oldEvent);
}
break;
@@ -1227,7 +1236,8 @@ public class CameraServiceProxy extends SystemService
doneEvent.markCompleted(internalReconfigureCount, requestCount,
resultErrorCount, deviceError, streamStats, userTag,
- videoStabilizationMode, usedUltraWide, extSessionStats);
+ videoStabilizationMode, usedUltraWide, usedZoomOverride,
+ extSessionStats);
mCameraUsageHistory.add(doneEvent);
// Do not double count device error
deviceError = false;
diff --git a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
index 9b7b8de633c4..cb4cf9d3162c 100644
--- a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
+++ b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
@@ -356,15 +356,23 @@ public class BackgroundActivityStartController {
public String toString() {
StringBuilder builder = new StringBuilder();
- if (mBackground) {
- builder.append("Background ");
- }
- builder.append("Activity start allowed: " + mMessage + ".");
- builder.append("BAL Code: ");
+ builder.append(". BAL Code: ");
builder.append(balCodeToString(mCode));
- if (mProcessInfo != null) {
+ if (DEBUG_ACTIVITY_STARTS) {
builder.append(" ");
- builder.append(mProcessInfo);
+ if (mBackground) {
+ builder.append("Background ");
+ }
+ builder.append("Activity start ");
+ if (mCode == BAL_BLOCK) {
+ builder.append("denied");
+ } else {
+ builder.append("allowed: ").append(mMessage);
+ }
+ if (mProcessInfo != null) {
+ builder.append(" ");
+ builder.append(mProcessInfo);
+ }
}
return builder.toString();
}
diff --git a/services/tests/servicestests/src/com/android/server/contentcapture/ContentCaptureManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/contentcapture/ContentCaptureManagerServiceTest.java
index 78bf9b0bc828..9a5241ea242a 100644
--- a/services/tests/servicestests/src/com/android/server/contentcapture/ContentCaptureManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/contentcapture/ContentCaptureManagerServiceTest.java
@@ -21,6 +21,7 @@ import static android.view.contentprotection.flags.Flags.FLAG_PARSE_GROUPS_CONFI
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
@@ -31,7 +32,6 @@ import android.annotation.NonNull;
import android.content.ComponentName;
import android.content.ContentCaptureOptions;
import android.content.Context;
-import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
import android.content.pm.UserInfo;
import android.platform.test.flag.junit.SetFlagsRule;
@@ -130,63 +130,154 @@ public class ContentCaptureManagerServiceTest {
}
@Test
- public void constructor_contentProtection_flagDisabled_noManagers() {
+ public void constructor_contentProtection_disabled_noManagers() {
assertThat(mContentProtectionAllowlistManagersCreated).isEqualTo(0);
- assertThat(mContentProtectionServiceInfosCreated).isEqualTo(0);
assertThat(mContentProtectionConsentManagersCreated).isEqualTo(0);
+ assertThat(mContentProtectionServiceInfosCreated).isEqualTo(0);
verifyZeroInteractions(mMockContentProtectionAllowlistManager);
verifyZeroInteractions(mMockContentProtectionConsentManager);
}
@Test
- public void constructor_contentProtection_componentNameNull_noManagers() {
- mConfigDefaultContentProtectionService = null;
+ public void constructor_contentProtection_enabled_createsManagers() {
+ mDevCfgEnableContentProtectionReceiver = true;
mContentCaptureManagerService = new TestContentCaptureManagerService();
+ assertThat(mContentProtectionAllowlistManagersCreated).isEqualTo(1);
+ assertThat(mContentProtectionConsentManagersCreated).isEqualTo(1);
+ assertThat(mContentProtectionServiceInfosCreated).isEqualTo(0);
+ verify(mMockContentProtectionAllowlistManager).start(anyLong());
+ verify(mMockContentProtectionAllowlistManager, never()).stop();
+ verifyZeroInteractions(mMockContentProtectionConsentManager);
+ }
+
+ @Test
+ public void setFineTuneParamsFromDeviceConfig_contentProtection_disabled_to_disabled() {
+ mContentCaptureManagerService.setFineTuneParamsFromDeviceConfig();
+
assertThat(mContentProtectionAllowlistManagersCreated).isEqualTo(0);
+ assertThat(mContentProtectionConsentManagersCreated).isEqualTo(0);
+ assertThat(mContentProtectionServiceInfosCreated).isEqualTo(0);
+ verifyZeroInteractions(mMockContentProtectionAllowlistManager);
+ verifyZeroInteractions(mMockContentProtectionConsentManager);
+ }
+
+ @Test
+ public void setFineTuneParamsFromDeviceConfig_contentProtection_disabled_to_enabled() {
+ mDevCfgEnableContentProtectionReceiver = true;
+
+ mContentCaptureManagerService.setFineTuneParamsFromDeviceConfig();
+
+ assertThat(mContentProtectionAllowlistManagersCreated).isEqualTo(1);
+ assertThat(mContentProtectionConsentManagersCreated).isEqualTo(1);
assertThat(mContentProtectionServiceInfosCreated).isEqualTo(0);
+ verify(mMockContentProtectionAllowlistManager).start(anyLong());
+ verify(mMockContentProtectionAllowlistManager, never()).stop();
+ verifyZeroInteractions(mMockContentProtectionConsentManager);
+ }
+
+ @Test
+ public void setFineTuneParamsFromDeviceConfig_contentProtection_enabled_to_enabled() {
+ mDevCfgEnableContentProtectionReceiver = true;
+ mContentCaptureManagerService.setFineTuneParamsFromDeviceConfig();
+
+ mContentCaptureManagerService.setFineTuneParamsFromDeviceConfig();
+
+ assertThat(mContentProtectionAllowlistManagersCreated).isEqualTo(1);
+ assertThat(mContentProtectionConsentManagersCreated).isEqualTo(1);
+ assertThat(mContentProtectionServiceInfosCreated).isEqualTo(0);
+ verify(mMockContentProtectionAllowlistManager).start(anyLong());
+ verify(mMockContentProtectionAllowlistManager, never()).stop();
+ verifyZeroInteractions(mMockContentProtectionConsentManager);
+ }
+
+ @Test
+ public void setFineTuneParamsFromDeviceConfig_contentProtection_enabled_to_disabled() {
+ mDevCfgEnableContentProtectionReceiver = true;
+ mContentCaptureManagerService.setFineTuneParamsFromDeviceConfig();
+ mDevCfgEnableContentProtectionReceiver = false;
+
+ mContentCaptureManagerService.setFineTuneParamsFromDeviceConfig();
+
+ assertThat(mContentProtectionAllowlistManagersCreated).isEqualTo(1);
+ assertThat(mContentProtectionConsentManagersCreated).isEqualTo(1);
+ assertThat(mContentProtectionServiceInfosCreated).isEqualTo(0);
+ verify(mMockContentProtectionAllowlistManager).start(anyLong());
+ verify(mMockContentProtectionAllowlistManager).stop();
+ verifyZeroInteractions(mMockContentProtectionConsentManager);
+ }
+
+ @Test
+ public void setFineTuneParamsFromDeviceConfig_contentProtection_enabled_componentNameNull() {
+ mDevCfgEnableContentProtectionReceiver = true;
+ mConfigDefaultContentProtectionService = null;
+
+ mContentCaptureManagerService.setFineTuneParamsFromDeviceConfig();
+
+ assertThat(mContentProtectionAllowlistManagersCreated).isEqualTo(0);
assertThat(mContentProtectionConsentManagersCreated).isEqualTo(0);
+ assertThat(mContentProtectionServiceInfosCreated).isEqualTo(0);
verifyZeroInteractions(mMockContentProtectionAllowlistManager);
verifyZeroInteractions(mMockContentProtectionConsentManager);
}
@Test
- public void constructor_contentProtection_componentNameBlank_noManagers() {
+ public void setFineTuneParamsFromDeviceConfig_contentProtection_enabled_componentNameBlank() {
+ mDevCfgEnableContentProtectionReceiver = true;
mConfigDefaultContentProtectionService = " ";
- mContentCaptureManagerService = new TestContentCaptureManagerService();
+ mContentCaptureManagerService.setFineTuneParamsFromDeviceConfig();
assertThat(mContentProtectionAllowlistManagersCreated).isEqualTo(0);
- assertThat(mContentProtectionServiceInfosCreated).isEqualTo(0);
assertThat(mContentProtectionConsentManagersCreated).isEqualTo(0);
+ assertThat(mContentProtectionServiceInfosCreated).isEqualTo(0);
verifyZeroInteractions(mMockContentProtectionAllowlistManager);
verifyZeroInteractions(mMockContentProtectionConsentManager);
}
@Test
- public void constructor_contentProtection_enabled_createsManagers() {
+ public void setFineTuneParamsFromDeviceConfig_contentProtection_disabled_componentNameNull() {
mDevCfgEnableContentProtectionReceiver = true;
+ mContentCaptureManagerService.setFineTuneParamsFromDeviceConfig();
+ mDevCfgEnableContentProtectionReceiver = false;
+ mConfigDefaultContentProtectionService = null;
- mContentCaptureManagerService = new TestContentCaptureManagerService();
+ mContentCaptureManagerService.setFineTuneParamsFromDeviceConfig();
assertThat(mContentProtectionAllowlistManagersCreated).isEqualTo(1);
assertThat(mContentProtectionConsentManagersCreated).isEqualTo(1);
assertThat(mContentProtectionServiceInfosCreated).isEqualTo(0);
+ verify(mMockContentProtectionAllowlistManager).start(anyLong());
+ verify(mMockContentProtectionAllowlistManager).stop();
verifyZeroInteractions(mMockContentProtectionConsentManager);
}
@Test
- public void getOptions_contentCaptureDisabled_contentProtectionDisabled() {
+ public void setFineTuneParamsFromDeviceConfig_contentProtection_disabled_componentNameBlank() {
mDevCfgEnableContentProtectionReceiver = true;
- mContentCaptureManagerService = new TestContentCaptureManagerService();
+ mContentCaptureManagerService.setFineTuneParamsFromDeviceConfig();
+ mDevCfgEnableContentProtectionReceiver = false;
+ mConfigDefaultContentProtectionService = " ";
+ mContentCaptureManagerService.setFineTuneParamsFromDeviceConfig();
+
+ assertThat(mContentProtectionAllowlistManagersCreated).isEqualTo(1);
+ assertThat(mContentProtectionConsentManagersCreated).isEqualTo(1);
+ assertThat(mContentProtectionServiceInfosCreated).isEqualTo(0);
+ verify(mMockContentProtectionAllowlistManager).start(anyLong());
+ verify(mMockContentProtectionAllowlistManager).stop();
+ verifyZeroInteractions(mMockContentProtectionConsentManager);
+ }
+
+ @Test
+ public void getOptions_contentCaptureDisabled_contentProtectionDisabled() {
ContentCaptureOptions actual =
mContentCaptureManagerService.mGlobalContentCaptureOptions.getOptions(
USER_ID, PACKAGE_NAME);
assertThat(actual).isNull();
- verify(mMockContentProtectionConsentManager).isConsentGranted(USER_ID);
+ verify(mMockContentProtectionConsentManager, never()).isConsentGranted(anyInt());
verify(mMockContentProtectionAllowlistManager, never()).isAllowed(anyString());
}
@@ -210,8 +301,6 @@ public class ContentCaptureManagerServiceTest {
@Test
public void getOptions_contentCaptureEnabled_contentProtectionDisabled() {
- mDevCfgEnableContentProtectionReceiver = true;
- mContentCaptureManagerService = new TestContentCaptureManagerService();
mContentCaptureManagerService.mGlobalContentCaptureOptions.setWhitelist(
USER_ID, ImmutableList.of(PACKAGE_NAME), /* components= */ null);
@@ -224,7 +313,7 @@ public class ContentCaptureManagerServiceTest {
assertThat(actual.contentProtectionOptions).isNotNull();
assertThat(actual.contentProtectionOptions.enableReceiver).isFalse();
assertThat(actual.whitelistedComponents).isNull();
- verify(mMockContentProtectionConsentManager).isConsentGranted(USER_ID);
+ verify(mMockContentProtectionConsentManager, never()).isConsentGranted(anyInt());
verify(mMockContentProtectionAllowlistManager, never()).isAllowed(anyString());
}
@@ -249,22 +338,20 @@ public class ContentCaptureManagerServiceTest {
}
@Test
- public void isWhitelisted_packageName_contentCaptureDisabled_contentProtectionNotGranted() {
- mDevCfgEnableContentProtectionReceiver = true;
- mContentCaptureManagerService = new TestContentCaptureManagerService();
-
+ public void isWhitelisted_packageName_contentCaptureDisabled_contentProtectionDisabled() {
boolean actual =
mContentCaptureManagerService.mGlobalContentCaptureOptions.isWhitelisted(
USER_ID, PACKAGE_NAME);
assertThat(actual).isFalse();
- verify(mMockContentProtectionConsentManager).isConsentGranted(USER_ID);
+ verify(mMockContentProtectionConsentManager, never()).isConsentGranted(anyInt());
verify(mMockContentProtectionAllowlistManager, never()).isAllowed(anyString());
}
@Test
- public void isWhitelisted_packageName_contentCaptureDisabled_contentProtectionDisabled() {
+ public void isWhitelisted_packageName_contentCaptureDisabled_contentProtectionEnabled() {
when(mMockContentProtectionConsentManager.isConsentGranted(USER_ID)).thenReturn(true);
+ when(mMockContentProtectionAllowlistManager.isAllowed(PACKAGE_NAME)).thenReturn(true);
mDevCfgEnableContentProtectionReceiver = true;
mContentCaptureManagerService = new TestContentCaptureManagerService();
@@ -272,26 +359,25 @@ public class ContentCaptureManagerServiceTest {
mContentCaptureManagerService.mGlobalContentCaptureOptions.isWhitelisted(
USER_ID, PACKAGE_NAME);
- assertThat(actual).isFalse();
- verify(mMockContentProtectionAllowlistManager).isAllowed(PACKAGE_NAME);
+ assertThat(actual).isTrue();
}
@Test
- public void isWhitelisted_packageName_contentCaptureDisabled_contentProtectionEnabled() {
- when(mMockContentProtectionConsentManager.isConsentGranted(USER_ID)).thenReturn(true);
- when(mMockContentProtectionAllowlistManager.isAllowed(PACKAGE_NAME)).thenReturn(true);
- mDevCfgEnableContentProtectionReceiver = true;
- mContentCaptureManagerService = new TestContentCaptureManagerService();
+ public void isWhitelisted_packageName_contentCaptureEnabled_contentProtectionDisabled() {
+ mContentCaptureManagerService.mGlobalContentCaptureOptions.setWhitelist(
+ USER_ID, ImmutableList.of(PACKAGE_NAME), /* components= */ null);
boolean actual =
mContentCaptureManagerService.mGlobalContentCaptureOptions.isWhitelisted(
USER_ID, PACKAGE_NAME);
assertThat(actual).isTrue();
+ verify(mMockContentProtectionConsentManager, never()).isConsentGranted(anyInt());
+ verify(mMockContentProtectionAllowlistManager, never()).isAllowed(anyString());
}
@Test
- public void isWhitelisted_packageName_contentCaptureEnabled_contentProtectionNotChecked() {
+ public void isWhitelisted_packageName_contentCaptureEnabled_contentProtectionEnabled() {
mDevCfgEnableContentProtectionReceiver = true;
mContentCaptureManagerService = new TestContentCaptureManagerService();
mContentCaptureManagerService.mGlobalContentCaptureOptions.setWhitelist(
@@ -307,22 +393,20 @@ public class ContentCaptureManagerServiceTest {
}
@Test
- public void isWhitelisted_componentName_contentCaptureDisabled_contentProtectionNotGranted() {
- mDevCfgEnableContentProtectionReceiver = true;
- mContentCaptureManagerService = new TestContentCaptureManagerService();
-
+ public void isWhitelisted_componentName_contentCaptureDisabled_contentProtectionDisabled() {
boolean actual =
mContentCaptureManagerService.mGlobalContentCaptureOptions.isWhitelisted(
USER_ID, COMPONENT_NAME);
assertThat(actual).isFalse();
- verify(mMockContentProtectionConsentManager).isConsentGranted(USER_ID);
+ verify(mMockContentProtectionConsentManager, never()).isConsentGranted(anyInt());
verify(mMockContentProtectionAllowlistManager, never()).isAllowed(anyString());
}
@Test
- public void isWhitelisted_componentName_contentCaptureDisabled_contentProtectionDisabled() {
+ public void isWhitelisted_componentName_contentCaptureDisabled_contentProtectionEnabled() {
when(mMockContentProtectionConsentManager.isConsentGranted(USER_ID)).thenReturn(true);
+ when(mMockContentProtectionAllowlistManager.isAllowed(PACKAGE_NAME)).thenReturn(true);
mDevCfgEnableContentProtectionReceiver = true;
mContentCaptureManagerService = new TestContentCaptureManagerService();
@@ -330,26 +414,25 @@ public class ContentCaptureManagerServiceTest {
mContentCaptureManagerService.mGlobalContentCaptureOptions.isWhitelisted(
USER_ID, COMPONENT_NAME);
- assertThat(actual).isFalse();
- verify(mMockContentProtectionAllowlistManager).isAllowed(PACKAGE_NAME);
+ assertThat(actual).isTrue();
}
@Test
- public void isWhitelisted_componentName_contentCaptureDisabled_contentProtectionEnabled() {
- when(mMockContentProtectionConsentManager.isConsentGranted(USER_ID)).thenReturn(true);
- when(mMockContentProtectionAllowlistManager.isAllowed(PACKAGE_NAME)).thenReturn(true);
- mDevCfgEnableContentProtectionReceiver = true;
- mContentCaptureManagerService = new TestContentCaptureManagerService();
+ public void isWhitelisted_componentName_contentCaptureEnabled_contentProtectionDisabled() {
+ mContentCaptureManagerService.mGlobalContentCaptureOptions.setWhitelist(
+ USER_ID, /* packageNames= */ null, ImmutableList.of(COMPONENT_NAME));
boolean actual =
mContentCaptureManagerService.mGlobalContentCaptureOptions.isWhitelisted(
USER_ID, COMPONENT_NAME);
assertThat(actual).isTrue();
+ verify(mMockContentProtectionConsentManager, never()).isConsentGranted(anyInt());
+ verify(mMockContentProtectionAllowlistManager, never()).isAllowed(anyString());
}
@Test
- public void isWhitelisted_componentName_contentCaptureEnabled_contentProtectionNotChecked() {
+ public void isWhitelisted_componentName_contentCaptureEnabled_contentProtectionEnabled() {
mDevCfgEnableContentProtectionReceiver = true;
mContentCaptureManagerService = new TestContentCaptureManagerService();
mContentCaptureManagerService.mGlobalContentCaptureOptions.setWhitelist(
@@ -544,8 +627,6 @@ public class ContentCaptureManagerServiceTest {
TestContentCaptureManagerService() {
super(sContext);
- this.mDevCfgEnableContentProtectionReceiver =
- ContentCaptureManagerServiceTest.this.mDevCfgEnableContentProtectionReceiver;
this.mDevCfgContentProtectionRequiredGroups =
ContentCaptureManagerServiceTest.this.mDevCfgContentProtectionRequiredGroups;
this.mDevCfgContentProtectionOptionalGroups =
@@ -553,12 +634,13 @@ public class ContentCaptureManagerServiceTest {
}
@Override
- protected boolean getEnableContentProtectionReceiverLocked() {
+ protected boolean getDeviceConfigEnableContentProtectionReceiver() {
return ContentCaptureManagerServiceTest.this.mDevCfgEnableContentProtectionReceiver;
}
@Override
- protected ContentProtectionAllowlistManager createContentProtectionAllowlistManager() {
+ protected ContentProtectionAllowlistManager createContentProtectionAllowlistManager(
+ long timeoutMs) {
mContentProtectionAllowlistManagersCreated++;
return mMockContentProtectionAllowlistManager;
}
@@ -570,7 +652,7 @@ public class ContentCaptureManagerServiceTest {
@Override
protected ContentCaptureServiceInfo createContentProtectionServiceInfo(
- @NonNull ComponentName componentName) throws PackageManager.NameNotFoundException {
+ @NonNull ComponentName componentName) {
mContentProtectionServiceInfosCreated++;
if (mContentProtectionServiceInfoConstructorShouldThrow) {
throw new RuntimeException("TEST RUNTIME EXCEPTION");
diff --git a/services/tests/servicestests/src/com/android/server/contentprotection/ContentProtectionAllowlistManagerTest.java b/services/tests/servicestests/src/com/android/server/contentprotection/ContentProtectionAllowlistManagerTest.java
index 6767a85035fe..dc38f2bf3083 100644
--- a/services/tests/servicestests/src/com/android/server/contentprotection/ContentProtectionAllowlistManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/contentprotection/ContentProtectionAllowlistManagerTest.java
@@ -16,15 +16,35 @@
package com.android.server.contentprotection;
+import static android.view.contentprotection.flags.Flags.FLAG_BLOCKLIST_UPDATE_ENABLED;
+
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+import android.os.Handler;
+import android.os.UserHandle;
+import android.os.test.TestLooper;
+import android.platform.test.flag.junit.SetFlagsRule;
+
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
+import com.android.internal.content.PackageMonitor;
+import com.android.server.contentcapture.ContentCaptureManagerService;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
@@ -40,13 +60,236 @@ public class ContentProtectionAllowlistManagerTest {
private static final String PACKAGE_NAME = "com.test.package.name";
+ private static final long TIMEOUT_MS = 111_111_111L;
+
+ private static final long DELAY_MS = 222_222_222L;
+
@Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+ @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
+ @Mock private ContentCaptureManagerService mMockContentCaptureManagerService;
+
+ @Mock private PackageMonitor mMockPackageMonitor;
+
+ @Mock private RemoteContentProtectionService mMockRemoteContentProtectionService;
+
+ private final TestLooper mTestLooper = new TestLooper();
+
+ private Handler mHandler;
+
private ContentProtectionAllowlistManager mContentProtectionAllowlistManager;
@Before
public void setup() {
- mContentProtectionAllowlistManager = new ContentProtectionAllowlistManager();
+ mHandler = new Handler(mTestLooper.getLooper());
+ mContentProtectionAllowlistManager = new TestContentProtectionAllowlistManager();
+ }
+
+ @Test
+ public void constructor() {
+ assertThat(mHandler.hasMessagesOrCallbacks()).isFalse();
+ verifyZeroInteractions(mMockContentCaptureManagerService);
+ verifyZeroInteractions(mMockPackageMonitor);
+ }
+
+ @Test
+ public void start_updateEnabled_firstTime_beforeDelay() {
+ mSetFlagsRule.enableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
+
+ mContentProtectionAllowlistManager.start(DELAY_MS);
+ mTestLooper.dispatchAll();
+
+ assertThat(mHandler.hasMessagesOrCallbacks()).isTrue();
+ verifyZeroInteractions(mMockContentCaptureManagerService);
+ verifyZeroInteractions(mMockPackageMonitor);
+ }
+
+ @Test
+ public void start_updateEnabled_firstTime_afterDelay() {
+ mSetFlagsRule.enableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
+
+ mContentProtectionAllowlistManager.start(DELAY_MS);
+ mTestLooper.moveTimeForward(DELAY_MS);
+ mTestLooper.dispatchNext();
+
+ assertThat(mHandler.hasMessagesOrCallbacks()).isFalse();
+ verify(mMockContentCaptureManagerService).createRemoteContentProtectionService();
+ verify(mMockPackageMonitor).register(any(), eq(UserHandle.ALL), eq(mHandler));
+ verify(mMockPackageMonitor, never()).unregister();
+ }
+
+ @Test
+ public void start_updateEnabled_secondTime() {
+ mSetFlagsRule.enableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
+ mContentProtectionAllowlistManager.start(DELAY_MS);
+ mTestLooper.moveTimeForward(DELAY_MS);
+ mTestLooper.dispatchNext();
+
+ mContentProtectionAllowlistManager.start(DELAY_MS);
+
+ assertThat(mHandler.hasMessagesOrCallbacks()).isFalse();
+ verify(mMockContentCaptureManagerService).createRemoteContentProtectionService();
+ verify(mMockPackageMonitor).register(any(), eq(UserHandle.ALL), eq(mHandler));
+ verify(mMockPackageMonitor, never()).unregister();
+ }
+
+ @Test
+ public void start_updateDisabled_firstTime_beforeDelay() {
+ mSetFlagsRule.disableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
+
+ mContentProtectionAllowlistManager.start(DELAY_MS);
+ mTestLooper.dispatchAll();
+
+ assertThat(mHandler.hasMessagesOrCallbacks()).isTrue();
+ verifyZeroInteractions(mMockContentCaptureManagerService);
+ verifyZeroInteractions(mMockPackageMonitor);
+ }
+
+ @Test
+ public void start_updateDisabled_firstTime_afterDelay() {
+ mSetFlagsRule.disableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
+
+ mContentProtectionAllowlistManager.start(DELAY_MS);
+ mTestLooper.moveTimeForward(DELAY_MS);
+ mTestLooper.dispatchNext();
+
+ assertThat(mHandler.hasMessagesOrCallbacks()).isFalse();
+ verifyZeroInteractions(mMockContentCaptureManagerService);
+ verify(mMockPackageMonitor).register(any(), eq(UserHandle.ALL), eq(mHandler));
+ verify(mMockPackageMonitor, never()).unregister();
+ }
+
+ @Test
+ public void start_updateDisabled_secondTime() {
+ mSetFlagsRule.disableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
+ mContentProtectionAllowlistManager.start(DELAY_MS);
+ mTestLooper.moveTimeForward(DELAY_MS);
+ mTestLooper.dispatchNext();
+
+ mContentProtectionAllowlistManager.start(DELAY_MS);
+
+ assertThat(mHandler.hasMessagesOrCallbacks()).isFalse();
+ verifyZeroInteractions(mMockContentCaptureManagerService);
+ verify(mMockPackageMonitor).register(any(), eq(UserHandle.ALL), eq(mHandler));
+ verify(mMockPackageMonitor, never()).unregister();
+ }
+
+ @Test
+ public void stop_updateEnabled_notStarted() {
+ mSetFlagsRule.enableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
+ doThrow(new IllegalStateException("NOT REGISTERED")).when(mMockPackageMonitor).unregister();
+
+ mContentProtectionAllowlistManager.stop();
+
+ assertThat(mHandler.hasMessagesOrCallbacks()).isFalse();
+ verifyZeroInteractions(mMockContentCaptureManagerService);
+ verify(mMockPackageMonitor, never()).register(any(), any(), any());
+ verify(mMockPackageMonitor).unregister();
+ }
+
+ @Test
+ public void stop_updateEnabled_started_beforeDelay() {
+ mSetFlagsRule.enableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
+ doThrow(new IllegalStateException("NOT REGISTERED")).when(mMockPackageMonitor).unregister();
+ mContentProtectionAllowlistManager.start(DELAY_MS);
+ mTestLooper.dispatchAll();
+
+ mContentProtectionAllowlistManager.stop();
+
+ assertThat(mHandler.hasMessagesOrCallbacks()).isFalse();
+ verifyZeroInteractions(mMockContentCaptureManagerService);
+ verify(mMockPackageMonitor, never()).register(any(), any(), any());
+ verify(mMockPackageMonitor).unregister();
+ }
+
+ @Test
+ public void stop_updateEnabled_started_afterDelay() {
+ mSetFlagsRule.enableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
+ mContentProtectionAllowlistManager.start(DELAY_MS);
+ mTestLooper.moveTimeForward(DELAY_MS);
+ mTestLooper.dispatchNext();
+
+ mContentProtectionAllowlistManager.stop();
+
+ assertThat(mHandler.hasMessagesOrCallbacks()).isFalse();
+ verify(mMockContentCaptureManagerService).createRemoteContentProtectionService();
+ verify(mMockPackageMonitor).register(any(), eq(UserHandle.ALL), eq(mHandler));
+ verify(mMockPackageMonitor).unregister();
+ }
+
+ @Test
+ public void stop_updateDisabled_notStarted() {
+ mSetFlagsRule.disableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
+ doThrow(new IllegalStateException("NOT REGISTERED")).when(mMockPackageMonitor).unregister();
+
+ mContentProtectionAllowlistManager.stop();
+
+ assertThat(mHandler.hasMessagesOrCallbacks()).isFalse();
+ verifyZeroInteractions(mMockContentCaptureManagerService);
+ verify(mMockPackageMonitor, never()).register(any(), any(), any());
+ verify(mMockPackageMonitor).unregister();
+ }
+
+ @Test
+ public void stop_updateDisabled_started_beforeDelay() {
+ mSetFlagsRule.disableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
+ doThrow(new IllegalStateException("NOT REGISTERED")).when(mMockPackageMonitor).unregister();
+ mContentProtectionAllowlistManager.start(DELAY_MS);
+ mTestLooper.dispatchAll();
+
+ mContentProtectionAllowlistManager.stop();
+
+ assertThat(mHandler.hasMessagesOrCallbacks()).isFalse();
+ verifyZeroInteractions(mMockContentCaptureManagerService);
+ verify(mMockPackageMonitor, never()).register(any(), any(), any());
+ verify(mMockPackageMonitor).unregister();
+ }
+
+ @Test
+ public void stop_updateDisabled_started_afterDelay() {
+ mSetFlagsRule.disableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
+ mContentProtectionAllowlistManager.start(DELAY_MS);
+ mTestLooper.moveTimeForward(DELAY_MS);
+ mTestLooper.dispatchNext();
+
+ mContentProtectionAllowlistManager.stop();
+
+ assertThat(mHandler.hasMessagesOrCallbacks()).isFalse();
+ verifyZeroInteractions(mMockContentCaptureManagerService);
+ verify(mMockPackageMonitor).register(any(), eq(UserHandle.ALL), eq(mHandler));
+ verify(mMockPackageMonitor).unregister();
+ }
+
+ @Test
+ public void start_afterStop_beforeDelay() {
+ mContentProtectionAllowlistManager.start(DELAY_MS);
+ mTestLooper.dispatchAll();
+ mContentProtectionAllowlistManager.stop();
+
+ mContentProtectionAllowlistManager.start(DELAY_MS);
+ mTestLooper.moveTimeForward(DELAY_MS);
+ mTestLooper.dispatchNext();
+
+ assertThat(mHandler.hasMessagesOrCallbacks()).isFalse();
+ verify(mMockPackageMonitor).register(any(), eq(UserHandle.ALL), eq(mHandler));
+ verify(mMockPackageMonitor).unregister();
+ }
+
+ @Test
+ public void start_afterStop_afterDelay() {
+ mContentProtectionAllowlistManager.start(DELAY_MS);
+ mTestLooper.moveTimeForward(DELAY_MS);
+ mTestLooper.dispatchNext();
+ mContentProtectionAllowlistManager.stop();
+
+ mContentProtectionAllowlistManager.start(DELAY_MS);
+ mTestLooper.moveTimeForward(DELAY_MS);
+ mTestLooper.dispatchNext();
+
+ assertThat(mHandler.hasMessagesOrCallbacks()).isFalse();
+ verify(mMockPackageMonitor, times(2)).register(any(), eq(UserHandle.ALL), eq(mHandler));
+ verify(mMockPackageMonitor).unregister();
}
@Test
@@ -54,5 +297,86 @@ public class ContentProtectionAllowlistManagerTest {
boolean actual = mContentProtectionAllowlistManager.isAllowed(PACKAGE_NAME);
assertThat(actual).isFalse();
+ verifyZeroInteractions(mMockContentCaptureManagerService);
+ verifyZeroInteractions(mMockPackageMonitor);
+ }
+
+ @Test
+ public void handleUpdate_updateDisabled() {
+ mSetFlagsRule.disableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
+ ContentProtectionAllowlistManager manager =
+ new ContentProtectionAllowlistManager(
+ mMockContentCaptureManagerService, mHandler, TIMEOUT_MS);
+
+ manager.mPackageMonitor.onSomePackagesChanged();
+
+ verifyZeroInteractions(mMockContentCaptureManagerService);
+ }
+
+ @Test
+ public void handleUpdate_updateEnabled() {
+ mSetFlagsRule.enableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
+ ContentProtectionAllowlistManager manager =
+ new ContentProtectionAllowlistManager(
+ mMockContentCaptureManagerService, mHandler, TIMEOUT_MS);
+
+ manager.mPackageMonitor.onSomePackagesChanged();
+
+ verify(mMockContentCaptureManagerService).createRemoteContentProtectionService();
+ }
+
+ @Test
+ public void handleUpdate_rateLimit_noService() {
+ mSetFlagsRule.enableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
+ ContentProtectionAllowlistManager manager =
+ new ContentProtectionAllowlistManager(
+ mMockContentCaptureManagerService, mHandler, TIMEOUT_MS);
+
+ manager.mPackageMonitor.onSomePackagesChanged();
+ manager.mPackageMonitor.onSomePackagesChanged();
+
+ verify(mMockContentCaptureManagerService, times(2)).createRemoteContentProtectionService();
+ }
+
+ @Test
+ public void handleUpdate_rateLimit_beforeTimeout() {
+ mSetFlagsRule.enableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
+ ContentProtectionAllowlistManager manager =
+ new ContentProtectionAllowlistManager(
+ mMockContentCaptureManagerService, mHandler, TIMEOUT_MS);
+ when(mMockContentCaptureManagerService.createRemoteContentProtectionService())
+ .thenReturn(mMockRemoteContentProtectionService);
+
+ manager.mPackageMonitor.onSomePackagesChanged();
+ manager.mPackageMonitor.onSomePackagesChanged();
+
+ verify(mMockContentCaptureManagerService).createRemoteContentProtectionService();
+ }
+
+ @Test
+ public void handleUpdate_rateLimit_afterTimeout() {
+ mSetFlagsRule.enableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
+ ContentProtectionAllowlistManager manager =
+ new ContentProtectionAllowlistManager(
+ mMockContentCaptureManagerService, mHandler, /* timeoutMs= */ 0L);
+ when(mMockContentCaptureManagerService.createRemoteContentProtectionService())
+ .thenReturn(mMockRemoteContentProtectionService);
+
+ manager.mPackageMonitor.onSomePackagesChanged();
+ manager.mPackageMonitor.onSomePackagesChanged();
+
+ verify(mMockContentCaptureManagerService, times(2)).createRemoteContentProtectionService();
+ }
+
+ private class TestContentProtectionAllowlistManager extends ContentProtectionAllowlistManager {
+
+ TestContentProtectionAllowlistManager() {
+ super(mMockContentCaptureManagerService, mHandler, TIMEOUT_MS);
+ }
+
+ @Override
+ protected PackageMonitor createPackageMonitor() {
+ return mMockPackageMonitor;
+ }
}
}
diff --git a/services/tests/servicestests/src/com/android/server/contentprotection/ContentProtectionConsentManagerTest.java b/services/tests/servicestests/src/com/android/server/contentprotection/ContentProtectionConsentManagerTest.java
index 0e80bfdae291..5fe60d779fa6 100644
--- a/services/tests/servicestests/src/com/android/server/contentprotection/ContentProtectionConsentManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/contentprotection/ContentProtectionConsentManagerTest.java
@@ -55,9 +55,15 @@ public class ContentProtectionConsentManagerTest {
private static final String KEY_PACKAGE_VERIFIER_USER_CONSENT = "package_verifier_user_consent";
+ private static final String KEY_CONTENT_PROTECTION_USER_CONSENT =
+ "content_protection_user_consent";
+
private static final Uri URI_PACKAGE_VERIFIER_USER_CONSENT =
Settings.Global.getUriFor(KEY_PACKAGE_VERIFIER_USER_CONSENT);
+ private static final Uri URI_CONTENT_PROTECTION_USER_CONSENT =
+ Settings.Global.getUriFor(KEY_CONTENT_PROTECTION_USER_CONSENT);
+
private static final int VALUE_TRUE = 1;
private static final int VALUE_FALSE = -1;
@@ -96,7 +102,18 @@ public class ContentProtectionConsentManagerTest {
@Test
public void isConsentGranted_packageVerifierNotGranted() {
ContentProtectionConsentManager manager =
- createContentProtectionConsentManager(VALUE_FALSE);
+ createContentProtectionConsentManager(VALUE_FALSE, VALUE_TRUE);
+
+ boolean actual = manager.isConsentGranted(TEST_USER_ID);
+
+ assertThat(actual).isFalse();
+ verifyZeroInteractions(mMockDevicePolicyManagerInternal);
+ }
+
+ @Test
+ public void isConsentGranted_contentProtectionNotGranted() {
+ ContentProtectionConsentManager manager =
+ createContentProtectionConsentManager(VALUE_TRUE, VALUE_FALSE);
boolean actual = manager.isConsentGranted(TEST_USER_ID);
@@ -106,7 +123,8 @@ public class ContentProtectionConsentManagerTest {
@Test
public void isConsentGranted_packageVerifierGranted_userNotManaged() {
- ContentProtectionConsentManager manager = createContentProtectionConsentManager(VALUE_TRUE);
+ ContentProtectionConsentManager manager =
+ createContentProtectionConsentManager(VALUE_TRUE, VALUE_TRUE);
boolean actual = manager.isConsentGranted(TEST_USER_ID);
@@ -118,7 +136,8 @@ public class ContentProtectionConsentManagerTest {
public void isConsentGranted_packageVerifierGranted_userManaged() {
when(mMockDevicePolicyManagerInternal.isUserOrganizationManaged(TEST_USER_ID))
.thenReturn(true);
- ContentProtectionConsentManager manager = createContentProtectionConsentManager(VALUE_TRUE);
+ ContentProtectionConsentManager manager =
+ createContentProtectionConsentManager(VALUE_TRUE, VALUE_TRUE);
boolean actual = manager.isConsentGranted(TEST_USER_ID);
@@ -128,7 +147,7 @@ public class ContentProtectionConsentManagerTest {
@Test
public void isConsentGranted_packageVerifierDefault() {
ContentProtectionConsentManager manager =
- createContentProtectionConsentManager(VALUE_DEFAULT);
+ createContentProtectionConsentManager(VALUE_DEFAULT, VALUE_TRUE);
boolean actual = manager.isConsentGranted(TEST_USER_ID);
@@ -137,15 +156,27 @@ public class ContentProtectionConsentManagerTest {
}
@Test
- public void contentObserver() throws Exception {
- ContentProtectionConsentManager manager = createContentProtectionConsentManager(VALUE_TRUE);
+ public void isConsentGranted_contentProtectionDefault() {
+ ContentProtectionConsentManager manager =
+ createContentProtectionConsentManager(VALUE_TRUE, VALUE_DEFAULT);
+
+ boolean actual = manager.isConsentGranted(TEST_USER_ID);
+
+ assertThat(actual).isTrue();
+ verify(mMockDevicePolicyManagerInternal).isUserOrganizationManaged(TEST_USER_ID);
+ }
+
+ @Test
+ public void contentObserver_packageVerifier() {
+ ContentProtectionConsentManager manager =
+ createContentProtectionConsentManager(VALUE_TRUE, VALUE_DEFAULT);
boolean firstActual = manager.isConsentGranted(TEST_USER_ID);
- Settings.Global.putInt(
- mTestableContentResolver, KEY_PACKAGE_VERIFIER_USER_CONSENT, VALUE_FALSE);
- // Observer has to be called manually, mTestableContentResolver is not propagating
- manager.mContentObserver.onChange(
- /* selfChange= */ false, URI_PACKAGE_VERIFIER_USER_CONSENT, TEST_USER_ID);
+ notifyContentObserver(
+ manager,
+ URI_PACKAGE_VERIFIER_USER_CONSENT,
+ KEY_PACKAGE_VERIFIER_USER_CONSENT,
+ VALUE_FALSE);
boolean secondActual = manager.isConsentGranted(TEST_USER_ID);
assertThat(firstActual).isTrue();
@@ -153,6 +184,31 @@ public class ContentProtectionConsentManagerTest {
verify(mMockDevicePolicyManagerInternal).isUserOrganizationManaged(TEST_USER_ID);
}
+ @Test
+ public void contentObserver_contentProtection() {
+ ContentProtectionConsentManager manager =
+ createContentProtectionConsentManager(VALUE_TRUE, VALUE_DEFAULT);
+ boolean firstActual = manager.isConsentGranted(TEST_USER_ID);
+
+ notifyContentObserver(
+ manager,
+ URI_CONTENT_PROTECTION_USER_CONSENT,
+ KEY_CONTENT_PROTECTION_USER_CONSENT,
+ VALUE_FALSE);
+ boolean secondActual = manager.isConsentGranted(TEST_USER_ID);
+
+ assertThat(firstActual).isTrue();
+ assertThat(secondActual).isFalse();
+ verify(mMockDevicePolicyManagerInternal).isUserOrganizationManaged(TEST_USER_ID);
+ }
+
+ private void notifyContentObserver(
+ ContentProtectionConsentManager manager, Uri uri, String key, int value) {
+ Settings.Global.putInt(mTestableContentResolver, key, value);
+ // Observer has to be called manually, mTestableContentResolver is not propagating
+ manager.mContentObserver.onChange(/* selfChange= */ false, uri, TEST_USER_ID);
+ }
+
private ContentProtectionConsentManager createContentProtectionConsentManager(
ContentResolver contentResolver) {
return new ContentProtectionConsentManager(
@@ -162,11 +218,15 @@ public class ContentProtectionConsentManagerTest {
}
private ContentProtectionConsentManager createContentProtectionConsentManager(
- int valuePackageVerifierUserConsent) {
+ int valuePackageVerifierUserConsent, int valueContentProtectionUserConsent) {
Settings.Global.putInt(
mTestableContentResolver,
KEY_PACKAGE_VERIFIER_USER_CONSENT,
valuePackageVerifierUserConsent);
+ Settings.Global.putInt(
+ mTestableContentResolver,
+ KEY_CONTENT_PROTECTION_USER_CONSENT,
+ valueContentProtectionUserConsent);
return createContentProtectionConsentManager(mTestableContentResolver);
}
}