1b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby/*
2b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby * Copyright (C) 2011 The Android Open Source Project
3b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby *
4b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby * Licensed under the Apache License, Version 2.0 (the "License");
5b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby * you may not use this file except in compliance with the License.
6b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby * You may obtain a copy of the License at
7b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby *
8b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby *      http://www.apache.org/licenses/LICENSE-2.0
9b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby *
10b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby * Unless required by applicable law or agreed to in writing, software
11b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby * distributed under the License is distributed on an "AS IS" BASIS,
12b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby * See the License for the specific language governing permissions and
14b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby * limitations under the License.
15b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby */
16b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby
17b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hambypackage com.android.internal.telephony;
18b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby
19b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hambyimport android.content.ContentResolver;
20b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hambyimport android.provider.Settings;
21b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hambyimport android.util.Log;
22b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby
23b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hambyimport java.util.ArrayList;
24b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hambyimport java.util.HashMap;
25b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hambyimport java.util.Iterator;
26b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hambyimport java.util.Map;
27b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby
28b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby/**
29b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby * Implement the per-application based SMS control, which limits the number of
30b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby * SMS/MMS messages an app can send in the checking period.
31b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby *
32b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby * This code was formerly part of {@link SMSDispatcher}, and has been moved
33b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby * into a separate class to support instantiation of multiple SMSDispatchers on
34b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby * dual-mode devices that require support for both 3GPP and 3GPP2 format messages.
35b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby */
36b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hambypublic class SmsUsageMonitor {
37b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby    private static final String TAG = "SmsStorageMonitor";
38b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby
39b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby    /** Default checking period for SMS sent without user permission. */
40b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby    private static final int DEFAULT_SMS_CHECK_PERIOD = 3600000;
41b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby
42b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby    /** Default number of SMS sent in checking period without user permission. */
43b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby    private static final int DEFAULT_SMS_MAX_COUNT = 100;
44b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby
45b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby    private final int mCheckPeriod;
46b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby    private final int mMaxAllowed;
47b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby    private final HashMap<String, ArrayList<Long>> mSmsStamp =
48b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby            new HashMap<String, ArrayList<Long>>();
49b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby
50b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby    /**
51b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby     * Create SMS usage monitor.
52b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby     * @param resolver the ContentResolver to use to load from secure settings
53b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby     */
54b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby    public SmsUsageMonitor(ContentResolver resolver) {
55b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby        mMaxAllowed = Settings.Secure.getInt(resolver,
56b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby                Settings.Secure.SMS_OUTGOING_CHECK_MAX_COUNT,
57b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby                DEFAULT_SMS_MAX_COUNT);
58b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby
59b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby        mCheckPeriod = Settings.Secure.getInt(resolver,
60b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby                Settings.Secure.SMS_OUTGOING_CHECK_INTERVAL_MS,
61b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby                DEFAULT_SMS_CHECK_PERIOD);
62b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby    }
63b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby
64b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby    /** Clear the SMS application list for disposal. */
65b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby    void dispose() {
66b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby        mSmsStamp.clear();
67b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby    }
68b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby
69b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby    /**
70b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby     * Check to see if an application is allowed to send new SMS messages.
71b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby     *
72b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby     * @param appName the application sending sms
73b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby     * @param smsWaiting the number of new messages desired to send
74b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby     * @return true if application is allowed to send the requested number
75b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby     *  of new sms messages
76b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby     */
77b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby    public boolean check(String appName, int smsWaiting) {
78b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby        synchronized (mSmsStamp) {
79b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby            removeExpiredTimestamps();
80b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby
81b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby            ArrayList<Long> sentList = mSmsStamp.get(appName);
82b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby            if (sentList == null) {
83b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby                sentList = new ArrayList<Long>();
84b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby                mSmsStamp.put(appName, sentList);
85b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby            }
86b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby
87b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby            return isUnderLimit(sentList, smsWaiting);
88b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby        }
89b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby    }
90b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby
91b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby    /**
92b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby     * Remove keys containing only old timestamps. This can happen if an SMS app is used
93b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby     * to send messages and then uninstalled.
94b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby     */
95b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby    private void removeExpiredTimestamps() {
96b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby        long beginCheckPeriod = System.currentTimeMillis() - mCheckPeriod;
97b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby
98b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby        synchronized (mSmsStamp) {
99b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby            Iterator<Map.Entry<String, ArrayList<Long>>> iter = mSmsStamp.entrySet().iterator();
100b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby            while (iter.hasNext()) {
101b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby                Map.Entry<String, ArrayList<Long>> entry = iter.next();
102b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby                ArrayList<Long> oldList = entry.getValue();
103b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby                if (oldList.isEmpty() || oldList.get(oldList.size() - 1) < beginCheckPeriod) {
104b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby                    iter.remove();
105b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby                }
106b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby            }
107b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby        }
108b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby    }
109b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby
110b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby    private boolean isUnderLimit(ArrayList<Long> sent, int smsWaiting) {
111b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby        Long ct = System.currentTimeMillis();
112b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby        long beginCheckPeriod = ct - mCheckPeriod;
113b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby
114b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby        Log.d(TAG, "SMS send size=" + sent.size() + " time=" + ct);
115b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby
116b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby        while (!sent.isEmpty() && sent.get(0) < beginCheckPeriod) {
117b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby            sent.remove(0);
118b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby        }
119b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby
120b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby        if ((sent.size() + smsWaiting) <= mMaxAllowed) {
121b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby            for (int i = 0; i < smsWaiting; i++ ) {
122b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby                sent.add(ct);
123b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby            }
124b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby            return true;
125b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby        }
126b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby        return false;
127b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby    }
128b7945cae5ad0feaad09378d0db77f2b3105e5235Jake Hamby}
129