Merge "Refactor simState & activeSubscriptionInfo"
diff --git a/proto/src/telephony.proto b/proto/src/telephony.proto
index 39cf5fc..3436d12 100644
--- a/proto/src/telephony.proto
+++ b/proto/src/telephony.proto
@@ -50,6 +50,9 @@
 
   // Hardware revision (EVT, DVT, PVT etc.)
   optional string hardware_revision = 9;
+
+  // The active subscription info for a specific slot.
+  repeated ActiveSubscriptionInfo active_subscription_info = 10;
 }
 
 // The time information
@@ -276,9 +279,6 @@
 
   // Current data radio technology
   optional RadioAccessTechnology data_rat = 6 [default = UNKNOWN];
-
-  // All the active subscription information.
-  repeated ActiveSubscriptionInfo active_subscription_info = 7;
 }
 
 // Radio access families
@@ -619,9 +619,6 @@
 
   // The network interface name e.g. wlan0, rmnet_data0.
   optional string iframe = 3;
-
-  // All the active subscription information.
-  repeated ActiveSubscriptionInfo active_subscription_info = 4;
 }
 
 message TelephonyEvent {
@@ -675,35 +672,41 @@
     // Carrier Key Change event.
     CARRIER_KEY_CHANGED = 14;
 
-    // Phone status change event.
-    PHONE_STATUS_CHANGED = 15;
-
     // Data switch event.
-    DATA_SWITCH = 16;
+    DATA_SWITCH = 15;
 
     // Network validate event.
-    NETWORK_VALIDATE = 17;
+    NETWORK_VALIDATE = 16;
 
     // On deman data switch event.
-    ON_DEMAND_DATA_SWITCH = 18;
+    ON_DEMAND_DATA_SWITCH = 17;
+
+    // SIM state change event.
+    SIM_STATE_CHANGE = 18;
+
+    // Active subscription info change event.
+    ACTIVE_SUBSCRIPTION_INFO_CHANGE = 19;
+
+    // Enabled modem change event.
+    ENABLED_MODEM_CHANGE = 20;
   }
 
   enum ApnType {
-      DEFAULT = 0;
-      MMS = 1;
-      SUPL = 2;
-      DUN = 3;
-      HIPRI = 4;
-      FOTA = 5;
-      IMS = 6;
-      CBS = 7;
-      IA = 8;
-      EMERGENCY = 9;
+      DEFAULT = 1;
+      MMS = 2;
+      SUPL = 3;
+      DUN = 4;
+      HIPRI = 5;
+      FOTA = 6;
+      IMS = 7;
+      CBS = 8;
+      IA = 9;
+      EMERGENCY = 10;
   }
 
   enum EventState {
-      START = 0;
-      END = 1;
+      START = 1;
+      END = 2;
   }
 
   enum NetworkValidationState {
@@ -1542,17 +1545,6 @@
     optional string mccmnc = 3;
   }
 
-  message PhoneStatus {
-      /** The sim state of each active slot. */
-      repeated SimState sim_state = 1;
-
-      /**
-       * The modem state represent by a bitmap, the i-th bit(LSB) indicates the i-th modem
-       * state(0 - disabled, 1 - enabled).
-       */
-      optional int32 enabled_modem_bitmap = 2;
-  }
-
   // Time when event happened on device, in milliseconds since epoch
   optional int64 timestamp_millis = 1;
 
@@ -1604,9 +1596,6 @@
   // Carrier key change
   optional CarrierKeyChange carrier_key_change = 17;
 
-  // Phone status
-  optional PhoneStatus phone_status = 18;
-
   // Data switch event
   optional DataSwitch data_switch = 19;
 
@@ -1615,17 +1604,27 @@
 
   // On demand data switch event
   optional OnDemandDataSwitch on_demand_data_switch = 21;
+
+  // Sim state for each slot.
+  repeated SimState sim_state = 22;
+
+  // The active subscription info for a specific slot.
+  optional ActiveSubscriptionInfo active_subscription_info = 23;
+
+  // The modem state represent by a bitmap, the i-th bit(LSB) indicates the i-th modem
+  // state(0 - disabled, 1 - enabled).
+  optional int32 enabled_modem_bitmap = 24;
 }
 
 message ActiveSubscriptionInfo {
-    /** The slot index which this subscription associated with. */
+    /** The slot index which this subscription is associated with. */
     optional int32 slot_index = 1;
 
-    /** The Carrier id of this subscription. */
+    /** The Carrier id of this subscription. -1 indicates unknown value. */
     optional int32 carrier_id = 2;
 
-    /** whether subscription is opportunistic. */
-    optional bool is_opportunistic = 3;
+    /** whether subscription is opportunistic (0 - false, 1 - true, -1 - unknown). */
+    optional int32 is_opportunistic = 3;
 };
 
 enum SimState {
@@ -2007,12 +2006,6 @@
 
   // Indicating some call events are dropped
   optional bool events_dropped = 4;
-
-  // SIM state of the active slots
-  repeated SimState sim_states = 5;
-
-  // All the active subscription information.
-  repeated ActiveSubscriptionInfo active_subscription_info = 6;
 }
 
 message SmsSession {
@@ -2227,12 +2220,6 @@
 
   // Indicating some sms session events are dropped
   optional bool events_dropped = 4;
-
-  // SIM state of the active slots.
-  repeated SimState sim_state = 5;
-
-  // All the active subscription information.
-  repeated ActiveSubscriptionInfo active_subscription_info = 6;
 }
 
 // Power stats for modem
diff --git a/src/java/com/android/internal/telephony/metrics/TelephonyEventBuilder.java b/src/java/com/android/internal/telephony/metrics/TelephonyEventBuilder.java
index 31ca457..30aca43 100644
--- a/src/java/com/android/internal/telephony/metrics/TelephonyEventBuilder.java
+++ b/src/java/com/android/internal/telephony/metrics/TelephonyEventBuilder.java
@@ -19,6 +19,7 @@
 import static com.android.internal.telephony.nano.TelephonyProto.ImsCapabilities;
 import static com.android.internal.telephony.nano.TelephonyProto.ImsConnectionState;
 import static com.android.internal.telephony.nano.TelephonyProto.RilDataCall;
+import static com.android.internal.telephony.nano.TelephonyProto.SimState;
 import static com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent;
 import static com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.CarrierIdMatching;
 import static com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.CarrierKeyChange;
@@ -30,12 +31,16 @@
 import static com.android.internal.telephony.nano.TelephonyProto.TelephonySettings;
 
 import android.os.SystemClock;
+import android.telephony.TelephonyManager;
+import android.util.SparseArray;
 
+import com.android.internal.telephony.nano.TelephonyProto.ActiveSubscriptionInfo;
 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.DataSwitch;
 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.OnDemandDataSwitch;
-import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.PhoneStatus;
 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.Type;
 
+import java.util.Arrays;
+
 public class TelephonyEventBuilder {
     private final TelephonyEvent mEvent = new TelephonyEvent();
 
@@ -144,12 +149,32 @@
         return this;
     }
 
-    /**
-     * Set and build phone status changed event.
-     */
-    public TelephonyEventBuilder setPhoneStatusChange(PhoneStatus phoneStatus) {
-        mEvent.type = Type.PHONE_STATUS_CHANGED;
-        mEvent.phoneStatus = phoneStatus;
+    /** Set and build SIM state change event. */
+    public TelephonyEventBuilder setSimStateChange(SparseArray<Integer> simStates) {
+        int phoneCount = TelephonyManager.getDefault().getPhoneCount();
+        mEvent.simState = new int[phoneCount];
+        Arrays.fill(mEvent.simState, SimState.SIM_STATE_UNKNOWN);
+        mEvent.type = Type.SIM_STATE_CHANGE;
+        for (int i = 0; i < simStates.size(); i++) {
+            int key = simStates.keyAt(i);
+            if (0 <= key && key < phoneCount) {
+                mEvent.simState[key] = simStates.get(key);
+            }
+        }
+        return this;
+    }
+
+    /** Set and build subscription info change event. */
+    public TelephonyEventBuilder setActiveSubscriptionInfoChange(ActiveSubscriptionInfo info) {
+        mEvent.type = Type.ACTIVE_SUBSCRIPTION_INFO_CHANGE;
+        mEvent.activeSubscriptionInfo = info;
+        return this;
+    }
+
+    /** Set and build enabled modem bitmap change event. */
+    public TelephonyEventBuilder setEnabledModemBitmap(int enabledModemBitmap) {
+        mEvent.type = Type.ENABLED_MODEM_CHANGE;
+        mEvent.enabledModemBitmap = enabledModemBitmap;
         return this;
     }
 
diff --git a/src/java/com/android/internal/telephony/metrics/TelephonyMetrics.java b/src/java/com/android/internal/telephony/metrics/TelephonyMetrics.java
index 55af72d..5ab19cd 100644
--- a/src/java/com/android/internal/telephony/metrics/TelephonyMetrics.java
+++ b/src/java/com/android/internal/telephony/metrics/TelephonyMetrics.java
@@ -89,7 +89,6 @@
 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.DataSwitch;
 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.ModemRestart;
 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.OnDemandDataSwitch;
-import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.PhoneStatus;
 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.RilDeactivateDataCall;
 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.RilDeactivateDataCall.DeactivateReason;
 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.RilSetupDataCall;
@@ -600,7 +599,18 @@
             addTelephonyEvent(event);
         }
 
-        writePhoneStatusChangedEvent();
+        for (int i = 0; i < mLastActiveSubscriptionInfos.size(); i++) {
+            final int key = mLastActiveSubscriptionInfos.keyAt(i);
+            TelephonyEvent event = new TelephonyEventBuilder(mStartElapsedTimeMs, key)
+                    .setActiveSubscriptionInfoChange(mLastActiveSubscriptionInfos.get(key)).build();
+            addTelephonyEvent(event);
+        }
+
+        addTelephonyEvent(new TelephonyEventBuilder(mStartElapsedTimeMs, -1 /* phoneId */)
+                .setSimStateChange(mLastSimState).build());
+
+        addTelephonyEvent(new TelephonyEventBuilder(mStartElapsedTimeMs, -1 /* phoneId */)
+                .setEnabledModemBitmap(mLastEnabledModemBitmap).build());
     }
 
     /**
@@ -657,6 +667,16 @@
         log.endTime = new TelephonyProto.Time();
         log.endTime.systemTimestampMillis = System.currentTimeMillis();
         log.endTime.elapsedTimestampMillis = SystemClock.elapsedRealtime();
+
+        // Log the last active subscription information.
+        ActiveSubscriptionInfo[] activeSubscriptionInfo =
+                new ActiveSubscriptionInfo[mLastActiveSubscriptionInfos.size()];
+        for (int i = 0; i < mLastActiveSubscriptionInfos.size(); i++) {
+            int key = mLastActiveSubscriptionInfos.keyAt(i);
+            activeSubscriptionInfo[key] = mLastActiveSubscriptionInfos.get(key);
+        }
+        log.activeSubscriptionInfo = activeSubscriptionInfo;
+
         return log;
     }
 
@@ -666,19 +686,41 @@
         Integer lastSimState = mLastSimState.get(phoneId);
         if (lastSimState == null || !lastSimState.equals(state)) {
             mLastSimState.put(phoneId, state);
-            writePhoneStatusChangedEvent();
+            addTelephonyEvent(new TelephonyEventBuilder().setSimStateChange(mLastSimState).build());
         }
     }
 
     /** Update active subscription info list. */
     public void updateActiveSubscriptionInfoList(List<SubscriptionInfo> subInfos) {
-        mLastActiveSubscriptionInfos.clear();
+        List<Integer> inActivePhoneList = new ArrayList<>();
+        for (int i = 0; i < mLastActiveSubscriptionInfos.size(); i++) {
+            inActivePhoneList.add(mLastActiveSubscriptionInfos.keyAt(i));
+        }
+
         for (SubscriptionInfo info : subInfos) {
             int phoneId = SubscriptionManager.getPhoneId(info.getSubscriptionId());
+            inActivePhoneList.removeIf(value -> value.equals(phoneId));
             ActiveSubscriptionInfo activeSubscriptionInfo = new ActiveSubscriptionInfo();
-            activeSubscriptionInfo.isOpportunistic = info.isOpportunistic();
+            activeSubscriptionInfo.slotIndex = phoneId;
+            activeSubscriptionInfo.isOpportunistic = info.isOpportunistic() ? 1 : 0;
             activeSubscriptionInfo.carrierId = info.getCarrierId();
-            mLastActiveSubscriptionInfos.put(phoneId, activeSubscriptionInfo);
+            if (isDifferentSubscriptionInfo(
+                    mLastActiveSubscriptionInfos.get(phoneId), activeSubscriptionInfo)) {
+                addTelephonyEvent(new TelephonyEventBuilder(phoneId)
+                        .setActiveSubscriptionInfoChange(activeSubscriptionInfo).build());
+
+                mLastActiveSubscriptionInfos.put(phoneId, activeSubscriptionInfo);
+            }
+        }
+
+        for (int phoneId : inActivePhoneList) {
+            mLastActiveSubscriptionInfos.remove(phoneId);
+            ActiveSubscriptionInfo invalidSubInfo = new ActiveSubscriptionInfo();
+            invalidSubInfo.slotIndex = phoneId;
+            invalidSubInfo.carrierId = -1;
+            invalidSubInfo.isOpportunistic = -1;
+            addTelephonyEvent(new TelephonyEventBuilder(phoneId)
+                    .setActiveSubscriptionInfoChange(invalidSubInfo).build());
         }
     }
 
@@ -686,28 +728,8 @@
     public void updateEnabledModemBitmap(int enabledModemBitmap) {
         if (mLastEnabledModemBitmap == enabledModemBitmap) return;
         mLastEnabledModemBitmap = enabledModemBitmap;
-        writePhoneStatusChangedEvent();
-    }
-
-    /** Write the event of phone status changed. */
-    public void writePhoneStatusChangedEvent() {
-        int phoneCount = TelephonyManager.getDefault().getPhoneCount();
-        PhoneStatus phoneStatus = new PhoneStatus();
-        phoneStatus.enabledModemBitmap = mLastEnabledModemBitmap;
-        phoneStatus.simState = new int[phoneCount];
-        Arrays.fill(phoneStatus.simState, SimState.SIM_STATE_ABSENT);
-        for (int i = 0; i < mLastSimState.size(); i++) {
-            int phoneId = mLastSimState.keyAt(i);
-            if (SubscriptionManager.isValidPhoneId(phoneId)) {
-                phoneStatus.simState[phoneId] = mLastSimState.get(phoneId);
-            }
-        }
-
-        // Phone status is not associated with any phone id, so set the phone id to -1 for the phone
-        // status changed event.
-        addTelephonyEvent(new TelephonyEventBuilder(-1 /* phoneId */)
-                .setPhoneStatusChange(phoneStatus)
-                .build());
+        addTelephonyEvent(new TelephonyEventBuilder()
+                .setEnabledModemBitmap(mLastEnabledModemBitmap).build());
     }
 
     /**
@@ -2462,4 +2484,14 @@
                 return SimState.SIM_STATE_UNKNOWN;
         }
     }
+
+    private static boolean isDifferentSubscriptionInfo(
+            ActiveSubscriptionInfo oldInfo, ActiveSubscriptionInfo newInfo) {
+        if (oldInfo == null || newInfo == null) {
+            return oldInfo == newInfo;
+        }
+
+        return oldInfo.slotIndex != newInfo.slotIndex || oldInfo.carrierId != newInfo.carrierId
+                || oldInfo.isOpportunistic != newInfo.isOpportunistic;
+    }
 }