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