DownloadManager.java revision 66dde9460badebf8e740275cabde9cca256006eb
1cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause/*
2cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause * Copyright (C) 2008 Esmertec AG.
3cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause * Copyright (C) 2008 The Android Open Source Project
4cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause *
5cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause * Licensed under the Apache License, Version 2.0 (the "License");
6cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause * you may not use this file except in compliance with the License.
7cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause * You may obtain a copy of the License at
8849bc5bfd940cea4e55332e805e0a7da4a765bcdDmitri Plotnikov *
9cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause *      http://www.apache.org/licenses/LICENSE-2.0
10cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause *
114a0b3738f8a710d2ffc8c49b3ae7e44100c88839Tim Park * Unless required by applicable law or agreed to in writing, software
124a0b3738f8a710d2ffc8c49b3ae7e44100c88839Tim Park * distributed under the License is distributed on an "AS IS" BASIS,
134a0b3738f8a710d2ffc8c49b3ae7e44100c88839Tim Park * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
144a0b3738f8a710d2ffc8c49b3ae7e44100c88839Tim Park * See the License for the specific language governing permissions and
154a0b3738f8a710d2ffc8c49b3ae7e44100c88839Tim Park * limitations under the License.
16cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause */
17cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause
18cd0189299f484dcbd51400b994daf585923e9e8dDavid Krausepackage com.android.mms.util;
19cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause
20cd0189299f484dcbd51400b994daf585923e9e8dDavid Krauseimport com.android.internal.telephony.TelephonyIntents;
21849bc5bfd940cea4e55332e805e0a7da4a765bcdDmitri Plotnikovimport com.android.internal.telephony.TelephonyProperties;
22cd0189299f484dcbd51400b994daf585923e9e8dDavid Krauseimport com.android.mms.R;
23cd0189299f484dcbd51400b994daf585923e9e8dDavid Krauseimport com.android.mms.ui.MessagingPreferenceActivity;
24cd0189299f484dcbd51400b994daf585923e9e8dDavid Krauseimport com.google.android.mms.MmsException;
25cd0189299f484dcbd51400b994daf585923e9e8dDavid Krauseimport com.google.android.mms.pdu.EncodedStringValue;
26cd0189299f484dcbd51400b994daf585923e9e8dDavid Krauseimport com.google.android.mms.pdu.NotificationInd;
27cd0189299f484dcbd51400b994daf585923e9e8dDavid Krauseimport com.google.android.mms.pdu.PduPersister;
28cd0189299f484dcbd51400b994daf585923e9e8dDavid Krauseimport com.google.android.mms.util.SqliteWrapper;
29cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause
30cd0189299f484dcbd51400b994daf585923e9e8dDavid Krauseimport android.content.BroadcastReceiver;
31cd0189299f484dcbd51400b994daf585923e9e8dDavid Krauseimport android.content.ContentValues;
32cd0189299f484dcbd51400b994daf585923e9e8dDavid Krauseimport android.content.Context;
33cd0189299f484dcbd51400b994daf585923e9e8dDavid Krauseimport android.content.Intent;
34cd0189299f484dcbd51400b994daf585923e9e8dDavid Krauseimport android.content.IntentFilter;
35cd0189299f484dcbd51400b994daf585923e9e8dDavid Krauseimport android.content.SharedPreferences;
36cd0189299f484dcbd51400b994daf585923e9e8dDavid Krauseimport android.content.SharedPreferences.OnSharedPreferenceChangeListener;
374a0b3738f8a710d2ffc8c49b3ae7e44100c88839Tim Parkimport android.database.Cursor;
38cd0189299f484dcbd51400b994daf585923e9e8dDavid Krauseimport android.net.Uri;
39cd0189299f484dcbd51400b994daf585923e9e8dDavid Krauseimport android.os.Handler;
404a0b3738f8a710d2ffc8c49b3ae7e44100c88839Tim Parkimport android.os.SystemProperties;
414a0b3738f8a710d2ffc8c49b3ae7e44100c88839Tim Parkimport android.preference.PreferenceManager;
424a0b3738f8a710d2ffc8c49b3ae7e44100c88839Tim Parkimport android.provider.Telephony.Mms;
434a0b3738f8a710d2ffc8c49b3ae7e44100c88839Tim Parkimport android.telephony.ServiceState;
44cd0189299f484dcbd51400b994daf585923e9e8dDavid Krauseimport android.util.Config;
45cd0189299f484dcbd51400b994daf585923e9e8dDavid Krauseimport android.util.Log;
46cd0189299f484dcbd51400b994daf585923e9e8dDavid Krauseimport android.widget.Toast;
47cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause
48cd0189299f484dcbd51400b994daf585923e9e8dDavid Krausepublic class DownloadManager {
49cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause    private static final String TAG = "DownloadManager";
50cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause    private static final boolean DEBUG = false;
51cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause    private static final boolean LOCAL_LOGV = DEBUG ? Config.LOGD : Config.LOGV;
52cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause
53cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause    private static final int DEFERRED_MASK           = 0x04;
54cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause
55cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause    public static final int STATE_UNSTARTED         = 0x80;
56cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause    public static final int STATE_DOWNLOADING       = 0x81;
57cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause    public static final int STATE_TRANSIENT_FAILURE = 0x82;
58cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause    public static final int STATE_PERMANENT_FAILURE = 0x87;
59cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause
60cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause    private final Context mContext;
61cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause    private final Handler mHandler;
62cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause    private final SharedPreferences mPreferences;
63cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause    private boolean mAutoDownload;
64cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause
65cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause    private final OnSharedPreferenceChangeListener mPreferencesChangeListener =
664a0b3738f8a710d2ffc8c49b3ae7e44100c88839Tim Park        new OnSharedPreferenceChangeListener() {
674a0b3738f8a710d2ffc8c49b3ae7e44100c88839Tim Park        public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
684a0b3738f8a710d2ffc8c49b3ae7e44100c88839Tim Park            if (MessagingPreferenceActivity.AUTO_RETRIEVAL.equals(key)
694a0b3738f8a710d2ffc8c49b3ae7e44100c88839Tim Park                    || MessagingPreferenceActivity.RETRIEVAL_DURING_ROAMING.equals(key)) {
704a0b3738f8a710d2ffc8c49b3ae7e44100c88839Tim Park                if (LOCAL_LOGV) {
714a0b3738f8a710d2ffc8c49b3ae7e44100c88839Tim Park                    Log.v(TAG, "Preferences updated.");
724a0b3738f8a710d2ffc8c49b3ae7e44100c88839Tim Park                }
734a0b3738f8a710d2ffc8c49b3ae7e44100c88839Tim Park
744a0b3738f8a710d2ffc8c49b3ae7e44100c88839Tim Park                synchronized (sInstance) {
754a0b3738f8a710d2ffc8c49b3ae7e44100c88839Tim Park                    mAutoDownload = getAutoDownloadState(prefs);
764a0b3738f8a710d2ffc8c49b3ae7e44100c88839Tim Park                    if (LOCAL_LOGV) {
774a0b3738f8a710d2ffc8c49b3ae7e44100c88839Tim Park                        Log.v(TAG, "mAutoDownload ------> " + mAutoDownload);
784a0b3738f8a710d2ffc8c49b3ae7e44100c88839Tim Park                    }
794a0b3738f8a710d2ffc8c49b3ae7e44100c88839Tim Park                }
804a0b3738f8a710d2ffc8c49b3ae7e44100c88839Tim Park            }
814a0b3738f8a710d2ffc8c49b3ae7e44100c88839Tim Park        }
824a0b3738f8a710d2ffc8c49b3ae7e44100c88839Tim Park    };
834a0b3738f8a710d2ffc8c49b3ae7e44100c88839Tim Park
844a0b3738f8a710d2ffc8c49b3ae7e44100c88839Tim Park    private final BroadcastReceiver mRoamingStateListener =
854a0b3738f8a710d2ffc8c49b3ae7e44100c88839Tim Park        new BroadcastReceiver() {
864a0b3738f8a710d2ffc8c49b3ae7e44100c88839Tim Park        @Override
874a0b3738f8a710d2ffc8c49b3ae7e44100c88839Tim Park        public void onReceive(Context context, Intent intent) {
884a0b3738f8a710d2ffc8c49b3ae7e44100c88839Tim Park            if (TelephonyIntents.ACTION_SERVICE_STATE_CHANGED.equals(intent.getAction())) {
894a0b3738f8a710d2ffc8c49b3ae7e44100c88839Tim Park                if (LOCAL_LOGV) {
904a0b3738f8a710d2ffc8c49b3ae7e44100c88839Tim Park                    Log.v(TAG, "Service state changed: " + intent.getExtras());
914a0b3738f8a710d2ffc8c49b3ae7e44100c88839Tim Park                }
924a0b3738f8a710d2ffc8c49b3ae7e44100c88839Tim Park
934a0b3738f8a710d2ffc8c49b3ae7e44100c88839Tim Park                ServiceState state = ServiceState.newFromBundle(intent.getExtras());
94cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause                boolean isRoaming = state.getRoaming();
954a0b3738f8a710d2ffc8c49b3ae7e44100c88839Tim Park                if (LOCAL_LOGV) {
964a0b3738f8a710d2ffc8c49b3ae7e44100c88839Tim Park                    Log.v(TAG, "roaming ------> " + isRoaming);
97cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause                }
98cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause                synchronized (sInstance) {
99cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause                    mAutoDownload = getAutoDownloadState(mPreferences, isRoaming);
100cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause                    if (LOCAL_LOGV) {
101cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause                        Log.v(TAG, "mAutoDownload ------> " + mAutoDownload);
102cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause                    }
103cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause                }
104cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause            }
105cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause        }
106cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause    };
107cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause
108cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause    private static DownloadManager sInstance;
109cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause
110cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause    private DownloadManager(Context context) {
111cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause        mContext = context;
112cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause        mHandler = new Handler();
113cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause        mPreferences = PreferenceManager.getDefaultSharedPreferences(context);
114cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause        mPreferences.registerOnSharedPreferenceChangeListener(mPreferencesChangeListener);
115cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause
116cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause        context.registerReceiver(
117948a17dc246520345b81455fdae0e1d628adc263Li Zhe                mRoamingStateListener,
118cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause                new IntentFilter(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED));
119cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause
120cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause        mAutoDownload = getAutoDownloadState(mPreferences);
121cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause        if (LOCAL_LOGV) {
122cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause            Log.v(TAG, "mAutoDownload ------> " + mAutoDownload);
123cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause        }
124cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause    }
125cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause
126cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause    public boolean isAuto() {
127cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause        return mAutoDownload;
128cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause    }
129cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause
130cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause    public static void init(Context context) {
131cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause        if (LOCAL_LOGV) {
132cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause            Log.v(TAG, "DownloadManager.init()");
133cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause        }
134cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause
135cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause        if (sInstance != null) {
136cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause            Log.w(TAG, "Already initialized.");
137cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause        }
138cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause        sInstance = new DownloadManager(context);
139cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause    }
140cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause
141cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause    public static DownloadManager getInstance() {
142cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause        if (sInstance == null) {
143cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause            throw new IllegalStateException("Uninitialized.");
144cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause        }
145cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause        return sInstance;
146cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause    }
147cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause
148cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause    static boolean getAutoDownloadState(SharedPreferences prefs) {
149cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause        return getAutoDownloadState(prefs, isRoaming());
150cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause    }
151cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause
152cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause    static boolean getAutoDownloadState(SharedPreferences prefs, boolean roaming) {
153cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause        boolean autoDownload = prefs.getBoolean(
154cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause                MessagingPreferenceActivity.AUTO_RETRIEVAL, true);
155cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause
156cd0189299f484dcbd51400b994daf585923e9e8dDavid Krause        if (LOCAL_LOGV) {
157            Log.v(TAG, "auto download without roaming -> " + autoDownload);
158        }
159
160        if (autoDownload) {
161            boolean alwaysAuto = prefs.getBoolean(
162                    MessagingPreferenceActivity.RETRIEVAL_DURING_ROAMING, false);
163
164            if (LOCAL_LOGV) {
165                Log.v(TAG, "auto download during roaming -> " + alwaysAuto);
166            }
167
168            if (!roaming || alwaysAuto) {
169                return true;
170            }
171        }
172        return false;
173    }
174
175    static boolean isRoaming() {
176        String roaming = SystemProperties.get(
177                TelephonyProperties.PROPERTY_OPERATOR_ISROAMING, null);
178        if (LOCAL_LOGV) {
179            Log.v(TAG, "roaming ------> " + roaming);
180        }
181        return "true".equals(roaming);
182    }
183
184    public void markState(final Uri uri, int state) {
185        // Notify user if downloading permanently failed.
186        if (state == STATE_PERMANENT_FAILURE) {
187            mHandler.post(new Runnable() {
188                public void run() {
189                    try {
190                        Toast.makeText(mContext, getMessage(uri),
191                                Toast.LENGTH_LONG).show();
192                    } catch (MmsException e) {
193                        Log.e(TAG, e.getMessage(), e);
194                    }
195                }
196            });
197        } else if (!mAutoDownload) {
198            state |= DEFERRED_MASK;
199        }
200
201        // Use the STATUS field to store the state of downloading process
202        // because it's useless for M-Notification.ind.
203        ContentValues values = new ContentValues(1);
204        values.put(Mms.STATUS, state);
205        SqliteWrapper.update(mContext, mContext.getContentResolver(),
206                    uri, values, null, null);
207    }
208
209    private String getMessage(Uri uri) throws MmsException {
210        NotificationInd ind = (NotificationInd) PduPersister
211                .getPduPersister(mContext).load(uri);
212
213        EncodedStringValue v = ind.getSubject();
214        String subject = (v != null) ? v.getString()
215                : mContext.getString(R.string.no_subject);
216
217        v = ind.getFrom();
218        String from = (v != null)
219                ? ContactInfoCache.getInstance().getContactName(v.getString())
220                : mContext.getString(R.string.unknown_sender);
221
222        return mContext.getString(R.string.dl_failure_notification, subject, from);
223    }
224
225    public int getState(Uri uri) {
226        Cursor cursor = SqliteWrapper.query(mContext, mContext.getContentResolver(),
227                            uri, new String[] {Mms.STATUS}, null, null, null);
228
229        if (cursor != null) {
230            try {
231                if (cursor.moveToFirst()) {
232                    return cursor.getInt(0) &~ DEFERRED_MASK;
233                }
234            } finally {
235                cursor.close();
236            }
237        }
238        return STATE_UNSTARTED;
239    }
240}
241