Compare commits
1 commit
Author | SHA1 | Date | |
---|---|---|---|
d6190b1e0f |
7 changed files with 272 additions and 0 deletions
19
lib/Android.bp
Normal file
19
lib/Android.bp
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
//
|
||||||
|
// SPDX-FileCopyrightText: 2019 The LineageOS Project
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
//
|
||||||
|
|
||||||
|
lineage_sdk_lib_src = "src/java/org/lineageos/lib/"
|
||||||
|
|
||||||
|
java_library {
|
||||||
|
name: "org.lineageos.lib.phone",
|
||||||
|
sdk_version: "current",
|
||||||
|
static_libs: [
|
||||||
|
"libphonenumber",
|
||||||
|
],
|
||||||
|
|
||||||
|
srcs: [
|
||||||
|
lineage_sdk_lib_src + "/phone/*.java",
|
||||||
|
":spn-info",
|
||||||
|
],
|
||||||
|
}
|
47
lib/SpnInfo.xsd
Normal file
47
lib/SpnInfo.xsd
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ Copyright (C) 2021 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.
|
||||||
|
-->
|
||||||
|
<xs:schema version="2.0"
|
||||||
|
elementFormDefault="qualified"
|
||||||
|
attributeFormDefault="unqualified"
|
||||||
|
xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||||
|
|
||||||
|
<xs:element name="sensitivePNS">
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:sequence>
|
||||||
|
<xs:element name="sensitivePN" maxOccurs="unbounded" type="sensitivePN" />
|
||||||
|
</xs:sequence>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
|
||||||
|
<xs:complexType name="sensitivePN">
|
||||||
|
<xs:sequence>
|
||||||
|
<xs:element name="item" maxOccurs="unbounded" type="item" />
|
||||||
|
</xs:sequence>
|
||||||
|
<xs:attribute name="network" type="xs:string" use="required" />
|
||||||
|
</xs:complexType>
|
||||||
|
|
||||||
|
<xs:complexType name="item">
|
||||||
|
<xs:sequence>
|
||||||
|
<xs:element name="number" type="xs:string" />
|
||||||
|
<xs:element name="name" minOccurs="0" type="xs:string" />
|
||||||
|
<xs:element name="categories" minOccurs="0" type="xs:string" />
|
||||||
|
<xs:element name="languages" minOccurs="0" type="xs:string" />
|
||||||
|
<xs:element name="organization" minOccurs="0" type="xs:string" />
|
||||||
|
<xs:element name="website" minOccurs="0" type="xs:anyURI" />
|
||||||
|
</xs:sequence>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:schema>
|
40
lib/schema/current.txt
Normal file
40
lib/schema/current.txt
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
// Signature format: 2.0
|
||||||
|
package org.lineageos.lib.phone.spn {
|
||||||
|
|
||||||
|
public class Item {
|
||||||
|
ctor public Item();
|
||||||
|
method public String getCategories();
|
||||||
|
method public String getLanguages();
|
||||||
|
method public String getName();
|
||||||
|
method public String getNumber();
|
||||||
|
method public String getOrganization();
|
||||||
|
method public String getWebsite();
|
||||||
|
method public void setCategories(String);
|
||||||
|
method public void setLanguages(String);
|
||||||
|
method public void setName(String);
|
||||||
|
method public void setNumber(String);
|
||||||
|
method public void setOrganization(String);
|
||||||
|
method public void setWebsite(String);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SensitivePN {
|
||||||
|
ctor public SensitivePN();
|
||||||
|
method public java.util.List<org.lineageos.lib.phone.spn.Item> getItem();
|
||||||
|
method public String getNetwork();
|
||||||
|
method public void setNetwork(String);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SensitivePNS {
|
||||||
|
ctor public SensitivePNS();
|
||||||
|
method public java.util.List<org.lineageos.lib.phone.spn.SensitivePN> getSensitivePN();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class XmlParser {
|
||||||
|
ctor public XmlParser();
|
||||||
|
method public static org.lineageos.lib.phone.spn.SensitivePNS read(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
|
||||||
|
method public static String readText(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
|
||||||
|
method public static void skip(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
0
lib/schema/last_current.txt
Normal file
0
lib/schema/last_current.txt
Normal file
0
lib/schema/last_removed.txt
Normal file
0
lib/schema/last_removed.txt
Normal file
1
lib/schema/removed.txt
Normal file
1
lib/schema/removed.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
// Signature format: 2.0
|
165
lib/src/java/org/lineageos/lib/phone/SensitivePhoneNumbers.java
Normal file
165
lib/src/java/org/lineageos/lib/phone/SensitivePhoneNumbers.java
Normal file
|
@ -0,0 +1,165 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2017 The Android Open Source Project
|
||||||
|
* SPDX-FileCopyrightText: 2017-2021 The LineageOS Project
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.lineageos.lib.phone;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.telephony.PhoneNumberUtils;
|
||||||
|
import android.telephony.SubscriptionInfo;
|
||||||
|
import android.telephony.SubscriptionManager;
|
||||||
|
import android.telephony.TelephonyManager;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.google.i18n.phonenumbers.NumberParseException;
|
||||||
|
import com.google.i18n.phonenumbers.PhoneNumberUtil;
|
||||||
|
import com.google.i18n.phonenumbers.PhoneNumberUtil.PhoneNumberFormat;
|
||||||
|
import com.google.i18n.phonenumbers.Phonenumber;
|
||||||
|
|
||||||
|
import org.lineageos.lib.phone.spn.Item;
|
||||||
|
import org.lineageos.lib.phone.spn.SensitivePN;
|
||||||
|
import org.lineageos.lib.phone.spn.XmlParser;
|
||||||
|
import org.xmlpull.v1.XmlPullParserException;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.xml.datatype.DatatypeConfigurationException;
|
||||||
|
|
||||||
|
public class SensitivePhoneNumbers {
|
||||||
|
private final String LOG_TAG = this.getClass().getSimpleName();
|
||||||
|
|
||||||
|
public static final String SENSIBLE_PHONENUMBERS_FILE_PATH = "/product/etc/sensitive_pn.xml";
|
||||||
|
private static final String ns = null;
|
||||||
|
|
||||||
|
private static SensitivePhoneNumbers sInstance = null;
|
||||||
|
private static boolean sNumbersLoaded;
|
||||||
|
|
||||||
|
private HashMap<String, ArrayList<Item>> mSensitiveNumbersMap = new HashMap<>();
|
||||||
|
|
||||||
|
private SensitivePhoneNumbers() { }
|
||||||
|
|
||||||
|
public static SensitivePhoneNumbers getInstance() {
|
||||||
|
if (sInstance == null) {
|
||||||
|
sInstance = new SensitivePhoneNumbers();
|
||||||
|
}
|
||||||
|
return sInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadSensiblePhoneNumbers() {
|
||||||
|
if (sNumbersLoaded) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
File sensiblePNFile = new File(SENSIBLE_PHONENUMBERS_FILE_PATH);
|
||||||
|
FileInputStream sensiblePNInputStream;
|
||||||
|
|
||||||
|
try {
|
||||||
|
sensiblePNInputStream = new FileInputStream(sensiblePNFile);
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
Log.w(LOG_TAG, "Can not open " + sensiblePNFile.getAbsolutePath());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
for (SensitivePN sensitivePN : new XmlParser().read(sensiblePNInputStream).getSensitivePN()) {
|
||||||
|
String[] mccs = sensitivePN.getNetwork().split(",");
|
||||||
|
for (String mcc : mccs) {
|
||||||
|
mSensitiveNumbersMap.put(mcc, new ArrayList(sensitivePN.getItem()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (DatatypeConfigurationException | IOException | XmlPullParserException e) {
|
||||||
|
Log.w(LOG_TAG, "Exception in spn-conf parser", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
sNumbersLoaded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArrayList<Item> getSensitivePnInfosForMcc(String mcc) {
|
||||||
|
loadSensiblePhoneNumbers();
|
||||||
|
return mSensitiveNumbersMap.getOrDefault(mcc, new ArrayList<Item>());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSensitiveNumber(Context context, String numberToCheck, int subId) {
|
||||||
|
String nationalNumber = formatNumberToNational(context, numberToCheck);
|
||||||
|
if (TextUtils.isEmpty(nationalNumber)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
loadSensiblePhoneNumbers();
|
||||||
|
|
||||||
|
SubscriptionManager subManager = context.getSystemService(SubscriptionManager.class);
|
||||||
|
List<SubscriptionInfo> list = subManager.getActiveSubscriptionInfoList();
|
||||||
|
if (list != null) {
|
||||||
|
// Test all subscriptions so an accidential use of a wrong sim also hides the number
|
||||||
|
for (SubscriptionInfo subInfo : list) {
|
||||||
|
String mcc = String.valueOf(subInfo.getMcc());
|
||||||
|
if (isSensitiveNumber(nationalNumber, mcc)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fall back to check with the passed subId
|
||||||
|
TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class);
|
||||||
|
if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
|
||||||
|
subId = SubscriptionManager.getDefaultSubscriptionId();
|
||||||
|
}
|
||||||
|
telephonyManager = telephonyManager.createForSubscriptionId(subId);
|
||||||
|
String networkUsed = telephonyManager.getNetworkOperator();
|
||||||
|
if (!TextUtils.isEmpty(networkUsed)) {
|
||||||
|
String networkMCC = networkUsed.substring(0, 3);
|
||||||
|
if (isSensitiveNumber(nationalNumber, networkMCC)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Also try the sim's operator
|
||||||
|
if (telephonyManager.getSimState() == TelephonyManager.SIM_STATE_READY) {
|
||||||
|
String simOperator = telephonyManager.getSimOperator();
|
||||||
|
if (!TextUtils.isEmpty(simOperator)) {
|
||||||
|
String networkMCC = simOperator.substring(0, 3);
|
||||||
|
if (isSensitiveNumber(nationalNumber, networkMCC)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isSensitiveNumber(String numberToCheck, String mcc) {
|
||||||
|
if (mSensitiveNumbersMap.containsKey(mcc)) {
|
||||||
|
for (Item item : mSensitiveNumbersMap.get(mcc)) {
|
||||||
|
if (PhoneNumberUtils.compare(numberToCheck, item.getNumber())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String formatNumberToNational(Context context, String number) {
|
||||||
|
PhoneNumberUtil util = PhoneNumberUtil.getInstance();
|
||||||
|
String countryIso = context.getResources().getConfiguration().locale.getCountry();
|
||||||
|
|
||||||
|
Phonenumber.PhoneNumber pn = null;
|
||||||
|
try {
|
||||||
|
pn = util.parse(number, countryIso);
|
||||||
|
} catch (NumberParseException e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pn != null) {
|
||||||
|
return util.format(pn, PhoneNumberFormat.NATIONAL);
|
||||||
|
} else {
|
||||||
|
return number;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue