| /* |
| * Copyright (C) 2007-2008 Esmertec AG. |
| * Copyright (C) 2007-2008 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.mms.ui; |
| |
| import android.app.Activity; |
| import android.app.AlertDialog; |
| import android.content.ContentResolver; |
| import android.content.ContentUris; |
| import android.content.ContentValues; |
| import android.content.DialogInterface; |
| import android.content.DialogInterface.OnClickListener; |
| import android.content.Intent; |
| import android.database.Cursor; |
| import android.database.sqlite.SqliteWrapper; |
| import android.net.Uri; |
| import android.os.Bundle; |
| import android.os.Handler; |
| import android.os.Message; |
| import android.os.SystemClock; |
| import android.provider.Telephony.Sms; |
| import android.provider.Telephony.Sms.Inbox; |
| import android.telephony.SmsMessage; |
| import android.text.TextUtils; |
| import android.util.Log; |
| import android.view.Window; |
| |
| import com.android.mms.R; |
| import com.android.mms.transaction.MessagingNotification; |
| |
| import java.util.ArrayList; |
| |
| /** |
| * Display a class-zero SMS message to the user. Wait for the user to dismiss |
| * it. |
| */ |
| public class ClassZeroActivity extends Activity { |
| private static final String BUFFER = " "; |
| private static final int BUFFER_OFFSET = BUFFER.length() * 2; |
| private static final String TAG = "display_00"; |
| private static final int ON_AUTO_SAVE = 1; |
| private static final String[] REPLACE_PROJECTION = new String[] { Sms._ID, |
| Sms.ADDRESS, Sms.PROTOCOL }; |
| private static final int REPLACE_COLUMN_ID = 0; |
| |
| /** Default timer to dismiss the dialog. */ |
| private static final long DEFAULT_TIMER = 5 * 60 * 1000; |
| |
| /** To remember the exact time when the timer should fire. */ |
| private static final String TIMER_FIRE = "timer_fire"; |
| |
| private SmsMessage mMessage = null; |
| |
| /** Is the message read. */ |
| private boolean mRead = false; |
| |
| /** The timer to dismiss the dialog automatically. */ |
| private long mTimerSet = 0; |
| private AlertDialog mDialog = null; |
| |
| private ArrayList<SmsMessage> mMessageQueue = null; |
| |
| private Handler mHandler = new Handler() { |
| @Override |
| public void handleMessage(Message msg) { |
| // Do not handle an invalid message. |
| if (msg.what == ON_AUTO_SAVE) { |
| mRead = false; |
| mDialog.dismiss(); |
| saveMessage(); |
| processNextMessage(); |
| } |
| } |
| }; |
| |
| private boolean queueMsgFromIntent(Intent msgIntent) { |
| byte[] pdu = msgIntent.getByteArrayExtra("pdu"); |
| String format = msgIntent.getStringExtra("format"); |
| SmsMessage rawMessage = SmsMessage.createFromPdu(pdu, format); |
| String message = rawMessage.getMessageBody(); |
| if (TextUtils.isEmpty(message)) { |
| if (mMessageQueue.size() == 0) { |
| finish(); |
| } |
| return false; |
| } |
| mMessageQueue.add(rawMessage); |
| return true; |
| } |
| |
| private void processNextMessage() { |
| mMessageQueue.remove(0); |
| if (mMessageQueue.size() == 0) { |
| finish(); |
| } else { |
| displayZeroMessage(mMessageQueue.get(0)); |
| } |
| } |
| |
| private void saveMessage() { |
| Uri messageUri = null; |
| if (mMessage.isReplace()) { |
| messageUri = replaceMessage(mMessage); |
| } else { |
| messageUri = storeMessage(mMessage); |
| } |
| if (!mRead && messageUri != null) { |
| MessagingNotification.nonBlockingUpdateNewMessageIndicator( |
| this, |
| MessagingNotification.THREAD_ALL, // always notify on class-zero msgs |
| false); |
| } |
| } |
| |
| @Override |
| protected void onNewIntent(Intent msgIntent) { |
| /* Running with another visible message, queue this one */ |
| queueMsgFromIntent(msgIntent); |
| } |
| |
| @Override |
| protected void onCreate(Bundle icicle) { |
| super.onCreate(icicle); |
| requestWindowFeature(Window.FEATURE_NO_TITLE); |
| getWindow().setBackgroundDrawableResource( |
| R.drawable.class_zero_background); |
| |
| if (mMessageQueue == null) { |
| mMessageQueue = new ArrayList<SmsMessage>(); |
| } |
| |
| if (!queueMsgFromIntent(getIntent())) { |
| return; |
| } |
| |
| if (mMessageQueue.size() == 1) { |
| displayZeroMessage(mMessageQueue.get(0)); |
| } |
| |
| if (icicle != null) { |
| mTimerSet = icicle.getLong(TIMER_FIRE, mTimerSet); |
| } |
| } |
| |
| private void displayZeroMessage(SmsMessage rawMessage) { |
| String message = rawMessage.getMessageBody(); |
| /* This'll be used by the save action */ |
| mMessage = rawMessage; |
| |
| mDialog = new AlertDialog.Builder(this, AlertDialog.THEME_HOLO_DARK).setMessage(message) |
| .setPositiveButton(R.string.save, mSaveListener) |
| .setNegativeButton(android.R.string.cancel, mCancelListener) |
| .setCancelable(false).show(); |
| long now = SystemClock.uptimeMillis(); |
| mTimerSet = now + DEFAULT_TIMER; |
| } |
| |
| @Override |
| protected void onStart() { |
| super.onStart(); |
| long now = SystemClock.uptimeMillis(); |
| if (mTimerSet <= now) { |
| // Save the message if the timer already expired. |
| mHandler.sendEmptyMessage(ON_AUTO_SAVE); |
| } else { |
| mHandler.sendEmptyMessageAtTime(ON_AUTO_SAVE, mTimerSet); |
| if (false) { |
| Log.d(TAG, "onRestart time = " + Long.toString(mTimerSet) + " " |
| + this.toString()); |
| } |
| } |
| } |
| |
| @Override |
| protected void onSaveInstanceState(Bundle outState) { |
| super.onSaveInstanceState(outState); |
| outState.putLong(TIMER_FIRE, mTimerSet); |
| if (false) { |
| Log.d(TAG, "onSaveInstanceState time = " + Long.toString(mTimerSet) |
| + " " + this.toString()); |
| } |
| } |
| |
| @Override |
| protected void onStop() { |
| super.onStop(); |
| mHandler.removeMessages(ON_AUTO_SAVE); |
| if (false) { |
| Log.d(TAG, "onStop time = " + Long.toString(mTimerSet) |
| + " " + this.toString()); |
| } |
| } |
| |
| private final OnClickListener mCancelListener = new OnClickListener() { |
| public void onClick(DialogInterface dialog, int whichButton) { |
| dialog.dismiss(); |
| processNextMessage(); |
| } |
| }; |
| |
| private final OnClickListener mSaveListener = new OnClickListener() { |
| public void onClick(DialogInterface dialog, int whichButton) { |
| mRead = true; |
| saveMessage(); |
| dialog.dismiss(); |
| processNextMessage(); |
| } |
| }; |
| |
| private ContentValues extractContentValues(SmsMessage sms) { |
| // Store the message in the content provider. |
| ContentValues values = new ContentValues(); |
| |
| values.put(Inbox.ADDRESS, sms.getDisplayOriginatingAddress()); |
| |
| // Use now for the timestamp to avoid confusion with clock |
| // drift between the handset and the SMSC. |
| values.put(Inbox.DATE, new Long(System.currentTimeMillis())); |
| values.put(Inbox.PROTOCOL, sms.getProtocolIdentifier()); |
| values.put(Inbox.READ, Integer.valueOf(mRead ? 1 : 0)); |
| values.put(Inbox.SEEN, Integer.valueOf(mRead ? 1 : 0)); |
| |
| if (sms.getPseudoSubject().length() > 0) { |
| values.put(Inbox.SUBJECT, sms.getPseudoSubject()); |
| } |
| values.put(Inbox.REPLY_PATH_PRESENT, sms.isReplyPathPresent() ? 1 : 0); |
| values.put(Inbox.SERVICE_CENTER, sms.getServiceCenterAddress()); |
| return values; |
| } |
| |
| private Uri replaceMessage(SmsMessage sms) { |
| ContentValues values = extractContentValues(sms); |
| |
| values.put(Inbox.BODY, sms.getMessageBody()); |
| |
| ContentResolver resolver = getContentResolver(); |
| String originatingAddress = sms.getOriginatingAddress(); |
| int protocolIdentifier = sms.getProtocolIdentifier(); |
| String selection = Sms.ADDRESS + " = ? AND " + Sms.PROTOCOL + " = ?"; |
| String[] selectionArgs = new String[] { originatingAddress, |
| Integer.toString(protocolIdentifier) }; |
| |
| Cursor cursor = SqliteWrapper.query(this, resolver, Inbox.CONTENT_URI, |
| REPLACE_PROJECTION, selection, selectionArgs, null); |
| |
| try { |
| if (cursor.moveToFirst()) { |
| long messageId = cursor.getLong(REPLACE_COLUMN_ID); |
| Uri messageUri = ContentUris.withAppendedId( |
| Sms.CONTENT_URI, messageId); |
| |
| SqliteWrapper.update(this, resolver, messageUri, values, |
| null, null); |
| return messageUri; |
| } |
| } finally { |
| cursor.close(); |
| } |
| return storeMessage(sms); |
| } |
| |
| private Uri storeMessage(SmsMessage sms) { |
| // Store the message in the content provider. |
| ContentValues values = extractContentValues(sms); |
| values.put(Inbox.BODY, sms.getDisplayMessageBody()); |
| ContentResolver resolver = getContentResolver(); |
| if (false) { |
| Log.d(TAG, "storeMessage " + this.toString()); |
| } |
| return SqliteWrapper.insert(this, resolver, Inbox.CONTENT_URI, values); |
| } |
| } |