172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project/*
272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * Copyright (C) 2008 Esmertec AG.
372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project *
572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * you may not use this file except in compliance with the License.
772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * You may obtain a copy of the License at
872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project *
972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
1072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project *
1172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * Unless required by applicable law or agreed to in writing, software
1272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
1372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * See the License for the specific language governing permissions and
1572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * limitations under the License.
1672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project */
1772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
1872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectpackage com.android.mms.util;
1972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
20fd644551e8506266aad2b76463b51b44154ed62fTom Taylorimport android.database.sqlite.SqliteWrapper;
2172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
2272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.content.BroadcastReceiver;
2372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.content.ContentValues;
2472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.content.Context;
2572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.content.Intent;
2672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.content.IntentFilter;
2772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.database.Cursor;
28f7e8281a223af6228e6399055a6197a1edd9bc3aTom Taylorimport android.provider.Telephony.Mms.Rate;
2972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.util.Log;
3072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
3172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectpublic class RateController {
3272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final String TAG = "RateController";
3372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final boolean DEBUG = false;
34150c4179995cc0a75f934ef194372f9295957ca2Joe Onorato    private static final boolean LOCAL_LOGV = false;
3572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
3672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final int RATE_LIMIT = 100;
3772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final long ONE_HOUR = 1000 * 60 * 60;
3872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
3972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final int NO_ANSWER  = 0;
4072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final int ANSWER_YES = 1;
4172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final int ANSWER_NO  = 2;
4272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
4372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    public static final int ANSWER_TIMEOUT = 20000;
4472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    public static final String RATE_LIMIT_SURPASSED_ACTION =
4572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        "com.android.mms.RATE_LIMIT_SURPASSED";
4672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    public static final String RATE_LIMIT_CONFIRMED_ACTION =
4772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        "com.android.mms.RATE_LIMIT_CONFIRMED";
4872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
4972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static RateController sInstance;
5072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static boolean sMutexLock;
5172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
5272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private final Context mContext;
5372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private int mAnswer;
5472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
5572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
5672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        @Override
5772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        public void onReceive(Context context, Intent intent) {
5872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            if (LOCAL_LOGV) {
5972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                Log.v(TAG, "Intent received: " + intent);
6072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            }
6172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
6272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            if (RATE_LIMIT_CONFIRMED_ACTION.equals(intent.getAction())) {
6372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                synchronized (this) {
6472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                    mAnswer = intent.getBooleanExtra("answer", false)
6572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                                            ? ANSWER_YES : ANSWER_NO;
6672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                    notifyAll();
6772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                }
6872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            }
6972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
7072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    };
7172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
7272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private RateController(Context context) {
7372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        mContext = context;
7472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
7572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
7672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    public static void init(Context context) {
7772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        if (LOCAL_LOGV) {
7872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            Log.v(TAG, "RateController.init()");
7972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
8072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
8172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        if (sInstance != null) {
8272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            Log.w(TAG, "Already initialized.");
8372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
8472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        sInstance = new RateController(context);
8572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
8672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
8772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    public static RateController getInstance() {
8872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        if (sInstance == null) {
8972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            throw new IllegalStateException("Uninitialized.");
9072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
9172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        return sInstance;
9272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
9372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
9472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    public final void update() {
9572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        ContentValues values = new ContentValues(1);
9672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        values.put(Rate.SENT_TIME, System.currentTimeMillis());
9772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        SqliteWrapper.insert(mContext, mContext.getContentResolver(),
9872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                             Rate.CONTENT_URI, values);
9972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
10072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
10172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    public final boolean isLimitSurpassed() {
10272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        long oneHourAgo = System.currentTimeMillis() - ONE_HOUR;
10372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        Cursor c = SqliteWrapper.query(mContext, mContext.getContentResolver(),
10472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                Rate.CONTENT_URI, new String[] { "COUNT(*) AS rate" },
10572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                Rate.SENT_TIME + ">" + oneHourAgo, null, null);
10672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        if (c != null) {
10772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            try {
10872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                if (c.moveToFirst()) {
10972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                    return c.getInt(0) >= RATE_LIMIT;
11072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                }
11172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            } finally {
11272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                c.close();
11372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            }
11472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
11572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        return false;
11672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
11772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
11872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    synchronized public boolean isAllowedByUser() {
11972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        while (sMutexLock) {
12072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            try {
12172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                wait();
12272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            } catch (InterruptedException _) {
12372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                 // Ignore it.
12472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            }
12572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
12672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        sMutexLock = true;
12772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
12872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        mContext.registerReceiver(mBroadcastReceiver,
12972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                new IntentFilter(RATE_LIMIT_CONFIRMED_ACTION));
13072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
13172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        mAnswer = NO_ANSWER;
13272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        try {
13372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            Intent intent = new Intent(RATE_LIMIT_SURPASSED_ACTION);
13472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            // Using NEW_TASK here is necessary because we're calling
13572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            // startActivity from outside an activity.
13672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
13772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            mContext.startActivity(intent);
13872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            return waitForAnswer() == ANSWER_YES;
13972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        } finally {
14072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            mContext.unregisterReceiver(mBroadcastReceiver);
14172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            sMutexLock = false;
14272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            notifyAll();
14372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
14472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
14572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
14672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    synchronized private int waitForAnswer() {
14772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        for (int t = 0; (mAnswer == NO_ANSWER) && (t < ANSWER_TIMEOUT); t += 1000) {
14872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            try {
14972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                if (LOCAL_LOGV) {
15072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                    Log.v(TAG, "Waiting for answer..." + t / 1000);
15172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                }
15272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                wait(1000L);
15372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            } catch (InterruptedException _) {
15472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                 // Ignore it.
15572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            }
15672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
15772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        return mAnswer;
15872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
15972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project}
160