1/*
2 * Copyright (C) 2008 Esmertec AG.
3 * Copyright (C) 2008 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *      http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18package com.android.mms.util;
19
20import android.database.sqlite.SqliteWrapper;
21
22import android.content.BroadcastReceiver;
23import android.content.ContentValues;
24import android.content.Context;
25import android.content.Intent;
26import android.content.IntentFilter;
27import android.database.Cursor;
28import android.provider.Telephony.Mms.Rate;
29import android.util.Log;
30
31public class RateController {
32    private static final String TAG = "RateController";
33    private static final boolean DEBUG = false;
34    private static final boolean LOCAL_LOGV = false;
35
36    private static final int RATE_LIMIT = 100;
37    private static final long ONE_HOUR = 1000 * 60 * 60;
38
39    private static final int NO_ANSWER  = 0;
40    private static final int ANSWER_YES = 1;
41    private static final int ANSWER_NO  = 2;
42
43    public static final int ANSWER_TIMEOUT = 20000;
44    public static final String RATE_LIMIT_SURPASSED_ACTION =
45        "com.android.mms.RATE_LIMIT_SURPASSED";
46    public static final String RATE_LIMIT_CONFIRMED_ACTION =
47        "com.android.mms.RATE_LIMIT_CONFIRMED";
48
49    private static RateController sInstance;
50    private static boolean sMutexLock;
51
52    private final Context mContext;
53    private int mAnswer;
54
55    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
56        @Override
57        public void onReceive(Context context, Intent intent) {
58            if (LOCAL_LOGV) {
59                Log.v(TAG, "Intent received: " + intent);
60            }
61
62            if (RATE_LIMIT_CONFIRMED_ACTION.equals(intent.getAction())) {
63                synchronized (this) {
64                    mAnswer = intent.getBooleanExtra("answer", false)
65                                            ? ANSWER_YES : ANSWER_NO;
66                    notifyAll();
67                }
68            }
69        }
70    };
71
72    private RateController(Context context) {
73        mContext = context;
74    }
75
76    public static void init(Context context) {
77        if (LOCAL_LOGV) {
78            Log.v(TAG, "RateController.init()");
79        }
80
81        if (sInstance != null) {
82            Log.w(TAG, "Already initialized.");
83        }
84        sInstance = new RateController(context);
85    }
86
87    public static RateController getInstance() {
88        if (sInstance == null) {
89            throw new IllegalStateException("Uninitialized.");
90        }
91        return sInstance;
92    }
93
94    public final void update() {
95        ContentValues values = new ContentValues(1);
96        values.put(Rate.SENT_TIME, System.currentTimeMillis());
97        SqliteWrapper.insert(mContext, mContext.getContentResolver(),
98                             Rate.CONTENT_URI, values);
99    }
100
101    public final boolean isLimitSurpassed() {
102        long oneHourAgo = System.currentTimeMillis() - ONE_HOUR;
103        Cursor c = SqliteWrapper.query(mContext, mContext.getContentResolver(),
104                Rate.CONTENT_URI, new String[] { "COUNT(*) AS rate" },
105                Rate.SENT_TIME + ">" + oneHourAgo, null, null);
106        if (c != null) {
107            try {
108                if (c.moveToFirst()) {
109                    return c.getInt(0) >= RATE_LIMIT;
110                }
111            } finally {
112                c.close();
113            }
114        }
115        return false;
116    }
117
118    synchronized public boolean isAllowedByUser() {
119        while (sMutexLock) {
120            try {
121                wait();
122            } catch (InterruptedException _) {
123                 // Ignore it.
124            }
125        }
126        sMutexLock = true;
127
128        mContext.registerReceiver(mBroadcastReceiver,
129                new IntentFilter(RATE_LIMIT_CONFIRMED_ACTION));
130
131        mAnswer = NO_ANSWER;
132        try {
133            Intent intent = new Intent(RATE_LIMIT_SURPASSED_ACTION);
134            // Using NEW_TASK here is necessary because we're calling
135            // startActivity from outside an activity.
136            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
137            mContext.startActivity(intent);
138            return waitForAnswer() == ANSWER_YES;
139        } finally {
140            mContext.unregisterReceiver(mBroadcastReceiver);
141            sMutexLock = false;
142            notifyAll();
143        }
144    }
145
146    synchronized private int waitForAnswer() {
147        for (int t = 0; (mAnswer == NO_ANSWER) && (t < ANSWER_TIMEOUT); t += 1000) {
148            try {
149                if (LOCAL_LOGV) {
150                    Log.v(TAG, "Waiting for answer..." + t / 1000);
151                }
152                wait(1000L);
153            } catch (InterruptedException _) {
154                 // Ignore it.
155            }
156        }
157        return mAnswer;
158    }
159}
160