Merge "Camera: Add user tag field to CameraActionEvent" into tm-dev
diff --git a/core/java/android/hardware/CameraSessionStats.java b/core/java/android/hardware/CameraSessionStats.java
index 698cc76..9ef6306 100644
--- a/core/java/android/hardware/CameraSessionStats.java
+++ b/core/java/android/hardware/CameraSessionStats.java
@@ -61,6 +61,7 @@
     private boolean mDeviceError;
     private float mMaxPreviewFps;
     private ArrayList<CameraStreamStats> mStreamStats;
+    private String mUserTag;
 
     public CameraSessionStats() {
         mFacing = -1;
@@ -131,6 +132,7 @@
         dest.writeLong(mResultErrorCount);
         dest.writeBoolean(mDeviceError);
         dest.writeTypedList(mStreamStats);
+        dest.writeString(mUserTag);
     }
 
     public void readFromParcel(Parcel in) {
@@ -151,6 +153,8 @@
         ArrayList<CameraStreamStats> streamStats = new ArrayList<CameraStreamStats>();
         in.readTypedList(streamStats, CameraStreamStats.CREATOR);
         mStreamStats = streamStats;
+
+        mUserTag = in.readString();
     }
 
     public String getCameraId() {
@@ -208,4 +212,8 @@
     public List<CameraStreamStats> getStreamStats() {
         return mStreamStats;
     }
+
+    public String getUserTag() {
+        return mUserTag;
+    }
 }
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 9884c38..15e59e0 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -266,6 +266,8 @@
 
     private int mRequestType = -1;
 
+    private static final String SET_TAG_STRING_PREFIX =
+            "android.hardware.camera2.CaptureRequest.setTag.";
     /**
      * Get the type of the capture request
      *
@@ -614,6 +616,11 @@
                 throw new RuntimeException("Reading cached CaptureRequest is not supported");
             }
         }
+
+        boolean hasUserTagStr = (in.readInt() == 1) ? true : false;
+        if (hasUserTagStr) {
+            mUserTag = in.readString();
+        }
     }
 
     @Override
@@ -656,6 +663,19 @@
                 dest.writeInt(0);
             }
         }
+
+        // Write string for user tag if set to something in the same namespace
+        if (mUserTag != null) {
+            String userTagStr = mUserTag.toString();
+            if (userTagStr != null && userTagStr.startsWith(SET_TAG_STRING_PREFIX)) {
+                dest.writeInt(1);
+                dest.writeString(userTagStr.substring(SET_TAG_STRING_PREFIX.length()));
+            } else {
+                dest.writeInt(0);
+            }
+        } else {
+            dest.writeInt(0);
+        }
     }
 
     /**
@@ -938,7 +958,10 @@
          * <p>This tag is not used for anything by the camera device, but can be
          * used by an application to easily identify a CaptureRequest when it is
          * returned by
-         * {@link CameraCaptureSession.CaptureCallback#onCaptureCompleted CaptureCallback.onCaptureCompleted}
+         * {@link CameraCaptureSession.CaptureCallback#onCaptureCompleted CaptureCallback.onCaptureCompleted}.</p>
+         *
+         * <p>If the application overrides the tag object's {@link Object#toString} function, the
+         * returned string must not contain personal identifiable information.</p>
          *
          * @param tag an arbitrary Object to store with this request
          * @see CaptureRequest#getTag
diff --git a/services/core/java/com/android/server/camera/CameraServiceProxy.java b/services/core/java/com/android/server/camera/CameraServiceProxy.java
index 7db99f1..be11253 100644
--- a/services/core/java/com/android/server/camera/CameraServiceProxy.java
+++ b/services/core/java/com/android/server/camera/CameraServiceProxy.java
@@ -239,6 +239,8 @@
         public long mResultErrorCount;
         public boolean mDeviceError;
         public List<CameraStreamStats> mStreamStats;
+        public String mUserTag;
+
         private long mDurationOrStartTimeMs;  // Either start time, or duration once completed
 
         CameraUsageEvent(String cameraId, int facing, String clientName, int apiLevel,
@@ -257,7 +259,7 @@
 
         public void markCompleted(int internalReconfigure, long requestCount,
                 long resultErrorCount, boolean deviceError,
-                List<CameraStreamStats>  streamStats) {
+                List<CameraStreamStats>  streamStats, String userTag) {
             if (mCompleted) {
                 return;
             }
@@ -268,6 +270,7 @@
             mResultErrorCount = resultErrorCount;
             mDeviceError = deviceError;
             mStreamStats = streamStats;
+            mUserTag = userTag;
             if (CameraServiceProxy.DEBUG) {
                 Slog.v(TAG, "A camera facing " + cameraFacingToString(mCameraFacing) +
                         " was in use by " + mClientName + " for " +
@@ -794,7 +797,8 @@
                         + ", requestCount " + e.mRequestCount
                         + ", resultErrorCount " + e.mResultErrorCount
                         + ", deviceError " + e.mDeviceError
-                        + ", streamCount is " + streamCount);
+                        + ", streamCount is " + streamCount
+                        + ", userTag is " + e.mUserTag);
             }
             // Convert from CameraStreamStats to CameraStreamProto
             CameraStreamProto[] streamProtos = new CameraStreamProto[MAX_STREAM_STATISTICS];
@@ -851,7 +855,8 @@
                     MessageNano.toByteArray(streamProtos[1]),
                     MessageNano.toByteArray(streamProtos[2]),
                     MessageNano.toByteArray(streamProtos[3]),
-                    MessageNano.toByteArray(streamProtos[4]));
+                    MessageNano.toByteArray(streamProtos[4]),
+                    e.mUserTag);
         }
     }
 
@@ -1038,6 +1043,7 @@
         long resultErrorCount = cameraState.getResultErrorCount();
         boolean deviceError = cameraState.getDeviceErrorFlag();
         List<CameraStreamStats> streamStats = cameraState.getStreamStats();
+        String userTag = cameraState.getUserTag();
         synchronized(mLock) {
             // Update active camera list and notify NFC if necessary
             boolean wasEmpty = mActiveCameraUsage.isEmpty();
@@ -1091,7 +1097,8 @@
                     if (oldEvent != null) {
                         Slog.w(TAG, "Camera " + cameraId + " was already marked as active");
                         oldEvent.markCompleted(/*internalReconfigure*/0, /*requestCount*/0,
-                                /*resultErrorCount*/0, /*deviceError*/false, streamStats);
+                                /*resultErrorCount*/0, /*deviceError*/false, streamStats,
+                                /*userTag*/"");
                         mCameraUsageHistory.add(oldEvent);
                     }
                     break;
@@ -1101,7 +1108,7 @@
                     if (doneEvent != null) {
 
                         doneEvent.markCompleted(internalReconfigureCount, requestCount,
-                                resultErrorCount, deviceError, streamStats);
+                                resultErrorCount, deviceError, streamStats, userTag);
                         mCameraUsageHistory.add(doneEvent);
 
                         // Check current active camera IDs to see if this package is still