DownloadManager.java revision 33a87f96f8c625aa10131a77a3968c97c4ec5a62
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
18package com.android.mms.util;
19
20import com.android.internal.telephony.TelephonyIntents;
21import com.android.internal.telephony.TelephonyProperties;
22import com.android.mms.R;
23import com.android.mms.data.Contact;
24import com.android.mms.ui.MessagingPreferenceActivity;
25import com.google.android.mms.MmsException;
26import com.google.android.mms.pdu.EncodedStringValue;
27import com.google.android.mms.pdu.NotificationInd;
28import com.google.android.mms.pdu.PduPersister;
29import com.google.android.mms.util.SqliteWrapper;
30
31import android.content.BroadcastReceiver;
32import android.content.ContentValues;
33import android.content.Context;
34import android.content.Intent;
35import android.content.IntentFilter;
36import android.content.SharedPreferences;
37import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
38import android.database.Cursor;
39import android.net.Uri;
40import android.os.Handler;
41import android.os.SystemProperties;
42import android.preference.PreferenceManager;
43import android.provider.Telephony.Mms;
44import android.telephony.ServiceState;
45import android.util.Config;
46import android.util.Log;
47import android.widget.Toast;
48
49public class DownloadManager {
50    private static final String TAG = "DownloadManager";
51    private static final boolean DEBUG = false;
52    private static final boolean LOCAL_LOGV = DEBUG ? Config.LOGD : Config.LOGV;
53
54    private static final int DEFERRED_MASK           = 0x04;
55
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
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
127    public boolean isAuto() {
128        return mAutoDownload;
129    }
130
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
142    public static DownloadManager getInstance() {
143        if (sInstance == null) {
144            throw new IllegalStateException("Uninitialized.");
145        }
146        return sInstance;
147    }
148
149    static boolean getAutoDownloadState(SharedPreferences prefs) {
150        return getAutoDownloadState(prefs, isRoaming());
151    }
152
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
176    static boolean isRoaming() {
177        String roaming = SystemProperties.get(
178                TelephonyProperties.PROPERTY_OPERATOR_ISROAMING, null);
179        if (LOCAL_LOGV) {
180            Log.v(TAG, "roaming ------> " + roaming);
181        }
182        return "true".equals(roaming);
183    }
184
185    public void markState(final Uri uri, int state) {
186        // Notify user if downloading permanently failed.
187        if (state == STATE_PERMANENT_FAILURE) {
188            mHandler.post(new Runnable() {
189                public void run() {
190                    try {
191                        Toast.makeText(mContext, getMessage(uri),
192                                Toast.LENGTH_LONG).show();
193                    } catch (MmsException e) {
194                        Log.e(TAG, e.getMessage(), e);
195                    }
196                }
197            });
198        } else if (!mAutoDownload) {
199            state |= DEFERRED_MASK;
200        }
201
202        // Use the STATUS field to store the state of downloading process
203        // because it's useless for M-Notification.ind.
204        ContentValues values = new ContentValues(1);
205        values.put(Mms.STATUS, state);
206        SqliteWrapper.update(mContext, mContext.getContentResolver(),
207                    uri, values, null, null);
208    }
209
210    private String getMessage(Uri uri) throws MmsException {
211        NotificationInd ind = (NotificationInd) PduPersister
212                .getPduPersister(mContext).load(uri);
213
214        EncodedStringValue v = ind.getSubject();
215        String subject = (v != null) ? v.getString()
216                : mContext.getString(R.string.no_subject);
217
218        v = ind.getFrom();
219        String from = (v != null)
220                ? Contact.get(v.getString(), true).getName()
221                : mContext.getString(R.string.unknown_sender);
222
223        return mContext.getString(R.string.dl_failure_notification, subject, from);
224    }
225
226    public int getState(Uri uri) {
227        Cursor cursor = SqliteWrapper.query(mContext, mContext.getContentResolver(),
228                            uri, new String[] {Mms.STATUS}, null, null, null);
229
230        if (cursor != null) {
231            try {
232                if (cursor.moveToFirst()) {
233                    return cursor.getInt(0) &~ DEFERRED_MASK;
234                }
235            } finally {
236                cursor.close();
237            }
238        }
239        return STATE_UNSTARTED;
240    }
241}
242