summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--media/java/android/media/projection/IMediaProjection.aidl3
-rw-r--r--media/java/android/media/projection/IMediaProjectionManager.aidl17
-rw-r--r--media/java/android/media/projection/MediaProjection.java2
-rw-r--r--media/java/android/media/projection/MediaProjectionManager.java4
-rw-r--r--media/java/android/media/projection/StopReason.aidl36
-rw-r--r--media/tests/projection/src/android/media/projection/FakeIMediaProjection.java2
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepositoryTest.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepository.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionRepository.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractor.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java3
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/mediaprojection/data/repository/FakeMediaProjectionRepository.kt3
-rw-r--r--services/core/java/com/android/server/media/projection/FrameworkStatsLogWrapper.java20
-rw-r--r--services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java63
-rw-r--r--services/core/java/com/android/server/media/projection/MediaProjectionMetricsLogger.java191
-rw-r--r--services/core/java/com/android/server/wm/ContentRecorder.java57
-rw-r--r--services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java47
-rw-r--r--services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionMetricsLoggerTest.java197
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java29
19 files changed, 536 insertions, 155 deletions
diff --git a/media/java/android/media/projection/IMediaProjection.aidl b/media/java/android/media/projection/IMediaProjection.aidl
index 8ee966ddc377..dacd1bd06cc0 100644
--- a/media/java/android/media/projection/IMediaProjection.aidl
+++ b/media/java/android/media/projection/IMediaProjection.aidl
@@ -17,13 +17,14 @@
package android.media.projection;
import android.media.projection.IMediaProjectionCallback;
+import android.media.projection.StopReason;
import android.os.IBinder;
import android.app.ActivityOptions.LaunchCookie;
/** {@hide} */
interface IMediaProjection {
void start(IMediaProjectionCallback callback);
- void stop();
+ void stop(StopReason stopReason);
boolean canProjectAudio();
boolean canProjectVideo();
diff --git a/media/java/android/media/projection/IMediaProjectionManager.aidl b/media/java/android/media/projection/IMediaProjectionManager.aidl
index b104972572b9..1d92eabb726d 100644
--- a/media/java/android/media/projection/IMediaProjectionManager.aidl
+++ b/media/java/android/media/projection/IMediaProjectionManager.aidl
@@ -16,11 +16,13 @@
package android.media.projection;
+import android.graphics.Rect;
import android.media.projection.IMediaProjection;
import android.media.projection.IMediaProjectionCallback;
import android.media.projection.IMediaProjectionWatcherCallback;
import android.media.projection.MediaProjectionInfo;
import android.media.projection.ReviewGrantedConsentResult;
+import android.media.projection.StopReason;
import android.os.IBinder;
import android.view.ContentRecordingSession;
@@ -107,12 +109,7 @@ interface IMediaProjectionManager {
@EnforcePermission("MANAGE_MEDIA_PROJECTION")
@JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
+ ".permission.MANAGE_MEDIA_PROJECTION)")
- void stopActiveProjection();
-
- @EnforcePermission("MANAGE_MEDIA_PROJECTION")
- @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
- + ".permission.MANAGE_MEDIA_PROJECTION)")
- void notifyActiveProjectionCapturedContentResized(int width, int height);
+ void stopActiveProjection(in StopReason stopReason);
@EnforcePermission("MANAGE_MEDIA_PROJECTION")
@JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
@@ -227,5 +224,11 @@ interface IMediaProjectionManager {
@EnforcePermission("MANAGE_MEDIA_PROJECTION")
@JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
+ ".permission.MANAGE_MEDIA_PROJECTION)")
- void notifyWindowingModeChanged(int contentToRecord, int targetProcessUid, int windowingMode);
+ oneway void notifyWindowingModeChanged(int contentToRecord, int targetProcessUid, int windowingMode);
+
+ @EnforcePermission("MANAGE_MEDIA_PROJECTION")
+ @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
+ + ".permission.MANAGE_MEDIA_PROJECTION)")
+ oneway void notifyCaptureBoundsChanged(int contentToRecord, int targetProcessUid,
+ in Rect captureBounds);
}
diff --git a/media/java/android/media/projection/MediaProjection.java b/media/java/android/media/projection/MediaProjection.java
index 4114f5359ace..f7f10df5786a 100644
--- a/media/java/android/media/projection/MediaProjection.java
+++ b/media/java/android/media/projection/MediaProjection.java
@@ -317,7 +317,7 @@ public final class MediaProjection {
public void stop() {
try {
Log.d(TAG, "Content Recording: stopping projection");
- mImpl.stop();
+ mImpl.stop(StopReason.STOP_HOST_APP);
} catch (RemoteException e) {
Log.e(TAG, "Unable to stop projection", e);
}
diff --git a/media/java/android/media/projection/MediaProjectionManager.java b/media/java/android/media/projection/MediaProjectionManager.java
index dc55e41fb74c..9cc2cca441a4 100644
--- a/media/java/android/media/projection/MediaProjectionManager.java
+++ b/media/java/android/media/projection/MediaProjectionManager.java
@@ -297,10 +297,10 @@ public final class MediaProjectionManager {
* Stop the current projection if there is one.
* @hide
*/
- public void stopActiveProjection() {
+ public void stopActiveProjection(@StopReason int stopReason) {
try {
Log.d(TAG, "Content Recording: stopping active projection");
- mService.stopActiveProjection();
+ mService.stopActiveProjection(stopReason);
} catch (RemoteException e) {
Log.e(TAG, "Unable to stop the currently active media projection", e);
}
diff --git a/media/java/android/media/projection/StopReason.aidl b/media/java/android/media/projection/StopReason.aidl
new file mode 100644
index 000000000000..8611def3d2b9
--- /dev/null
+++ b/media/java/android/media/projection/StopReason.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2024 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.media.projection;
+
+/**
+ * Identifies the reason for a MediaProjection being stopped (for metric logging purposes)
+ * @hide
+ */
+@Backing(type="int")
+enum StopReason {
+ STOP_UNKNOWN = 0,
+ STOP_HOST_APP = 1,
+ STOP_TARGET_REMOVED = 2,
+ STOP_DEVICE_LOCKED = 3,
+ STOP_PRIVACY_CHIP = 4,
+ STOP_QS_TILE = 5,
+ STOP_USER_SWITCH = 6,
+ STOP_FOREGROUND_SERVICE_CHANGE = 7,
+ STOP_NEW_PROJECTION = 8,
+ STOP_NEW_MEDIA_ROUTE = 9,
+ STOP_ERROR = 10,
+}
diff --git a/media/tests/projection/src/android/media/projection/FakeIMediaProjection.java b/media/tests/projection/src/android/media/projection/FakeIMediaProjection.java
index c9807e626429..58aa56babb64 100644
--- a/media/tests/projection/src/android/media/projection/FakeIMediaProjection.java
+++ b/media/tests/projection/src/android/media/projection/FakeIMediaProjection.java
@@ -46,7 +46,7 @@ public final class FakeIMediaProjection extends IMediaProjection.Stub {
}
@Override
- public void stop() throws RemoteException {
+ public void stop(@StopReason int stopReason) throws RemoteException {
// Pass along to the client's callback wrapper.
mIMediaProjectionCallback.onStop();
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepositoryTest.kt
index 02825a55923f..ff00bfb540c6 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepositoryTest.kt
@@ -18,6 +18,7 @@ package com.android.systemui.mediaprojection.data.repository
import android.hardware.display.displayManager
import android.media.projection.MediaProjectionInfo
+import android.media.projection.StopReason
import android.os.Binder
import android.os.Handler
import android.os.UserHandle
@@ -339,8 +340,9 @@ class MediaProjectionManagerRepositoryTest : SysuiTestCase() {
@Test
fun stopProjecting_invokesManager() =
testScope.runTest {
- repo.stopProjecting()
+ repo.stopProjecting(StopReason.STOP_QS_TILE)
- verify(fakeMediaProjectionManager.mediaProjectionManager).stopActiveProjection()
+ verify(fakeMediaProjectionManager.mediaProjectionManager)
+ .stopActiveProjection(StopReason.STOP_QS_TILE)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepository.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepository.kt
index 35efd751b8fe..7d3094827e17 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepository.kt
@@ -20,6 +20,7 @@ import android.app.ActivityManager.RunningTaskInfo
import android.hardware.display.DisplayManager
import android.media.projection.MediaProjectionInfo
import android.media.projection.MediaProjectionManager
+import android.media.projection.StopReason
import android.os.Handler
import android.view.ContentRecordingSession
import android.view.ContentRecordingSession.RECORD_CONTENT_DISPLAY
@@ -72,7 +73,7 @@ constructor(
}
}
- override suspend fun stopProjecting() {
+ override suspend fun stopProjecting(@StopReason stopReason: Int) {
withContext(backgroundDispatcher) {
logger.log(
TAG,
@@ -80,7 +81,7 @@ constructor(
{},
{ "Requesting MediaProjectionManager#stopActiveProjection" },
)
- mediaProjectionManager.stopActiveProjection()
+ mediaProjectionManager.stopActiveProjection(stopReason)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionRepository.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionRepository.kt
index 50182d7a3b33..a01d8c2c98de 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionRepository.kt
@@ -17,6 +17,7 @@
package com.android.systemui.mediaprojection.data.repository
import android.app.ActivityManager.RunningTaskInfo
+import android.media.projection.StopReason
import com.android.systemui.mediaprojection.data.model.MediaProjectionState
import kotlinx.coroutines.flow.Flow
@@ -27,7 +28,7 @@ interface MediaProjectionRepository {
suspend fun switchProjectedTask(task: RunningTaskInfo)
/** Stops the currently active projection. */
- suspend fun stopProjecting()
+ suspend fun stopProjecting(@StopReason stopReason: Int)
/** Represents the current [MediaProjectionState]. */
val mediaProjectionState: Flow<MediaProjectionState>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractor.kt
index af238f697a18..49c44798d2ea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractor.kt
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.chips.mediaprojection.domain.interactor
import android.content.pm.PackageManager
+import android.media.projection.StopReason
import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.systemui.Flags
import com.android.systemui.dagger.SysUISingleton
@@ -105,7 +106,7 @@ constructor(
/** Stops the currently active projection. */
fun stopProjecting() {
- scope.launch { mediaProjectionRepository.stopProjecting() }
+ scope.launch { mediaProjectionRepository.stopProjecting(StopReason.STOP_PRIVACY_CHIP) }
}
companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java
index a115baad257d..52f80fbf50fd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java
@@ -24,6 +24,7 @@ import android.media.MediaRouter;
import android.media.MediaRouter.RouteInfo;
import android.media.projection.MediaProjectionInfo;
import android.media.projection.MediaProjectionManager;
+import android.media.projection.StopReason;
import android.os.Handler;
import android.util.ArrayMap;
@@ -190,7 +191,7 @@ public class CastControllerImpl implements CastController {
if (isProjection) {
final MediaProjectionInfo projection = (MediaProjectionInfo) device.getTag();
if (Objects.equals(mProjectionManager.getActiveProjectionInfo(), projection)) {
- mProjectionManager.stopActiveProjection();
+ mProjectionManager.stopActiveProjection(StopReason.STOP_QS_TILE);
} else {
mLogger.logStopCastingNoProjection(projection);
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/mediaprojection/data/repository/FakeMediaProjectionRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/mediaprojection/data/repository/FakeMediaProjectionRepository.kt
index d631f926176d..e6256a58a365 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/mediaprojection/data/repository/FakeMediaProjectionRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/mediaprojection/data/repository/FakeMediaProjectionRepository.kt
@@ -17,6 +17,7 @@
package com.android.systemui.mediaprojection.data.repository
import android.app.ActivityManager
+import android.media.projection.StopReason
import com.android.systemui.mediaprojection.data.model.MediaProjectionState
import kotlinx.coroutines.flow.MutableStateFlow
@@ -28,7 +29,7 @@ class FakeMediaProjectionRepository : MediaProjectionRepository {
var stopProjectingInvoked = false
- override suspend fun stopProjecting() {
+ override suspend fun stopProjecting(@StopReason stopReason: Int) {
stopProjectingInvoked = true
}
}
diff --git a/services/core/java/com/android/server/media/projection/FrameworkStatsLogWrapper.java b/services/core/java/com/android/server/media/projection/FrameworkStatsLogWrapper.java
index 6c74cba99bcb..05fe78114eca 100644
--- a/services/core/java/com/android/server/media/projection/FrameworkStatsLogWrapper.java
+++ b/services/core/java/com/android/server/media/projection/FrameworkStatsLogWrapper.java
@@ -30,7 +30,8 @@ public class FrameworkStatsLogWrapper {
int hostUid,
int targetUid,
int timeSinceLastActive,
- int creationSource) {
+ int creationSource,
+ int stopSource) {
FrameworkStatsLog.write(
code,
sessionId,
@@ -39,7 +40,8 @@ public class FrameworkStatsLogWrapper {
hostUid,
targetUid,
timeSinceLastActive,
- creationSource);
+ creationSource,
+ stopSource);
}
/** Wrapper around {@link FrameworkStatsLog#write} for MediaProjectionTargetChanged atom. */
@@ -49,13 +51,23 @@ public class FrameworkStatsLogWrapper {
int targetType,
int hostUid,
int targetUid,
- int windowingMode) {
+ int windowingMode,
+ int width,
+ int height,
+ int centerX,
+ int centerY,
+ int targetChangeType) {
FrameworkStatsLog.write(
code,
sessionId,
targetType,
hostUid,
targetUid,
- windowingMode);
+ windowingMode,
+ width,
+ height,
+ centerX,
+ centerY,
+ targetChangeType);
}
}
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
index df5ecf872df4..c428f39fd9d0 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
@@ -51,6 +51,7 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManager.ApplicationInfoFlags;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ServiceInfo;
+import android.graphics.Rect;
import android.hardware.display.DisplayManager;
import android.media.MediaRouter;
import android.media.projection.IMediaProjection;
@@ -60,6 +61,7 @@ import android.media.projection.IMediaProjectionWatcherCallback;
import android.media.projection.MediaProjectionInfo;
import android.media.projection.MediaProjectionManager;
import android.media.projection.ReviewGrantedConsentResult;
+import android.media.projection.StopReason;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
@@ -178,7 +180,7 @@ public final class MediaProjectionManagerService extends SystemService
if (!mMediaProjectionStopController.isExemptFromStopping(mProjectionGrant, reason)) {
Slog.d(TAG, "Content Recording: Stopping MediaProjection due to "
+ MediaProjectionStopController.stopReasonToString(reason));
- mProjectionGrant.stop();
+ mProjectionGrant.stop(StopReason.STOP_DEVICE_LOCKED);
}
}
}
@@ -257,7 +259,7 @@ public final class MediaProjectionManagerService extends SystemService
synchronized (mLock) {
if (mProjectionGrant != null) {
Slog.d(TAG, "Content Recording: Stopped MediaProjection due to user switching");
- mProjectionGrant.stop();
+ mProjectionGrant.stop(StopReason.STOP_USER_SWITCH);
}
}
}
@@ -295,7 +297,7 @@ public final class MediaProjectionManagerService extends SystemService
Slog.d(TAG,
"Content Recording: Stopped MediaProjection due to foreground service change");
if (mProjectionGrant != null) {
- mProjectionGrant.stop();
+ mProjectionGrant.stop(StopReason.STOP_FOREGROUND_SERVICE_CHANGE);
}
}
}
@@ -304,7 +306,7 @@ public final class MediaProjectionManagerService extends SystemService
if (mProjectionGrant != null) {
Slog.d(TAG, "Content Recording: Stopped MediaProjection to start new "
+ "incoming projection");
- mProjectionGrant.stop();
+ mProjectionGrant.stop(StopReason.STOP_NEW_PROJECTION);
}
if (mMediaRouteInfo != null) {
mMediaRouter.getFallbackRoute().select();
@@ -314,7 +316,10 @@ public final class MediaProjectionManagerService extends SystemService
dispatchStart(projection);
}
- private void stopProjectionLocked(final MediaProjection projection) {
+ private void stopProjectionLocked(
+ final MediaProjection projection,
+ @StopReason int stopReason
+ ) {
Slog.d(TAG, "Content Recording: Stopped active MediaProjection and "
+ "dispatching stop to callbacks");
ContentRecordingSession session = projection.mSession;
@@ -322,7 +327,7 @@ public final class MediaProjectionManagerService extends SystemService
session != null
? session.getTargetUid()
: ContentRecordingSession.TARGET_UID_UNKNOWN;
- mMediaProjectionMetricsLogger.logStopped(projection.uid, targetUid);
+ mMediaProjectionMetricsLogger.logStopped(projection.uid, targetUid, stopReason);
mProjectionToken = null;
mProjectionGrant = null;
dispatchStop(projection);
@@ -403,7 +408,7 @@ public final class MediaProjectionManagerService extends SystemService
+ "ContentRecordingSession - id= "
+ mProjectionGrant.getVirtualDisplayId() + "type=" + projectionType);
- mProjectionGrant.stop();
+ mProjectionGrant.stop(StopReason.STOP_ERROR);
}
return false;
}
@@ -517,6 +522,18 @@ public final class MediaProjectionManagerService extends SystemService
}
}
+ @VisibleForTesting
+ void notifyCaptureBoundsChanged(int contentToRecord, int targetUid, Rect captureBounds) {
+ synchronized (mLock) {
+ if (mProjectionGrant == null) {
+ Slog.i(TAG, "Cannot log MediaProjectionTargetChanged atom due to null projection");
+ } else {
+ mMediaProjectionMetricsLogger.logChangedCaptureBounds(
+ contentToRecord, mProjectionGrant.uid, targetUid, captureBounds);
+ }
+ }
+ }
+
/**
* Handles result of dialog shown from
* {@link BinderService#buildReviewGrantedConsentIntentLocked()}.
@@ -557,7 +574,7 @@ public final class MediaProjectionManagerService extends SystemService
Slog.w(TAG, "Content Recording: Stopped MediaProjection due to user "
+ "consent result of CANCEL - "
+ "id= " + mProjectionGrant.getVirtualDisplayId());
- mProjectionGrant.stop();
+ mProjectionGrant.stop(StopReason.STOP_ERROR);
}
break;
case RECORD_CONTENT_DISPLAY:
@@ -773,14 +790,14 @@ public final class MediaProjectionManagerService extends SystemService
@android.annotation.EnforcePermission(android.Manifest.permission.MANAGE_MEDIA_PROJECTION)
@Override // Binder call
- public void stopActiveProjection() {
+ public void stopActiveProjection(@StopReason int stopReason) {
stopActiveProjection_enforcePermission();
final long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
if (mProjectionGrant != null) {
Slog.d(TAG, "Content Recording: Stopping active projection");
- mProjectionGrant.stop();
+ mProjectionGrant.stop(stopReason);
}
}
} finally {
@@ -790,8 +807,9 @@ public final class MediaProjectionManagerService extends SystemService
@android.annotation.EnforcePermission(android.Manifest.permission.MANAGE_MEDIA_PROJECTION)
@Override // Binder call
- public void notifyActiveProjectionCapturedContentResized(int width, int height) {
- notifyActiveProjectionCapturedContentResized_enforcePermission();
+ public void notifyCaptureBoundsChanged(
+ int contentToRecord, int targetProcessUid, Rect newBounds) {
+ notifyCaptureBoundsChanged_enforcePermission();
synchronized (mLock) {
if (!isCurrentProjection(mProjectionGrant)) {
return;
@@ -801,7 +819,13 @@ public final class MediaProjectionManagerService extends SystemService
try {
synchronized (mLock) {
if (mProjectionGrant != null && mCallbackDelegate != null) {
- mCallbackDelegate.dispatchResize(mProjectionGrant, width, height);
+ // log metrics for the new bounds
+ MediaProjectionManagerService.this.notifyCaptureBoundsChanged(
+ contentToRecord, targetProcessUid, newBounds);
+
+ // update clients of the new update bounds
+ mCallbackDelegate.dispatchResize(
+ mProjectionGrant, newBounds.width(), newBounds.height());
}
}
} finally {
@@ -1133,7 +1157,7 @@ public final class MediaProjectionManagerService extends SystemService
Slog.d(TAG, "Content Recording: MediaProjection stopped by Binder death - "
+ "id= " + mVirtualDisplayId);
mCallbackDelegate.remove(callback);
- stop();
+ stop(StopReason.STOP_TARGET_REMOVED);
};
mToken.linkToDeath(mDeathEater, 0);
} catch (RemoteException e) {
@@ -1182,7 +1206,7 @@ public final class MediaProjectionManagerService extends SystemService
}
@Override // Binder call
- public void stop() {
+ public void stop(@StopReason int stopReason) {
synchronized (mLock) {
if (!isCurrentProjection(asBinder())) {
Slog.w(TAG, "Attempted to stop inactive MediaProjection "
@@ -1211,7 +1235,7 @@ public final class MediaProjectionManagerService extends SystemService
Slog.d(TAG, "Content Recording: handling stopping this projection token"
+ " createTime= " + mCreateTimeMillis
+ " countStarts= " + mCountStarts);
- stopProjectionLocked(this);
+ stopProjectionLocked(this, stopReason);
mToken.unlinkToDeath(mDeathEater, 0);
mToken = null;
unregisterCallback(mCallback);
@@ -1295,7 +1319,7 @@ public final class MediaProjectionManagerService extends SystemService
Slog.v(TAG, "Reusing token: Throw exception due to invalid projection.");
// Tear down projection here; necessary to ensure (among other reasons) that
// stop is dispatched to client and cast icon disappears from status bar.
- mProjectionGrant.stop();
+ mProjectionGrant.stop(StopReason.STOP_ERROR);
throw new SecurityException("Don't re-use the resultData to retrieve "
+ "the same projection instance, and don't use a token that has "
+ "timed out. Don't take multiple captures by invoking "
@@ -1315,10 +1339,9 @@ public final class MediaProjectionManagerService extends SystemService
Slog.w(TAG,
"Content Recording: MediaProjection start disallowed, aborting "
+ "MediaProjection");
- stop();
+ stop(StopReason.STOP_DEVICE_LOCKED);
return;
}
-
mVirtualDisplayId = displayId;
// If prior session was does not have a valid display id, then update the display
@@ -1357,7 +1380,7 @@ public final class MediaProjectionManagerService extends SystemService
if (mProjectionGrant != null) {
Slog.d(TAG, "Content Recording: Stopped MediaProjection due to "
+ "route type of REMOTE_DISPLAY not selected");
- mProjectionGrant.stop();
+ mProjectionGrant.stop(StopReason.STOP_NEW_MEDIA_ROUTE);
}
}
}
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionMetricsLogger.java b/services/core/java/com/android/server/media/projection/MediaProjectionMetricsLogger.java
index be2a25a755a5..8e5c01685275 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionMetricsLogger.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionMetricsLogger.java
@@ -19,15 +19,34 @@ package com.android.server.media.projection;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.view.ContentRecordingSession.RECORD_CONTENT_DISPLAY;
import static android.view.ContentRecordingSession.RECORD_CONTENT_TASK;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_CANCELLED;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_UNKNOWN;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_DEVICE_LOCK;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_ERROR;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_FOREGROUND_SERVICE_CHANGE;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_HOST_APP_STOP;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_NEW_MEDIA_ROUTE;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_NEW_PROJECTION;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_QS_TILE;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_STATUS_BAR_CHIP_STOP;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_TASK_APP_CLOSE;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN;
import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN;
import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_APP_SELECTOR_DISPLAYED;
import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_CAPTURING_IN_PROGRESS;
import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_INITIATED;
import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_PERMISSION_REQUEST_DISPLAYED;
import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_STOPPED;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_USER_SWITCH;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_CHANGE_TYPE__TARGET_CHANGE_BOUNDS;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_CHANGE_TYPE__TARGET_CHANGE_POSITION;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_CHANGE_TYPE__TARGET_CHANGE_WINDOWING_MODE;
import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_TYPE__TARGET_TYPE_APP_TASK;
import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_TYPE__TARGET_TYPE_DISPLAY;
import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_TYPE__TARGET_TYPE_UNKNOWN;
@@ -36,8 +55,12 @@ import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGE
import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_WINDOWING_MODE__WINDOWING_MODE_SPLIT_SCREEN;
import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_WINDOWING_MODE__WINDOWING_MODE_UNKNOWN;
+import android.app.WindowConfiguration;
import android.app.WindowConfiguration.WindowingMode;
import android.content.Context;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.media.projection.StopReason;
import android.util.Log;
import android.view.ContentRecordingSession.RecordContent;
@@ -59,8 +82,10 @@ public class MediaProjectionMetricsLogger {
private final MediaProjectionSessionIdGenerator mSessionIdGenerator;
private final MediaProjectionTimestampStore mTimestampStore;
- private int mPreviousState =
- FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_UNKNOWN;
+ private final Rect mPreviousTargetBounds = new Rect();
+ private int mPreviousTargetWindowingMode = WINDOWING_MODE_UNDEFINED;
+ private int mPreviousProjectionState =
+ MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_UNKNOWN;
MediaProjectionMetricsLogger(
FrameworkStatsLogWrapper frameworkStatsLogWrapper,
@@ -113,7 +138,8 @@ public class MediaProjectionMetricsLogger {
hostUid,
TARGET_UID_UNKNOWN,
timeSinceLastActiveInSeconds,
- sessionCreationSource);
+ sessionCreationSource,
+ MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN);
}
/**
@@ -130,7 +156,8 @@ public class MediaProjectionMetricsLogger {
hostUid,
TARGET_UID_UNKNOWN,
TIME_SINCE_LAST_ACTIVE_UNKNOWN,
- MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN);
+ MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN,
+ MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN);
}
/**
@@ -141,13 +168,12 @@ public class MediaProjectionMetricsLogger {
public void logProjectionPermissionRequestCancelled(int hostUid) {
writeStateChanged(
mSessionIdGenerator.getCurrentSessionId(),
- FrameworkStatsLog
- .MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_CANCELLED,
+ MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_CANCELLED,
hostUid,
TARGET_UID_UNKNOWN,
TIME_SINCE_LAST_ACTIVE_UNKNOWN,
- FrameworkStatsLog
- .MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN);
+ MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN,
+ MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN);
}
/**
@@ -163,7 +189,8 @@ public class MediaProjectionMetricsLogger {
hostUid,
TARGET_UID_UNKNOWN,
TIME_SINCE_LAST_ACTIVE_UNKNOWN,
- MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN);
+ MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN,
+ MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN);
}
/**
@@ -180,7 +207,8 @@ public class MediaProjectionMetricsLogger {
hostUid,
targetUid,
TIME_SINCE_LAST_ACTIVE_UNKNOWN,
- MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN);
+ MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN,
+ MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN);
}
/**
@@ -196,14 +224,63 @@ public class MediaProjectionMetricsLogger {
*/
public void logChangedWindowingMode(
int contentToRecord, int hostUid, int targetUid, int windowingMode) {
- Log.d(TAG, "logChangedWindowingMode");
+ Log.d(TAG, "logChangedWindowingMode: windowingMode= "
+ + WindowConfiguration.windowingModeToString(windowingMode));
+ Log.d(TAG, "targetChangeType= changeWindowingMode");
writeTargetChanged(
mSessionIdGenerator.getCurrentSessionId(),
contentToRecordToTargetType(contentToRecord),
hostUid,
targetUid,
- windowingModeToTargetWindowingMode(windowingMode));
+ windowingModeToTargetWindowingMode(windowingMode),
+ mPreviousTargetBounds.width(),
+ mPreviousTargetBounds.height(),
+ mPreviousTargetBounds.centerX(),
+ mPreviousTargetBounds.centerY(),
+ MEDIA_PROJECTION_TARGET_CHANGED__TARGET_CHANGE_TYPE__TARGET_CHANGE_WINDOWING_MODE);
+ mPreviousTargetWindowingMode = windowingMode;
+ }
+ /**
+ * Logs that the bounds of projection's capture target has changed.
+ *
+ * @param contentToRecord ContentRecordingSession.RecordContent indicating whether it is a
+ * task capture or display capture - gets converted to the corresponding
+ * TargetType before being logged.
+ * @param hostUid UID of the package that initiates MediaProjection.
+ * @param targetUid UID of the package that is captured if selected.
+ * @param captureBounds Updated bounds of the captured region.
+ */
+ public void logChangedCaptureBounds(
+ int contentToRecord, int hostUid, int targetUid, Rect captureBounds) {
+ final Point capturePosition = new Point(captureBounds.centerX(), captureBounds.centerY());
+ Log.d(TAG, "logChangedCaptureBounds: captureBounds= " + captureBounds + " position= "
+ + capturePosition);
+
+ writeTargetChanged(
+ mSessionIdGenerator.getCurrentSessionId(),
+ contentToRecordToTargetType(contentToRecord),
+ hostUid,
+ targetUid,
+ mPreviousTargetWindowingMode,
+ captureBounds.width(),
+ captureBounds.height(),
+ captureBounds.centerX(),
+ captureBounds.centerY(),
+ captureBoundsToTargetChangeType(captureBounds));
+ mPreviousTargetBounds.set(captureBounds);
+ }
+
+ private int captureBoundsToTargetChangeType(Rect captureBounds) {
+ final boolean hasChangedSize = captureBounds.width() != mPreviousTargetBounds.width()
+ && captureBounds.height() != mPreviousTargetBounds.height();
+
+ if (hasChangedSize) {
+ Log.d(TAG, "targetChangeType= changeBounds");
+ return MEDIA_PROJECTION_TARGET_CHANGED__TARGET_CHANGE_TYPE__TARGET_CHANGE_BOUNDS;
+ }
+ Log.d(TAG, "targetChangeType= changePosition");
+ return MEDIA_PROJECTION_TARGET_CHANGED__TARGET_CHANGE_TYPE__TARGET_CHANGE_POSITION;
}
@VisibleForTesting
@@ -231,45 +308,85 @@ public class MediaProjectionMetricsLogger {
};
}
+ @VisibleForTesting
+ public int stopReasonToSessionStopSource(@StopReason int stopReason) {
+ return switch (stopReason) {
+ case StopReason.STOP_HOST_APP ->
+ MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_HOST_APP_STOP;
+ case StopReason.STOP_TARGET_REMOVED ->
+ MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_TASK_APP_CLOSE;
+ case StopReason.STOP_DEVICE_LOCKED->
+ MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_DEVICE_LOCK;
+ case StopReason.STOP_PRIVACY_CHIP ->
+ MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_STATUS_BAR_CHIP_STOP;
+ case StopReason.STOP_QS_TILE ->
+ MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_QS_TILE;
+ case StopReason.STOP_USER_SWITCH ->
+ MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_USER_SWITCH;
+ case StopReason.STOP_FOREGROUND_SERVICE_CHANGE ->
+ MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_FOREGROUND_SERVICE_CHANGE;
+ case StopReason.STOP_NEW_PROJECTION ->
+ MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_NEW_PROJECTION;
+ case StopReason.STOP_NEW_MEDIA_ROUTE ->
+ MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_NEW_MEDIA_ROUTE;
+ case StopReason.STOP_ERROR ->
+ MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_ERROR;
+ default ->
+ MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN;
+ };
+ }
+
/**
* Logs that the capturing stopped, either normally or because of error.
*
* @param hostUid UID of the package that initiates MediaProjection.
* @param targetUid UID of the package that is captured if selected.
*/
- public void logStopped(int hostUid, int targetUid) {
+ public void logStopped(int hostUid, int targetUid, int stopReason) {
boolean wasCaptureInProgress =
- mPreviousState
+ mPreviousProjectionState
== MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_CAPTURING_IN_PROGRESS;
- Log.d(TAG, "logStopped: wasCaptureInProgress=" + wasCaptureInProgress);
+ Log.d(TAG, "logStopped: wasCaptureInProgress=" + wasCaptureInProgress +
+ " stopReason=" + stopReason);
writeStateChanged(
mSessionIdGenerator.getCurrentSessionId(),
MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_STOPPED,
hostUid,
targetUid,
TIME_SINCE_LAST_ACTIVE_UNKNOWN,
- MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN);
+ MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN,
+ stopReasonToSessionStopSource(stopReason));
if (wasCaptureInProgress) {
mTimestampStore.registerActiveSessionEnded();
}
}
- public void notifyProjectionStateChange(int hostUid, int state, int sessionCreationSource) {
- writeStateChanged(hostUid, state, sessionCreationSource);
+ public void notifyProjectionStateChange(
+ int hostUid,
+ int state,
+ int sessionCreationSource,
+ int sessionStopSource
+ ) {
+ writeStateChanged(hostUid, state, sessionCreationSource, sessionStopSource);
}
- private void writeStateChanged(int hostUid, int state, int sessionCreationSource) {
+ private void writeStateChanged(
+ int hostUid,
+ int state,
+ int sessionCreationSource,
+ int sessionStopSource
+ ) {
mFrameworkStatsLogWrapper.writeStateChanged(
- /* code */ FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED,
+ /* code */ MEDIA_PROJECTION_STATE_CHANGED,
/* session_id */ 123,
/* state */ state,
- /* previous_state */ FrameworkStatsLog
- .MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_UNKNOWN,
+ /* previous_state */ MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_UNKNOWN,
/* host_uid */ hostUid,
/* target_uid */ -1,
/* time_since_last_active */ 0,
- /* creation_source */ sessionCreationSource);
+ /* creation_source */ sessionCreationSource,
+ /* stop_source */ sessionStopSource);
}
private void writeStateChanged(
@@ -278,17 +395,19 @@ public class MediaProjectionMetricsLogger {
int hostUid,
int targetUid,
int timeSinceLastActive,
- int creationSource) {
+ int creationSource,
+ int stopSource) {
mFrameworkStatsLogWrapper.writeStateChanged(
- /* code */ FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED,
+ /* code */ MEDIA_PROJECTION_STATE_CHANGED,
sessionId,
state,
- mPreviousState,
+ mPreviousProjectionState,
hostUid,
targetUid,
timeSinceLastActive,
- creationSource);
- mPreviousState = state;
+ creationSource,
+ stopSource);
+ mPreviousProjectionState = state;
}
private void writeTargetChanged(
@@ -296,13 +415,23 @@ public class MediaProjectionMetricsLogger {
int targetType,
int hostUid,
int targetUid,
- int targetWindowingMode) {
+ int targetWindowingMode,
+ int width,
+ int height,
+ int centerX,
+ int centerY,
+ int targetChangeType) {
mFrameworkStatsLogWrapper.writeTargetChanged(
- /* code */ FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED,
+ /* code */ MEDIA_PROJECTION_TARGET_CHANGED,
sessionId,
targetType,
hostUid,
targetUid,
- targetWindowingMode);
+ targetWindowingMode,
+ width,
+ height,
+ centerX,
+ centerY,
+ targetChangeType);
}
}
diff --git a/services/core/java/com/android/server/wm/ContentRecorder.java b/services/core/java/com/android/server/wm/ContentRecorder.java
index 0b5872b3e601..93ccd74c6b23 100644
--- a/services/core/java/com/android/server/wm/ContentRecorder.java
+++ b/services/core/java/com/android/server/wm/ContentRecorder.java
@@ -32,6 +32,7 @@ import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
import android.media.projection.IMediaProjectionManager;
+import android.media.projection.StopReason;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -226,6 +227,7 @@ final class ContentRecorder implements WindowContainerListener {
+ "size %s",
mDisplayContent.getDisplayId(), recordedContentBounds,
recordedContentOrientation, surfaceSize);
+
updateMirroredSurface(mRecordedWindowContainer.getSyncTransaction(),
recordedContentBounds, surfaceSize);
} else {
@@ -295,12 +297,12 @@ final class ContentRecorder implements WindowContainerListener {
* Ensure recording does not fall back to the display stack; ensure the recording is stopped
* and the client notified by tearing down the virtual display.
*/
- private void stopMediaProjection() {
+ private void stopMediaProjection(@StopReason int stopReason) {
ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
"Content Recording: Stop MediaProjection on virtual display %d",
mDisplayContent.getDisplayId());
if (mMediaProjectionManager != null) {
- mMediaProjectionManager.stopActiveProjection();
+ mMediaProjectionManager.stopActiveProjection(stopReason);
}
}
@@ -507,7 +509,7 @@ final class ContentRecorder implements WindowContainerListener {
if (shouldExitTaskRecording) {
// Clean up the cached session first to ensure recording doesn't re-start, since
// tearing down the display will generate display events which will trickle back here.
- stopMediaProjection();
+ stopMediaProjection(StopReason.STOP_ERROR);
}
}
@@ -599,9 +601,13 @@ final class ContentRecorder implements WindowContainerListener {
mLastRecordedBounds = new Rect(recordedContentBounds);
mLastConsumingSurfaceSize.x = surfaceSize.x;
mLastConsumingSurfaceSize.y = surfaceSize.y;
- // Request to notify the client about the resize.
- mMediaProjectionManager.notifyActiveProjectionCapturedContentResized(
- mLastRecordedBounds.width(), mLastRecordedBounds.height());
+
+ // Request to notify the client about the updated bounds.
+ mMediaProjectionManager.notifyCaptureBoundsChanged(
+ mContentRecordingSession.getContentToRecord(),
+ mContentRecordingSession.getTargetUid(),
+ mLastRecordedBounds
+ );
}
/**
@@ -641,7 +647,7 @@ final class ContentRecorder implements WindowContainerListener {
clearContentRecordingSession();
// Clean up the cached session first to ensure recording doesn't re-start, since
// tearing down the display will generate display events which will trickle back here.
- stopMediaProjection();
+ stopMediaProjection(StopReason.STOP_TARGET_REMOVED);
}
// WindowContainerListener
@@ -674,10 +680,10 @@ final class ContentRecorder implements WindowContainerListener {
}
@VisibleForTesting interface MediaProjectionManagerWrapper {
- void stopActiveProjection();
- void notifyActiveProjectionCapturedContentResized(int width, int height);
+ void stopActiveProjection(@StopReason int stopReason);
void notifyActiveProjectionCapturedContentVisibilityChanged(boolean isVisible);
void notifyWindowingModeChanged(int contentToRecord, int targetUid, int windowingMode);
+ void notifyCaptureBoundsChanged(int contentToRecord, int targetUid, Rect captureBounds);
}
private static final class RemoteMediaProjectionManagerWrapper implements
@@ -691,7 +697,7 @@ final class ContentRecorder implements WindowContainerListener {
}
@Override
- public void stopActiveProjection() {
+ public void stopActiveProjection(@StopReason int stopReason) {
fetchMediaProjectionManager();
if (mIMediaProjectionManager == null) {
return;
@@ -700,7 +706,7 @@ final class ContentRecorder implements WindowContainerListener {
ProtoLog.e(WM_DEBUG_CONTENT_RECORDING,
"Content Recording: stopping active projection for display %d",
mDisplayId);
- mIMediaProjectionManager.stopActiveProjection();
+ mIMediaProjectionManager.stopActiveProjection(stopReason);
} catch (RemoteException e) {
ProtoLog.e(WM_DEBUG_CONTENT_RECORDING,
"Content Recording: Unable to tell MediaProjectionManagerService to stop "
@@ -710,52 +716,51 @@ final class ContentRecorder implements WindowContainerListener {
}
@Override
- public void notifyActiveProjectionCapturedContentResized(int width, int height) {
+ public void notifyActiveProjectionCapturedContentVisibilityChanged(boolean isVisible) {
fetchMediaProjectionManager();
if (mIMediaProjectionManager == null) {
return;
}
try {
- mIMediaProjectionManager.notifyActiveProjectionCapturedContentResized(width,
- height);
+ mIMediaProjectionManager.notifyActiveProjectionCapturedContentVisibilityChanged(
+ isVisible);
} catch (RemoteException e) {
ProtoLog.e(WM_DEBUG_CONTENT_RECORDING,
"Content Recording: Unable to tell MediaProjectionManagerService about "
- + "resizing the active projection: %s",
+ + "visibility change on the active projection: %s",
e);
}
}
@Override
- public void notifyActiveProjectionCapturedContentVisibilityChanged(boolean isVisible) {
+ public void notifyWindowingModeChanged(int contentToRecord, int targetUid,
+ int windowingMode) {
fetchMediaProjectionManager();
if (mIMediaProjectionManager == null) {
return;
}
try {
- mIMediaProjectionManager.notifyActiveProjectionCapturedContentVisibilityChanged(
- isVisible);
+ mIMediaProjectionManager.notifyWindowingModeChanged(
+ contentToRecord, targetUid, windowingMode);
} catch (RemoteException e) {
ProtoLog.e(WM_DEBUG_CONTENT_RECORDING,
- "Content Recording: Unable to tell MediaProjectionManagerService about "
- + "visibility change on the active projection: %s",
- e);
+ "Content Recording: Unable to tell log windowing mode change: %s", e);
}
}
@Override
- public void notifyWindowingModeChanged(int contentToRecord, int targetUid,
- int windowingMode) {
+ public void notifyCaptureBoundsChanged(int contentToRecord, int targetUid,
+ Rect captureBounds) {
fetchMediaProjectionManager();
if (mIMediaProjectionManager == null) {
return;
}
try {
- mIMediaProjectionManager.notifyWindowingModeChanged(
- contentToRecord, targetUid, windowingMode);
+ mIMediaProjectionManager.notifyCaptureBoundsChanged(
+ contentToRecord, targetUid, captureBounds);
} catch (RemoteException e) {
ProtoLog.e(WM_DEBUG_CONTENT_RECORDING,
- "Content Recording: Unable to tell log windowing mode change: %s", e);
+ "Content Recording: Unable to tell log bounds change: %s", e);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java
index b2a7d20fb948..3ced56a04138 100644
--- a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java
@@ -67,10 +67,12 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.ApplicationInfoFlags;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.graphics.Rect;
import android.media.projection.IMediaProjection;
import android.media.projection.IMediaProjectionCallback;
import android.media.projection.IMediaProjectionWatcherCallback;
import android.media.projection.ReviewGrantedConsentResult;
+import android.media.projection.StopReason;
import android.os.Binder;
import android.os.IBinder;
import android.os.Looper;
@@ -549,7 +551,7 @@ public class MediaProjectionManagerServiceTest {
MediaProjectionManagerService.MediaProjection projection =
startProjectionPreconditions(service);
- projection.stop();
+ projection.stop(StopReason.STOP_UNKNOWN);
verifyZeroInteractions(mMediaProjectionMetricsLogger);
}
@@ -562,10 +564,10 @@ public class MediaProjectionManagerServiceTest {
startProjectionPreconditions(service);
projection.start(mIMediaProjectionCallback);
- projection.stop();
+ final @StopReason int stopReason = StopReason.STOP_UNKNOWN;
+ projection.stop(stopReason);
- verify(mMediaProjectionMetricsLogger)
- .logStopped(UID, TARGET_UID_UNKNOWN);
+ verify(mMediaProjectionMetricsLogger).logStopped(UID, TARGET_UID_UNKNOWN, stopReason);
}
@Test
@@ -580,15 +582,16 @@ public class MediaProjectionManagerServiceTest {
.setContentRecordingSession(any(ContentRecordingSession.class));
service.setContentRecordingSession(DISPLAY_SESSION);
- projection.stop();
+ final @StopReason int stopReason = StopReason.STOP_UNKNOWN;
+ projection.stop(stopReason);
- verify(mMediaProjectionMetricsLogger)
- .logStopped(UID, TARGET_UID_FULL_SCREEN);
+ verify(mMediaProjectionMetricsLogger).logStopped(UID, TARGET_UID_FULL_SCREEN, stopReason);
}
@Test
public void stop_taskSession_logsHostUidAndTargetUid() throws Exception {
int targetUid = 1234;
+ int stopReason = StopReason.STOP_UNKNOWN;
MediaProjectionManagerService service =
new MediaProjectionManagerService(mContext, mMediaProjectionMetricsLoggerInjector);
MediaProjectionManagerService.MediaProjection projection =
@@ -601,9 +604,9 @@ public class MediaProjectionManagerServiceTest {
taskSession.setTargetUid(targetUid);
service.setContentRecordingSession(taskSession);
- projection.stop();
+ projection.stop(stopReason);
- verify(mMediaProjectionMetricsLogger).logStopped(UID, targetUid);
+ verify(mMediaProjectionMetricsLogger).logStopped(UID, targetUid, stopReason);
}
@Test
@@ -638,7 +641,7 @@ public class MediaProjectionManagerServiceTest {
projection.start(mIMediaProjectionCallback);
assertThat(projection.isValid()).isTrue();
- projection.stop();
+ projection.stop(StopReason.STOP_UNKNOWN);
// Second start - so not valid.
projection.start(mIMediaProjectionCallback);
@@ -692,7 +695,7 @@ public class MediaProjectionManagerServiceTest {
MediaProjectionManagerService.MediaProjection projection = startProjectionPreconditions(
service);
projection.start(mIMediaProjectionCallback);
- projection.stop();
+ projection.stop(StopReason.STOP_UNKNOWN);
// Second start - so not valid.
projection.start(mIMediaProjectionCallback);
@@ -708,7 +711,7 @@ public class MediaProjectionManagerServiceTest {
MediaProjectionManagerService.MediaProjection projection = startProjectionPreconditions(
service);
projection.start(mIMediaProjectionCallback);
- projection.stop();
+ projection.stop(StopReason.STOP_UNKNOWN);
// Second start - so not valid.
projection.start(mIMediaProjectionCallback);
@@ -947,6 +950,26 @@ public class MediaProjectionManagerServiceTest {
projection.uid, targetUid, WINDOWING_MODE_MULTI_WINDOW);
}
+ @Test
+ public void notifyCaptureBoundsChanged_forwardsToLoggerAndResizeCallbacks() throws Exception {
+ int targetUid = 123;
+ mService =
+ new MediaProjectionManagerService(mContext, mMediaProjectionMetricsLoggerInjector);
+
+ ContentRecordingSession taskSession = createTaskSession(mock(IBinder.class));
+ taskSession.setTargetUid(targetUid);
+ mService.setContentRecordingSession(taskSession);
+
+ MediaProjectionManagerService.MediaProjection projection = startProjectionPreconditions();
+ projection.start(mIMediaProjectionCallback);
+
+ Rect newBounds = new Rect(0, 0, 1000, 2000);
+ mService.notifyCaptureBoundsChanged(RECORD_CONTENT_TASK, targetUid, newBounds);
+
+ verify(mMediaProjectionMetricsLogger)
+ .logChangedCaptureBounds(RECORD_CONTENT_TASK, projection.uid, targetUid, newBounds);
+ }
+
/**
* Executes and validates scenario where the consent result indicates the projection ends.
*/
diff --git a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionMetricsLoggerTest.java b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionMetricsLoggerTest.java
index 72ce9fe9a23f..c727bb6bbf7d 100644
--- a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionMetricsLoggerTest.java
+++ b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionMetricsLoggerTest.java
@@ -32,6 +32,17 @@ import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE
import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_PERMISSION_REQUEST_DISPLAYED;
import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_STOPPED;
import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_UNKNOWN;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_DEVICE_LOCK;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_ERROR;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_FOREGROUND_SERVICE_CHANGE;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_HOST_APP_STOP;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_NEW_MEDIA_ROUTE;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_NEW_PROJECTION;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_QS_TILE;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_STATUS_BAR_CHIP_STOP;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_TASK_APP_CLOSE;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_USER_SWITCH;
import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_TYPE__TARGET_TYPE_APP_TASK;
import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_TYPE__TARGET_TYPE_DISPLAY;
import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_TARGET_CHANGED__TARGET_TYPE__TARGET_TYPE_UNKNOWN;
@@ -46,6 +57,7 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.media.projection.StopReason;
import android.platform.test.annotations.Presubmit;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -81,6 +93,7 @@ public class MediaProjectionMetricsLoggerTest {
private static final int TEST_WINDOWING_MODE = 987;
private static final int TEST_CONTENT_TO_RECORD = 654;
+ private static final int TEST_STOP_SOURCE = 321;
@Mock private FrameworkStatsLogWrapper mFrameworkStatsLogWrapper;
@Mock private MediaProjectionSessionIdGenerator mSessionIdGenerator;
@@ -136,6 +149,14 @@ public class MediaProjectionMetricsLoggerTest {
}
@Test
+ public void logInitiated_logsUnknownStopSource() {
+ mLogger.logInitiated(TEST_HOST_UID, TEST_CREATION_SOURCE);
+
+ verifyStopSourceLogged(
+ MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN);
+ }
+
+ @Test
public void logInitiated_noPreviousSession_logsUnknownTimeSinceLastActive() {
when(mTimestampStore.timeSinceLastActiveSession()).thenReturn(null);
@@ -177,7 +198,7 @@ public class MediaProjectionMetricsLoggerTest {
@Test
public void logStopped_logsStateChangedAtomId() {
- mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID);
+ mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID, TEST_STOP_SOURCE);
verifyStateChangedAtomIdLogged();
}
@@ -187,42 +208,49 @@ public class MediaProjectionMetricsLoggerTest {
int currentSessionId = 987;
when(mSessionIdGenerator.getCurrentSessionId()).thenReturn(currentSessionId);
- mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID);
+ mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID, TEST_STOP_SOURCE);
verifySessionIdLogged(currentSessionId);
}
@Test
public void logStopped_logsStateStopped() {
- mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID);
+ mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID, TEST_STOP_SOURCE);
verifyStateLogged(MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_STOPPED);
}
@Test
public void logStopped_logsHostUid() {
- mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID);
+ mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID, TEST_STOP_SOURCE);
verifyStateChangedHostUidLogged(TEST_HOST_UID);
}
@Test
public void logStopped_logsTargetUid() {
- mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID);
+ mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID, TEST_STOP_SOURCE);
verifyStageChangedTargetUidLogged(TEST_TARGET_UID);
}
@Test
+ public void logStopped_logsStopSource() {
+ mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID, StopReason.STOP_UNKNOWN);
+
+ verifyStopSourceLogged(MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN);
+ }
+
+ @Test
public void logStopped_logsUnknownTimeSinceLastActive() {
- mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID);
+ mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID, TEST_STOP_SOURCE);
verifyTimeSinceLastActiveSessionLogged(-1);
}
@Test
public void logStopped_logsUnknownSessionCreationSource() {
- mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID);
+ mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID, TEST_STOP_SOURCE);
verifyCreationSourceLogged(
MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN);
@@ -230,7 +258,7 @@ public class MediaProjectionMetricsLoggerTest {
@Test
public void logStopped_logsPreviousState() {
- mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID);
+ mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID, TEST_STOP_SOURCE);
verifyPreviousStateLogged(
MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_UNKNOWN);
@@ -238,7 +266,7 @@ public class MediaProjectionMetricsLoggerTest {
verifyPreviousStateLogged(
MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_STOPPED);
- mLogger.logStopped(TEST_HOST_UID, TEST_CREATION_SOURCE);
+ mLogger.logStopped(TEST_HOST_UID, TEST_CREATION_SOURCE, TEST_STOP_SOURCE);
verifyPreviousStateLogged(
MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_INITIATED);
}
@@ -247,14 +275,14 @@ public class MediaProjectionMetricsLoggerTest {
public void logStopped_capturingWasInProgress_registersActiveSessionEnded() {
mLogger.logInProgress(TEST_HOST_UID, TEST_TARGET_UID);
- mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID);
+ mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID, TEST_STOP_SOURCE);
verify(mTimestampStore).registerActiveSessionEnded();
}
@Test
public void logStopped_capturingWasNotInProgress_doesNotRegistersActiveSessionEnded() {
- mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID);
+ mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID, TEST_STOP_SOURCE);
verify(mTimestampStore, never()).registerActiveSessionEnded();
}
@@ -314,6 +342,14 @@ public class MediaProjectionMetricsLoggerTest {
}
@Test
+ public void logInProgress_logsUnknownSessionStopSource() {
+ mLogger.logInProgress(TEST_HOST_UID, TEST_TARGET_UID);
+
+ verifyStopSourceLogged(
+ MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN);
+ }
+
+ @Test
public void logInProgress_logsPreviousState() {
mLogger.logInitiated(TEST_HOST_UID, TEST_CREATION_SOURCE);
verifyPreviousStateLogged(
@@ -323,7 +359,7 @@ public class MediaProjectionMetricsLoggerTest {
verifyPreviousStateLogged(
MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_INITIATED);
- mLogger.logStopped(TEST_HOST_UID, TEST_CREATION_SOURCE);
+ mLogger.logStopped(TEST_HOST_UID, TEST_CREATION_SOURCE, TEST_STOP_SOURCE);
verifyPreviousStateLogged(
MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_CAPTURING_IN_PROGRESS);
@@ -387,6 +423,14 @@ public class MediaProjectionMetricsLoggerTest {
}
@Test
+ public void logPermissionRequestDisplayed_logsUnknownSessionStopSource() {
+ mLogger.logPermissionRequestDisplayed(TEST_HOST_UID);
+
+ verifyStopSourceLogged(
+ MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN);
+ }
+
+ @Test
public void logPermissionRequestDisplayed_logsPreviousState() {
mLogger.logInitiated(TEST_HOST_UID, TEST_CREATION_SOURCE);
verifyPreviousStateLogged(
@@ -396,7 +440,7 @@ public class MediaProjectionMetricsLoggerTest {
verifyPreviousStateLogged(
MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_INITIATED);
- mLogger.logStopped(TEST_HOST_UID, TEST_CREATION_SOURCE);
+ mLogger.logStopped(TEST_HOST_UID, TEST_CREATION_SOURCE, TEST_STOP_SOURCE);
verifyPreviousStateLogged(
MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_PERMISSION_REQUEST_DISPLAYED);
@@ -460,6 +504,14 @@ public class MediaProjectionMetricsLoggerTest {
}
@Test
+ public void logAppSelectorDisplayed_logsUnknownSessionStopSource() {
+ mLogger.logAppSelectorDisplayed(TEST_HOST_UID);
+
+ verifyStopSourceLogged(
+ MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN);
+ }
+
+ @Test
public void logAppSelectorDisplayed_logsPreviousState() {
mLogger.logInitiated(TEST_HOST_UID, TEST_CREATION_SOURCE);
verifyPreviousStateLogged(
@@ -469,7 +521,7 @@ public class MediaProjectionMetricsLoggerTest {
verifyPreviousStateLogged(
MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_INITIATED);
- mLogger.logStopped(TEST_HOST_UID, TEST_CREATION_SOURCE);
+ mLogger.logStopped(TEST_HOST_UID, TEST_CREATION_SOURCE, TEST_STOP_SOURCE);
verifyPreviousStateLogged(
MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_APP_SELECTOR_DISPLAYED);
@@ -536,6 +588,14 @@ public class MediaProjectionMetricsLoggerTest {
}
@Test
+ public void logProjectionPermissionRequestCancelled_logsUnknownStopSource() {
+ mLogger.logProjectionPermissionRequestCancelled(TEST_HOST_UID);
+
+ verifyStopSourceLogged(
+ MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN);
+ }
+
+ @Test
public void logWindowingModeChanged_logsTargetChangedAtomId() {
mLogger.logChangedWindowingMode(
TEST_CONTENT_TO_RECORD, TEST_HOST_UID, TEST_TARGET_UID, TEST_WINDOWING_MODE);
@@ -614,6 +674,42 @@ public class MediaProjectionMetricsLoggerTest {
.isEqualTo(MEDIA_PROJECTION_TARGET_CHANGED__TARGET_WINDOWING_MODE__WINDOWING_MODE_UNKNOWN);
}
+ @Test
+ public void testStopReasonToSessionStopSource() {
+ mExpect.that(mLogger.stopReasonToSessionStopSource(StopReason.STOP_HOST_APP))
+ .isEqualTo(MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_HOST_APP_STOP);
+
+ mExpect.that(mLogger.stopReasonToSessionStopSource(StopReason.STOP_TARGET_REMOVED))
+ .isEqualTo(MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_TASK_APP_CLOSE);
+
+ mExpect.that(mLogger.stopReasonToSessionStopSource(StopReason.STOP_DEVICE_LOCKED))
+ .isEqualTo(MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_DEVICE_LOCK);
+
+ mExpect.that(mLogger.stopReasonToSessionStopSource(StopReason.STOP_PRIVACY_CHIP))
+ .isEqualTo(MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_STATUS_BAR_CHIP_STOP);
+
+ mExpect.that(mLogger.stopReasonToSessionStopSource(StopReason.STOP_QS_TILE))
+ .isEqualTo(MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_QS_TILE);
+
+ mExpect.that(mLogger.stopReasonToSessionStopSource(StopReason.STOP_USER_SWITCH))
+ .isEqualTo(MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_USER_SWITCH);
+
+ mExpect.that(mLogger.stopReasonToSessionStopSource(StopReason.STOP_FOREGROUND_SERVICE_CHANGE))
+ .isEqualTo(MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_FOREGROUND_SERVICE_CHANGE);
+
+ mExpect.that(mLogger.stopReasonToSessionStopSource(StopReason.STOP_NEW_PROJECTION))
+ .isEqualTo(MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_NEW_PROJECTION);
+
+ mExpect.that(mLogger.stopReasonToSessionStopSource(StopReason.STOP_NEW_MEDIA_ROUTE))
+ .isEqualTo(MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_NEW_MEDIA_ROUTE);
+
+ mExpect.that(mLogger.stopReasonToSessionStopSource(StopReason.STOP_ERROR))
+ .isEqualTo(MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_ERROR);
+
+ mExpect.that(mLogger.stopReasonToSessionStopSource(StopReason.STOP_UNKNOWN))
+ .isEqualTo(MEDIA_PROJECTION_STATE_CHANGED__STOP_SOURCE__STOP_SOURCE_UNKNOWN);
+ }
+
private void verifyStateChangedAtomIdLogged() {
verify(mFrameworkStatsLogWrapper)
.writeStateChanged(
@@ -624,7 +720,8 @@ public class MediaProjectionMetricsLoggerTest {
/* hostUid= */ anyInt(),
/* targetUid= */ anyInt(),
/* timeSinceLastActive= */ anyInt(),
- /* creationSource= */ anyInt());
+ /* creationSource= */ anyInt(),
+ /* stopSource= */ anyInt());
}
private void verifyStateLogged(int state) {
@@ -637,7 +734,8 @@ public class MediaProjectionMetricsLoggerTest {
/* hostUid= */ anyInt(),
/* targetUid= */ anyInt(),
/* timeSinceLastActive= */ anyInt(),
- /* creationSource= */ anyInt());
+ /* creationSource= */ anyInt(),
+ /* stopSource= */ anyInt());
}
private void verifyStateChangedHostUidLogged(int hostUid) {
@@ -650,7 +748,8 @@ public class MediaProjectionMetricsLoggerTest {
eq(hostUid),
/* targetUid= */ anyInt(),
/* timeSinceLastActive= */ anyInt(),
- /* creationSource= */ anyInt());
+ /* creationSource= */ anyInt(),
+ /* stopSource= */ anyInt());
}
private void verifyCreationSourceLogged(int creationSource) {
@@ -663,7 +762,22 @@ public class MediaProjectionMetricsLoggerTest {
/* hostUid= */ anyInt(),
/* targetUid= */ anyInt(),
/* timeSinceLastActive= */ anyInt(),
- eq(creationSource));
+ eq(creationSource),
+ /* stopSource= */ anyInt());
+ }
+
+ private void verifyStopSourceLogged(int stopSource) {
+ verify(mFrameworkStatsLogWrapper)
+ .writeStateChanged(
+ /* code= */ anyInt(),
+ /* sessionId= */ anyInt(),
+ /* state= */ anyInt(),
+ /* previousState= */ anyInt(),
+ /* hostUid= */ anyInt(),
+ /* targetUid= */ anyInt(),
+ /* timeSinceLastActive= */ anyInt(),
+ /* stopSource= */ anyInt(),
+ eq(stopSource));
}
private void verifyStageChangedTargetUidLogged(int targetUid) {
@@ -676,7 +790,8 @@ public class MediaProjectionMetricsLoggerTest {
/* hostUid= */ anyInt(),
eq(targetUid),
/* timeSinceLastActive= */ anyInt(),
- /* creationSource= */ anyInt());
+ /* creationSource= */ anyInt(),
+ /* stopSource= */ anyInt());
}
private void verifyTimeSinceLastActiveSessionLogged(int timeSinceLastActiveSession) {
@@ -689,7 +804,8 @@ public class MediaProjectionMetricsLoggerTest {
/* hostUid= */ anyInt(),
/* targetUid= */ anyInt(),
/* timeSinceLastActive= */ eq(timeSinceLastActiveSession),
- /* creationSource= */ anyInt());
+ /* creationSource= */ anyInt(),
+ /* stopSource= */ anyInt());
}
private void verifySessionIdLogged(int newSessionId) {
@@ -702,7 +818,8 @@ public class MediaProjectionMetricsLoggerTest {
/* hostUid= */ anyInt(),
/* targetUid= */ anyInt(),
/* timeSinceLastActive= */ anyInt(),
- /* creationSource= */ anyInt());
+ /* creationSource= */ anyInt(),
+ /* stopSource= */ anyInt());
}
private void verifyPreviousStateLogged(int previousState) {
@@ -715,7 +832,8 @@ public class MediaProjectionMetricsLoggerTest {
/* hostUid= */ anyInt(),
/* targetUid= */ anyInt(),
/* timeSinceLastActive= */ anyInt(),
- /* creationSource= */ anyInt());
+ /* creationSource= */ anyInt(),
+ /* stopSource= */ anyInt());
}
private void verifyTargetChangedAtomIdLogged() {
@@ -726,7 +844,12 @@ public class MediaProjectionMetricsLoggerTest {
/* targetType= */ anyInt(),
/* hostUid= */ anyInt(),
/* targetUid= */ anyInt(),
- /* targetWindowingMode= */ anyInt());
+ /* targetWindowingMode= */ anyInt(),
+ /* width= */ anyInt(),
+ /* height= */ anyInt(),
+ /* centerX= */ anyInt(),
+ /* centerY= */ anyInt(),
+ /* targetChangeType= */ anyInt());
}
private void verifyTargetTypeLogged(int targetType) {
@@ -737,7 +860,12 @@ public class MediaProjectionMetricsLoggerTest {
eq(targetType),
/* hostUid= */ anyInt(),
/* targetUid= */ anyInt(),
- /* targetWindowingMode= */ anyInt());
+ /* targetWindowingMode= */ anyInt(),
+ /* width= */ anyInt(),
+ /* height= */ anyInt(),
+ /* centerX= */ anyInt(),
+ /* centerY= */ anyInt(),
+ /* targetChangeType= */ anyInt());
}
private void verifyTargetChangedHostUidLogged(int hostUid) {
@@ -748,7 +876,12 @@ public class MediaProjectionMetricsLoggerTest {
/* targetType= */ anyInt(),
eq(hostUid),
/* targetUid= */ anyInt(),
- /* targetWindowingMode= */ anyInt());
+ /* targetWindowingMode= */ anyInt(),
+ /* width= */ anyInt(),
+ /* height= */ anyInt(),
+ /* centerX= */ anyInt(),
+ /* centerY= */ anyInt(),
+ /* targetChangeType= */ anyInt());
}
private void verifyTargetChangedTargetUidLogged(int targetUid) {
@@ -759,7 +892,12 @@ public class MediaProjectionMetricsLoggerTest {
/* targetType= */ anyInt(),
/* hostUid= */ anyInt(),
eq(targetUid),
- /* targetWindowingMode= */ anyInt());
+ /* targetWindowingMode= */ anyInt(),
+ /* width= */ anyInt(),
+ /* height= */ anyInt(),
+ /* centerX= */ anyInt(),
+ /* centerY= */ anyInt(),
+ /* targetChangeType= */ anyInt());
}
private void verifyWindowingModeLogged(int targetWindowingMode) {
@@ -770,6 +908,11 @@ public class MediaProjectionMetricsLoggerTest {
/* targetType= */ anyInt(),
/* hostUid= */ anyInt(),
/* targetUid= */ anyInt(),
- eq(targetWindowingMode));
+ eq(targetWindowingMode),
+ /* width= */ anyInt(),
+ /* height= */ anyInt(),
+ /* centerX= */ anyInt(),
+ /* centerY= */ anyInt(),
+ /* targetChangeType= */ anyInt());
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java b/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
index c51261f40ed5..76b994d013f3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
@@ -49,6 +49,7 @@ import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Point;
import android.graphics.Rect;
+import android.media.projection.StopReason;
import android.os.IBinder;
import android.platform.test.annotations.Presubmit;
import android.view.ContentRecordingSession;
@@ -213,7 +214,7 @@ public class ContentRecorderTests extends WindowTestsBase {
mContentRecorder.setContentRecordingSession(session);
mContentRecorder.updateRecording();
assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
- verify(mMediaProjectionManagerWrapper).stopActiveProjection();
+ verify(mMediaProjectionManagerWrapper).stopActiveProjection(StopReason.STOP_ERROR);
}
@Test
@@ -225,7 +226,7 @@ public class ContentRecorderTests extends WindowTestsBase {
mContentRecorder.setContentRecordingSession(invalidTaskSession);
mContentRecorder.updateRecording();
assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
- verify(mMediaProjectionManagerWrapper).stopActiveProjection();
+ verify(mMediaProjectionManagerWrapper).stopActiveProjection(StopReason.STOP_ERROR);
}
@Test
@@ -310,8 +311,7 @@ public class ContentRecorderTests extends WindowTestsBase {
mVirtualDisplayContent.getConfiguration().orientation, WINDOWING_MODE_FULLSCREEN);
// No resize is issued, only the initial transformations when we started recording.
- verify(mTransaction).setPosition(eq(mRecordedSurface), anyFloat(),
- anyFloat());
+ verify(mTransaction).setPosition(eq(mRecordedSurface), anyFloat(), anyFloat());
verify(mTransaction).setMatrix(eq(mRecordedSurface), anyFloat(), anyFloat(),
anyFloat(), anyFloat());
}
@@ -386,19 +386,18 @@ public class ContentRecorderTests extends WindowTestsBase {
// WHEN a configuration change arrives, and the recorded content is a different size.
Configuration configuration = mTask.getConfiguration();
- configuration.windowConfiguration.setBounds(new Rect(0, 0, recordedWidth, recordedHeight));
- configuration.windowConfiguration.setAppBounds(
- new Rect(0, 0, recordedWidth, recordedHeight));
+ Rect newBounds = new Rect(0, 0, recordedWidth, recordedHeight);
+ configuration.windowConfiguration.setBounds(newBounds);
+ configuration.windowConfiguration.setAppBounds(newBounds);
mTask.onConfigurationChanged(configuration);
assertThat(mContentRecorder.isCurrentlyRecording()).isTrue();
// THEN content in the captured DisplayArea is scaled to fit the surface size.
- verify(mTransaction, atLeastOnce()).setMatrix(eq(mRecordedSurface), anyFloat(), eq(0f),
- eq(0f),
- anyFloat());
+ verify(mTransaction, atLeastOnce()).setMatrix(
+ eq(mRecordedSurface), anyFloat(), eq(0f), eq(0f), anyFloat());
// THEN the resize callback is notified.
- verify(mMediaProjectionManagerWrapper).notifyActiveProjectionCapturedContentResized(
- recordedWidth, recordedHeight);
+ verify(mMediaProjectionManagerWrapper).notifyCaptureBoundsChanged(
+ mTaskSession.getContentToRecord(), mTaskSession.getTargetUid(), newBounds);
}
@Test
@@ -649,7 +648,7 @@ public class ContentRecorderTests extends WindowTestsBase {
mTask.removeImmediately();
- verify(mMediaProjectionManagerWrapper).stopActiveProjection();
+ verify(mMediaProjectionManagerWrapper).stopActiveProjection(StopReason.STOP_TARGET_REMOVED);
}
@Test
@@ -684,8 +683,8 @@ public class ContentRecorderTests extends WindowTestsBase {
int xInset = (mSurfaceSize.x - scaledWidth) / 2;
verify(mTransaction, atLeastOnce()).setPosition(mRecordedSurface, xInset, 0);
// THEN the resize callback is notified.
- verify(mMediaProjectionManagerWrapper).notifyActiveProjectionCapturedContentResized(
- displayAreaBounds.width(), displayAreaBounds.height());
+ verify(mMediaProjectionManagerWrapper).notifyCaptureBoundsChanged(
+ mDisplaySession.getContentToRecord(), mDisplaySession.getTargetUid(), displayAreaBounds);
}
@Test