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