10825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville/* 20825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Copyright (C) 2011 The Android Open Source Project 30825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * 40825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Licensed under the Apache License, Version 2.0 (the "License"); 50825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * you may not use this file except in compliance with the License. 60825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * You may obtain a copy of the License at 70825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * 80825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * http://www.apache.org/licenses/LICENSE-2.0 90825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * 100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Unless required by applicable law or agreed to in writing, software 110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * distributed under the License is distributed on an "AS IS" BASIS, 120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * See the License for the specific language governing permissions and 140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * limitations under the License. 150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */ 160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 170825495a331bb44df395a0cdb79fab85e68db5d5Wink Savillepackage com.android.internal.telephony; 180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 194658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport android.app.AppGlobals; 200825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.ContentResolver; 210825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.Context; 224658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport android.content.pm.ApplicationInfo; 230825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.res.XmlResourceParser; 240825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.database.ContentObserver; 254658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport android.os.Binder; 260825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.os.Handler; 274658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport android.os.Process; 284658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport android.os.RemoteException; 294658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport android.os.UserHandle; 300825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.provider.Settings; 310825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.telephony.PhoneNumberUtils; 324658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport android.util.AtomicFile; 3399c2e1d6749cfad2a8ca94a47857d8c3bfc09454Wink Savilleimport android.telephony.Rlog; 344658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport android.util.Xml; 350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 364658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport com.android.internal.util.FastXmlSerializer; 370825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.internal.util.XmlUtils; 380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 390825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport org.xmlpull.v1.XmlPullParser; 400825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport org.xmlpull.v1.XmlPullParserException; 414658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport org.xmlpull.v1.XmlSerializer; 420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 434658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport java.io.File; 444658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport java.io.FileInputStream; 454658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport java.io.FileNotFoundException; 464658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport java.io.FileOutputStream; 47a7700794b7fbe667e87d72d3117ae3a4d2501313Robert Greenwaltimport java.io.FileReader; 480825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.io.IOException; 49bfda9080cab9a819fc48bdb97ef70911016a0f21Wojciech Staszkiewiczimport java.nio.charset.StandardCharsets; 500825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.util.ArrayList; 51a7700794b7fbe667e87d72d3117ae3a4d2501313Robert Greenwaltimport java.util.concurrent.atomic.AtomicBoolean; 520825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.util.HashMap; 530825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.util.Iterator; 540825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.util.Map; 550825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.util.regex.Pattern; 560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville/** 580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Implement the per-application based SMS control, which limits the number of 590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * SMS/MMS messages an app can send in the checking period. 600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * 610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * This code was formerly part of {@link SMSDispatcher}, and has been moved 620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * into a separate class to support instantiation of multiple SMSDispatchers on 630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * dual-mode devices that require support for both 3GPP and 3GPP2 format messages. 640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */ 650825495a331bb44df395a0cdb79fab85e68db5d5Wink Savillepublic class SmsUsageMonitor { 660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private static final String TAG = "SmsUsageMonitor"; 67a7700794b7fbe667e87d72d3117ae3a4d2501313Robert Greenwalt private static final boolean DBG = false; 680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private static final boolean VDBG = false; 690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 70a7700794b7fbe667e87d72d3117ae3a4d2501313Robert Greenwalt private static final String SHORT_CODE_PATH = "/data/misc/sms/codes"; 71a7700794b7fbe667e87d72d3117ae3a4d2501313Robert Greenwalt 720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** Default checking period for SMS sent without user permission. */ 73e7fd4f7253d22528de63bb3f0fa1f9f9ca879a86Jake Hamby private static final int DEFAULT_SMS_CHECK_PERIOD = 60000; // 1 minute 740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** Default number of SMS sent in checking period without user permission. */ 760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private static final int DEFAULT_SMS_MAX_COUNT = 30; 770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** Return value from {@link #checkDestination} for regular phone numbers. */ 790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville static final int CATEGORY_NOT_SHORT_CODE = 0; 800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** Return value from {@link #checkDestination} for free (no cost) short codes. */ 820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville static final int CATEGORY_FREE_SHORT_CODE = 1; 830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** Return value from {@link #checkDestination} for standard rate (non-premium) short codes. */ 850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville static final int CATEGORY_STANDARD_SHORT_CODE = 2; 860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** Return value from {@link #checkDestination} for possible premium short codes. */ 880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville static final int CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE = 3; 890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** Return value from {@link #checkDestination} for premium short codes. */ 910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville static final int CATEGORY_PREMIUM_SHORT_CODE = 4; 920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 93ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt /** @hide */ 94ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt public static int mergeShortCodeCategories(int type1, int type2) { 95ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt if (type1 > type2) return type1; 96ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt return type2; 97ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt } 98ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt 994658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby /** Premium SMS permission for a new package (ask user when first premium SMS sent). */ 1004658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby public static final int PREMIUM_SMS_PERMISSION_UNKNOWN = 0; 1014658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 1024658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby /** Default premium SMS permission (ask user for each premium SMS sent). */ 1034658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby public static final int PREMIUM_SMS_PERMISSION_ASK_USER = 1; 1044658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 1054658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby /** Premium SMS permission when the owner has denied the app from sending premium SMS. */ 1064658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby public static final int PREMIUM_SMS_PERMISSION_NEVER_ALLOW = 2; 1074658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 1084658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby /** Premium SMS permission when the owner has allowed the app to send premium SMS. */ 1094658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby public static final int PREMIUM_SMS_PERMISSION_ALWAYS_ALLOW = 3; 1104658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 1110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private final int mCheckPeriod; 1120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private final int mMaxAllowed; 1130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 1140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private final HashMap<String, ArrayList<Long>> mSmsStamp = 1150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville new HashMap<String, ArrayList<Long>>(); 1160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 1170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** Context for retrieving regexes from XML resource. */ 1180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private final Context mContext; 1190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 1200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** Country code for the cached short code pattern matcher. */ 1210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private String mCurrentCountry; 1220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 1230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** Cached short code pattern matcher for {@link #mCurrentCountry}. */ 1240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private ShortCodePatternMatcher mCurrentPatternMatcher; 1250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 126a7700794b7fbe667e87d72d3117ae3a4d2501313Robert Greenwalt /** Notice when the enabled setting changes - can be changed through gservices */ 127a7700794b7fbe667e87d72d3117ae3a4d2501313Robert Greenwalt private final AtomicBoolean mCheckEnabled = new AtomicBoolean(true); 128a7700794b7fbe667e87d72d3117ae3a4d2501313Robert Greenwalt 1290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** Handler for responding to content observer updates. */ 1300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private final SettingsObserverHandler mSettingsObserverHandler; 1310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 132a7700794b7fbe667e87d72d3117ae3a4d2501313Robert Greenwalt /** File holding the patterns */ 133a7700794b7fbe667e87d72d3117ae3a4d2501313Robert Greenwalt private final File mPatternFile = new File(SHORT_CODE_PATH); 134a7700794b7fbe667e87d72d3117ae3a4d2501313Robert Greenwalt 135a7700794b7fbe667e87d72d3117ae3a4d2501313Robert Greenwalt /** Last modified time for pattern file */ 136a7700794b7fbe667e87d72d3117ae3a4d2501313Robert Greenwalt private long mPatternFileLastModified = 0; 1374658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 1384658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby /** Directory for per-app SMS permission XML file. */ 13958c8356d4b119d4e9c0b6fe73526f4daca1112ecRobert Greenwalt private static final String SMS_POLICY_FILE_DIRECTORY = "/data/misc/sms"; 1404658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 1414658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby /** Per-app SMS permission XML filename. */ 1424658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby private static final String SMS_POLICY_FILE_NAME = "premium_sms_policy.xml"; 1434658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 1440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** XML tag for root element. */ 1450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private static final String TAG_SHORTCODES = "shortcodes"; 1460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 1470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** XML tag for short code patterns for a specific country. */ 1480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private static final String TAG_SHORTCODE = "shortcode"; 1490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 1500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** XML attribute for the country code. */ 1510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private static final String ATTR_COUNTRY = "country"; 1520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 1530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** XML attribute for the short code regex pattern. */ 1540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private static final String ATTR_PATTERN = "pattern"; 1550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 1560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** XML attribute for the premium short code regex pattern. */ 1570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private static final String ATTR_PREMIUM = "premium"; 1580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 1590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** XML attribute for the free short code regex pattern. */ 1600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private static final String ATTR_FREE = "free"; 1610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 1620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** XML attribute for the standard rate short code regex pattern. */ 1630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private static final String ATTR_STANDARD = "standard"; 1640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 1654658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby /** Stored copy of premium SMS package permissions. */ 1664658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby private AtomicFile mPolicyFile; 1674658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 1684658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby /** Loaded copy of premium SMS package permissions. */ 1694658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby private final HashMap<String, Integer> mPremiumSmsPolicy = new HashMap<String, Integer>(); 1704658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 1714658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby /** XML tag for root element of premium SMS permissions. */ 1724658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby private static final String TAG_SMS_POLICY_BODY = "premium-sms-policy"; 1734658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 1744658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby /** XML tag for a package. */ 1754658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby private static final String TAG_PACKAGE = "package"; 1764658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 1774658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby /** XML attribute for the package name. */ 1784658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby private static final String ATTR_PACKAGE_NAME = "name"; 1794658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 1804658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby /** XML attribute for the package's premium SMS permission (integer type). */ 1814658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby private static final String ATTR_PACKAGE_SMS_POLICY = "sms-policy"; 1824658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 1830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** 1840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * SMS short code regex pattern matcher for a specific country. 1850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */ 1860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private static final class ShortCodePatternMatcher { 1870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private final Pattern mShortCodePattern; 1880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private final Pattern mPremiumShortCodePattern; 1890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private final Pattern mFreeShortCodePattern; 1900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private final Pattern mStandardShortCodePattern; 1910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 1920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville ShortCodePatternMatcher(String shortCodeRegex, String premiumShortCodeRegex, 1930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville String freeShortCodeRegex, String standardShortCodeRegex) { 1940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville mShortCodePattern = (shortCodeRegex != null ? Pattern.compile(shortCodeRegex) : null); 1950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville mPremiumShortCodePattern = (premiumShortCodeRegex != null ? 1960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville Pattern.compile(premiumShortCodeRegex) : null); 1970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville mFreeShortCodePattern = (freeShortCodeRegex != null ? 1980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville Pattern.compile(freeShortCodeRegex) : null); 1990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville mStandardShortCodePattern = (standardShortCodeRegex != null ? 2000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville Pattern.compile(standardShortCodeRegex) : null); 2010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 2020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 2030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville int getNumberCategory(String phoneNumber) { 2040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (mFreeShortCodePattern != null && mFreeShortCodePattern.matcher(phoneNumber) 2050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville .matches()) { 2060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return CATEGORY_FREE_SHORT_CODE; 2070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 2080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (mStandardShortCodePattern != null && mStandardShortCodePattern.matcher(phoneNumber) 2090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville .matches()) { 2100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return CATEGORY_STANDARD_SHORT_CODE; 2110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 2120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (mPremiumShortCodePattern != null && mPremiumShortCodePattern.matcher(phoneNumber) 2130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville .matches()) { 2140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return CATEGORY_PREMIUM_SHORT_CODE; 2150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 2160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (mShortCodePattern != null && mShortCodePattern.matcher(phoneNumber).matches()) { 2170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE; 2180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 2190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return CATEGORY_NOT_SHORT_CODE; 2200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 2210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 2220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 2230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** 224a7700794b7fbe667e87d72d3117ae3a4d2501313Robert Greenwalt * Observe the secure setting for enable flag 2250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */ 2260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private static class SettingsObserver extends ContentObserver { 227a7700794b7fbe667e87d72d3117ae3a4d2501313Robert Greenwalt private final Context mContext; 228a7700794b7fbe667e87d72d3117ae3a4d2501313Robert Greenwalt private final AtomicBoolean mEnabled; 2290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 230a7700794b7fbe667e87d72d3117ae3a4d2501313Robert Greenwalt SettingsObserver(Handler handler, Context context, AtomicBoolean enabled) { 2310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville super(handler); 232a7700794b7fbe667e87d72d3117ae3a4d2501313Robert Greenwalt mContext = context; 233a7700794b7fbe667e87d72d3117ae3a4d2501313Robert Greenwalt mEnabled = enabled; 234a7700794b7fbe667e87d72d3117ae3a4d2501313Robert Greenwalt onChange(false); 2350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 2360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 2370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville @Override 2380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville public void onChange(boolean selfChange) { 239a7700794b7fbe667e87d72d3117ae3a4d2501313Robert Greenwalt mEnabled.set(Settings.Global.getInt(mContext.getContentResolver(), 240a7700794b7fbe667e87d72d3117ae3a4d2501313Robert Greenwalt Settings.Global.SMS_SHORT_CODE_CONFIRMATION, 1) != 0); 2410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 2420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 2430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 244a7700794b7fbe667e87d72d3117ae3a4d2501313Robert Greenwalt private static class SettingsObserverHandler extends Handler { 245a7700794b7fbe667e87d72d3117ae3a4d2501313Robert Greenwalt SettingsObserverHandler(Context context, AtomicBoolean enabled) { 246a7700794b7fbe667e87d72d3117ae3a4d2501313Robert Greenwalt ContentResolver resolver = context.getContentResolver(); 247a7700794b7fbe667e87d72d3117ae3a4d2501313Robert Greenwalt ContentObserver globalObserver = new SettingsObserver(this, context, enabled); 2484658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby resolver.registerContentObserver(Settings.Global.getUriFor( 2494658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby Settings.Global.SMS_SHORT_CODE_CONFIRMATION), false, globalObserver); 2504658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } 2510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 2520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 2530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** 2540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Create SMS usage monitor. 2550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @param context the context to use to load resources and get TelephonyManager service 2560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */ 2570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville public SmsUsageMonitor(Context context) { 2580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville mContext = context; 2590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville ContentResolver resolver = context.getContentResolver(); 2600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 2614658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby mMaxAllowed = Settings.Global.getInt(resolver, 2624658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby Settings.Global.SMS_OUTGOING_CHECK_MAX_COUNT, 2630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville DEFAULT_SMS_MAX_COUNT); 2640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 2654658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby mCheckPeriod = Settings.Global.getInt(resolver, 2664658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby Settings.Global.SMS_OUTGOING_CHECK_INTERVAL_MS, 2670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville DEFAULT_SMS_CHECK_PERIOD); 2680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 269a7700794b7fbe667e87d72d3117ae3a4d2501313Robert Greenwalt mSettingsObserverHandler = new SettingsObserverHandler(mContext, mCheckEnabled); 2704658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 2714658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby loadPremiumSmsPolicyDb(); 2720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 2730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 2740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** 2750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Return a pattern matcher object for the specified country. 2760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @param country the country to search for 2770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @return a {@link ShortCodePatternMatcher} for the specified country, or null if not found 2780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */ 279a7700794b7fbe667e87d72d3117ae3a4d2501313Robert Greenwalt private ShortCodePatternMatcher getPatternMatcherFromFile(String country) { 280a7700794b7fbe667e87d72d3117ae3a4d2501313Robert Greenwalt FileReader patternReader = null; 281a7700794b7fbe667e87d72d3117ae3a4d2501313Robert Greenwalt XmlPullParser parser = null; 2820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville try { 283a7700794b7fbe667e87d72d3117ae3a4d2501313Robert Greenwalt patternReader = new FileReader(mPatternFile); 284a7700794b7fbe667e87d72d3117ae3a4d2501313Robert Greenwalt parser = Xml.newPullParser(); 285a7700794b7fbe667e87d72d3117ae3a4d2501313Robert Greenwalt parser.setInput(patternReader); 28681ddb888952763b5eb7a4a38fb293fc86b897968Robert Greenwalt return getPatternMatcherFromXmlParser(parser, country); 28781ddb888952763b5eb7a4a38fb293fc86b897968Robert Greenwalt } catch (FileNotFoundException e) { 28899c2e1d6749cfad2a8ca94a47857d8c3bfc09454Wink Saville Rlog.e(TAG, "Short Code Pattern File not found"); 28981ddb888952763b5eb7a4a38fb293fc86b897968Robert Greenwalt } catch (XmlPullParserException e) { 29099c2e1d6749cfad2a8ca94a47857d8c3bfc09454Wink Saville Rlog.e(TAG, "XML parser exception reading short code pattern file", e); 29181ddb888952763b5eb7a4a38fb293fc86b897968Robert Greenwalt } finally { 29281ddb888952763b5eb7a4a38fb293fc86b897968Robert Greenwalt mPatternFileLastModified = mPatternFile.lastModified(); 29381ddb888952763b5eb7a4a38fb293fc86b897968Robert Greenwalt if (patternReader != null) { 29481ddb888952763b5eb7a4a38fb293fc86b897968Robert Greenwalt try { 29581ddb888952763b5eb7a4a38fb293fc86b897968Robert Greenwalt patternReader.close(); 29681ddb888952763b5eb7a4a38fb293fc86b897968Robert Greenwalt } catch (IOException e) {} 29781ddb888952763b5eb7a4a38fb293fc86b897968Robert Greenwalt } 29881ddb888952763b5eb7a4a38fb293fc86b897968Robert Greenwalt } 29981ddb888952763b5eb7a4a38fb293fc86b897968Robert Greenwalt return null; 30081ddb888952763b5eb7a4a38fb293fc86b897968Robert Greenwalt } 30181ddb888952763b5eb7a4a38fb293fc86b897968Robert Greenwalt 30281ddb888952763b5eb7a4a38fb293fc86b897968Robert Greenwalt private ShortCodePatternMatcher getPatternMatcherFromResource(String country) { 30381ddb888952763b5eb7a4a38fb293fc86b897968Robert Greenwalt int id = com.android.internal.R.xml.sms_short_codes; 30481ddb888952763b5eb7a4a38fb293fc86b897968Robert Greenwalt XmlResourceParser parser = null; 30581ddb888952763b5eb7a4a38fb293fc86b897968Robert Greenwalt try { 30681ddb888952763b5eb7a4a38fb293fc86b897968Robert Greenwalt parser = mContext.getResources().getXml(id); 30781ddb888952763b5eb7a4a38fb293fc86b897968Robert Greenwalt return getPatternMatcherFromXmlParser(parser, country); 30881ddb888952763b5eb7a4a38fb293fc86b897968Robert Greenwalt } finally { 30981ddb888952763b5eb7a4a38fb293fc86b897968Robert Greenwalt if (parser != null) parser.close(); 31081ddb888952763b5eb7a4a38fb293fc86b897968Robert Greenwalt } 31181ddb888952763b5eb7a4a38fb293fc86b897968Robert Greenwalt } 31281ddb888952763b5eb7a4a38fb293fc86b897968Robert Greenwalt 31381ddb888952763b5eb7a4a38fb293fc86b897968Robert Greenwalt private ShortCodePatternMatcher getPatternMatcherFromXmlParser(XmlPullParser parser, 31481ddb888952763b5eb7a4a38fb293fc86b897968Robert Greenwalt String country) { 31581ddb888952763b5eb7a4a38fb293fc86b897968Robert Greenwalt try { 316a7700794b7fbe667e87d72d3117ae3a4d2501313Robert Greenwalt XmlUtils.beginDocument(parser, TAG_SHORTCODES); 317a7700794b7fbe667e87d72d3117ae3a4d2501313Robert Greenwalt 318a7700794b7fbe667e87d72d3117ae3a4d2501313Robert Greenwalt while (true) { 319a7700794b7fbe667e87d72d3117ae3a4d2501313Robert Greenwalt XmlUtils.nextElement(parser); 320a7700794b7fbe667e87d72d3117ae3a4d2501313Robert Greenwalt String element = parser.getName(); 32110270d2586e2d940dea23b19f6ad733f702609beRobert Greenwalt if (element == null) { 32299c2e1d6749cfad2a8ca94a47857d8c3bfc09454Wink Saville Rlog.e(TAG, "Parsing pattern data found null"); 32310270d2586e2d940dea23b19f6ad733f702609beRobert Greenwalt break; 32410270d2586e2d940dea23b19f6ad733f702609beRobert Greenwalt } 325a7700794b7fbe667e87d72d3117ae3a4d2501313Robert Greenwalt 326a7700794b7fbe667e87d72d3117ae3a4d2501313Robert Greenwalt if (element.equals(TAG_SHORTCODE)) { 327a7700794b7fbe667e87d72d3117ae3a4d2501313Robert Greenwalt String currentCountry = parser.getAttributeValue(null, ATTR_COUNTRY); 32899c2e1d6749cfad2a8ca94a47857d8c3bfc09454Wink Saville if (VDBG) Rlog.d(TAG, "Found country " + currentCountry); 329a7700794b7fbe667e87d72d3117ae3a4d2501313Robert Greenwalt if (country.equals(currentCountry)) { 330a7700794b7fbe667e87d72d3117ae3a4d2501313Robert Greenwalt String pattern = parser.getAttributeValue(null, ATTR_PATTERN); 331a7700794b7fbe667e87d72d3117ae3a4d2501313Robert Greenwalt String premium = parser.getAttributeValue(null, ATTR_PREMIUM); 332a7700794b7fbe667e87d72d3117ae3a4d2501313Robert Greenwalt String free = parser.getAttributeValue(null, ATTR_FREE); 333a7700794b7fbe667e87d72d3117ae3a4d2501313Robert Greenwalt String standard = parser.getAttributeValue(null, ATTR_STANDARD); 334a7700794b7fbe667e87d72d3117ae3a4d2501313Robert Greenwalt return new ShortCodePatternMatcher(pattern, premium, free, standard); 335a7700794b7fbe667e87d72d3117ae3a4d2501313Robert Greenwalt } 336a7700794b7fbe667e87d72d3117ae3a4d2501313Robert Greenwalt } else { 33799c2e1d6749cfad2a8ca94a47857d8c3bfc09454Wink Saville Rlog.e(TAG, "Error: skipping unknown XML tag " + element); 338a7700794b7fbe667e87d72d3117ae3a4d2501313Robert Greenwalt } 339a7700794b7fbe667e87d72d3117ae3a4d2501313Robert Greenwalt } 3400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } catch (XmlPullParserException e) { 34199c2e1d6749cfad2a8ca94a47857d8c3bfc09454Wink Saville Rlog.e(TAG, "XML parser exception reading short code patterns", e); 3420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } catch (IOException e) { 34399c2e1d6749cfad2a8ca94a47857d8c3bfc09454Wink Saville Rlog.e(TAG, "I/O exception reading short code patterns", e); 3440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 34599c2e1d6749cfad2a8ca94a47857d8c3bfc09454Wink Saville if (DBG) Rlog.d(TAG, "Country (" + country + ") not found"); 3460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return null; // country not found 3470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 3480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 3490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** Clear the SMS application list for disposal. */ 3500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville void dispose() { 3510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville mSmsStamp.clear(); 3520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 3530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 3540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** 3550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Check to see if an application is allowed to send new SMS messages, and confirm with 3560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * user if the send limit was reached or if a non-system app is potentially sending to a 3570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * premium SMS short code or number. 3580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * 3590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @param appName the package name of the app requesting to send an SMS 3600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @param smsWaiting the number of new messages desired to send 3610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @return true if application is allowed to send the requested number 3620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * of new sms messages 3630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */ 3640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville public boolean check(String appName, int smsWaiting) { 3650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville synchronized (mSmsStamp) { 3660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville removeExpiredTimestamps(); 3670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 3680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville ArrayList<Long> sentList = mSmsStamp.get(appName); 3690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (sentList == null) { 3700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville sentList = new ArrayList<Long>(); 3710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville mSmsStamp.put(appName, sentList); 3720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 3730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 3740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return isUnderLimit(sentList, smsWaiting); 3750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 3760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 3770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 3780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** 3790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Check if the destination is a possible premium short code. 3800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * NOTE: the caller is expected to strip non-digits from the destination number with 3810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * {@link PhoneNumberUtils#extractNetworkPortion} before calling this method. 3820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * This happens in {@link SMSDispatcher#sendRawPdu} so that we use the same phone number 3830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * for testing and in the user confirmation dialog if the user needs to confirm the number. 3840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * This makes it difficult for malware to fool the user or the short code pattern matcher 3850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * by using non-ASCII characters to make the number appear to be different from the real 3860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * destination phone number. 3870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * 3880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @param destAddress the destination address to test for possible short code 3890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @return {@link #CATEGORY_NOT_SHORT_CODE}, {@link #CATEGORY_FREE_SHORT_CODE}, 3900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * {@link #CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE}, or {@link #CATEGORY_PREMIUM_SHORT_CODE}. 3910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */ 3920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville public int checkDestination(String destAddress, String countryIso) { 3930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville synchronized (mSettingsObserverHandler) { 3940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // always allow emergency numbers 3950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (PhoneNumberUtils.isEmergencyNumber(destAddress, countryIso)) { 39699c2e1d6749cfad2a8ca94a47857d8c3bfc09454Wink Saville if (DBG) Rlog.d(TAG, "isEmergencyNumber"); 3970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return CATEGORY_NOT_SHORT_CODE; 3980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 3994658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby // always allow if the feature is disabled 400a7700794b7fbe667e87d72d3117ae3a4d2501313Robert Greenwalt if (!mCheckEnabled.get()) { 40199c2e1d6749cfad2a8ca94a47857d8c3bfc09454Wink Saville if (DBG) Rlog.e(TAG, "check disabled"); 4024658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby return CATEGORY_NOT_SHORT_CODE; 4034658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } 4040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 4050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (countryIso != null) { 406a7700794b7fbe667e87d72d3117ae3a4d2501313Robert Greenwalt if (mCurrentCountry == null || !countryIso.equals(mCurrentCountry) || 407a7700794b7fbe667e87d72d3117ae3a4d2501313Robert Greenwalt mPatternFile.lastModified() != mPatternFileLastModified) { 40881ddb888952763b5eb7a4a38fb293fc86b897968Robert Greenwalt if (mPatternFile.exists()) { 40999c2e1d6749cfad2a8ca94a47857d8c3bfc09454Wink Saville if (DBG) Rlog.d(TAG, "Loading SMS Short Code patterns from file"); 41010270d2586e2d940dea23b19f6ad733f702609beRobert Greenwalt mCurrentPatternMatcher = getPatternMatcherFromFile(countryIso); 41181ddb888952763b5eb7a4a38fb293fc86b897968Robert Greenwalt } else { 41299c2e1d6749cfad2a8ca94a47857d8c3bfc09454Wink Saville if (DBG) Rlog.d(TAG, "Loading SMS Short Code patterns from resource"); 41310270d2586e2d940dea23b19f6ad733f702609beRobert Greenwalt mCurrentPatternMatcher = getPatternMatcherFromResource(countryIso); 41481ddb888952763b5eb7a4a38fb293fc86b897968Robert Greenwalt } 4150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville mCurrentCountry = countryIso; 4160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 4170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 4180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 41910270d2586e2d940dea23b19f6ad733f702609beRobert Greenwalt if (mCurrentPatternMatcher != null) { 42010270d2586e2d940dea23b19f6ad733f702609beRobert Greenwalt return mCurrentPatternMatcher.getNumberCategory(destAddress); 4210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } else { 4220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // Generic rule: numbers of 5 digits or less are considered potential short codes 42399c2e1d6749cfad2a8ca94a47857d8c3bfc09454Wink Saville Rlog.e(TAG, "No patterns for \"" + countryIso + "\": using generic short code rule"); 4240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (destAddress.length() <= 5) { 4250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE; 4260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } else { 4270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return CATEGORY_NOT_SHORT_CODE; 4280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 4290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 4300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 4310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 4320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 4330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** 4344658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby * Load the premium SMS policy from an XML file. 4354658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby * Based on code from NotificationManagerService. 4364658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby */ 4374658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby private void loadPremiumSmsPolicyDb() { 4384658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby synchronized (mPremiumSmsPolicy) { 4394658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby if (mPolicyFile == null) { 4404658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby File dir = new File(SMS_POLICY_FILE_DIRECTORY); 4414658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby mPolicyFile = new AtomicFile(new File(dir, SMS_POLICY_FILE_NAME)); 4424658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 4434658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby mPremiumSmsPolicy.clear(); 4444658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 4454658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby FileInputStream infile = null; 4464658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby try { 4474658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby infile = mPolicyFile.openRead(); 4484658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby final XmlPullParser parser = Xml.newPullParser(); 449bfda9080cab9a819fc48bdb97ef70911016a0f21Wojciech Staszkiewicz parser.setInput(infile, StandardCharsets.UTF_8.name()); 4504658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 4514658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby XmlUtils.beginDocument(parser, TAG_SMS_POLICY_BODY); 4524658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 4534658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby while (true) { 4544658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby XmlUtils.nextElement(parser); 4554658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 4564658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby String element = parser.getName(); 4574658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby if (element == null) break; 4584658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 4594658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby if (element.equals(TAG_PACKAGE)) { 4604658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby String packageName = parser.getAttributeValue(null, ATTR_PACKAGE_NAME); 4614658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby String policy = parser.getAttributeValue(null, ATTR_PACKAGE_SMS_POLICY); 4624658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby if (packageName == null) { 46399c2e1d6749cfad2a8ca94a47857d8c3bfc09454Wink Saville Rlog.e(TAG, "Error: missing package name attribute"); 4644658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } else if (policy == null) { 46599c2e1d6749cfad2a8ca94a47857d8c3bfc09454Wink Saville Rlog.e(TAG, "Error: missing package policy attribute"); 4664658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } else try { 4674658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby mPremiumSmsPolicy.put(packageName, Integer.parseInt(policy)); 4684658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } catch (NumberFormatException e) { 46999c2e1d6749cfad2a8ca94a47857d8c3bfc09454Wink Saville Rlog.e(TAG, "Error: non-numeric policy type " + policy); 4704658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } 4714658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } else { 47299c2e1d6749cfad2a8ca94a47857d8c3bfc09454Wink Saville Rlog.e(TAG, "Error: skipping unknown XML tag " + element); 4734658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } 4744658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } 4754658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } catch (FileNotFoundException e) { 4764658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby // No data yet 4774658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } catch (IOException e) { 47899c2e1d6749cfad2a8ca94a47857d8c3bfc09454Wink Saville Rlog.e(TAG, "Unable to read premium SMS policy database", e); 4794658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } catch (NumberFormatException e) { 48099c2e1d6749cfad2a8ca94a47857d8c3bfc09454Wink Saville Rlog.e(TAG, "Unable to parse premium SMS policy database", e); 4814658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } catch (XmlPullParserException e) { 48299c2e1d6749cfad2a8ca94a47857d8c3bfc09454Wink Saville Rlog.e(TAG, "Unable to parse premium SMS policy database", e); 4834658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } finally { 4844658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby if (infile != null) { 4854658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby try { 4864658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby infile.close(); 4874658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } catch (IOException ignored) { 4884658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } 4894658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } 4904658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } 4914658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } 4924658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } 4934658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } 4944658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 4954658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby /** 4964658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby * Persist the premium SMS policy to an XML file. 4974658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby * Based on code from NotificationManagerService. 4984658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby */ 4994658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby private void writePremiumSmsPolicyDb() { 5004658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby synchronized (mPremiumSmsPolicy) { 5014658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby FileOutputStream outfile = null; 5024658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby try { 5034658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby outfile = mPolicyFile.startWrite(); 5044658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 5054658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby XmlSerializer out = new FastXmlSerializer(); 506bfda9080cab9a819fc48bdb97ef70911016a0f21Wojciech Staszkiewicz out.setOutput(outfile, StandardCharsets.UTF_8.name()); 5074658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 5084658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby out.startDocument(null, true); 5094658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 5104658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby out.startTag(null, TAG_SMS_POLICY_BODY); 5114658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 5124658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby for (Map.Entry<String, Integer> policy : mPremiumSmsPolicy.entrySet()) { 5134658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby out.startTag(null, TAG_PACKAGE); 5144658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby out.attribute(null, ATTR_PACKAGE_NAME, policy.getKey()); 5154658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby out.attribute(null, ATTR_PACKAGE_SMS_POLICY, policy.getValue().toString()); 5164658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby out.endTag(null, TAG_PACKAGE); 5174658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } 5184658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 5194658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby out.endTag(null, TAG_SMS_POLICY_BODY); 5204658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby out.endDocument(); 5214658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 5224658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby mPolicyFile.finishWrite(outfile); 5234658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } catch (IOException e) { 52499c2e1d6749cfad2a8ca94a47857d8c3bfc09454Wink Saville Rlog.e(TAG, "Unable to write premium SMS policy database", e); 5254658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby if (outfile != null) { 5264658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby mPolicyFile.failWrite(outfile); 5274658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } 5284658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } 5294658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } 5304658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } 5314658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 5324658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby /** 5334658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby * Returns the premium SMS permission for the specified package. If the package has never 5344658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby * been seen before, the default {@link #PREMIUM_SMS_PERMISSION_ASK_USER} 5354658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby * will be returned. 5364658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby * @param packageName the name of the package to query permission 5374658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby * @return one of {@link #PREMIUM_SMS_PERMISSION_UNKNOWN}, 5384658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby * {@link #PREMIUM_SMS_PERMISSION_ASK_USER}, 5394658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby * {@link #PREMIUM_SMS_PERMISSION_NEVER_ALLOW}, or 5404658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby * {@link #PREMIUM_SMS_PERMISSION_ALWAYS_ALLOW} 5414658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby * @throws SecurityException if the caller is not a system process 5424658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby */ 5434658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby public int getPremiumSmsPermission(String packageName) { 544f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal checkCallerIsSystemOrPhoneOrSameApp(packageName); 5454658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby synchronized (mPremiumSmsPolicy) { 5464658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby Integer policy = mPremiumSmsPolicy.get(packageName); 5474658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby if (policy == null) { 5484658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby return PREMIUM_SMS_PERMISSION_UNKNOWN; 5494658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } else { 5504658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby return policy; 5514658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } 5524658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } 5534658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } 5544658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 5554658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby /** 5564658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby * Sets the premium SMS permission for the specified package and save the value asynchronously 5574658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby * to persistent storage. 5584658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby * @param packageName the name of the package to set permission 5594658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby * @param permission one of {@link #PREMIUM_SMS_PERMISSION_ASK_USER}, 5604658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby * {@link #PREMIUM_SMS_PERMISSION_NEVER_ALLOW}, or 5614658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby * {@link #PREMIUM_SMS_PERMISSION_ALWAYS_ALLOW} 5624658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby * @throws SecurityException if the caller is not a system process 5634658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby */ 5644658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby public void setPremiumSmsPermission(String packageName, int permission) { 5654658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby checkCallerIsSystemOrPhoneApp(); 5664658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby if (permission < PREMIUM_SMS_PERMISSION_ASK_USER 5674658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby || permission > PREMIUM_SMS_PERMISSION_ALWAYS_ALLOW) { 5684658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby throw new IllegalArgumentException("invalid SMS permission type " + permission); 5694658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } 5704658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby synchronized (mPremiumSmsPolicy) { 5714658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby mPremiumSmsPolicy.put(packageName, permission); 5724658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } 5734658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby // write policy file in the background 5744658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby new Thread(new Runnable() { 5754658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby @Override 5764658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby public void run() { 5774658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby writePremiumSmsPolicyDb(); 5784658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } 5794658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby }).start(); 5804658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } 5814658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 582f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal private static void checkCallerIsSystemOrPhoneOrSameApp(String pkg) { 5834658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby int uid = Binder.getCallingUid(); 584f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal int appId = UserHandle.getAppId(uid); 585f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal if (appId == Process.SYSTEM_UID || appId == Process.PHONE_UID || uid == 0) { 5864658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby return; 5874658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } 5884658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby try { 5894658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby ApplicationInfo ai = AppGlobals.getPackageManager().getApplicationInfo( 5904658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby pkg, 0, UserHandle.getCallingUserId()); 5914658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby if (!UserHandle.isSameApp(ai.uid, uid)) { 5924658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby throw new SecurityException("Calling uid " + uid + " gave package" 5934658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby + pkg + " which is owned by uid " + ai.uid); 5944658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } 5954658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } catch (RemoteException re) { 5964658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby throw new SecurityException("Unknown package " + pkg + "\n" + re); 5974658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } 5984658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } 5994658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 6004658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby private static void checkCallerIsSystemOrPhoneApp() { 6014658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby int uid = Binder.getCallingUid(); 6024658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby int appId = UserHandle.getAppId(uid); 6034658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby if (appId == Process.SYSTEM_UID || appId == Process.PHONE_UID || uid == 0) { 6044658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby return; 6054658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } 6064658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby throw new SecurityException("Disallowed call for uid " + uid); 6074658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } 6084658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 6094658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby /** 6100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Remove keys containing only old timestamps. This can happen if an SMS app is used 6110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * to send messages and then uninstalled. 6120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */ 6130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private void removeExpiredTimestamps() { 6140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville long beginCheckPeriod = System.currentTimeMillis() - mCheckPeriod; 6150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 6160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville synchronized (mSmsStamp) { 6170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville Iterator<Map.Entry<String, ArrayList<Long>>> iter = mSmsStamp.entrySet().iterator(); 6180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville while (iter.hasNext()) { 6190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville Map.Entry<String, ArrayList<Long>> entry = iter.next(); 6200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville ArrayList<Long> oldList = entry.getValue(); 6210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (oldList.isEmpty() || oldList.get(oldList.size() - 1) < beginCheckPeriod) { 6220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville iter.remove(); 6230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 6240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 6250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 6260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 6270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 6280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private boolean isUnderLimit(ArrayList<Long> sent, int smsWaiting) { 6290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville Long ct = System.currentTimeMillis(); 6300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville long beginCheckPeriod = ct - mCheckPeriod; 6310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 6320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (VDBG) log("SMS send size=" + sent.size() + " time=" + ct); 6330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 6340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville while (!sent.isEmpty() && sent.get(0) < beginCheckPeriod) { 6350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville sent.remove(0); 6360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 6370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 6380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if ((sent.size() + smsWaiting) <= mMaxAllowed) { 6390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville for (int i = 0; i < smsWaiting; i++ ) { 6400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville sent.add(ct); 6410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 6420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return true; 6430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 6440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return false; 6450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 6460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 6470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private static void log(String msg) { 64899c2e1d6749cfad2a8ca94a47857d8c3bfc09454Wink Saville Rlog.d(TAG, msg); 6490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 6500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville} 651