ModemActivityInfo with rat information

- Add technology specific activity stats info for each rats
- backward compatible with legacy api (UNKNOWN rat)

Bug: 202413770
Test: atest ModemActivityInfoTest
Test: atest TelephonyManagerTest#testRequestModemActivityInfo
Change-Id: Ia0569a8f004d12ccf65fe9436ec1020bdef8a4a5
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index 77bcd0c..fcdbd48 100755
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -73,6 +73,8 @@
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
+import android.telephony.AccessNetworkConstants;
+import android.telephony.ActivityStatsTechSpecificInfo;
 import android.telephony.Annotation.ApnType;
 import android.telephony.Annotation.ThermalMitigationResult;
 import android.telephony.CallForwardingInfo;
@@ -1399,43 +1401,39 @@
                     ar = (AsyncResult) msg.obj;
                     request = (MainThreadRequest) ar.userObj;
                     ResultReceiver result = (ResultReceiver) request.argument;
-
-                    ModemActivityInfo ret = null;
                     int error = 0;
+                    if (mLastModemActivityInfo == null) {
+                        mLastModemActivitySpecificInfo = new ActivityStatsTechSpecificInfo[1];
+                        mLastModemActivitySpecificInfo[0] =
+                                new ActivityStatsTechSpecificInfo(
+                                        0,
+                                        0,
+                                        new int[ModemActivityInfo.getNumTxPowerLevels()],
+                                        0);
+                        mLastModemActivityInfo =
+                                new ModemActivityInfo(0, 0, 0, mLastModemActivitySpecificInfo);
+                    }
+
                     if (ar.exception == null && ar.result != null) {
                         // Update the last modem activity info and the result of the request.
                         ModemActivityInfo info = (ModemActivityInfo) ar.result;
                         if (isModemActivityInfoValid(info)) {
-                            int[] mergedTxTimeMs = new int[ModemActivityInfo.getNumTxPowerLevels()];
-                            int[] txTimeMs = info.getTransmitTimeMillis();
-                            int[] lastModemTxTimeMs = mLastModemActivityInfo
-                                    .getTransmitTimeMillis();
-                            for (int i = 0; i < mergedTxTimeMs.length; i++) {
-                                mergedTxTimeMs[i] = txTimeMs[i] + lastModemTxTimeMs[i];
-                            }
-                            mLastModemActivityInfo.setTimestamp(info.getTimestampMillis());
-                            mLastModemActivityInfo.setSleepTimeMillis(info.getSleepTimeMillis()
-                                    + mLastModemActivityInfo.getSleepTimeMillis());
-                            mLastModemActivityInfo.setIdleTimeMillis(info.getIdleTimeMillis()
-                                    + mLastModemActivityInfo.getIdleTimeMillis());
-                            mLastModemActivityInfo.setTransmitTimeMillis(mergedTxTimeMs);
-                            mLastModemActivityInfo.setReceiveTimeMillis(
-                                    info.getReceiveTimeMillis()
-                                            + mLastModemActivityInfo.getReceiveTimeMillis());
+                            mergeModemActivityInfo(info);
                         }
-                        ret = new ModemActivityInfo(mLastModemActivityInfo.getTimestampMillis(),
-                                mLastModemActivityInfo.getSleepTimeMillis(),
-                                mLastModemActivityInfo.getIdleTimeMillis(),
-                                mLastModemActivityInfo.getTransmitTimeMillis(),
-                                mLastModemActivityInfo.getReceiveTimeMillis());
+                        mLastModemActivityInfo =
+                                new ModemActivityInfo(
+                                        mLastModemActivityInfo.getTimestampMillis(),
+                                        mLastModemActivityInfo.getSleepTimeMillis(),
+                                        mLastModemActivityInfo.getIdleTimeMillis(),
+                                        mLastModemActivitySpecificInfo);
+
                     } else {
                         if (ar.result == null) {
                             loge("queryModemActivityInfo: Empty response");
                             error = TelephonyManager.ModemActivityInfoException
                                     .ERROR_INVALID_INFO_RECEIVED;
                         } else if (ar.exception instanceof CommandException) {
-                            loge("queryModemActivityInfo: CommandException: " +
-                                    ar.exception);
+                            loge("queryModemActivityInfo: CommandException: " + ar.exception);
                             error = TelephonyManager.ModemActivityInfoException
                                     .ERROR_MODEM_RESPONSE_ERROR;
                         } else {
@@ -1445,8 +1443,10 @@
                         }
                     }
                     Bundle bundle = new Bundle();
-                    if (ret != null) {
-                        bundle.putParcelable(TelephonyManager.MODEM_ACTIVITY_RESULT_KEY, ret);
+                    if (mLastModemActivityInfo != null) {
+                        bundle.putParcelable(
+                                TelephonyManager.MODEM_ACTIVITY_RESULT_KEY,
+                                mLastModemActivityInfo);
                     } else {
                         bundle.putInt(TelephonyManager.EXCEPTION_RESULT_KEY, error);
                     }
@@ -7930,8 +7930,8 @@
                 mApp.getAttributionTag());
     }
 
-    private final ModemActivityInfo mLastModemActivityInfo =
-            new ModemActivityInfo(0, 0, 0, new int[ModemActivityInfo.getNumTxPowerLevels()], 0);
+    private ActivityStatsTechSpecificInfo[] mLastModemActivitySpecificInfo = null;
+    private ModemActivityInfo mLastModemActivityInfo = null;
 
     /**
      * Responds to the ResultReceiver with the {@link android.telephony.ModemActivityInfo} object
@@ -7971,6 +7971,91 @@
             && (totalTxTimeMs <= activityDurationMs));
     }
 
+    private void updateLastModemActivityInfo(ModemActivityInfo info, int rat, int freq) {
+        int[] mergedTxTimeMs = new int [ModemActivityInfo.getNumTxPowerLevels()];
+        int[] txTimeMs = info.getTransmitTimeMillis(rat, freq);
+        int[] lastModemTxTimeMs = mLastModemActivityInfo.getTransmitTimeMillis(rat, freq);
+
+        for (int lvl = 0; lvl < mergedTxTimeMs.length; lvl++) {
+            mergedTxTimeMs[lvl] = txTimeMs[lvl] + lastModemTxTimeMs[lvl];
+        }
+
+        mLastModemActivityInfo.setTransmitTimeMillis(rat, freq, mergedTxTimeMs);
+        mLastModemActivityInfo.setReceiveTimeMillis(
+                rat,
+                freq,
+                info.getReceiveTimeMillis(rat, freq)
+                        + mLastModemActivityInfo.getReceiveTimeMillis(rat, freq));
+    }
+
+    private void updateLastModemActivityInfo(ModemActivityInfo info, int rat) {
+        int[] mergedTxTimeMs = new int [ModemActivityInfo.getNumTxPowerLevels()];
+        int[] txTimeMs = info.getTransmitTimeMillis(rat);
+        int[] lastModemTxTimeMs = mLastModemActivityInfo.getTransmitTimeMillis(rat);
+
+        for (int lvl = 0; lvl < mergedTxTimeMs.length; lvl++) {
+            mergedTxTimeMs[lvl] = txTimeMs[lvl] + lastModemTxTimeMs[lvl];
+        }
+        mLastModemActivityInfo.setTransmitTimeMillis(rat, mergedTxTimeMs);
+        mLastModemActivityInfo.setReceiveTimeMillis(
+                rat,
+                info.getReceiveTimeMillis(rat) + mLastModemActivityInfo.getReceiveTimeMillis(rat));
+    }
+
+   /**
+    * Merge this ModemActivityInfo with mLastModemActivitySpecificInfo
+    * @param info recent ModemActivityInfo
+    */
+    private void mergeModemActivityInfo(ModemActivityInfo info) {
+        List<ActivityStatsTechSpecificInfo> merged = new ArrayList<>();
+        ActivityStatsTechSpecificInfo mDeltaSpecificInfo;
+        boolean matched;
+        for (int i = 0; i < info.getSpecificInfoLength(); i++) {
+            matched = false;
+            int rat = info.getSpecificInfoRat(i);
+            int freq = info.getSpecificInfoFrequencyRange(i);
+            //Check each ActivityStatsTechSpecificInfo in this ModemActivityInfo for new rat returns
+            //Add a new ActivityStatsTechSpecificInfo if is a new rat, and merge with the original
+            //if it already exists
+            for (int j = 0; j < mLastModemActivitySpecificInfo.length; j++) {
+                if (rat == mLastModemActivityInfo.getSpecificInfoRat(j) && !matched) {
+                    //Merged based on frequency range (MMWAVE vs SUB6) for 5G
+                    if (rat == AccessNetworkConstants.AccessNetworkType.NGRAN) {
+                        if (freq == mLastModemActivityInfo.getSpecificInfoFrequencyRange(j)) {
+                            updateLastModemActivityInfo(info, rat, freq);
+                            matched = true;
+                        }
+                    } else {
+                        updateLastModemActivityInfo(info, rat);
+                        matched = true;
+                    }
+                }
+            }
+
+            if (!matched) {
+                mDeltaSpecificInfo =
+                        new ActivityStatsTechSpecificInfo(
+                                rat,
+                                freq,
+                                info.getTransmitTimeMillis(rat, freq),
+                                (int) info.getReceiveTimeMillis(rat, freq));
+                merged.addAll(Arrays.asList(mDeltaSpecificInfo));
+            }
+        }
+        merged.addAll(Arrays.asList(mLastModemActivitySpecificInfo));
+        mLastModemActivitySpecificInfo =
+                new ActivityStatsTechSpecificInfo[merged.size()];
+        merged.toArray(mLastModemActivitySpecificInfo);
+
+        mLastModemActivityInfo.setTimestamp(info.getTimestampMillis());
+        mLastModemActivityInfo.setSleepTimeMillis(
+                info.getSleepTimeMillis()
+                + mLastModemActivityInfo.getSleepTimeMillis());
+        mLastModemActivityInfo.setIdleTimeMillis(
+                info.getIdleTimeMillis()
+                + mLastModemActivityInfo.getIdleTimeMillis());
+    }
+
     /**
      * Returns the service state information on specified subscription.
      */