Add origin (PID & UID) to transactions

Test: N/A
Change-Id: I891ad31a0d4c5ed35dd387c8e3f3539004dd09ca
diff --git a/tools/winscope/src/TransactionEntry.vue b/tools/winscope/src/TransactionEntry.vue
index 8ca4b02..393ba97 100644
--- a/tools/winscope/src/TransactionEntry.vue
+++ b/tools/winscope/src/TransactionEntry.vue
@@ -12,6 +12,9 @@
       </div>
     </div>
     <div class="type-column">{{transactionTypeOf(source)}}</div>
+    <div class="origin-column">
+      <span style="white-space: pre;">{{formatOrigin(source)}}</span>
+    </div>
     <div class="affected-surfaces-column">
       <span v-for="(surface, index) in sufacesAffectedBy(source)">
         {{surface.id}}<span v-if="surface.name"> ({{ surface.name }})</span>
@@ -63,7 +66,7 @@
     },
     sufacesAffectedBy(transaction) {
       if (transaction.type !== 'transaction') {
-        return [{name: transaction.obj?.name, id: transaction.obj.id}];
+        return [{name: transaction.layerName, id: transaction.obj.id}];
       }
 
       const surfaceIds = new Set();
@@ -72,12 +75,19 @@
         const id = transaction.obj.id;
         if (!surfaceIds.has(id)) {
           surfaceIds.add(id);
-          affectedSurfaces.push({name: transaction.obj?.name, id});
+          affectedSurfaces.push({name: transaction.layerName, id});
         }
       }
 
       return affectedSurfaces
     },
+    formatOrigin(transaction) {
+      if (!transaction.origin) {
+        return "unavailable";
+      }
+
+      return `PID: ${transaction.origin.pid},\nUID: ${transaction.origin.uid}`;
+    },
   },
 }
 </script>
@@ -95,6 +105,10 @@
   width: 12em;
 }
 
+.origin-column {
+  width: 9em;
+}
+
 .affected-surfaces-column {
   word-wrap: break-word;
   width: 30em;
diff --git a/tools/winscope/src/TransactionsView.vue b/tools/winscope/src/TransactionsView.vue
index 2e03181..5fdea06 100644
--- a/tools/winscope/src/TransactionsView.vue
+++ b/tools/winscope/src/TransactionsView.vue
@@ -14,44 +14,40 @@
 -->
 <template>
   <md-card-content class="container">
-    <md-table v-model="filteredData" class="transaction-table card" md-card md-fixed-header>
-      <md-table-toolbar>
-        <div class="filters">
-          <md-field>
-            <label>Transaction Type</label>
-            <md-select v-model="selectedTransactionTypes" multiple>
-              <md-option v-for="type in transactionTypes" :value="type">{{ type }}</md-option>
-            </md-select>
-          </md-field>
 
-          <div>
-            <md-autocomplete v-model="selectedProperty" :md-options="properties">
-              <label>Changed property</label>
-            </md-autocomplete>
-            <!-- TODO(b/159582192): Add way to select value a property has changed to,
-                 figure out how to handle properties that are objects... -->
-          </div>
+    <md-card class="changes card">
+      <md-content md-tag="md-toolbar" md-elevation="0" class="card-toolbar md-transparent md-dense">
+        <h2 class="md-title" style="flex: 1">Log</h2>
+      </md-content>
+      <div class="filters">
+        <md-field>
+          <label>Transaction Type</label>
+          <md-select v-model="selectedTransactionTypes" multiple>
+            <md-option v-for="type in transactionTypes" :value="type">{{ type }}</md-option>
+          </md-select>
+        </md-field>
 
-          <md-chips v-model="filters" md-placeholder="Add surface id or name...">
-            <div class="md-helper-text">Press enter to add</div>
-          </md-chips>
+        <div>
+          <md-autocomplete v-model="selectedProperty" :md-options="properties">
+            <label>Changed property</label>
+          </md-autocomplete>
+          <!-- TODO(b/159582192): Add way to select value a property has changed to,
+                figure out how to handle properties that are objects... -->
         </div>
-      </md-table-toolbar>
 
-      <md-table-row class="row" slot="md-table-row" slot-scope="{ item }" @click="transactionSelected(item)">
-        <md-table-cell md-label="Time">{{ item.time }}</md-table-cell>
-        <md-table-cell md-label="Type(s)">
-          {{ transactionTypeOf(item) }}
-        </md-table-cell>
-        <md-table-cell md-label="Affected Surfaces">
-          <span v-for="(surface, index) in sufacesAffectedBy(item)">
-            {{surface.id}}<span v-if="surface.name"> ({{ surface.name }})</span>
-            <span v-if="index + 1 < sufacesAffectedBy(item).length">,&nbsp;</span>
-          </span>
-        </md-table-cell>
-      </md-table-row>
+        <md-chips v-model="filters" md-placeholder="Add surface id or name...">
+          <div class="md-helper-text">Press enter to add</div>
+        </md-chips>
+      </div>
 
-    </md-table>
+      <virtual-list style="height: 360px; overflow-y: auto;"
+        :data-key="'timestamp'"
+        :data-sources="filteredData"
+        :data-component="transactionEntryComponent"
+        :extra-props="{'onClick': transactionSelected}"
+        ref="loglist"
+      />
+    </md-card>
 
     <md-card class="changes card">
       <md-content md-tag="md-toolbar" md-elevation="0" class="card-toolbar md-transparent md-dense">
@@ -70,6 +66,8 @@
 </template>
 <script>
 import TreeView from './TreeView.vue';
+import VirtualList from '../libs/virtualList/VirtualList';
+import TransactionEntry from './TransactionEntry.vue';
 
 import { transform_json } from './transform.js';
 import { stableIdCompatibilityFixup } from './utils/utils.js'
@@ -100,6 +98,7 @@
       selectedTree: null,
       filters: [],
       selectedProperty: null,
+      transactionEntryComponent: TransactionEntry,
     };
   },
   computed: {
@@ -265,39 +264,9 @@
 
       return [surfaceChanges, displayChanges];
     },
-    transactionTypeOf(transaction) {
-      if (transaction.type !== 'transaction') {
-        return transaction.type;
-      }
-
-      if (transaction.transactions.length === 0) {
-        return "Empty Transaction";
-      }
-
-      const types = new Set();
-      transaction.transactions.forEach(t => types.add(t.type));
-
-      return Array.from(types).join(", ");
-    },
-    sufacesAffectedBy(transaction) {
-      if (transaction.type !== 'transaction') {
-        return [{name: transaction.layerName, id: transaction.obj.id}];
-      }
-
-      const surfaceIds = new Set();
-      const affectedSurfaces = [];
-      for (const transaction of transaction.transactions) {
-        const id = transaction.obj.id;
-        if (!surfaceIds.has(id)) {
-          surfaceIds.add(id);
-          affectedSurfaces.push({name: transaction.layerName, id});
-        }
-      }
-
-      return affectedSurfaces
-    },
   },
   components: {
+    'virtual-list': VirtualList,
     'tree-view': TreeView,
   }
 }
diff --git a/tools/winscope/src/transform_transaction.js b/tools/winscope/src/transform_transaction.js
index d055759..16c8bb1 100644
--- a/tools/winscope/src/transform_transaction.js
+++ b/tools/winscope/src/transform_transaction.js
@@ -26,6 +26,7 @@
       layerName: layerIdToName[surfaceChange.id],
     }));
   }
+
   for (const displayChange of transaction.displayChange) {
     transactions.push(Object.freeze({
       type: 'displayChange',
@@ -44,10 +45,13 @@
 
   switch (type) {
     case "transaction":
+      const origin = entry.transaction.origin;
+
       return Object.freeze({
         type,
         transactions: transform_transaction(entry.transaction, layerIdToName),
         time,
+        origin,
         timestamp,
       });
 
@@ -62,7 +66,7 @@
         layerName: entry[type].name ?? layerIdToName[entry[type].id],
         time,
         timestamp,
-      })
+      });
   }
 }
 
diff --git a/tools/winscope/yarn.lock b/tools/winscope/yarn.lock
index 9e7e040..d105ce3 100644
--- a/tools/winscope/yarn.lock
+++ b/tools/winscope/yarn.lock
@@ -1776,7 +1776,7 @@
     browserslist "^4.8.5"
     semver "7.0.0"
 
-core-js@^2.4.0, core-js@^2.5.0, core-js@^2.6.5:
+core-js@^2.6.5:
   version "2.6.11"
   resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.11.tgz#38831469f9922bded8ee21c9dc46985e0399308c"
   integrity sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==