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

Commit b0721761 authored by Olaia Segovia's avatar Olaia Segovia Committed by LuK1337
Browse files

Telecomm: Make sensitive phone numbers not to be shown in call log history.



Author: Olaia Segovia <olaia.segovia@bq.com>
Date:   Thu Mar 16 08:40:30 2017 +0100

    (1/2) Make sensitive phone numbers not to be shown in call log history.

    Considering sensitive phone numbers to be, hotlines dealing with
    violence against women.
    In the EU, these numbers do not show up in the phone bill.
    In order to avoid these phone numbers to be listed in the Call Log, we
    have implemented a new XML file which is parsed with phone numbers
    from different countries to be filtered. This file needs to be copied to
    device via desired Android.mk file in order to be able to process it.
    The comparison is made checking the network MCC the SIM is connected to
    in order to consider roaming and multisim scenarios.

    Test: CallLogManagerTest.testDontLogCallsToSensitivePhoneNumber PASS

    Change-Id: I4a59ff0577942ce56924f1a434ae0a3a38eacc62
    Signed-off-by: default avatarOlaia Segovia <olaia.segovia@bq.com>

Author: Paul Keith <javelinanddart@gmail.com>
Date:   Thu Jun 22 19:40:56 2017 +0200

    SensitivePhoneNumbers: Handle lists of MCC codes

    * Some countries have multiple MCC codes, so handle it
    * In the sensitivePN network field, enter the list of
      MCCs like so: https://review.lineageos.org/178233

    Change-Id: I34225473404b2be2640ea9ab05691dc985c49fa0

Author: Paul Keith <javelinanddart@gmail.com>
Date:   Thu Jul 6 16:12:12 2017 -0500

    SensitivePhoneNumbers: Fix number comparison

    * Currently, we just compare the strings for equality,
      which results in incorrect detection of sensitive nums
      a lot of the time, because adding (or removing) the
      country code is enough to make the detection fail,
      meaning the call to that phone number is logged
    * Use Android's PhoneNumberUtils comparison method to
      fix this, since it takes these factors into account

    Change-Id: I26ac180f8a6552cf87a4bada1d370f0ebb884ee1

Change-Id: Id07a7df56ba23d1bfce5a9b646cfb08ff2ce7bab
parent ff508f7a
Loading
Loading
Loading
Loading
+7 −2
Original line number Original line Diff line number Diff line
@@ -128,6 +128,7 @@ public final class CallLogManager extends CallsManagerListenerBase {


    private Object mLock;
    private Object mLock;
    private String mCurrentCountryIso;
    private String mCurrentCountryIso;
    private SensitivePhoneNumbers mSensitivePhoneNumbers;


    public CallLogManager(Context context, PhoneAccountRegistrar phoneAccountRegistrar,
    public CallLogManager(Context context, PhoneAccountRegistrar phoneAccountRegistrar,
            MissedCallNotifier missedCallNotifier) {
            MissedCallNotifier missedCallNotifier) {
@@ -135,6 +136,7 @@ public final class CallLogManager extends CallsManagerListenerBase {
        mPhoneAccountRegistrar = phoneAccountRegistrar;
        mPhoneAccountRegistrar = phoneAccountRegistrar;
        mMissedCallNotifier = missedCallNotifier;
        mMissedCallNotifier = missedCallNotifier;
        mLock = new Object();
        mLock = new Object();
        mSensitivePhoneNumbers = new SensitivePhoneNumbers();
    }
    }


    @Override
    @Override
@@ -289,8 +291,11 @@ public final class CallLogManager extends CallsManagerListenerBase {
                    CarrierConfigManager.KEY_ALLOW_EMERGENCY_NUMBERS_IN_CALL_LOG_BOOL);
                    CarrierConfigManager.KEY_ALLOW_EMERGENCY_NUMBERS_IN_CALL_LOG_BOOL);
        }
        }


        // Don't log emergency numbers if the device doesn't allow it.
        // Don't log emergency nor sensitive numbers if the device doesn't allow it.
        final boolean isOkToLogThisCall = !isEmergency || okToLogEmergencyNumber;
        boolean isSensitiveNumber = mSensitivePhoneNumbers.isSensitiveNumber(mContext, number,
                accountHandle.getId());
        Log.d(TAG, "isSensitiveNumber: " + isSensitiveNumber);
        final boolean isOkToLogThisCall = (!isEmergency || okToLogEmergencyNumber) && !isSensitiveNumber;


        sendAddCallBroadcast(callType, duration);
        sendAddCallBroadcast(callType, duration);


+90 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2017 The Android Open Source Project
 * Copyright (C) 2017 The LineageOS 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;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import java.io.IOException;
import java.util.ArrayList;

public class SensitivePhoneNumber {
    private static final String LOG_TAG = "SensitivePhoneNumber";
    private static final String ns = null;

    private String networkNumeric;
    private ArrayList<String> phoneNumbers;

    public SensitivePhoneNumber(String networkNumeric, ArrayList<String> phoneNumbers) {
        this.networkNumeric = networkNumeric;
        this.phoneNumbers = phoneNumbers;
    }

    public String getNetworkNumeric() {
        return networkNumeric;
    }

    public ArrayList<String> getPhoneNumbers() {
        return phoneNumbers;
    }

    public void setNetworkNumeric(String networkNumeric) {
        this.networkNumeric = networkNumeric;
    }

    public void setPhoneNumbers(ArrayList<String> phoneNumbers) {
        this.phoneNumbers = phoneNumbers;
    }

    public void addPhoneNumber(String phoneNumber) {
        this.phoneNumbers.add(phoneNumber);
    }

    public static SensitivePhoneNumber readSensitivePhoneNumbers (XmlPullParser parser)
                throws XmlPullParserException, IOException {
        parser.require(XmlPullParser.START_TAG, ns, "sensitivePN");

        String numeric = parser.getAttributeValue(null, "network");

        ArrayList<String> numbers = null;
        numbers = readPhoneNumber(parser);

        return new SensitivePhoneNumber(numeric, numbers);
    }

    private static ArrayList<String> readPhoneNumber (XmlPullParser parser)
                throws XmlPullParserException, IOException {
        ArrayList<String> numbers = new ArrayList<>();
        while (parser.next() != XmlPullParser.END_TAG) {
            if (parser.getEventType() != XmlPullParser.START_TAG) {
                continue;
            }
            parser.require(XmlPullParser.START_TAG, ns, "item");

            String item = "";
            if (parser.next() == XmlPullParser.TEXT) {
                item = parser.getText();
                parser.nextTag();
            }
            parser.require(XmlPullParser.END_TAG, ns, "item");

            numbers.add(item);
        }
        return numbers;
    }
}
+121 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2017 The Android Open Source Project
 * Copyright (C) 2017 The LineageOS 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;

import android.content.Context;
import android.os.Environment;
import android.telephony.PhoneNumberUtils;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
import android.util.Xml;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;

public class SensitivePhoneNumbers {
    private final String LOG_TAG = this.getClass().getSimpleName();

    public static final String SENSIBLE_PHONENUMBERS_FILE_PATH = "etc/sensitive_pn.xml";
    private static final String ns = null;

    private HashMap<String, ArrayList<String>> mSensitiveNumbersMap = new HashMap<>();

    public SensitivePhoneNumbers() {
        loadSensiblePhoneNumbers();
    }

    private void loadSensiblePhoneNumbers() {
        FileReader sensiblePNReader;

        File sensiblePNFile = new File(Environment.getRootDirectory(),
                SENSIBLE_PHONENUMBERS_FILE_PATH);

        try {
            sensiblePNReader = new FileReader(sensiblePNFile);
        } catch (FileNotFoundException e) {
            Log.w(LOG_TAG, "Can not open " + sensiblePNFile.getAbsolutePath());
            return;
        }

        try {
            XmlPullParser parser = Xml.newPullParser();
            parser.setInput(sensiblePNReader);
            parser.nextTag();

            readSensitivePNS(parser);

            sensiblePNReader.close();
        } catch (IOException | XmlPullParserException e) {
            Log.w(LOG_TAG, "Exception in spn-conf parser", e);
        }
    }

    private void readSensitivePNS(XmlPullParser parser)
                throws XmlPullParserException, IOException {
        parser.require(XmlPullParser.START_TAG, ns, "sensitivePNS");
        while (parser.next() != XmlPullParser.END_TAG) {
            if (parser.getEventType() != XmlPullParser.START_TAG) {
                continue;
            }
            String name = parser.getName();
            if (!"sensitivePN".equals(name)) {
                break;
            }
            SensitivePhoneNumber sensitivePN = SensitivePhoneNumber
                    .readSensitivePhoneNumbers(parser);
            String[] mccs = sensitivePN.getNetworkNumeric().split(",");
            ArrayList<String> sensitive_nums = sensitivePN.getPhoneNumbers();
            for (String mcc : mccs) {
                mSensitiveNumbersMap.put(mcc, sensitive_nums);
            }
        }
    }

    public boolean isSensitiveNumber(Context context, String numberToCheck, String subId) {
        TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class);

        int subIdInt = SubscriptionManager.getDefaultSubscriptionId();
        try {
            subIdInt = Integer.valueOf(subId);
        } catch (NumberFormatException e) {
            Log.w(LOG_TAG, "Error parsing subId");
        }

        String networkUsed = telephonyManager.getNetworkOperator(subIdInt);
        if (!TextUtils.isEmpty(networkUsed)) {
            String networkMCC = networkUsed.substring(0, 3);
            if (mSensitiveNumbersMap.containsKey(networkMCC)) {
                for (String num : mSensitiveNumbersMap.get(networkMCC)) {
                    if (PhoneNumberUtils.compare(numberToCheck, num)) {
                        return true;
                    }
                }
            }
        }
        return false;
    }
}
+50 −0
Original line number Original line Diff line number Diff line
@@ -27,6 +27,7 @@ import android.location.Country;
import android.location.CountryDetector;
import android.location.CountryDetector;
import android.location.CountryListener;
import android.location.CountryListener;
import android.net.Uri;
import android.net.Uri;
import android.os.Environment;
import android.os.Looper;
import android.os.Looper;
import android.os.PersistableBundle;
import android.os.PersistableBundle;
import android.os.UserHandle;
import android.os.UserHandle;
@@ -40,15 +41,18 @@ import android.telecom.PhoneAccountHandle;
import android.telecom.VideoProfile;
import android.telecom.VideoProfile;
import android.telephony.CarrierConfigManager;
import android.telephony.CarrierConfigManager;
import android.telephony.PhoneNumberUtils;
import android.telephony.PhoneNumberUtils;
import android.telephony.TelephonyManager;
import android.test.suitebuilder.annotation.MediumTest;
import android.test.suitebuilder.annotation.MediumTest;
import android.test.suitebuilder.annotation.SmallTest;
import android.test.suitebuilder.annotation.SmallTest;


import com.android.server.telecom.Call;
import com.android.server.telecom.Call;
import com.android.server.telecom.CallLogManager;
import com.android.server.telecom.CallLogManager;
import com.android.server.telecom.CallState;
import com.android.server.telecom.CallState;
import com.android.server.telecom.CallsManager;
import com.android.server.telecom.HandoverState;
import com.android.server.telecom.HandoverState;
import com.android.server.telecom.MissedCallNotifier;
import com.android.server.telecom.MissedCallNotifier;
import com.android.server.telecom.PhoneAccountRegistrar;
import com.android.server.telecom.PhoneAccountRegistrar;
import com.android.server.telecom.SensitivePhoneNumbers;
import com.android.server.telecom.TelephonyUtil;
import com.android.server.telecom.TelephonyUtil;


import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertEquals;
@@ -61,6 +65,7 @@ import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.when;
@@ -71,9 +76,11 @@ import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.junit.runners.JUnit4;
import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.mockito.stubbing.Answer;


import java.io.File;
import java.util.Arrays;
import java.util.Arrays;


@RunWith(JUnit4.class)
@RunWith(JUnit4.class)
@@ -87,6 +94,7 @@ public class CallLogManagerTest extends TelecomTestCase {
    private PhoneAccountHandle mSelfManagedAccountHandle;
    private PhoneAccountHandle mSelfManagedAccountHandle;


    private static final Uri TEL_PHONEHANDLE = Uri.parse("tel:5555551234");
    private static final Uri TEL_PHONEHANDLE = Uri.parse("tel:5555551234");
    private static final Uri TEL_SENSITIVE_PHONEHANDLE = Uri.parse("tel:016");


    private static final PhoneAccountHandle EMERGENCY_ACCT_HANDLE = TelephonyUtil
    private static final PhoneAccountHandle EMERGENCY_ACCT_HANDLE = TelephonyUtil
            .getDefaultEmergencyPhoneAccount()
            .getDefaultEmergencyPhoneAccount()
@@ -243,6 +251,33 @@ public class CallLogManagerTest extends TelecomTestCase {
        verifyNoInsertion();
        verifyNoInsertion();
    }
    }


    @MediumTest
    @Test
    public void testDontLogCallsToSensitivePhoneNumber() {
        when(mMockPhoneAccountRegistrar.getPhoneAccountUnchecked(any(PhoneAccountHandle.class)))
                .thenReturn(makeFakePhoneAccount(mDefaultAccountHandle, CURRENT_USER_ID));

        TelephonyManager mockTelephonyManager =
                (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
        when(mockTelephonyManager.getNetworkOperator(Mockito.anyInt())).thenReturn("21407");

        Call fakeCall = makeFakeCall(
                DisconnectCause.OTHER, // disconnectCauseCode
                false, // isConference
                false, // isIncoming
                1L, // creationTimeMillis
                1000L, // ageMillis
                TEL_SENSITIVE_PHONEHANDLE, // callHandle
                mDefaultAccountHandle, // phoneAccountHandle
                NO_VIDEO_STATE, // callVideoState
                POST_DIAL_STRING, // postDialDigits
                VIA_NUMBER_STRING, // viaNumber
                UserHandle.of(CURRENT_USER_ID)
        );
        mCallLogManager.onCallStateChanged(fakeCall, CallState.ACTIVE, CallState.DISCONNECTED);
        verifyNoInsertionIfFileExists();
    }

    @MediumTest
    @MediumTest
    @Test
    @Test
    public void testLogCallDirectionOutgoing() {
    public void testLogCallDirectionOutgoing() {
@@ -747,6 +782,21 @@ public class CallLogManagerTest extends TelecomTestCase {
        }
        }
    }
    }


    private void verifyNoInsertionIfFileExists() {
        File sensiblePNFile = new File(Environment.getRootDirectory(),
                SensitivePhoneNumbers.SENSIBLE_PHONENUMBERS_FILE_PATH);
        try {
            Thread.sleep(TEST_TIMEOUT_MILLIS);
            verify(mContentProvider,
                    sensiblePNFile.exists() ? never() : atLeastOnce()).insert(any(String.class),
                    any(Uri.class), any(ContentValues.class));
        } catch (android.os.RemoteException e) {
            fail("Remote exception occurred during test execution");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }



    private void verifyNoInsertionInUser(int userId) {
    private void verifyNoInsertionInUser(int userId) {
        try {
        try {