[automerger skipped] Import translations. DO NOT MERGE am: 258c9e234d -s ours
am: e1a47fad7a -s ours
am skip reason: subject contains skip directive

Change-Id: I9b47b345f0682ab0b266e18d4a04243ed61fb226
diff --git a/proto/telecom.proto b/proto/telecom.proto
index 2f4fae8..73eba87 100644
--- a/proto/telecom.proto
+++ b/proto/telecom.proto
@@ -16,6 +16,9 @@
 
   // Hardware revision (EVT, DVT, PVT etc.)
   optional string hardware_revision = 3;
+
+  // Carrier ID that the device is associated to
+  optional int32 carrier_id = 4;
 }
 
 message LogSessionTiming {
diff --git a/src/com/android/server/telecom/Analytics.java b/src/com/android/server/telecom/Analytics.java
index 1d3a90e..2997454 100644
--- a/src/com/android/server/telecom/Analytics.java
+++ b/src/com/android/server/telecom/Analytics.java
@@ -16,6 +16,7 @@
 
 package com.android.server.telecom;
 
+import android.content.Context;
 import android.os.SystemProperties;
 
 import android.telecom.Connection;
@@ -23,6 +24,8 @@
 import android.telecom.Logging.EventManager;
 import android.telecom.ParcelableCallAnalytics;
 import android.telecom.TelecomAnalytics;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
 import android.util.Base64;
 import android.telecom.Log;
 
@@ -37,10 +40,12 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.PriorityQueue;
 import java.util.concurrent.LinkedBlockingDeque;
 import java.util.stream.Collectors;
@@ -628,7 +633,7 @@
         return new TelecomAnalytics(sessionTimings, calls);
     }
 
-    public static void dumpToEncodedProto(PrintWriter pw, String[] args) {
+    public static void dumpToEncodedProto(Context context, PrintWriter pw, String[] args) {
         TelecomLogClass.TelecomLog result = new TelecomLogClass.TelecomLog();
 
         synchronized (sLock) {
@@ -642,6 +647,7 @@
                             .setTimeMillis(timing.getTime()))
                     .toArray(TelecomLogClass.LogSessionTiming[]::new);
             result.setHardwareRevision(SystemProperties.get("ro.boot.revision", ""));
+            result.setCarrierId(getCarrierId(context));
             if (args.length > 1 && CLEAR_ANALYTICS_ARG.equals(args[1])) {
                 sCallIdToInfo.clear();
                 sSessionTimings.clear();
@@ -652,6 +658,29 @@
         pw.write(encodedProto);
     }
 
+    private static int getCarrierId(Context context) {
+        SubscriptionManager subscriptionManager =
+                context.getSystemService(SubscriptionManager.class);
+        List<SubscriptionInfo> subInfos = subscriptionManager.getActiveSubscriptionInfoList();
+        if (subInfos == null) {
+            return -1;
+        }
+        return subInfos.stream()
+                .max(Comparator.comparing(Analytics::scoreSubscriptionInfo))
+                .map(SubscriptionInfo::getCarrierId).orElse(-1);
+    }
+
+    // Copied over from Telephony's server-side logic for consistency
+    private static int scoreSubscriptionInfo(SubscriptionInfo subInfo) {
+        final int scoreCarrierId = 0b100;
+        final int scoreNotOpportunistic = 0b010;
+        final int scoreSlot0 = 0b001;
+
+        return ((subInfo.getCarrierId() >= 0) ? scoreCarrierId : 0)
+                + (subInfo.isOpportunistic() ? 0 : scoreNotOpportunistic)
+                + ((subInfo.getSimSlotIndex() == 0) ? scoreSlot0 : 0);
+    }
+
     public static void dump(IndentingPrintWriter writer) {
         synchronized (sLock) {
             int prefixLength = CallsManager.TELECOM_CALL_ID_PREFIX.length();
diff --git a/src/com/android/server/telecom/AsyncRingtonePlayer.java b/src/com/android/server/telecom/AsyncRingtonePlayer.java
index 8f11882..93041c8 100644
--- a/src/com/android/server/telecom/AsyncRingtonePlayer.java
+++ b/src/com/android/server/telecom/AsyncRingtonePlayer.java
@@ -224,10 +224,11 @@
                 // can know whether to trigger the vibrator.
                 if (mHapticsFuture != null && !mHapticsFuture.isDone()) {
                     boolean hasHaptics = factory.hasHapticChannels(mRingtone);
-
                     Log.i(this, "handlePlay: hasHaptics=%b, isVibrationEnabled=%b", hasHaptics,
                             isVibrationEnabled);
-                    if (hasHaptics) {
+                    SystemSettingsUtil systemSettingsUtil = new SystemSettingsUtil();
+                    if (hasHaptics && (volumeShaperConfig == null
+                            || systemSettingsUtil.enableAudioCoupledVibrationForRampingRinger())) {
                         AudioAttributes attributes = mRingtone.getAudioAttributes();
                         Log.d(this, "handlePlay: %s haptic channel",
                                 (isVibrationEnabled ? "unmuting" : "muting"));
diff --git a/src/com/android/server/telecom/Ringer.java b/src/com/android/server/telecom/Ringer.java
index 1dceb01..d62a580 100644
--- a/src/com/android/server/telecom/Ringer.java
+++ b/src/com/android/server/telecom/Ringer.java
@@ -332,6 +332,12 @@
                             isUsingAudioCoupledHaptics, mIsHapticPlaybackSupportedByDevice);
                     maybeStartVibration(foregroundCall, shouldRingForContact, effect,
                             isVibratorEnabled, isRingerAudible);
+                } else if (mSystemSettingsUtil.applyRampingRinger(mContext)
+                           && mSystemSettingsUtil.enableRampingRingerFromDeviceConfig()
+                           && !mSystemSettingsUtil.enableAudioCoupledVibrationForRampingRinger()) {
+                    Log.i(this, "startRinging: apply ramping ringer vibration");
+                    maybeStartVibration(foregroundCall, shouldRingForContact, effect,
+                            isVibratorEnabled, isRingerAudible);
                 } else {
                     Log.addEvent(foregroundCall, LogUtils.Events.SKIP_VIBRATION,
                             "using audio-coupled haptics");
@@ -354,7 +360,6 @@
 
     private void maybeStartVibration(Call foregroundCall, boolean shouldRingForContact,
         VibrationEffect effect, boolean isVibrationEnabled, boolean isRingerAudible) {
-
         if (isVibrationEnabled
                 && !mIsVibrating && shouldRingForContact) {
             if (mSystemSettingsUtil.applyRampingRinger(mContext)
diff --git a/src/com/android/server/telecom/TelecomServiceImpl.java b/src/com/android/server/telecom/TelecomServiceImpl.java
index 8bf42a8..e8030c8 100644
--- a/src/com/android/server/telecom/TelecomServiceImpl.java
+++ b/src/com/android/server/telecom/TelecomServiceImpl.java
@@ -1376,10 +1376,13 @@
                 return;
             }
 
+
             if (args.length > 0 && Analytics.ANALYTICS_DUMPSYS_ARG.equals(args[0])) {
-                Analytics.dumpToEncodedProto(writer, args);
+                Binder.withCleanCallingIdentity(() ->
+                        Analytics.dumpToEncodedProto(mContext, writer, args));
                 return;
             }
+
             boolean isTimeLineView = (args.length > 0 && TIME_LINE_ARG.equalsIgnoreCase(args[0]));
 
             final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
diff --git a/tests/src/com/android/server/telecom/tests/AnalyticsTests.java b/tests/src/com/android/server/telecom/tests/AnalyticsTests.java
index 1fad3f7..ec5f7ba 100644
--- a/tests/src/com/android/server/telecom/tests/AnalyticsTests.java
+++ b/tests/src/com/android/server/telecom/tests/AnalyticsTests.java
@@ -25,6 +25,7 @@
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 import android.content.Context;
 import android.os.Build;
@@ -39,6 +40,8 @@
 import android.telecom.TelecomManager;
 import android.telecom.VideoCallImpl;
 import android.telecom.VideoProfile;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
 import android.test.suitebuilder.annotation.MediumTest;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Base64;
@@ -60,6 +63,7 @@
 import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
@@ -70,10 +74,16 @@
 
 @RunWith(JUnit4.class)
 public class AnalyticsTests extends TelecomSystemTest {
+    private SubscriptionManager mSubscriptionManager;
+
     @Override
     @Before
     public void setUp() throws Exception {
         super.setUp();
+        // this is a mock
+        mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class);
+        when(mSubscriptionManager.getActiveSubscriptionInfoList())
+                .thenReturn(Collections.emptyList());
     }
 
     @Override
@@ -253,7 +263,7 @@
 
         StringWriter sw = new StringWriter();
         PrintWriter pw = new PrintWriter(sw);
-        Analytics.dumpToEncodedProto(pw, new String[]{});
+        Analytics.dumpToEncodedProto(mContext, pw, new String[]{});
         TelecomLogClass.TelecomLog analyticsProto =
                 TelecomLogClass.TelecomLog.parseFrom(Base64.decode(sw.toString(), Base64.DEFAULT));
 
@@ -300,6 +310,7 @@
     @Test
     public void testAnalyticsDumpToProto() throws Exception {
         Analytics.reset();
+        setupCarrierIds();
         IdPair testCall = startAndMakeActiveIncomingCall(
                 "650-555-1212",
                 mPhoneAccountA0.getAccountHandle(),
@@ -311,10 +322,11 @@
 
         StringWriter sw = new StringWriter();
         PrintWriter pw = new PrintWriter(sw);
-        Analytics.dumpToEncodedProto(pw, new String[]{});
+        Analytics.dumpToEncodedProto(mContext, pw, new String[]{});
         TelecomLogClass.TelecomLog analyticsProto =
                 TelecomLogClass.TelecomLog.parseFrom(Base64.decode(sw.toString(), Base64.DEFAULT));
 
+        assertEquals(1, analyticsProto.getCarrierId());
         assertEquals(1, analyticsProto.callLogs.length);
         TelecomLogClass.CallLog callLog = analyticsProto.callLogs[0];
 
@@ -413,7 +425,7 @@
 
         StringWriter sw = new StringWriter();
         PrintWriter pw = new PrintWriter(sw);
-        Analytics.dumpToEncodedProto(pw, new String[]{});
+        Analytics.dumpToEncodedProto(mContext, pw, new String[]{});
         TelecomLogClass.TelecomLog analyticsProto =
                 TelecomLogClass.TelecomLog.parseFrom(Base64.decode(sw.toString(), Base64.DEFAULT));
 
@@ -432,7 +444,7 @@
 
         StringWriter sw = new StringWriter();
         PrintWriter pw = new PrintWriter(sw);
-        Analytics.dumpToEncodedProto(pw, new String[]{});
+        Analytics.dumpToEncodedProto(mContext, pw, new String[]{});
         TelecomLogClass.TelecomLog analyticsProto =
                 TelecomLogClass.TelecomLog.parseFrom(Base64.decode(sw.toString(), Base64.DEFAULT));
 
@@ -445,4 +457,17 @@
     private void assertIsRoundedToOneSigFig(long x) {
         assertEquals(x, Analytics.roundToOneSigFig(x));
     }
+
+    private void setupCarrierIds() {
+        SubscriptionInfo subInfo1 = mock(SubscriptionInfo.class);
+        SubscriptionInfo subInfo2 = mock(SubscriptionInfo.class);
+        when(subInfo1.getCarrierId()).thenReturn(1);
+        when(subInfo2.getCarrierId()).thenReturn(2);
+        when(subInfo1.isOpportunistic()).thenReturn(false);
+        when(subInfo2.isOpportunistic()).thenReturn(true);
+        when(subInfo1.getSimSlotIndex()).thenReturn(0);
+        when(subInfo2.getSimSlotIndex()).thenReturn(1);
+        when(mSubscriptionManager.getActiveSubscriptionInfoList())
+                .thenReturn(Arrays.asList(subInfo2, subInfo1));
+    }
 }
diff --git a/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java b/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java
index 19278a5..e6e8ba1 100644
--- a/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java
+++ b/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java
@@ -212,6 +212,8 @@
                 return Context.TELEPHONY_SERVICE;
             } else if (svcClass == CarrierConfigManager.class) {
                 return Context.CARRIER_CONFIG_SERVICE;
+            } else if (svcClass == SubscriptionManager.class) {
+                return Context.TELEPHONY_SUBSCRIPTION_SERVICE;
             }
             throw new UnsupportedOperationException();
         }
diff --git a/tests/src/com/android/server/telecom/tests/SessionTest.java b/tests/src/com/android/server/telecom/tests/SessionTest.java
new file mode 100644
index 0000000..7957a28
--- /dev/null
+++ b/tests/src/com/android/server/telecom/tests/SessionTest.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.telecom.tests;
+
+import static junit.framework.Assert.fail;
+
+import android.telecom.Logging.Session;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Unit tests for android.telecom.Logging.Session
+ */
+
+@RunWith(JUnit4.class)
+public class SessionTest {
+
+    /**
+     * Ensure creating two sessions that are parent/child of each other does not lead to a crash
+     * or infinite recursion.
+     */
+    @SmallTest
+    @Test
+    public void testRecursion() {
+        Session parentSession =  createTestSession("parent", "p");
+        Session childSession =  createTestSession("child", "c");
+        parentSession.addChild(childSession);
+        parentSession.setParentSession(childSession);
+        childSession.addChild(parentSession);
+        childSession.setParentSession(parentSession);
+
+        // Make sure calling these methods does not result in a crash
+        try {
+            parentSession.printFullSessionTree();
+            childSession.printFullSessionTree();
+            parentSession.getFullMethodPath(false);
+            childSession.getFullMethodPath(false);
+            parentSession.toString();
+            childSession.toString();
+            Session.Info.getInfo(parentSession);
+            Session.Info.getInfo(childSession);
+        } catch (Exception e) {
+            fail();
+        }
+    }
+
+    private Session createTestSession(String name, String methodName) {
+        return new Session(name, methodName, 0, false, null);
+    }
+}