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 18 package com.android.mms.util; 19 20 import android.database.sqlite.SqliteWrapper; 21 22 import android.content.BroadcastReceiver; 23 import android.content.ContentValues; 24 import android.content.Context; 25 import android.content.Intent; 26 import android.content.IntentFilter; 27 import android.database.Cursor; 28 import android.provider.Telephony.Mms.Rate; 29 import android.util.Config; 30 import android.util.Log; 31 32 public class RateController { 33 private static final String TAG = "RateController"; 34 private static final boolean DEBUG = false; 35 private static final boolean LOCAL_LOGV = DEBUG ? Config.LOGD : Config.LOGV; 36 37 private static final int RATE_LIMIT = 100; 38 private static final long ONE_HOUR = 1000 * 60 * 60; 39 40 private static final int NO_ANSWER = 0; 41 private static final int ANSWER_YES = 1; 42 private static final int ANSWER_NO = 2; 43 44 public static final int ANSWER_TIMEOUT = 20000; 45 public static final String RATE_LIMIT_SURPASSED_ACTION = 46 "com.android.mms.RATE_LIMIT_SURPASSED"; 47 public static final String RATE_LIMIT_CONFIRMED_ACTION = 48 "com.android.mms.RATE_LIMIT_CONFIRMED"; 49 50 private static RateController sInstance; 51 private static boolean sMutexLock; 52 53 private final Context mContext; 54 private int mAnswer; 55 56 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 57 @Override 58 public void onReceive(Context context, Intent intent) { 59 if (LOCAL_LOGV) { 60 Log.v(TAG, "Intent received: " + intent); 61 } 62 63 if (RATE_LIMIT_CONFIRMED_ACTION.equals(intent.getAction())) { 64 synchronized (this) { 65 mAnswer = intent.getBooleanExtra("answer", false) 66 ? ANSWER_YES : ANSWER_NO; 67 notifyAll(); 68 } 69 } 70 } 71 }; 72 RateController(Context context)73 private RateController(Context context) { 74 mContext = context; 75 } 76 init(Context context)77 public static void init(Context context) { 78 if (LOCAL_LOGV) { 79 Log.v(TAG, "RateController.init()"); 80 } 81 82 if (sInstance != null) { 83 Log.w(TAG, "Already initialized."); 84 } 85 sInstance = new RateController(context); 86 } 87 getInstance()88 public static RateController getInstance() { 89 if (sInstance == null) { 90 throw new IllegalStateException("Uninitialized."); 91 } 92 return sInstance; 93 } 94 update()95 public final void update() { 96 ContentValues values = new ContentValues(1); 97 values.put(Rate.SENT_TIME, System.currentTimeMillis()); 98 SqliteWrapper.insert(mContext, mContext.getContentResolver(), 99 Rate.CONTENT_URI, values); 100 } 101 isLimitSurpassed()102 public final boolean isLimitSurpassed() { 103 long oneHourAgo = System.currentTimeMillis() - ONE_HOUR; 104 Cursor c = SqliteWrapper.query(mContext, mContext.getContentResolver(), 105 Rate.CONTENT_URI, new String[] { "COUNT(*) AS rate" }, 106 Rate.SENT_TIME + ">" + oneHourAgo, null, null); 107 if (c != null) { 108 try { 109 if (c.moveToFirst()) { 110 return c.getInt(0) >= RATE_LIMIT; 111 } 112 } finally { 113 c.close(); 114 } 115 } 116 return false; 117 } 118 isAllowedByUser()119 synchronized public boolean isAllowedByUser() { 120 while (sMutexLock) { 121 try { 122 wait(); 123 } catch (InterruptedException _) { 124 // Ignore it. 125 } 126 } 127 sMutexLock = true; 128 129 mContext.registerReceiver(mBroadcastReceiver, 130 new IntentFilter(RATE_LIMIT_CONFIRMED_ACTION)); 131 132 mAnswer = NO_ANSWER; 133 try { 134 Intent intent = new Intent(RATE_LIMIT_SURPASSED_ACTION); 135 // Using NEW_TASK here is necessary because we're calling 136 // startActivity from outside an activity. 137 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 138 mContext.startActivity(intent); 139 return waitForAnswer() == ANSWER_YES; 140 } finally { 141 mContext.unregisterReceiver(mBroadcastReceiver); 142 sMutexLock = false; 143 notifyAll(); 144 } 145 } 146 waitForAnswer()147 synchronized private int waitForAnswer() { 148 for (int t = 0; (mAnswer == NO_ANSWER) && (t < ANSWER_TIMEOUT); t += 1000) { 149 try { 150 if (LOCAL_LOGV) { 151 Log.v(TAG, "Waiting for answer..." + t / 1000); 152 } 153 wait(1000L); 154 } catch (InterruptedException _) { 155 // Ignore it. 156 } 157 } 158 return mAnswer; 159 } 160 } 161