/* * Copyright (C) 2011 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; import android.content.ContentResolver; import android.provider.Settings; import android.util.Log; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.Map; /** * Implement the per-application based SMS control, which limits the number of * SMS/MMS messages an app can send in the checking period. * * This code was formerly part of {@link SMSDispatcher}, and has been moved * into a separate class to support instantiation of multiple SMSDispatchers on * dual-mode devices that require support for both 3GPP and 3GPP2 format messages. */ public class SmsUsageMonitor { private static final String TAG = "SmsStorageMonitor"; /** Default checking period for SMS sent without user permission. */ private static final int DEFAULT_SMS_CHECK_PERIOD = 3600000; /** Default number of SMS sent in checking period without user permission. */ private static final int DEFAULT_SMS_MAX_COUNT = 100; private final int mCheckPeriod; private final int mMaxAllowed; private final HashMap<String, ArrayList<Long>> mSmsStamp = new HashMap<String, ArrayList<Long>>(); /** * Create SMS usage monitor. * @param resolver the ContentResolver to use to load from secure settings */ public SmsUsageMonitor(ContentResolver resolver) { mMaxAllowed = Settings.Secure.getInt(resolver, Settings.Secure.SMS_OUTGOING_CHECK_MAX_COUNT, DEFAULT_SMS_MAX_COUNT); mCheckPeriod = Settings.Secure.getInt(resolver, Settings.Secure.SMS_OUTGOING_CHECK_INTERVAL_MS, DEFAULT_SMS_CHECK_PERIOD); } /** Clear the SMS application list for disposal. */ void dispose() { mSmsStamp.clear(); } /** * Check to see if an application is allowed to send new SMS messages. * * @param appName the application sending sms * @param smsWaiting the number of new messages desired to send * @return true if application is allowed to send the requested number * of new sms messages */ public boolean check(String appName, int smsWaiting) { synchronized (mSmsStamp) { removeExpiredTimestamps(); ArrayList<Long> sentList = mSmsStamp.get(appName); if (sentList == null) { sentList = new ArrayList<Long>(); mSmsStamp.put(appName, sentList); } return isUnderLimit(sentList, smsWaiting); } } /** * Remove keys containing only old timestamps. This can happen if an SMS app is used * to send messages and then uninstalled. */ private void removeExpiredTimestamps() { long beginCheckPeriod = System.currentTimeMillis() - mCheckPeriod; synchronized (mSmsStamp) { Iterator<Map.Entry<String, ArrayList<Long>>> iter = mSmsStamp.entrySet().iterator(); while (iter.hasNext()) { Map.Entry<String, ArrayList<Long>> entry = iter.next(); ArrayList<Long> oldList = entry.getValue(); if (oldList.isEmpty() || oldList.get(oldList.size() - 1) < beginCheckPeriod) { iter.remove(); } } } } private boolean isUnderLimit(ArrayList<Long> sent, int smsWaiting) { Long ct = System.currentTimeMillis(); long beginCheckPeriod = ct - mCheckPeriod; Log.d(TAG, "SMS send size=" + sent.size() + " time=" + ct); while (!sent.isEmpty() && sent.get(0) < beginCheckPeriod) { sent.remove(0); } if ((sent.size() + smsWaiting) <= mMaxAllowed) { for (int i = 0; i < smsWaiting; i++ ) { sent.add(ct); } return true; } return false; } }