ClassZeroActivity.java revision 2b04a715ca8aba549ead0bc2b45f650386962c15
1/*
2 * Copyright (C) 2007-2008 Esmertec AG.
3 * Copyright (C) 2007-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.ui;
19
20import android.app.Activity;
21import android.app.AlertDialog;
22import android.content.ContentResolver;
23import android.content.ContentUris;
24import android.content.ContentValues;
25import android.content.DialogInterface;
26import android.content.DialogInterface.OnClickListener;
27import android.database.Cursor;
28import android.net.Uri;
29import android.os.Bundle;
30import android.os.Handler;
31import android.os.Message;
32import android.os.SystemClock;
33import android.provider.Telephony.Sms;
34import android.provider.Telephony.Sms.Inbox;
35import android.telephony.SmsMessage;
36import android.text.TextUtils;
37import android.util.Log;
38import android.view.Window;
39
40import com.android.mms.R;
41import com.android.mms.transaction.SmsReceiverService;
42import com.android.mms.transaction.MessagingNotification;
43
44import android.database.sqlite.SqliteWrapper;
45
46/**
47 * Display a class-zero SMS message to the user. Wait for the user to dismiss
48 * it.
49 */
50public class ClassZeroActivity extends Activity {
51    private static final String BUFFER = "         ";
52    private static final int BUFFER_OFFSET = BUFFER.length() * 2;
53    private static final String TAG = "display_00";
54    private static final int ON_AUTO_SAVE = 1;
55    private static final String[] REPLACE_PROJECTION = new String[] { Sms._ID,
56            Sms.ADDRESS, Sms.PROTOCOL };
57    private static final int REPLACE_COLUMN_ID = 0;
58
59    /** Default timer to dismiss the dialog. */
60    private static final long DEFAULT_TIMER = 5 * 60 * 1000;
61
62    /** To remember the exact time when the timer should fire. */
63    private static final String TIMER_FIRE = "timer_fire";
64
65    private SmsMessage mMessage = null;
66
67    /** Is the message read. */
68    private boolean mRead = false;
69
70    /** The timer to dismiss the dialog automatically. */
71    private long mTimerSet = 0;
72    private AlertDialog mDialog = null;
73
74    private Handler mHandler = new Handler() {
75        @Override
76        public void handleMessage(Message msg) {
77            // Do not handle an invalid message.
78            if (msg.what == ON_AUTO_SAVE) {
79                mRead = false;
80                mDialog.dismiss();
81                saveMessage();
82                finish();
83            }
84        }
85    };
86
87    private void saveMessage() {
88        Uri messageUri = null;
89        if (mMessage.isReplace()) {
90            messageUri = replaceMessage(mMessage);
91        } else {
92            messageUri = storeMessage(mMessage);
93        }
94        if (!mRead && messageUri != null) {
95            MessagingNotification.nonBlockingUpdateNewMessageIndicator(this, true, false);
96        }
97    }
98
99    @Override
100    protected void onCreate(Bundle icicle) {
101        super.onCreate(icicle);
102        requestWindowFeature(Window.FEATURE_NO_TITLE);
103        getWindow().setBackgroundDrawableResource(
104                R.drawable.class_zero_background);
105
106        byte[] pdu = getIntent().getByteArrayExtra("pdu");
107        String format = getIntent().getStringExtra("format");
108        mMessage = SmsMessage.createFromPdu(pdu, format);
109        CharSequence messageChars = mMessage.getMessageBody();
110        String message = messageChars.toString();
111        if (TextUtils.isEmpty(message)) {
112            finish();
113            return;
114        }
115        // TODO: The following line adds an emptry string before and after a message.
116        // This is not the correct way to layout a message. This is more of a hack
117        // to work-around a bug in AlertDialog. This needs to be fixed later when
118        // Android fixes the bug in AlertDialog.
119        if (message.length() < BUFFER_OFFSET) messageChars = BUFFER + message + BUFFER;
120        long now = SystemClock.uptimeMillis();
121        mDialog = new AlertDialog.Builder(this).setMessage(messageChars)
122                .setPositiveButton(R.string.save, mSaveListener)
123                .setNegativeButton(android.R.string.cancel, mCancelListener)
124                .setCancelable(false).show();
125        mTimerSet = now + DEFAULT_TIMER;
126        if (icicle != null) {
127            mTimerSet = icicle.getLong(TIMER_FIRE, mTimerSet);
128        }
129    }
130
131    @Override
132    protected void onStart() {
133        super.onStart();
134        long now = SystemClock.uptimeMillis();
135        if (mTimerSet <= now) {
136            // Save the message if the timer already expired.
137            mHandler.sendEmptyMessage(ON_AUTO_SAVE);
138        } else {
139            mHandler.sendEmptyMessageAtTime(ON_AUTO_SAVE, mTimerSet);
140            if (false) {
141                Log.d(TAG, "onRestart time = " + Long.toString(mTimerSet) + " "
142                        + this.toString());
143            }
144        }
145    }
146
147    @Override
148    protected void onSaveInstanceState(Bundle outState) {
149        super.onSaveInstanceState(outState);
150        outState.putLong(TIMER_FIRE, mTimerSet);
151        if (false) {
152            Log.d(TAG, "onSaveInstanceState time = " + Long.toString(mTimerSet)
153                    + " " + this.toString());
154        }
155    }
156
157    @Override
158    protected void onStop() {
159        super.onStop();
160        mHandler.removeMessages(ON_AUTO_SAVE);
161        if (false) {
162            Log.d(TAG, "onStop time = " + Long.toString(mTimerSet)
163                    + " " + this.toString());
164        }
165    }
166
167    private final OnClickListener mCancelListener = new OnClickListener() {
168        public void onClick(DialogInterface dialog, int whichButton) {
169            dialog.dismiss();
170            finish();
171        }
172    };
173
174    private final OnClickListener mSaveListener = new OnClickListener() {
175        public void onClick(DialogInterface dialog, int whichButton) {
176            mRead = true;
177            saveMessage();
178            dialog.dismiss();
179            finish();
180        }
181    };
182
183    private ContentValues extractContentValues(SmsMessage sms) {
184        // Store the message in the content provider.
185        ContentValues values = new ContentValues();
186
187        values.put(Inbox.ADDRESS, sms.getDisplayOriginatingAddress());
188
189        // Use now for the timestamp to avoid confusion with clock
190        // drift between the handset and the SMSC.
191        values.put(Inbox.DATE, new Long(System.currentTimeMillis()));
192        values.put(Inbox.PROTOCOL, sms.getProtocolIdentifier());
193        values.put(Inbox.READ, Integer.valueOf(mRead ? 1 : 0));
194        values.put(Inbox.SEEN, Integer.valueOf(mRead ? 1 : 0));
195
196        if (sms.getPseudoSubject().length() > 0) {
197            values.put(Inbox.SUBJECT, sms.getPseudoSubject());
198        }
199        values.put(Inbox.REPLY_PATH_PRESENT, sms.isReplyPathPresent() ? 1 : 0);
200        values.put(Inbox.SERVICE_CENTER, sms.getServiceCenterAddress());
201        return values;
202    }
203
204    private Uri replaceMessage(SmsMessage sms) {
205        ContentValues values = extractContentValues(sms);
206
207        values.put(Inbox.BODY, sms.getMessageBody());
208
209        ContentResolver resolver = getContentResolver();
210        String originatingAddress = sms.getOriginatingAddress();
211        int protocolIdentifier = sms.getProtocolIdentifier();
212        String selection = Sms.ADDRESS + " = ? AND " + Sms.PROTOCOL + " = ?";
213        String[] selectionArgs = new String[] { originatingAddress,
214                Integer.toString(protocolIdentifier) };
215
216        Cursor cursor = SqliteWrapper.query(this, resolver, Inbox.CONTENT_URI,
217                REPLACE_PROJECTION, selection, selectionArgs, null);
218
219        try {
220            if (cursor.moveToFirst()) {
221                long messageId = cursor.getLong(REPLACE_COLUMN_ID);
222                Uri messageUri = ContentUris.withAppendedId(
223                        Sms.CONTENT_URI, messageId);
224
225                SqliteWrapper.update(this, resolver, messageUri, values,
226                        null, null);
227                return messageUri;
228            }
229        } finally {
230            cursor.close();
231        }
232        return storeMessage(sms);
233    }
234
235    private Uri storeMessage(SmsMessage sms) {
236        // Store the message in the content provider.
237        ContentValues values = extractContentValues(sms);
238        values.put(Inbox.BODY, sms.getDisplayMessageBody());
239        ContentResolver resolver = getContentResolver();
240        if (false) {
241            Log.d(TAG, "storeMessage " + this.toString());
242        }
243        return SqliteWrapper.insert(this, resolver, Inbox.CONTENT_URI, values);
244    }
245}
246