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