Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d7fafde1 authored by Brad Ebinger's avatar Brad Ebinger
Browse files

Implement new API for UT call line supp service queries

Also fix a test bug where ImsResolver was scheduling a
dynamic query retry.

Bug: 122098288
Test: atest FrameworksTelephonyTests
Change-Id: I1fb9e63113a1a45f6dd861a5254ce47bf7e9c35a
parent 5c5a494a
Loading
Loading
Loading
Loading
+5 −2
Original line number Diff line number Diff line
@@ -72,6 +72,7 @@ import android.telephony.UssdResponse;
import android.telephony.ims.ImsCallForwardInfo;
import android.telephony.ims.ImsCallProfile;
import android.telephony.ims.ImsReasonInfo;
import android.telephony.ims.ImsSsData;
import android.telephony.ims.ImsSsInfo;
import android.text.TextUtils;

@@ -1532,10 +1533,12 @@ public class ImsPhone extends ImsPhoneBase {
                break;

            case EVENT_GET_CLIR_DONE:
                Bundle ssInfo = (Bundle) ar.result;
                ImsSsInfo ssInfo = (ImsSsInfo) ar.result;
                int[] clirInfo = null;
                if (ssInfo != null) {
                    clirInfo = ssInfo.getIntArray(ImsPhoneMmiCode.UT_BUNDLE_KEY_CLIR);
                    // Unfortunately callers still use the old {n,m} format of ImsSsInfo, so return
                    // that for compatibility
                    clirInfo = ssInfo.getCompatArray(ImsSsData.SS_CLIR);
                }
                sendResponse((Message) ar.userObj, clirInfo, ar.exception);
                break;
+26 −21
Original line number Diff line number Diff line
@@ -31,7 +31,6 @@ import android.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.res.Resources;
import android.os.AsyncResult;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.ResultReceiver;
@@ -41,6 +40,7 @@ import android.telephony.ims.ImsCallForwardInfo;
import android.telephony.ims.ImsReasonInfo;
import android.telephony.ims.ImsSsData;
import android.telephony.ims.ImsSsInfo;
import android.telephony.ims.ImsUtListener;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;

@@ -155,7 +155,19 @@ public final class ImsPhoneMmiCode extends Handler implements MmiCode {
    //***** Supplementary Service Query Bundle Keys
    // Used by IMS Service layer to put supp. serv. query
    // responses into the ssInfo Bundle.
    /**
     * @deprecated Use {@link ImsUtListener#onLineIdentificationSupplementaryServiceResponse(int,
     * ImsSsInfo)} API instead.
     */
    @Deprecated
    // Not used, only kept around to not break vendors using this key.
    public static final String UT_BUNDLE_KEY_CLIR = "queryClir";
    /**
     * @deprecated Use {@link ImsUtListener#onLineIdentificationSupplementaryServiceResponse(int,
     * ImsSsInfo)} API instead.
     */
    @Deprecated
    // Not used, only kept around to not break vendors using this key.
    public static final String UT_BUNDLE_KEY_SSINFO = "imsSsInfo";

    //***** Instance Variables
@@ -1485,12 +1497,10 @@ public final class ImsPhoneMmiCode extends Handler implements MmiCode {
                sb.append(getErrorMessage(ar));
            }
        } else {
            ImsSsInfo ssInfo = null;
            if (ar.result instanceof Bundle) {
            if (ar.result instanceof ImsSsInfo) {
                Rlog.d(LOG_TAG, "onSuppSvcQueryComplete: Received CLIP/COLP/COLR Response.");
                // Response for CLIP, COLP and COLR queries.
                Bundle ssInfoResp = (Bundle) ar.result;
                ssInfo = (ImsSsInfo) ssInfoResp.getParcelable(UT_BUNDLE_KEY_SSINFO);
                ImsSsInfo ssInfo = (ImsSsInfo) ar.result;
                if (ssInfo != null) {
                    Rlog.d(LOG_TAG,
                            "onSuppSvcQueryComplete: ImsSsInfo mStatus = " + ssInfo.getStatus());
@@ -1585,15 +1595,14 @@ public final class ImsPhoneMmiCode extends Handler implements MmiCode {
                sb.append(getImsErrorMessage(ar));
            }
        } else {
            Bundle ssInfo = (Bundle) ar.result;
            int[] clirInfo = ssInfo.getIntArray(UT_BUNDLE_KEY_CLIR);
            // clirInfo[0] = The 'n' parameter from TS 27.007 7.7
            // clirInfo[1] = The 'm' parameter from TS 27.007 7.7
            Rlog.d(LOG_TAG, "onQueryClirComplete: CLIR param n=" + clirInfo[0]
                    + " m=" + clirInfo[1]);
            ImsSsInfo ssInfo = (ImsSsInfo) ar.result;
            // ssInfo.getClirOutgoingState() = The 'n' parameter from TS 27.007 7.7
            // ssInfo.getClirInterrogationStatus() = The 'm' parameter from TS 27.007 7.7
            Rlog.d(LOG_TAG, "onQueryClirComplete: CLIR param n=" + ssInfo.getClirOutgoingState()
                    + " m=" + ssInfo.getClirInterrogationStatus());

            // 'm' parameter.
            switch (clirInfo[1]) {
            switch (ssInfo.getClirInterrogationStatus()) {
                case ImsSsInfo.CLIR_STATUS_NOT_PROVISIONED:
                    sb.append(mContext.getText(
                            com.android.internal.R.string.serviceNotProvisioned));
@@ -1606,7 +1615,7 @@ public final class ImsPhoneMmiCode extends Handler implements MmiCode {
                    break;
                case ImsSsInfo.CLIR_STATUS_TEMPORARILY_RESTRICTED:
                    // 'n' parameter.
                    switch (clirInfo[0]) {
                    switch (ssInfo.getClirOutgoingState()) {
                        case ImsSsInfo.CLIR_OUTGOING_DEFAULT:
                            sb.append(mContext.getText(
                                    com.android.internal.R.string.CLIRDefaultOnNextCallOn));
@@ -1630,7 +1639,7 @@ public final class ImsPhoneMmiCode extends Handler implements MmiCode {
                    break;
                case ImsSsInfo.CLIR_STATUS_TEMPORARILY_ALLOWED:
                    // 'n' parameter.
                    switch (clirInfo[0]) {
                    switch (ssInfo.getClirOutgoingState()) {
                        case ImsSsInfo.CLIR_OUTGOING_DEFAULT:
                            sb.append(mContext.getText(
                                    com.android.internal.R.string.CLIRDefaultOffNextCallOff));
@@ -1788,8 +1797,7 @@ public final class ImsPhoneMmiCode extends Handler implements MmiCode {
            case ImsSsData.SS_INTERROGATION:
                if (ssData.isTypeClir()) {
                    Rlog.d(LOG_TAG, "CLIR INTERROGATION");
                    Bundle clirInfo = new Bundle();
                    clirInfo.putIntArray(UT_BUNDLE_KEY_CLIR, ssData.getSuppServiceInfoCompat());
                    ImsSsInfo clirInfo = ssData.getSuppServiceInfo().get(0);
                    onQueryClirComplete(new AsyncResult(null, clirInfo, ex));
                } else if (ssData.isTypeCF()) {
                    Rlog.d(LOG_TAG, "CALL FORWARD INTERROGATION");
@@ -1807,11 +1815,8 @@ public final class ImsPhoneMmiCode extends Handler implements MmiCode {
                    onSuppSvcQueryComplete(new AsyncResult(null, ssData.getSuppServiceInfoCompat(),
                            ex));
                } else if (ssData.isTypeColr() || ssData.isTypeClip() || ssData.isTypeColp()) {
                    int[] suppServiceInfo = ssData.getSuppServiceInfoCompat();
                    ImsSsInfo ssInfo = new ImsSsInfo.Builder(suppServiceInfo[0]).build();
                    Bundle clInfo = new Bundle();
                    clInfo.putParcelable(UT_BUNDLE_KEY_SSINFO, ssInfo);
                    onSuppSvcQueryComplete(new AsyncResult(null, clInfo, ex));
                    onSuppSvcQueryComplete(new AsyncResult(null, ssData.getSuppServiceInfo().get(0),
                            ex));
                } else if (ssData.isTypeIcb()) {
                    onIcbQueryComplete(new AsyncResult(null, ssData.getSuppServiceInfo(), ex));
                } else {
+2 −4
Original line number Diff line number Diff line
@@ -1012,6 +1012,8 @@ public class ImsResolverTest extends ImsTestBase {
                ArgumentCaptor.forClass(ImsServiceFeatureQueryManager.Listener.class);
        verify(mMockQueryManagerFactory).create(any(Context.class), queryManagerCaptor.capture());
        mDynamicQueryListener = queryManagerCaptor.getValue();
        when(mMockQueryManager.startQuery(any(ComponentName.class), any(String.class)))
                .thenReturn(true);
        mLooper.processAllMessages();
    }

@@ -1036,8 +1038,6 @@ public class ImsResolverTest extends ImsTestBase {
            HashSet<ImsFeatureConfiguration.FeatureSlotPair> features, int times) {
        mLooper.processAllMessages();
        // ensure that startQuery was called
        when(mMockQueryManager.startQuery(any(ComponentName.class), any(String.class)))
                .thenReturn(true);
        verify(mMockQueryManager, times(times)).startQuery(eq(name), any(String.class));
        mDynamicQueryListener.onComplete(name, features);
        mLooper.processAllMessages();
@@ -1046,8 +1046,6 @@ public class ImsResolverTest extends ImsTestBase {
    private void setupDynamicQueryFeaturesFailure(ComponentName name, int times) {
        mLooper.processAllMessages();
        // ensure that startQuery was called
        when(mMockQueryManager.startQuery(any(ComponentName.class), any(String.class)))
                .thenReturn(true);
        verify(mMockQueryManager, times(times)).startQuery(eq(name), any(String.class));
        mDynamicQueryListener.onPermanentError(name);
        mLooper.processAllMessages();
+153 −0
Original line number Diff line number Diff line
/*
 * 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.internal.telephony.ims;

import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.TestCase.fail;

import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.verify;

import android.os.AsyncResult;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.telephony.ims.ImsSsInfo;
import android.telephony.ims.ImsUtListener;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;

import androidx.test.filters.SmallTest;

import com.android.ims.ImsUt;
import com.android.ims.internal.IImsUt;
import com.android.internal.telephony.TelephonyTest;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;

import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
public class ImsUtTest extends TelephonyTest {

    private static final int MSG_QUERY = 1;
    private static final int TEST_TIMEOUT_MS = 5000;

    private class TestHandler extends Handler {

        TestHandler(Looper looper) {
            super(looper);
        }

        private final LinkedBlockingQueue<ImsSsInfo> mPendingSsInfos = new LinkedBlockingQueue<>(1);
        @Override
        public void handleMessage(Message msg) {
            if (msg.what == MSG_QUERY) {
                AsyncResult ar = (AsyncResult) msg.obj;
                mPendingSsInfos.offer((ImsSsInfo) ar.result);
            }
        }
        public ImsSsInfo getPendingImsSsInfo() {
            try {
                return mPendingSsInfos.poll(TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
            } catch (InterruptedException e) {
                fail("test interrupted!");
            }
            return null;
        }
    }

    @Mock IImsUt mImsUtBinder;

    private TestHandler mHandler;

    @Before
    public void setUp() throws Exception {
        super.setUp("ImsUtTest");
        mHandler = new TestHandler(Looper.myLooper());
        processAllMessages();
    }

    @After
    public void tearDown() throws Exception {
        super.tearDown();
    }

    @Test
    @SmallTest
    public void testClirConversionCompat() throws Exception {
        ArgumentCaptor<ImsUt.IImsUtListenerProxy> captor =
                ArgumentCaptor.forClass(ImsUt.IImsUtListenerProxy.class);
        ImsUt mImsUt = new ImsUt(mImsUtBinder);
        verify(mImsUtBinder).setListener(captor.capture());
        ImsUt.IImsUtListenerProxy proxy = captor.getValue();
        assertNotNull(proxy);

        doReturn(2).when(mImsUtBinder).queryCLIR();
        mImsUt.queryCLIR(Message.obtain(mHandler, MSG_QUERY));

        Bundle result = new Bundle();
        result.putIntArray(ImsUtListener.BUNDLE_KEY_CLIR, new int[] {
                ImsSsInfo.CLIR_OUTGOING_INVOCATION, ImsSsInfo.CLIR_STATUS_PROVISIONED_PERMANENT});
        // This is deprecated, will be converted from Bundle -> ImsSsInfo
        proxy.utConfigurationQueried(null, 2 /*id*/, result);
        processAllMessages();


        ImsSsInfo info = mHandler.getPendingImsSsInfo();
        assertNotNull(info);
        assertEquals(ImsSsInfo.CLIR_OUTGOING_INVOCATION, info.getClirOutgoingState());
        assertEquals(ImsSsInfo.CLIR_STATUS_PROVISIONED_PERMANENT,
                info.getClirInterrogationStatus());
    }

    @Test
    @SmallTest
    public void testClipConversionCompat() throws Exception {
        ArgumentCaptor<ImsUt.IImsUtListenerProxy> captor =
                ArgumentCaptor.forClass(ImsUt.IImsUtListenerProxy.class);
        ImsUt mImsUt = new ImsUt(mImsUtBinder);
        verify(mImsUtBinder).setListener(captor.capture());
        ImsUt.IImsUtListenerProxy proxy = captor.getValue();
        assertNotNull(proxy);

        doReturn(2).when(mImsUtBinder).queryCLIP();
        mImsUt.queryCLIP(Message.obtain(mHandler, MSG_QUERY));

        ImsSsInfo info = new ImsSsInfo.Builder(ImsSsInfo.ENABLED).setProvisionStatus(
                ImsSsInfo.CLIR_STATUS_PROVISIONED_PERMANENT).build();
        Bundle result = new Bundle();
        result.putParcelable(ImsUtListener.BUNDLE_KEY_SSINFO, info);
        // This is deprecated, will be converted from Bundle -> ImsSsInfo
        proxy.utConfigurationQueried(null, 2 /*id*/, result);
        processAllMessages();

        ImsSsInfo resultInfo = mHandler.getPendingImsSsInfo();
        assertNotNull(resultInfo);
        assertEquals(info.getStatus(), resultInfo.getStatus());
        assertEquals(info.getProvisionStatus(), resultInfo.getProvisionStatus());
    }
}