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