Merge "Import translations. DO NOT MERGE ANYWHERE" into sc-v2-dev
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/config.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/config.xml
index fa5b133..72d87d8 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/config.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/config.xml
@@ -42,6 +42,6 @@
     <!-- The ComponentName of Assistant VoicePlate Activity, the Activity will be placed in
         VoicePlate TDA -->
     <string name="config_assistantVoicePlateActivity" translatable="false">
-        com.google.android.carassistant/com.google.android.apps.gsa.binaries.auto.app.voiceplate.VoicePlateActivity
+        com.google.android.carassistant/com.google.android.libraries.assistant.auto.tng.assistant.ui.activity.AutoAssistantActivity
     </string>
 </resources>
diff --git a/cpp/evs/manager/1.1/Enumerator.cpp b/cpp/evs/manager/1.1/Enumerator.cpp
index d6f532d..b33ddac 100644
--- a/cpp/evs/manager/1.1/Enumerator.cpp
+++ b/cpp/evs/manager/1.1/Enumerator.cpp
@@ -79,7 +79,7 @@
 
     // Connect with the underlying hardware enumerator
     mHwEnumerator = IEvsEnumerator::getService(hardwareServiceName);
-    bool result = (mHwEnumerator.get() != nullptr);
+    bool result = (mHwEnumerator != nullptr);
     if (result) {
         // Get an internal display identifier.
         mHwEnumerator->getDisplayIdList(
@@ -296,7 +296,7 @@
 Return<void> Enumerator::closeCamera(const ::android::sp<IEvsCamera_1_0>& clientCamera) {
     LOG(DEBUG) << __FUNCTION__;
 
-    if (clientCamera.get() == nullptr) {
+    if (clientCamera == nullptr) {
         LOG(ERROR) << "Ignoring call with null camera pointer.";
         return Void();
     }
@@ -317,6 +317,7 @@
             // NOTE:  This should drop our last reference to the camera, resulting in its
             //        destruction.
             mActiveCameras.erase(halCamera->getId());
+            mHwEnumerator->closeCamera(halCamera->getHwCamera());
             if (mMonitorEnabled) {
                 mClientsMonitor->unregisterClientToMonitor(halCamera->getId());
             }
@@ -358,8 +359,7 @@
                                                        mEmulatedCameraDevices[id]);
                 }
             } else {
-                device = IEvsCamera_1_1::castFrom(mHwEnumerator->openCamera_1_1(id, streamCfg))
-                         .withDefault(nullptr);
+                device = mHwEnumerator->openCamera_1_1(id, streamCfg);
             }
 
             if (device == nullptr) {
diff --git a/cpp/evs/manager/1.1/HalCamera.cpp b/cpp/evs/manager/1.1/HalCamera.cpp
index e527840..47cad2d 100644
--- a/cpp/evs/manager/1.1/HalCamera.cpp
+++ b/cpp/evs/manager/1.1/HalCamera.cpp
@@ -63,7 +63,7 @@
 }
 
 
-bool HalCamera::ownVirtualCamera(sp<VirtualCamera> virtualCamera) {
+bool HalCamera::ownVirtualCamera(sp<VirtualCamera>& virtualCamera) {
 
     if (virtualCamera == nullptr) {
         LOG(ERROR) << "Failed to create virtualCamera camera object";
@@ -86,20 +86,45 @@
     return true;
 }
 
-
-void HalCamera::disownVirtualCamera(sp<VirtualCamera> virtualCamera) {
+void HalCamera::disownVirtualCamera(sp<VirtualCamera>& virtualCamera) {
     // Ignore calls with null pointers
-    if (virtualCamera.get() == nullptr) {
+    if (virtualCamera == nullptr) {
         LOG(WARNING) << "Ignoring disownVirtualCamera call with null pointer";
         return;
     }
 
     // Remove the virtual camera from our client list
-    unsigned clientCount = mClients.size();
+    const auto clientCount = mClients.size();
     mClients.remove(virtualCamera);
     if (clientCount != mClients.size() + 1) {
-        LOG(ERROR) << "Couldn't find camera in our client list to remove it; "
-                   << "this client may be removed already.";
+        LOG(WARNING) << "Couldn't find camera in our client list to remove it; "
+                     << "this client may be removed already.";
+    }
+
+    // Recompute the number of buffers required with the target camera removed from the list
+    if (!changeFramesInFlight(0)) {
+        LOG(ERROR) << "Error when trying to reduce the in flight buffer count";
+    }
+
+    // Update statistics
+    mUsageStats->updateNumClients(mClients.size());
+}
+
+void HalCamera::disownVirtualCamera(const VirtualCamera* clientToDisown) {
+    // Ignore calls with null pointers
+    if (clientToDisown == nullptr) {
+        LOG(WARNING) << "Ignoring disownVirtualCamera call with null pointer";
+        return;
+    }
+
+    // Remove the virtual camera from our client list
+    const auto clientCount = mClients.size();
+    mClients.remove_if([&clientToDisown](wp<VirtualCamera>& client) {
+                           return client == clientToDisown;
+                       });
+    if (clientCount == mClients.size()) {
+        LOG(WARNING) << "Couldn't find camera in our client list to remove it; "
+                     << "this client may be removed already.";
     }
 
     // Recompute the number of buffers required with the target camera removed from the list
diff --git a/cpp/evs/manager/1.1/HalCamera.h b/cpp/evs/manager/1.1/HalCamera.h
index 1b05443..a63684a 100644
--- a/cpp/evs/manager/1.1/HalCamera.h
+++ b/cpp/evs/manager/1.1/HalCamera.h
@@ -58,7 +58,7 @@
 // stream from the hardware camera and distribute it to the associated VirtualCamera objects.
 class HalCamera : public IEvsCameraStream_1_1 {
 public:
-    HalCamera(sp<IEvsCamera_1_1> hwCamera,
+    HalCamera(sp<IEvsCamera_1_1>& hwCamera,
               std::string deviceId = "",
               int32_t recordId = 0,
               Stream cfg = {})
@@ -75,8 +75,9 @@
 
     // Factory methods for client VirtualCameras
     sp<VirtualCamera>     makeVirtualCamera();
-    bool                  ownVirtualCamera(sp<VirtualCamera> virtualCamera);
-    void                  disownVirtualCamera(sp<VirtualCamera> virtualCamera);
+    bool                  ownVirtualCamera(sp<VirtualCamera>& virtualCamera);
+    void                  disownVirtualCamera(sp<VirtualCamera>& virtualCamera);
+    void                  disownVirtualCamera(const VirtualCamera* virtualCamera);
 
     // Implementation details
     sp<IEvsCamera_1_0>  getHwCamera()       { return mHwCamera; };
diff --git a/cpp/evs/manager/1.1/VirtualCamera.cpp b/cpp/evs/manager/1.1/VirtualCamera.cpp
index 3b0ef95..2d416d2 100644
--- a/cpp/evs/manager/1.1/VirtualCamera.cpp
+++ b/cpp/evs/manager/1.1/VirtualCamera.cpp
@@ -86,6 +86,9 @@
 
             // Give the underlying hardware camera the heads up that it might be time to stop
             pHwCamera->clientStreamEnding(this);
+
+            // Retire from the participating HW camera's client list
+            pHwCamera->disownVirtualCamera(this);
         }
 
         // Join a capture thread
@@ -385,7 +388,6 @@
                     // This happens when either a new frame does not arrive
                     // before a timer expires or we're requested to stop
                     // capturing frames.
-                    LOG(DEBUG) << "Exiting a capture thread.";
                     break;
                 } else if (mStreamState == RUNNING) {
                     // Fetch frames and forward to the client
@@ -681,7 +683,7 @@
         return EvsResult::INVALID_ARG;
     }
 
-    if (display.get() == nullptr) {
+    if (display == nullptr) {
         LOG(ERROR) << __FUNCTION__
                    << ": Passed display is invalid";
         return EvsResult::INVALID_ARG;
diff --git a/cpp/evs/sampleDriver/EvsV4lCamera.cpp b/cpp/evs/sampleDriver/EvsV4lCamera.cpp
index db6e4ee..8fb4882 100644
--- a/cpp/evs/sampleDriver/EvsV4lCamera.cpp
+++ b/cpp/evs/sampleDriver/EvsV4lCamera.cpp
@@ -28,13 +28,10 @@
 #include <ui/GraphicBufferMapper.h>
 #include <utils/SystemClock.h>
 
+namespace {
 
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace evs {
-namespace V1_1 {
-namespace implementation {
+// The size of a pixel of RGBA format data in bytes
+constexpr auto kBytesPerPixelRGBA = 4;
 
 // Default camera output image resolution
 const std::array<int32_t, 2> kDefaultResolution = {640, 480};
@@ -43,6 +40,16 @@
 // Safeguards against unreasonable resource consumption and provides a testable limit
 static const unsigned MAX_BUFFERS_IN_FLIGHT = 100;
 
+}; // anonymous namespace
+
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace evs {
+namespace V1_1 {
+namespace implementation {
+
 EvsV4lCamera::EvsV4lCamera(const char *deviceName,
                            unique_ptr<ConfigManager::CameraInfo> &camInfo) :
         mFramesAllowed(0),
@@ -739,7 +746,7 @@
         android::base::unique_fd fd(open(filename.c_str(),
                                          O_WRONLY | O_CREAT,
                                          S_IRUSR | S_IWUSR | S_IRGRP));
-        LOG(ERROR) << filename << ", " << fd;
+        LOG(INFO) << filename << ", " << fd;
         if (fd == -1) {
             PLOG(ERROR) << "Failed to open a file, " << filename;
         } else {
@@ -775,6 +782,11 @@
         bufDesc_1_1.timestamp =
             pV4lBuff->timestamp.tv_sec * 1e+6 + pV4lBuff->timestamp.tv_usec;
 
+        const auto sizeInRGBA = pDesc->width * pDesc->height * kBytesPerPixelRGBA;
+        if (mColorSpaceConversionBuffer.size() < sizeInRGBA) {
+            mColorSpaceConversionBuffer.resize(sizeInRGBA);
+        }
+
         // Lock our output buffer for writing
         // TODO(b/145459970): Sometimes, physical camera device maps a buffer
         // into the address that is about to be unmapped by another device; this
@@ -799,7 +811,8 @@
 
         // Transfer the video image into the output buffer, making any needed
         // format conversion along the way
-        mFillBufferFromVideo(bufDesc_1_1, (uint8_t *)targetPixels, pData, mVideo.getStride());
+        mFillBufferFromVideo(bufDesc_1_1, (uint8_t *)targetPixels, pData,
+                             mColorSpaceConversionBuffer.data(), mStride);
 
         // Unlock the output buffer
         mapper.unlock(bufDesc_1_1.buffer.nativeHandle);
diff --git a/cpp/evs/sampleDriver/EvsV4lCamera.h b/cpp/evs/sampleDriver/EvsV4lCamera.h
index 4aa8bc7..28bd7b8 100644
--- a/cpp/evs/sampleDriver/EvsV4lCamera.h
+++ b/cpp/evs/sampleDriver/EvsV4lCamera.h
@@ -143,7 +143,7 @@
 
     // Which format specific function we need to use to move camera imagery into our output buffers
     void(*mFillBufferFromVideo)(const BufferDesc& tgtBuff, uint8_t* tgt,
-                                void* imgData, unsigned imgStride);
+                                void* imgData, void* buf, unsigned imgStride);
 
 
     EvsResult doneWithFrame_impl(const uint32_t id, const buffer_handle_t handle);
@@ -166,6 +166,9 @@
 
     // Frame counter
     uint64_t mFrameCounter = 0;
+
+    // A buffer to hold an intermediate color conversion data
+    std::vector<uint8_t> mColorSpaceConversionBuffer;
 };
 
 } // namespace implementation
diff --git a/cpp/evs/sampleDriver/bufferCopy.cpp b/cpp/evs/sampleDriver/bufferCopy.cpp
index 098af61..253e39d 100644
--- a/cpp/evs/sampleDriver/bufferCopy.cpp
+++ b/cpp/evs/sampleDriver/bufferCopy.cpp
@@ -19,6 +19,14 @@
 #include <android-base/logging.h>
 #include <libyuv.h>
 
+namespace {
+
+inline constexpr size_t kYuv422BytesPerPixel = 2;
+inline constexpr size_t kRgbaBytesPerPixel = 4;
+
+}; // anonymous namespace
+
+
 namespace android {
 namespace hardware {
 namespace automotive {
@@ -38,7 +46,8 @@
 }
 
 
-void fillNV21FromNV21(const BufferDesc& tgtBuff, uint8_t* tgt, void* imgData, unsigned) {
+void fillNV21FromNV21(
+        const BufferDesc& tgtBuff, uint8_t* tgt, void* imgData, void*, unsigned) {
     // The NV21 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 interleave U/V array.
     // It assumes an even width and height for the overall image, and a horizontal stride that is
     // an even multiple of 16 bytes for both the Y and UV arrays.
@@ -57,7 +66,8 @@
 }
 
 
-void fillNV21FromYUYV(const BufferDesc& tgtBuff, uint8_t* tgt, void* imgData, unsigned imgStride) {
+void fillNV21FromYUYV(
+        const BufferDesc& tgtBuff, uint8_t* tgt, void* imgData, void*, unsigned imgStride) {
     // The YUYV format provides an interleaved array of pixel values with U and V subsampled in
     // the horizontal direction only.  Also known as interleaved 422 format.  A 4 byte
     // "macro pixel" provides the Y value for two adjacent pixels and the U and V values shared
@@ -120,15 +130,17 @@
 }
 
 
-void fillRGBAFromYUYV(const BufferDesc& tgtBuff, uint8_t* tgt, void* imgData, unsigned imgStride) {
+void fillRGBAFromYUYV(
+        const BufferDesc& tgtBuff, uint8_t* tgt, void* imgData, void* buf, unsigned imgStride) {
     const AHardwareBuffer_Desc* pDesc =
         reinterpret_cast<const AHardwareBuffer_Desc*>(&tgtBuff.buffer.description);
     // Converts YUY2ToARGB (little endian).  Please note that libyuv uses the
     // little endian while we're using the big endian in RGB format names.
-    const auto dstStrideInBytes = pDesc->stride * 4;  // 4-byte per pixel
+    const auto srcStrideInBytes = imgStride * kYuv422BytesPerPixel;
+    const auto dstStrideInBytes = pDesc->stride * kRgbaBytesPerPixel;
     auto result = libyuv::YUY2ToARGB((const uint8_t*)imgData,
-                                     imgStride,             // input stride in bytes
-                                     tgt,
+                                     srcStrideInBytes,      // input stride in bytes
+                                     (uint8_t*)buf,
                                      dstStrideInBytes,      // output stride in bytes
                                      pDesc->width,
                                      pDesc->height);
@@ -137,10 +149,8 @@
         return;
     }
 
-    // Swaps R and B pixels to convert BGRA to RGBA in place.
-    // TODO(b/190783702): Consider allocating an extra space to store ARGB data
-    //                    temporarily if below operation is too slow.
-    result = libyuv::ABGRToARGB(tgt, dstStrideInBytes, tgt, dstStrideInBytes,
+    // Swaps R and B pixels to convert BGRA to RGBA
+    result = libyuv::ABGRToARGB((uint8_t*)buf, dstStrideInBytes, tgt, dstStrideInBytes,
                                 pDesc->width, pDesc->height);
     if (result) {
         LOG(ERROR) << "Failed to convert BGRA to RGBA.";
@@ -148,31 +158,60 @@
 }
 
 
-void fillYUYVFromYUYV(const BufferDesc& tgtBuff, uint8_t* tgt, void* imgData, unsigned imgStride) {
+void fillRGBAFromUYVY(
+        const BufferDesc& tgtBuff, uint8_t* tgt, void* imgData, void* buf, unsigned imgStride) {
     const AHardwareBuffer_Desc* pDesc =
         reinterpret_cast<const AHardwareBuffer_Desc*>(&tgtBuff.buffer.description);
-    unsigned width = pDesc->width;
-    unsigned height = pDesc->height;
-    uint8_t* src = (uint8_t*)imgData;
-    uint8_t* dst = (uint8_t*)tgt;
-    unsigned srcStrideBytes = imgStride;
-    unsigned dstStrideBytes = pDesc->stride * 2;
+    // Converts UYVYToARGB (little endian).  Please note that libyuv uses the
+    // little endian while we're using the big endian in RGB format names.
+    const auto srcStrideInBytes = imgStride * kYuv422BytesPerPixel;
+    const auto dstStrideInBytes = pDesc->stride * kRgbaBytesPerPixel;
+    auto result = libyuv::UYVYToARGB(static_cast<const uint8_t*>(imgData),
+                                     srcStrideInBytes,      // input stride in bytes
+                                     static_cast<uint8_t*>(buf),
+                                     dstStrideInBytes,      // output stride in bytes
+                                     pDesc->width,
+                                     pDesc->height);
+    if (result) {
+        LOG(ERROR) << "Failed to convert UYVY to BGRA.";
+        return;
+    }
 
-    for (unsigned r=0; r<height; r++) {
-        // Copy a pixel row at a time (2 bytes per pixel, averaged over a YUYV macro pixel)
-        memcpy(dst+r*dstStrideBytes, src+r*srcStrideBytes, width*2);
+    // Swaps R and B pixels to convert BGRA to RGBA
+    result = libyuv::ABGRToARGB(static_cast<uint8_t*>(buf), dstStrideInBytes, tgt,
+                                dstStrideInBytes, pDesc->width, pDesc->height);
+    if (result) {
+        LOG(WARNING) << "Failed to convert BGRA to RGBA.";
     }
 }
 
 
-void fillYUYVFromUYVY(const BufferDesc& tgtBuff, uint8_t* tgt, void* imgData, unsigned imgStride) {
+void fillYUYVFromYUYV(
+        const BufferDesc& tgtBuff, uint8_t* tgt, void* imgData, void *, unsigned imgStride) {
+    const AHardwareBuffer_Desc* pDesc =
+        reinterpret_cast<const AHardwareBuffer_Desc*>(&tgtBuff.buffer.description);
+    const auto height = pDesc->height;
+    uint8_t* src = (uint8_t*)imgData;
+    uint8_t* dst = (uint8_t*)tgt;
+    const auto srcStrideBytes = imgStride * kYuv422BytesPerPixel;
+    const auto dstStrideBytes = pDesc->stride * kYuv422BytesPerPixel;
+
+    for (unsigned r=0; r<height; r++) {
+        // Copy a pixel row at a time (2 bytes per pixel, averaged over a YUYV macro pixel)
+        memcpy(dst+r*dstStrideBytes, src+r*srcStrideBytes, srcStrideBytes);
+    }
+}
+
+
+void fillYUYVFromUYVY(
+        const BufferDesc& tgtBuff, uint8_t* tgt, void* imgData, void *, unsigned imgStride) {
     const AHardwareBuffer_Desc* pDesc =
         reinterpret_cast<const AHardwareBuffer_Desc*>(&tgtBuff.buffer.description);
     unsigned width = pDesc->width;
     unsigned height = pDesc->height;
     uint32_t* src = (uint32_t*)imgData;
     uint32_t* dst = (uint32_t*)tgt;
-    unsigned srcStridePixels = imgStride / 2;
+    unsigned srcStridePixels = imgStride;
     unsigned dstStridePixels = pDesc->stride;
 
     const int srcRowPadding32 = srcStridePixels/2 - width/2;  // 2 bytes per pixel, 4 bytes per word
diff --git a/cpp/evs/sampleDriver/bufferCopy.h b/cpp/evs/sampleDriver/bufferCopy.h
index b07a619..a6bb512 100644
--- a/cpp/evs/sampleDriver/bufferCopy.h
+++ b/cpp/evs/sampleDriver/bufferCopy.h
@@ -30,19 +30,22 @@
 
 
 void fillNV21FromNV21(const BufferDesc& tgtBuff, uint8_t* tgt,
-                      void* imgData, unsigned imgStride);
+                      void* imgData, void* buf, unsigned imgStride);
 
 void fillNV21FromYUYV(const BufferDesc& tgtBuff, uint8_t* tgt,
-                      void* imgData, unsigned imgStride);
+                      void* imgData, void* buf, unsigned imgStride);
 
 void fillRGBAFromYUYV(const BufferDesc& tgtBuff, uint8_t* tgt,
-                      void* imgData, unsigned imgStride);
+                      void* imgData, void* buf, unsigned imgStride);
+
+void fillRGBAFromUYVY(const BufferDesc& tgtBuff, uint8_t* tgt,
+                      void* imgData, void* buf, unsigned imgStride);
 
 void fillYUYVFromYUYV(const BufferDesc& tgtBuff, uint8_t* tgt,
-                      void* imgData, unsigned imgStride);
+                      void* imgData, void* buf, unsigned imgStride);
 
 void fillYUYVFromUYVY(const BufferDesc& tgtBuff, uint8_t* tgt,
-                      void* imgData, unsigned imgStride);
+                      void* imgData, void* buf, unsigned imgStride);
 
 } // namespace implementation
 } // namespace V1_1
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/car_telemetry_test.xml b/tests/EmbeddedKitchenSinkApp/res/layout/car_telemetry_test.xml
index 39c53fa..cfad246 100644
--- a/tests/EmbeddedKitchenSinkApp/res/layout/car_telemetry_test.xml
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/car_telemetry_test.xml
@@ -72,6 +72,56 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:orientation="horizontal">
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/app_start_memory_state_captured_config"/>
+        <Button
+            android:id="@+id/send_on_app_start_memory_state_captured_config"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/add_metrics_config"/>
+        <Button
+            android:id="@+id/remove_on_app_start_memory_state_captured_config"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/remove_metrics_config"/>
+        <Button
+            android:id="@+id/get_on_app_start_memory_state_captured_report"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/get_report"/>
+    </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/activity_foreground_state_changed_config"/>
+        <Button
+            android:id="@+id/send_on_activity_foreground_state_changed_config"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/add_metrics_config"/>
+        <Button
+            android:id="@+id/remove_on_activity_foreground_state_changed_config"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/remove_metrics_config"/>
+        <Button
+            android:id="@+id/get_on_activity_foreground_state_changed_report"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/get_report"/>
+    </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
         <Button
             android:id="@+id/show_mem_info_btn"
             android:layout_width="wrap_content"
diff --git a/tests/EmbeddedKitchenSinkApp/res/values/strings.xml b/tests/EmbeddedKitchenSinkApp/res/values/strings.xml
index 4fcb9f3..c4144e0 100644
--- a/tests/EmbeddedKitchenSinkApp/res/values/strings.xml
+++ b/tests/EmbeddedKitchenSinkApp/res/values/strings.xml
@@ -385,6 +385,8 @@
     <!-- CarTelemetryService Test -->
     <string name="gear_change_config" translate="false">on_gear_change:</string>
     <string name="process_memory_config" translate="false">process_memory:</string>
+    <string name="app_start_memory_state_captured_config" translate="false">app_start_memory_state_captured:</string>
+    <string name="activity_foreground_state_changed_config" translate="false">activity_foreground_state_changed:</string>
     <string name="add_metrics_config" translatable="false">Add MetricsConfig</string>
     <string name="remove_metrics_config" translatable="false">Remove MetricsConfig</string>
     <string name="get_report" translatable="false">Get Report</string>
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/telemetry/CarTelemetryTestFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/telemetry/CarTelemetryTestFragment.java
index 5f548ed..64f7aa8 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/telemetry/CarTelemetryTestFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/telemetry/CarTelemetryTestFragment.java
@@ -16,6 +16,8 @@
 
 package com.google.android.car.kitchensink.telemetry;
 
+import static com.android.car.telemetry.TelemetryProto.StatsPublisher.SystemMetric.ACTIVITY_FOREGROUND_STATE_CHANGED;
+import static com.android.car.telemetry.TelemetryProto.StatsPublisher.SystemMetric.APP_START_MEMORY_STATE_CAPTURED;
 import static com.android.car.telemetry.TelemetryProto.StatsPublisher.SystemMetric.PROCESS_MEMORY_STATE;
 
 import android.annotation.NonNull;
@@ -95,7 +97,8 @@
                     + "published_data.page_major_fault)\n")
             .append("    result.oom_adj_score_avg = calculateAverage("
                     + "published_data.oom_adj_score)\n")
-            .append("    result.rss_in_bytes_avg = calculateAverage(published_data.rss_in_bytes)\n")
+            .append("    result.rss_in_bytes_avg = calculateAverage("
+                    + "published_data.rss_in_bytes)\n")
             .append("    result.swap_in_bytes_avg = calculateAverage("
                     + "published_data.swap_in_bytes)\n")
             .append("    result.cache_in_bytes_avg = calculateAverage("
@@ -125,6 +128,90 @@
             METRICS_CONFIG_PROCESS_MEMORY_V1.getName(),
             METRICS_CONFIG_PROCESS_MEMORY_V1.getVersion());
 
+    /** AppStartMemoryStateCaptured metric test. */
+    private static final String LUA_SCRIPT_ON_APP_START_MEMORY_STATE_CAPTURED = new StringBuilder()
+            .append("function calculateAverage(tbl)\n")
+            .append("    sum = 0\n")
+            .append("    size = 0\n")
+            .append("    for _, value in ipairs(tbl) do\n")
+            .append("        sum = sum + value\n")
+            .append("        size = size + 1\n")
+            .append("    end\n")
+            .append("    return sum/size\n")
+            .append("end\n")
+            .append("function onAppStartMemoryStateCaptured(published_data, state)\n")
+            .append("    result = {}\n")
+            .append("    result.uid = published_data.uid\n")
+            .append("    result.page_fault_avg = calculateAverage(published_data.page_fault)\n")
+            .append("    result.major_page_fault_avg = calculateAverage("
+                    + "published_data.page_major_fault)\n")
+            .append("    result.rss_in_bytes_avg = calculateAverage("
+                    + "published_data.rss_in_bytes)\n")
+            .append("    result.swap_in_bytes_avg = calculateAverage("
+                    + "published_data.swap_in_bytes)\n")
+            .append("    result.cache_in_bytes_avg = calculateAverage("
+                    + "published_data.cache_in_bytes)\n")
+            .append("    on_script_finished(result)\n")
+            .append("end\n")
+            .toString();
+
+    private static final TelemetryProto.Publisher APP_START_MEMORY_STATE_CAPTURED_PUBLISHER =
+            TelemetryProto.Publisher.newBuilder()
+                    .setStats(
+                            TelemetryProto.StatsPublisher.newBuilder()
+                                    .setSystemMetric(APP_START_MEMORY_STATE_CAPTURED)
+                    ).build();
+    private static final TelemetryProto.MetricsConfig METRICS_CONFIG_APP_START_MEMORY_V1 =
+            TelemetryProto.MetricsConfig.newBuilder()
+                    .setName("app_start_memory_metrics_config")
+                    .setVersion(1)
+                    .setScript(LUA_SCRIPT_ON_APP_START_MEMORY_STATE_CAPTURED)
+                    .addSubscribers(
+                            TelemetryProto.Subscriber.newBuilder()
+                                    .setHandler("onAppStartMemoryStateCaptured")
+                                    .setPublisher(APP_START_MEMORY_STATE_CAPTURED_PUBLISHER)
+                                    .setPriority(0)) // high priority
+                    .build();
+    private static final MetricsConfigKey APP_START_MEMORY_STATE_CAPTURED_KEY_V1 =
+            new MetricsConfigKey(
+                    METRICS_CONFIG_APP_START_MEMORY_V1.getName(),
+                    METRICS_CONFIG_APP_START_MEMORY_V1.getVersion());
+
+    /** ActivityForegroundStateChanged metric test. */
+    private static final String LUA_SCRIPT_ON_ACTIVITY_FOREGROUND_STATE_CHANGED =
+            new StringBuilder()
+                .append("function onActivityForegroundStateChanged(published_data, state)\n")
+                .append("    result = {}\n")
+                .append("    result.uid = published_data.uid\n")
+                .append("    result.pkg_name = published_data.pkg_name\n")
+                .append("    result.class_name = published_data.class_name\n")
+                .append("    result.state = published_data.state\n")
+                .append("    on_script_finished(result)\n")
+                .append("end\n")
+                .toString();
+
+    private static final TelemetryProto.Publisher ACTIVITY_FOREGROUND_STATE_CHANGED_PUBLISHER =
+            TelemetryProto.Publisher.newBuilder()
+                    .setStats(
+                            TelemetryProto.StatsPublisher.newBuilder()
+                                    .setSystemMetric(ACTIVITY_FOREGROUND_STATE_CHANGED)
+                    ).build();
+    private static final TelemetryProto.MetricsConfig METRICS_CONFIG_ACTIVITY_FOREGROUND_STATE_V1 =
+            TelemetryProto.MetricsConfig.newBuilder()
+                    .setName("activity_foreground_state_changed_config")
+                    .setVersion(1)
+                    .setScript(LUA_SCRIPT_ON_ACTIVITY_FOREGROUND_STATE_CHANGED)
+                    .addSubscribers(
+                            TelemetryProto.Subscriber.newBuilder()
+                                    .setHandler("onActivityForegroundStateChanged")
+                                    .setPublisher(ACTIVITY_FOREGROUND_STATE_CHANGED_PUBLISHER)
+                                    .setPriority(0)) // high priority
+                    .build();
+    private static final MetricsConfigKey ACTIVITY_FOREGROUND_STATE_CHANGED_KEY_V1 =
+            new MetricsConfigKey(
+                    METRICS_CONFIG_ACTIVITY_FOREGROUND_STATE_V1.getName(),
+                    METRICS_CONFIG_ACTIVITY_FOREGROUND_STATE_V1.getVersion());
+
     private final Executor mExecutor = Executors.newSingleThreadExecutor();
 
     private CarTelemetryManager mCarTelemetryManager;
@@ -161,6 +248,18 @@
                 .setOnClickListener(this::onRemoveProcessMemoryConfigBtnClick);
         view.findViewById(R.id.get_on_process_memory_report)
                 .setOnClickListener(this::onGetProcessMemoryReportBtnClick);
+        view.findViewById(R.id.send_on_app_start_memory_state_captured_config)
+                .setOnClickListener(this::onSendAppStartMemoryStateCapturedConfigBtnClick);
+        view.findViewById(R.id.remove_on_app_start_memory_state_captured_config)
+                .setOnClickListener(this::onRemoveAppStartMemoryStateCapturedConfigBtnClick);
+        view.findViewById(R.id.get_on_app_start_memory_state_captured_report)
+                .setOnClickListener(this::onGetAppStartMemoryStateCapturedReportBtnClick);
+        view.findViewById(R.id.send_on_activity_foreground_state_changed_config)
+                .setOnClickListener(this::onSendActivityForegroundStateChangedConfigBtnClick);
+        view.findViewById(R.id.remove_on_activity_foreground_state_changed_config)
+                .setOnClickListener(this::onRemoveActivityForegroundStateChangedConfigBtnClick);
+        view.findViewById(R.id.get_on_activity_foreground_state_changed_report)
+                .setOnClickListener(this::onGetActivityForegroundStateChangedReportBtnClick);
         view.findViewById(R.id.show_mem_info_btn).setOnClickListener(this::onShowMemInfoBtnClick);
         return view;
     }
@@ -192,22 +291,56 @@
     }
 
     private void onSendProcessMemoryConfigBtnClick(View view) {
-        showOutput("Sending MetricsConfig that listens for process memory state...");
+        showOutput("Sending MetricsConfig that listens for PROCESS_MEMORY_STATE...");
         mCarTelemetryManager.addMetricsConfig(PROCESS_MEMORY_KEY_V1,
                 METRICS_CONFIG_PROCESS_MEMORY_V1.toByteArray());
     }
 
     private void onRemoveProcessMemoryConfigBtnClick(View view) {
-        showOutput("Removing MetricsConfig that listens for process memory state...");
+        showOutput("Removing MetricsConfig that listens for PROCESS_MEMORY_STATE...");
         mCarTelemetryManager.removeMetricsConfig(PROCESS_MEMORY_KEY_V1);
     }
 
     private void onGetProcessMemoryReportBtnClick(View view) {
-        showOutput("Fetching report for process memory state... If nothing shows up within 5 "
+        showOutput("Fetching report for PROCESS_MEMORY_STATE... If nothing shows up within 5 "
                 + "seconds, there is no result yet");
         mCarTelemetryManager.sendFinishedReports(PROCESS_MEMORY_KEY_V1);
     }
 
+    private void onSendAppStartMemoryStateCapturedConfigBtnClick(View view) {
+        showOutput("Sending MetricsConfig that listens for APP_START_MEMORY_STATE_CAPTURED...");
+        mCarTelemetryManager.addMetricsConfig(APP_START_MEMORY_STATE_CAPTURED_KEY_V1,
+                METRICS_CONFIG_APP_START_MEMORY_V1.toByteArray());
+    }
+
+    private void onRemoveAppStartMemoryStateCapturedConfigBtnClick(View view) {
+        showOutput("Removing MetricsConfig that listens for APP_START_MEMORY_STATE_CAPTURED...");
+        mCarTelemetryManager.removeMetricsConfig(APP_START_MEMORY_STATE_CAPTURED_KEY_V1);
+    }
+
+    private void onGetAppStartMemoryStateCapturedReportBtnClick(View view) {
+        showOutput("Fetching report for APP_START_MEMORY_STATE_CAPTURED... "
+                + "If nothing shows up within 5 seconds, there is no result yet");
+        mCarTelemetryManager.sendFinishedReports(APP_START_MEMORY_STATE_CAPTURED_KEY_V1);
+    }
+
+    private void onSendActivityForegroundStateChangedConfigBtnClick(View view) {
+        showOutput("Sending MetricsConfig that listens for ACTIVITY_FOREGROUND_STATE_CHANGED...");
+        mCarTelemetryManager.addMetricsConfig(ACTIVITY_FOREGROUND_STATE_CHANGED_KEY_V1,
+                METRICS_CONFIG_ACTIVITY_FOREGROUND_STATE_V1.toByteArray());
+    }
+
+    private void onRemoveActivityForegroundStateChangedConfigBtnClick(View view) {
+        showOutput("Removing MetricsConfig that listens for ACTIVITY_FOREGROUND_STATE_CHANGED...");
+        mCarTelemetryManager.removeMetricsConfig(ACTIVITY_FOREGROUND_STATE_CHANGED_KEY_V1);
+    }
+
+    private void onGetActivityForegroundStateChangedReportBtnClick(View view) {
+        showOutput("Fetching report for ACTIVITY_FOREGROUND_STATE_CHANGED... "
+                + "If nothing shows up within 5 seconds, there is no result yet");
+        mCarTelemetryManager.sendFinishedReports(ACTIVITY_FOREGROUND_STATE_CHANGED_KEY_V1);
+    }
+
     /** Gets a MemoryInfo object for the device's current memory status. */
     private ActivityManager.MemoryInfo getAvailableMemory() {
         ActivityManager activityManager = getActivity().getSystemService(ActivityManager.class);