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