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.content.BroadcastReceiver; 21 import android.content.ContentValues; 22 import android.content.Context; 23 import android.content.Intent; 24 import android.content.IntentFilter; 25 import android.content.SharedPreferences; 26 import android.content.SharedPreferences.OnSharedPreferenceChangeListener; 27 import android.database.Cursor; 28 import android.database.sqlite.SqliteWrapper; 29 import android.net.Uri; 30 import android.os.Handler; 31 import android.os.SystemProperties; 32 import android.preference.PreferenceManager; 33 import android.provider.Telephony.Mms; 34 import android.telephony.ServiceState; 35 import android.util.Log; 36 import android.widget.Toast; 37 38 import com.android.internal.telephony.TelephonyIntents; 39 import com.android.internal.telephony.TelephonyProperties; 40 import com.android.mms.LogTag; 41 import com.android.mms.R; 42 import com.android.mms.data.Contact; 43 import com.android.mms.ui.MessagingPreferenceActivity; 44 import com.google.android.mms.MmsException; 45 import com.google.android.mms.pdu.EncodedStringValue; 46 import com.google.android.mms.pdu.NotificationInd; 47 import com.google.android.mms.pdu.PduPersister; 48 49 public class DownloadManager { 50 private static final String TAG = LogTag.TAG; 51 private static final boolean DEBUG = false; 52 private static final boolean LOCAL_LOGV = false; 53 54 public static final int DEFERRED_MASK = 0x04; 55 56 public static final int STATE_UNKNOWN = 0x00; 57 public static final int STATE_UNSTARTED = 0x80; 58 public static final int STATE_DOWNLOADING = 0x81; 59 public static final int STATE_TRANSIENT_FAILURE = 0x82; 60 public static final int STATE_PERMANENT_FAILURE = 0x87; 61 public static final int STATE_PRE_DOWNLOADING = 0x88; 62 // TransactionService will skip downloading Mms if auto-download is off 63 public static final int STATE_SKIP_RETRYING = 0x89; 64 65 private final Context mContext; 66 private final Handler mHandler; 67 private final SharedPreferences mPreferences; 68 private boolean mAutoDownload; 69 70 private final OnSharedPreferenceChangeListener mPreferencesChangeListener = 71 new OnSharedPreferenceChangeListener() { 72 public void onSharedPreferenceChanged(SharedPreferences prefs, String key) { 73 if (MessagingPreferenceActivity.AUTO_RETRIEVAL.equals(key) 74 || MessagingPreferenceActivity.RETRIEVAL_DURING_ROAMING.equals(key)) { 75 if (LOCAL_LOGV) { 76 Log.v(TAG, "Preferences updated."); 77 } 78 79 synchronized (sInstance) { 80 mAutoDownload = getAutoDownloadState(prefs); 81 if (LOCAL_LOGV) { 82 Log.v(TAG, "mAutoDownload ------> " + mAutoDownload); 83 } 84 } 85 } 86 } 87 }; 88 89 private final BroadcastReceiver mRoamingStateListener = 90 new BroadcastReceiver() { 91 @Override 92 public void onReceive(Context context, Intent intent) { 93 if (TelephonyIntents.ACTION_SERVICE_STATE_CHANGED.equals(intent.getAction())) { 94 if (LOCAL_LOGV) { 95 Log.v(TAG, "Service state changed: " + intent.getExtras()); 96 } 97 98 ServiceState state = ServiceState.newFromBundle(intent.getExtras()); 99 boolean isRoaming = state.getRoaming(); 100 if (LOCAL_LOGV) { 101 Log.v(TAG, "roaming ------> " + isRoaming); 102 } 103 synchronized (sInstance) { 104 mAutoDownload = getAutoDownloadState(mPreferences, isRoaming); 105 if (LOCAL_LOGV) { 106 Log.v(TAG, "mAutoDownload ------> " + mAutoDownload); 107 } 108 } 109 } 110 } 111 }; 112 113 private static DownloadManager sInstance; 114 DownloadManager(Context context)115 private DownloadManager(Context context) { 116 mContext = context; 117 mHandler = new Handler(); 118 mPreferences = PreferenceManager.getDefaultSharedPreferences(context); 119 mPreferences.registerOnSharedPreferenceChangeListener(mPreferencesChangeListener); 120 121 context.registerReceiver( 122 mRoamingStateListener, 123 new IntentFilter(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED)); 124 125 mAutoDownload = getAutoDownloadState(mPreferences); 126 if (LOCAL_LOGV) { 127 Log.v(TAG, "mAutoDownload ------> " + mAutoDownload); 128 } 129 } 130 isAuto()131 public boolean isAuto() { 132 return mAutoDownload; 133 } 134 init(Context context)135 public static void init(Context context) { 136 if (LOCAL_LOGV) { 137 Log.v(TAG, "DownloadManager.init()"); 138 } 139 140 if (sInstance != null) { 141 Log.w(TAG, "Already initialized."); 142 } 143 sInstance = new DownloadManager(context); 144 } 145 getInstance()146 public static DownloadManager getInstance() { 147 if (sInstance == null) { 148 throw new IllegalStateException("Uninitialized."); 149 } 150 return sInstance; 151 } 152 getAutoDownloadState(SharedPreferences prefs)153 static boolean getAutoDownloadState(SharedPreferences prefs) { 154 return getAutoDownloadState(prefs, isRoaming()); 155 } 156 getAutoDownloadState(SharedPreferences prefs, boolean roaming)157 static boolean getAutoDownloadState(SharedPreferences prefs, boolean roaming) { 158 boolean autoDownload = prefs.getBoolean( 159 MessagingPreferenceActivity.AUTO_RETRIEVAL, true); 160 161 if (LOCAL_LOGV) { 162 Log.v(TAG, "auto download without roaming -> " + autoDownload); 163 } 164 165 if (autoDownload) { 166 boolean alwaysAuto = prefs.getBoolean( 167 MessagingPreferenceActivity.RETRIEVAL_DURING_ROAMING, false); 168 169 if (LOCAL_LOGV) { 170 Log.v(TAG, "auto download during roaming -> " + alwaysAuto); 171 } 172 173 if (!roaming || alwaysAuto) { 174 return true; 175 } 176 } 177 return false; 178 } 179 isRoaming()180 static boolean isRoaming() { 181 // TODO: fix and put in Telephony layer 182 String roaming = SystemProperties.get( 183 TelephonyProperties.PROPERTY_OPERATOR_ISROAMING, null); 184 if (LOCAL_LOGV) { 185 Log.v(TAG, "roaming ------> " + roaming); 186 } 187 return "true".equals(roaming); 188 } 189 markState(final Uri uri, int state)190 public void markState(final Uri uri, int state) { 191 // Notify user if the message has expired. 192 try { 193 NotificationInd nInd = (NotificationInd) PduPersister.getPduPersister(mContext) 194 .load(uri); 195 if ((nInd.getExpiry() < System.currentTimeMillis() / 1000L) 196 && (state == STATE_DOWNLOADING || state == STATE_PRE_DOWNLOADING)) { 197 mHandler.post(new Runnable() { 198 public void run() { 199 Toast.makeText(mContext, R.string.service_message_not_found, 200 Toast.LENGTH_LONG).show(); 201 } 202 }); 203 SqliteWrapper.delete(mContext, mContext.getContentResolver(), uri, null, null); 204 return; 205 } 206 } catch(MmsException e) { 207 Log.e(TAG, e.getMessage(), e); 208 return; 209 } 210 211 // Notify user if downloading permanently failed. 212 if (state == STATE_PERMANENT_FAILURE) { 213 mHandler.post(new Runnable() { 214 public void run() { 215 try { 216 Toast.makeText(mContext, getMessage(uri), 217 Toast.LENGTH_LONG).show(); 218 } catch (MmsException e) { 219 Log.e(TAG, e.getMessage(), e); 220 } 221 } 222 }); 223 } else if (!mAutoDownload) { 224 state |= DEFERRED_MASK; 225 } 226 227 // Use the STATUS field to store the state of downloading process 228 // because it's useless for M-Notification.ind. 229 ContentValues values = new ContentValues(1); 230 values.put(Mms.STATUS, state); 231 SqliteWrapper.update(mContext, mContext.getContentResolver(), 232 uri, values, null, null); 233 } 234 showErrorCodeToast(int errorStr)235 public void showErrorCodeToast(int errorStr) { 236 final int errStr = errorStr; 237 mHandler.post(new Runnable() { 238 public void run() { 239 try { 240 Toast.makeText(mContext, errStr, Toast.LENGTH_LONG).show(); 241 } catch (Exception e) { 242 Log.e(TAG,"Caught an exception in showErrorCodeToast"); 243 } 244 } 245 }); 246 } 247 getMessage(Uri uri)248 private String getMessage(Uri uri) throws MmsException { 249 NotificationInd ind = (NotificationInd) PduPersister 250 .getPduPersister(mContext).load(uri); 251 252 EncodedStringValue v = ind.getSubject(); 253 String subject = (v != null) ? v.getString() 254 : mContext.getString(R.string.no_subject); 255 256 v = ind.getFrom(); 257 String from = (v != null) 258 ? Contact.get(v.getString(), false).getName() 259 : mContext.getString(R.string.unknown_sender); 260 261 return mContext.getString(R.string.dl_failure_notification, subject, from); 262 } 263 getState(Uri uri)264 public int getState(Uri uri) { 265 Cursor cursor = SqliteWrapper.query(mContext, mContext.getContentResolver(), 266 uri, new String[] {Mms.STATUS}, null, null, null); 267 268 if (cursor != null) { 269 try { 270 if (cursor.moveToFirst()) { 271 return cursor.getInt(0) & ~DEFERRED_MASK; 272 } 273 } finally { 274 cursor.close(); 275 } 276 } 277 return STATE_UNSTARTED; 278 } 279 } 280