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