基于android原生短信app实现定时发短信功能

时间:2024-04-08 15:21:58

基于android 8.1 MtkMms,vendor/mediatek/proprietary/packages/apps/Mms/进行实现的
一个思路是参考草稿箱的数据库结构,新建一个类似草稿箱的类型timer,定时发送时先把短信内容标记成timer类型存入数据库,
到设定的时间后再从数据库中取出timer类型的短信内容发送出去,这种方式需要修改数据库新增一个timer类型,而且在发送的短信列表要读取timer类型的短信进行显示.

其实有更方便的方式实现,通过观察短信数据库/data/user_de/0/com.android.providers.telephony/databases/mmssms.db中sms表的type类型,可以发现除了有inbox/outbox/draft的短信类型,还有一种queue的类型,通过阅读短信的代码,发现短信发送时会先将短信标记成queue类型存入数据库,然后从数据库中读取一条
queue类型的短信标记成outbox类型发送出去,然后再从数据库中读取下一条queue类型的短信进行发送,直到数据库中没有queue类型的短信。

这样我们就可以在短信标记成queue类型存入数据库时加入一个定时字段,然后在读取queue类型的短信时判断定时字段的时间,通过AlarmManager设置定时。定时字段我们也不用修改数据库,可以直接使用sms表的date_sent字段,这个字段用来存储收到短信的时间,对于发送短信没有用都是0.

发送短信插入定时的逻辑在SmsMessageSender.java, 读取queue类型短信进行发送的逻辑在SmsReceiverService.java,通过处理SmsReceiverService.ACTION_SEND_MESSAGE广播来完成
patch如下

diff --git a/mediatek/proprietary/packages/apps/Mms/AndroidManifest.xml b/mediatek/proprietary/packages/apps/Mms/AndroidManifest.xml
index a2a0382..25a46f0 100755
--- a/mediatek/proprietary/packages/apps/Mms/AndroidManifest.xml
+++ b/mediatek/proprietary/packages/apps/Mms/AndroidManifest.xml
@@ -772,6 +772,13 @@
             android:launchMode="singleTask"
             android:theme="@style/MmsTheme"
             android:excludeFromRecents="true"/>
+        <!-- fangao cyj add for timer mms start -->
+        <activity android:name="com.android.mms.ui.DateTimePickerActivity"
+            android:configChanges="orientation|screenSize|keyboardHidden"
+            android:label="@string/timer_select_time"
+            android:launchMode="singleTask"
+            android:excludeFromRecents="true"/>
+        <!-- fangao cyj add for timer mms end -->
         <provider
             android:name="android.support.v4.content.FileProvider"
             android:authorities="@string/contacts_file_provider_authority"
diff --git a/mediatek/proprietary/packages/apps/Mms/res/drawable-xxxhdpi/ic_timer_date.png b/mediatek/proprietary/packages/apps/Mms/res/drawable-xxxhdpi/ic_timer_date.png
new file mode 100644
index 0000000..95f26cc
Binary files /dev/null and b/mediatek/proprietary/packages/apps/Mms/res/drawable-xxxhdpi/ic_timer_date.png differ
diff --git a/mediatek/proprietary/packages/apps/Mms/res/drawable/date_time_picker_bg.xml b/mediatek/proprietary/packages/apps/Mms/res/drawable/date_time_picker_bg.xml
new file mode 100755
index 0000000..9a89e21
--- /dev/null
+++ b/mediatek/proprietary/packages/apps/Mms/res/drawable/date_time_picker_bg.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <item android:state_pressed="true"
+        android:drawable="@color/timer_button_pressed_bg"
+        />
+    <item
+        android:drawable="@color/timer_button_bg"
+        />
+
+</selector>
diff --git a/mediatek/proprietary/packages/apps/Mms/res/layout-finger-1080X720/compose_message_activity.xml b/mediatek/proprietary/packages/apps/Mms/res/layout-finger-1080X720/compose_message_activity.xml
index c38ce83..ee0f4fc 100755
--- a/mediatek/proprietary/packages/apps/Mms/res/layout-finger-1080X720/compose_message_activity.xml
+++ b/mediatek/proprietary/packages/apps/Mms/res/layout-finger-1080X720/compose_message_activity.xml
@@ -177,7 +177,28 @@
                         android:layout_height="wrap_content"/>
                 </view>
             </ScrollView>
-
+                    <!-- fangao cyj add start -->
+            <LinearLayout
+                android:id="@+id/date_send_layout"
+                android:orientation="horizontal"
+                android:visibility="gone"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content">
+               <TextView
+                    android:id="@+id/date_send_text"
+                    android:paddingLeft="4dip"
+                    android:paddingTop="6dip"
+                    android:layout_width="wrap_content"
+                    android:layout_height="match_parent"
+                    android:textColor="#ff000000"
+                    />
+                <ImageView
+                    android:id="@+id/date_send_delete"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:src="@drawable/ic_delete_file_attachment"/>
+            </LinearLayout>
+                    <!-- fangao cyj add end -->
             <LinearLayout
                 android:id="@+id/bottom_panel"
                 android:orientation="horizontal"
diff --git a/mediatek/proprietary/packages/apps/Mms/res/layout/date_time_picker.xml b/mediatek/proprietary/packages/apps/Mms/res/layout/date_time_picker.xml
new file mode 100644
index 0000000..ab3f652
--- /dev/null
+++ b/mediatek/proprietary/packages/apps/Mms/res/layout/date_time_picker.xml
@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2008 Esmertec AG.
+ * Copyright (C) 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.
+ */
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+    
+    <Button
+        android:id="@+id/dateButton"
+        android:layout_width="match_parent"
+        android:layout_height="40dip"
+        android:layout_marginTop="20dip"
+        android:text="year-month-day"
+        android:textSize="18dip"
+        android:background="@drawable/date_time_picker_bg"
+        android:onClick="pickSendDate"
+        />
+    
+    <Button
+        android:id="@+id/timeButton"
+        android:layout_below="@id/dateButton"
+        android:layout_width="match_parent"
+        android:layout_height="40dip"
+        android:layout_marginTop="1dip"
+        android:text="hour:minute"
+        android:textSize="18dip"
+        android:background="@drawable/date_time_picker_bg"
+        android:onClick="pickSendTime"
+        />
+    
+    <DatePicker
+        android:id="@+id/datePicker"
+        android:layout_below="@id/timeButton"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_centerHorizontal="true"
+        android:layout_marginTop="20dp"
+        android:textColor="#ff000000"
+        android:startYear="2019"
+        android:endYear="2030"
+        android:datePickerMode="spinner"
+        android:visibility="gone"
+        />
+        
+    <TimePicker
+        android:id="@+id/timePicker"
+        android:layout_below="@id/timeButton"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_centerHorizontal="true"
+        android:textColor="#ff000000"
+        android:layout_marginTop="20dp"
+        android:timePickerMode="spinner"
+        android:visibility="gone"
+        />
+    <LinearLayout
+        android:layout_marginTop="220dip"
+        android:layout_below="@id/datePicker"
+        android:orientation="horizontal"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content">
+    <Button
+        android:id="@+id/cancelButton"
+        android:layout_weight="1"
+        android:layout_width="fill_parent"
+        android:layout_height="match_parent"
+        android:text="@string/Cancel"
+        android:onClick="cancelButtonClick"
+        />
+    
+    <Button
+        android:id="@+id/okButton"
+        android:layout_weight="1"
+        android:layout_width="fill_parent"
+        android:layout_height="match_parent"
+        android:text="@string/OK"
+        android:onClick="okButtonClick"
+        />
+    </LinearLayout>
+
+</RelativeLayout>
diff --git a/mediatek/proprietary/packages/apps/Mms/res/values/colors.xml b/mediatek/proprietary/packages/apps/Mms/res/values/colors.xml
index 0758b36..2caad6c 100644
--- a/mediatek/proprietary/packages/apps/Mms/res/values/colors.xml
+++ b/mediatek/proprietary/packages/apps/Mms/res/values/colors.xml
@@ -82,5 +82,8 @@
     
     <color name="primary">#76b20e</color>
     <color name="primary_dark">#63940f</color>
+
+    <color name="timer_button_pressed_bg">#DD5D04</color>
+    <color name="timer_button_bg">#F7F7F7</color>
         
 </resources>
diff --git a/mediatek/proprietary/packages/apps/Mms/res/values/strings.xml b/mediatek/proprietary/packages/apps/Mms/res/values/strings.xml
index 7a34505..a499ab9 100755
--- a/mediatek/proprietary/packages/apps/Mms/res/values/strings.xml
+++ b/mediatek/proprietary/packages/apps/Mms/res/values/strings.xml
@@ -841,5 +841,10 @@
     <string name="banner_sms_promo_title_initial">Messaging is not your SMS app</string>
     <string name="banner_sms_promo_title_application"><xliff:g id="appName">%s</xliff:g> is your SMS app</string>
     <string name="banner_sms_promo_message">You can change this in Settings</string>
+    <!-- fangao cyj add for timer mms -->
+    <string name="menu_insert_timer">插入定时</string>
+    <string name="timer_sent_text">将发送于</string>
+    <string name="timer_later_now">定时需晚于当前时间</string>
+    <string name="timer_select_time">请设定发送时间</string>
 </resources>
 
diff --git a/mediatek/proprietary/packages/apps/Mms/src/com/android/mms/data/WorkingMessage.java b/mediatek/proprietary/packages/apps/Mms/src/com/android/mms/data/WorkingMessage.java
index 0118221..78d79a4 100755
--- a/mediatek/proprietary/packages/apps/Mms/src/com/android/mms/data/WorkingMessage.java
+++ b/mediatek/proprietary/packages/apps/Mms/src/com/android/mms/data/WorkingMessage.java
@@ -164,6 +164,7 @@ public class WorkingMessage implements IWorkingMessageCallback {
 
     // Text of the message.
     private CharSequence mText;
+    private long mDateSent = 0;//fangao cyj add
     // Slideshow for this message, if applicable.  If it's a simple attachment,
     // i.e. not SLIDESHOW, it will contain only one slide.
     private SlideshowModel mSlideshow;
@@ -743,6 +744,16 @@ public class WorkingMessage implements IWorkingMessageCallback {
             }
         }
     }
+    
+    //fangao cyj add start
+    public void setDateSent(long datesent) {
+        mDateSent = datesent;
+    }
+    
+    public long getDateSent() {
+        return mDateSent;
+    }
+    //fangao cyj add end
 
     /**
      * Sets the text of the message to the specified CharSequence.
@@ -2336,7 +2347,8 @@ public class WorkingMessage implements IWorkingMessageCallback {
             MmsLog.dpi(LogTag.TRANSACTION, "sendSmsWorker sending message: recipients=" +
                     semiSepRecipients + ", threadId=" + threadId);
         }
-        MessageSender sender = new SmsMessageSender(mActivity, dests, msgText, threadId, subId);
+
+        MessageSender sender = new SmsMessageSender(mActivity, dests, msgText, threadId, subId, mDateSent);//fangao cyj add mDateSent
 
         try {
             sender.sendMessage(threadId);
@@ -2719,8 +2731,9 @@ public class WorkingMessage implements IWorkingMessageCallback {
     }
 
     private static final String SMS_DRAFT_WHERE = Sms.TYPE + "=" + Sms.MESSAGE_TYPE_DRAFT;
-    private static final String[] SMS_BODY_PROJECTION = { Sms.BODY };
+    private static final String[] SMS_BODY_PROJECTION = { Sms.BODY ,Sms.DATE_SENT};//fangao cyj add Sms.DATE_SENT
     private static final int SMS_BODY_INDEX = 0;
+    private static final int SMS_DATE_SENT_INDEX = 1;//fangao cyj add
 
     /**
      * Reads a draft message for the given thread ID from the database,
@@ -2747,6 +2760,7 @@ public class WorkingMessage implements IWorkingMessageCallback {
             try {
                 if (c.moveToFirst()) {
                     body = c.getString(SMS_BODY_INDEX);
+                    mDateSent = c.getLong(SMS_DATE_SENT_INDEX);//fangao cyj add
                     haveDraft = true;
                 }
             } finally {
@@ -2844,6 +2858,11 @@ public class WorkingMessage implements IWorkingMessageCallback {
         values.put(Sms.THREAD_ID, threadId);
         values.put(Sms.BODY, contents);
         values.put(Sms.TYPE, Sms.MESSAGE_TYPE_DRAFT);
+        //fangao cyj add start
+        if (mDateSent > 0) {
+            values.put(Sms.DATE_SENT, mDateSent);
+        }
+        //fangao cyj add end
         SqliteWrapper.insert(mActivity, mContentResolver, Sms.CONTENT_URI, values);
         Log.d(TAG_DRAFT,
                 "[updateDraftSmsMessage] mIsTurnToChooseAttach : " + mIsTurnToChooseAttach);
diff --git a/mediatek/proprietary/packages/apps/Mms/src/com/android/mms/transaction/SmsMessageSender.java b/mediatek/proprietary/packages/apps/Mms/src/com/android/mms/transaction/SmsMessageSender.java
index 1f2d99f..03bc697 100644
--- a/mediatek/proprietary/packages/apps/Mms/src/com/android/mms/transaction/SmsMessageSender.java
+++ b/mediatek/proprietary/packages/apps/Mms/src/com/android/mms/transaction/SmsMessageSender.java
@@ -22,6 +22,8 @@
 
 package com.android.mms.transaction;
 
+import android.content.ContentResolver;
+import android.content.ContentValues;
 import android.content.Context;
 import android.content.Intent;
 import android.content.SharedPreferences;
@@ -32,6 +34,7 @@ import android.net.Uri;
 import android.preference.PreferenceManager;
 import android.provider.Telephony.Sms;
 import android.provider.Telephony.Sms.Inbox;
+import android.telephony.Rlog;
 import android.util.Log;
 
 import com.android.mms.LogTag;
@@ -53,6 +56,7 @@ public class SmsMessageSender implements MessageSender {
     protected final long mThreadId;
     protected int mSubId;
     protected long mTimestamp;
+    protected long mDateSent; //fangao cyj add
     private static final String TAG = "SmsMessageSender";
 
     // Default preference values
@@ -88,6 +92,13 @@ public class SmsMessageSender implements MessageSender {
         mOpSmsMessageSender = OpMessageUtils.getOpMessagePlugin()
                 .getOpSmsMessageSenderExt();
     }
+    // fangao cyj add start
+    public SmsMessageSender(Context context, String[] dests, String msgText, long threadId,
+            int subId, long datesent) {
+        this(context, dests,  msgText,  threadId, subId);
+        mDateSent = datesent;
+    }
+    // fangao cyj add end
 
     public boolean sendMessage(long token) throws MmsException {
         // In order to send the message one by one, instead of sending now, the message will split,
@@ -122,13 +133,13 @@ public class SmsMessageSender implements MessageSender {
                         requestDeliveryReport, mThreadId, mSubId, -timeStamp);
 
                 if (smsUri == null) {
-                    Sms.addMessageToUri(mSubId,
+                    addMessageToUri(mSubId,    //fangao cyj change to addMessageToUri below
                             mContext.getContentResolver(),
                             Uri.parse("content://sms/queued"), mDests[i],
                             mMessageText, null, mTimestamp,
                             true /* read */,
                             requestDeliveryReport,
-                            mThreadId);
+                            mThreadId, mDateSent);
                 }
             } catch (SQLiteException e) {
                 if (LogTag.DEBUG_SEND) {
@@ -144,6 +155,41 @@ public class SmsMessageSender implements MessageSender {
                 SmsReceiver.class));
         return false;
     }
+    
+    // fangao cyj add mms timer start 20190603
+    public static Uri addMessageToUri(int subId, ContentResolver resolver,
+            Uri uri, String address, String body, String subject,
+            Long date, boolean read, boolean deliveryReport, long threadId, long datesent) {
+        ContentValues values = new ContentValues(8);
+
+        values.put(Sms.SUBSCRIPTION_ID, subId);
+        values.put(Sms.ADDRESS, address);
+        if (date != null) {
+            values.put(Sms.DATE, date);
+        }
+//        int index = body.lastIndexOf(DATASENDFLAG);
+//        if (index != -1) {
+//            try {
+//                values.put(Sms.DATE_SENT, Long.parseLong(body.substring(index+DATASENDFLAG.length())));
+//                body = body.substring(0, index);
+//            } catch(Exception e){}
+//            
+//        }
+        if (datesent > 0) {
+            values.put(Sms.DATE_SENT, datesent);
+        }
+        values.put(Sms.READ, read ? Integer.valueOf(1) : Integer.valueOf(0));
+        values.put(Sms.SUBJECT, subject);
+        values.put(Sms.BODY, body);
+        if (deliveryReport) {
+            values.put(Sms.STATUS, Sms.STATUS_PENDING);
+        }
+        if (threadId != -1L) {
+            values.put(Sms.THREAD_ID, threadId);
+        }
+        return resolver.insert(uri, values);
+    }
+    // fangao cyj add mms timer end 20190603
 
     /**
      * Get the service center to use for a reply.
diff --git a/mediatek/proprietary/packages/apps/Mms/src/com/android/mms/transaction/SmsReceiverService.java b/mediatek/proprietary/packages/apps/Mms/src/com/android/mms/transaction/SmsReceiverService.java
index 236f64e..f54a23c 100755
--- a/mediatek/proprietary/packages/apps/Mms/src/com/android/mms/transaction/SmsReceiverService.java
+++ b/mediatek/proprietary/packages/apps/Mms/src/com/android/mms/transaction/SmsReceiverService.java
@@ -26,6 +26,8 @@ import static android.content.Intent.ACTION_BOOT_COMPLETED;
 import static android.provider.Telephony.Sms.Intents.SMS_DELIVER_ACTION;
 
 import android.app.Activity;
+import android.app.AlarmManager;
+import android.app.PendingIntent;
 import android.app.Service;
 import android.content.ContentResolver;
 import android.content.ContentUris;
@@ -95,7 +97,9 @@ import com.mediatek.setting.SmsPreferenceActivity;
 import com.mediatek.simmessage.SimFullReceiver;
 import com.mediatek.telephony.MtkTelephonyManagerEx;
 
+import java.text.SimpleDateFormat;
 import java.util.ArrayList;
+import java.util.Date;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Locale;
@@ -137,6 +141,7 @@ public class SmsReceiverService extends Service implements ISmsReceiverServiceCa
         Sms.BODY,       //3
         Sms.STATUS,     //4
         Sms.SUBSCRIPTION_ID,     //5
+        Sms.DATE_SENT,  //6 // fangao cyj add
     };
     /// M:Code analyze 001, override handleMessage @{
     public Handler mToastHandler = new Handler() {
@@ -166,6 +171,7 @@ public class SmsReceiverService extends Service implements ISmsReceiverServiceCa
     private static final int SEND_COLUMN_BODY       = 3;
     private static final int SEND_COLUMN_STATUS     = 4;
     private static final int SEND_COLUMN_SUB_ID     = 5;
+    private static final int SEND_COLUMN_DATE_SENT     = 6;  // fangao cyj add
 
     private int mResultCode;
 
@@ -387,6 +393,24 @@ public class SmsReceiverService extends Service implements ISmsReceiverServiceCa
         moveOutboxMessagesToQueuedBox();
         sendFirstQueuedMessage();
     }
+    
+    // fangao cyj add start
+    private void senMessageAtTime(long timeAt) {
+        PendingIntent operation = PendingIntent.getBroadcast(
+                this, 0, new Intent(SmsReceiverService.ACTION_SEND_MESSAGE,
+                        null,
+                        this,
+                        SmsReceiver.class), PendingIntent.FLAG_ONE_SHOT);
+        AlarmManager am = (AlarmManager)getSystemService(
+                Context.ALARM_SERVICE);
+        
+        am.cancel(operation);
+        am.set(AlarmManager.RTC_WAKEUP, timeAt, operation);
+        
+        Log.i(TAG, "aaron timer sms at:"+new SimpleDateFormat( " yyyy-MM-dd HH:mm" ).format(new Date(timeAt)));
+        
+    }
+    // fangao cyj add end
 
     public synchronized void sendFirstQueuedMessage() {
         /// M:
@@ -417,6 +441,30 @@ public class SmsReceiverService extends Service implements ISmsReceiverServiceCa
         if (c != null) {
             try {
                 if (c.moveToFirst()) {
+                    // fangao cyj add start
+                    long date_send = c.getLong(SEND_COLUMN_DATE_SENT);
+                    long timestamp = System.currentTimeMillis();
+                    long min_date = 0;
+                    if (date_send > timestamp) {
+                        if (min_date ==0 || date_send < min_date) {
+                            min_date = date_send;
+                        }
+                        while (c.moveToNext()) {
+                            date_send = c.getLong(SEND_COLUMN_DATE_SENT);
+                            if (date_send > timestamp) {
+                                if (date_send < min_date) {
+                                    min_date = date_send;
+                                }
+                                continue;
+                            }
+                            break;
+                        }
+                    }
+                    if (date_send > timestamp) {
+                        senMessageAtTime(min_date);
+                        return;
+                    }
+                    // fangao cyj add end
                     String msgText = c.getString(SEND_COLUMN_BODY);
                     String address = c.getString(SEND_COLUMN_ADDRESS);
                     int threadId = c.getInt(SEND_COLUMN_THREAD_ID);
@@ -795,6 +843,7 @@ public class SmsReceiverService extends Service implements ISmsReceiverServiceCa
         if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE) || LogTag.DEBUG_SEND) {
             Log.v(TAG, "moveOutboxMessagesToFailedBox messageCount: " + messageCount);
         }
+
         return messageCount;
     }
 
@@ -1545,11 +1594,12 @@ public class SmsReceiverService extends Service implements ISmsReceiverServiceCa
         final Uri uri = Uri.parse("content://sms/queued");
         int messageCount = SqliteWrapper.update(
                 getApplicationContext(), getContentResolver(), uri,
-                values, "type = " + Sms.MESSAGE_TYPE_QUEUED , null);
+                values, "type = " + Sms.MESSAGE_TYPE_QUEUED+" AND date_sent = 0" , null);// fangao cyj change null to "date_sent = 0" not move timer mms
 
         if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE) || LogTag.DEBUG_SEND) {
             Log.v(TAG, "moveQueuedMessagesToFailedBox messageCount: " + messageCount);
         }
+
         return messageCount;
     }
 
diff --git a/mediatek/proprietary/packages/apps/Mms/src/com/android/mms/transaction/SmsSystemEventReceiver.java b/mediatek/proprietary/packages/apps/Mms/src/com/android/mms/transaction/SmsSystemEventReceiver.java
index 75656c8..52a7b6f 100644
--- a/mediatek/proprietary/packages/apps/Mms/src/com/android/mms/transaction/SmsSystemEventReceiver.java
+++ b/mediatek/proprietary/packages/apps/Mms/src/com/android/mms/transaction/SmsSystemEventReceiver.java
@@ -109,7 +109,7 @@ public class SmsSystemEventReceiver extends BroadcastReceiver {
         // to the user, so mark them as failed and notify the user, who can then decide whether to
         // resend them manually.
         int numMoved = moveOutboxMessagesToFailedBox(context, null);
-        numMoved = numMoved + moveQueuedMessagesToFailedBox(context, null);
+        numMoved = numMoved + moveQueuedMessagesToFailedBox(context, " AND date_sent = 0"); // fangao cyj change null to "date_sent = 0" not move timer mms
         if (numMoved > 0) {
             MessagingNotification.notifySendFailed(context.getApplicationContext(), true);
         }
diff --git a/mediatek/proprietary/packages/apps/Mms/src/com/android/mms/ui/ComposeMessageActivity.java b/mediatek/proprietary/packages/apps/Mms/src/com/android/mms/ui/ComposeMessageActivity.java
index 2ceb39a..0518ee7 100644
--- a/mediatek/proprietary/packages/apps/Mms/src/com/android/mms/ui/ComposeMessageActivity.java
+++ b/mediatek/proprietary/packages/apps/Mms/src/com/android/mms/ui/ComposeMessageActivity.java
@@ -121,7 +121,7 @@ import android.widget.SimpleAdapter;
 import android.widget.BaseAdapter;
 import android.widget.TextView;
 import android.widget.Toast;
-
+import java.util.Date;
 import com.android.browser.provider.Browser;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.TelephonyIntents;
@@ -213,6 +213,7 @@ import java.io.InputStream;
 import java.io.UnsupportedEncodingException;
 import java.lang.ref.WeakReference;
 import java.net.URLDecoder;
+import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -476,6 +477,12 @@ public class ComposeMessageActivity extends Activity
     private TextView mTopTitle;
     private ImageView mMuteLogo;
     private TextView mTopSubtitle;
+    
+    // fangao cyj add start
+    private LinearLayout mDateSentLayout;
+    private TextView mDateSentText;
+    private long mDateSent;
+    // fangao cyj add end
 
     private boolean mHadToSlideShowEditor = false;
 
@@ -3163,6 +3170,23 @@ public class ComposeMessageActivity extends Activity
 
         this.registerReceiver(mSubReceiver, intentFilter);
         /// @}
+        // fangao cyj add start
+        mDateSentText = (TextView) findViewById(R.id.date_send_text);
+        mDateSentLayout = (LinearLayout)findViewById(R.id.date_send_layout);
+        ImageView date_send_delete = (ImageView)findViewById(R.id.date_send_delete);
+        date_send_delete.setOnClickListener(new View.OnClickListener(){
+            @Override
+            public void onClick(View v) {
+                if (mDateSentLayout != null && mDateSentText != null) {
+                    mDateSentText.setText("");
+                    mDateSentLayout.setVisibility(View.GONE);
+                    mWorkingMessage.setDateSent(0);
+                }
+                
+            }
+            
+        });
+        // fangao cyj add end
     }
 
     private void showSubjectEditor(boolean show) {
@@ -4889,6 +4913,9 @@ public class ComposeMessageActivity extends Activity
             if (!mWorkingMessage.hasSlideshow()) {
                 menu.add(0, MENU_ADD_TEXT_VCARD, 0, R.string.menu_insert_text_vcard);
             }
+            // fangao cyj add start
+            menu.add(0, MENU_ADD_TIMER, 0, R.string.menu_insert_timer);
+            // fangao cyj add end
         }
         /// @}
         if (mIsSmsEnabled) {
@@ -4998,6 +5025,14 @@ public class ComposeMessageActivity extends Activity
                 break;
             }
             /// @}
+            // fangao cyj add start
+            case MENU_ADD_TIMER: {
+                Intent intent =
+                    new Intent(this, DateTimePickerActivity.class);
+                startActivityForResult(intent, REQUEST_CODE_TIMER);
+                break;
+            }
+            // fangao cyj add end
             case MENU_DISCARD:
                 /// M: fix bug for ConversationList select all performance,
                 /// update selected threads [email protected]{
@@ -5608,6 +5643,21 @@ public class ComposeMessageActivity extends Activity
                 misPickContatct = false;
                 return;
             /// @}
+                // fangao cyj add start
+            case REQUEST_CODE_TIMER:
+                if (data != null) {
+                    if (mDateSentLayout != null && mDateSentText != null) {
+                        mDateSentLayout.setVisibility(View.VISIBLE);
+                        mDateSent = data.getLongExtra("date_sent", 0);
+                        SimpleDateFormat sdf = new SimpleDateFormat( " yyyy-MM-dd HH:mm" );
+                        mDateSentText.setText(getString(R.string.timer_sent_text)+sdf.format(new Date(mDateSent)));
+                        mWorkingMessage.setDateSent(mDateSent);
+                    }
+
+                }
+                misPickContatct = false;
+                return;
+                // fangao cyj add end
             /// M: Code analyze 019, Add vcard [email protected]{
             case REQUEST_CODE_ATTACH_VCARD:
                 asyncAttachVCardByContactsId(data);
@@ -6669,6 +6719,11 @@ public class ComposeMessageActivity extends Activity
                 }
                 */
                 /// @}
+                // fangao cyj add start
+                if (mDateSentLayout != null) {
+                    mDateSentLayout.setVisibility(View.GONE);
+                }
+                // fangao cyj add end
                 mSendButtonCanResponse = false;
                 if (isPreparedForSending()) {
                     /// M: Since sending message here, why not disable button 'Send'??
@@ -7175,6 +7230,15 @@ public class ComposeMessageActivity extends Activity
                         drawTopPanel(false);
                         drawBottomPanel();
                         updateSendButtonState();
+                        //fangao cyj add start
+                        if (0<mWorkingMessage.getDateSent() && mDateSentLayout != null && mDateSentText != null) {
+                            mDateSentLayout.setVisibility(View.VISIBLE);
+                            mDateSent = mWorkingMessage.getDateSent();
+                            SimpleDateFormat sdf = new SimpleDateFormat( " yyyy-MM-dd HH:mm" );
+                            mDateSentText.setText(getString(R.string.timer_sent_text)+sdf.format(new Date(mDateSent)));
+                            mWorkingMessage.setDateSent(mDateSent);
+                        }
+                        //fangao cyj add end
                     }
                 });
 //        if (mConversation != null && mConversation.getRecipients() != null
@@ -8357,6 +8421,8 @@ public class ComposeMessageActivity extends Activity
      /// @}
 
      private static final int MENU_CALL_RECIPIENT_BY_VT  = 10;
+     private static final int MENU_ADD_TIMER         = 11; // fangao cyj add
+     public static final int REQUEST_CODE_TIMER       = 27;// fangao cyj add
      /// M: Code analyze 016, Add for select text copy. @{
      private static final int MENU_SELECT_TEXT             = 36;
      /// @}
diff --git a/mediatek/proprietary/packages/apps/Mms/src/com/android/mms/ui/DateTimePickerActivity.java b/mediatek/proprietary/packages/apps/Mms/src/com/android/mms/ui/DateTimePickerActivity.java
new file mode 100644
index 0000000..11bcd5e
--- /dev/null
+++ b/mediatek/proprietary/packages/apps/Mms/src/com/android/mms/ui/DateTimePickerActivity.java
@@ -0,0 +1,154 @@
+package com.android.mms.ui;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.Menu;
+import android.view.View;
+import android.widget.Button;
+import android.widget.DatePicker;
+import android.widget.DatePicker.OnDateChangedListener;//监听日期变化
+import android.widget.TimePicker;
+import android.widget.Toast;
+import android.widget.TimePicker.OnTimeChangedListener;//监听时间变化
+import com.android.mms.R;
+//fangao cyj add
+public class DateTimePickerActivity extends Activity {
+    
+//    private int year;
+//    private int month;
+//    private int day;
+//    private int hour;
+//    private int minute;
+    
+    private TimePicker timePicker = null;
+    private DatePicker datePicker = null;
+    private Button timeButton = null;
+    private Button dateButton = null;
+    private Date mDate = null;
+    //protected String[] time = null;
+    
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.date_time_picker);
+        
+        mDate = new Date();
+        timeButton = (Button)findViewById(R.id.timeButton);
+        dateButton = (Button)findViewById(R.id.dateButton);
+        
+        timePicker = (TimePicker)findViewById(R.id.timePicker);
+        timePicker.setIs24HourView(true);
+        //设定默认时间为当前系统时间
+        /*也可以用TimePicker的getCurrentHour()和getCurrentMinute()方法  获得当前时间*/
+        //time = getCurrentTime();
+        timePicker.setCurrentHour(mDate.getHours());
+        timePicker.setCurrentMinute(mDate.getMinutes());
+        
+        
+        //设置日期
+        datePicker = (DatePicker)findViewById(R.id.datePicker);
+        datePicker.setCalendarViewShown(false);
+        
+        //设置button上的默认日期时间
+        SimpleDateFormat sdf = new SimpleDateFormat( "HH:mm" );
+        timeButton.setText(sdf.format(mDate));
+        //timeButton.setText(timePicker.getCurrentHour()+":"+timePicker.getCurrentMinute());
+        sdf = new SimpleDateFormat( "yyyy-MM-dd" );
+        dateButton.setText(sdf.format(mDate));
+        //dateButton.setText(mDate.getYear()+1900+"年"+(mDate.getMonth()+1)+"月"+mDate.getDate()+"日");
+        
+        //设置日期选择器 默认可见
+        datePicker.setVisibility(View.VISIBLE);
+        dateButton.setBackgroundResource(R.color.timer_button_pressed_bg);
+        
+        //设置监听器
+        timePicker.setOnTimeChangedListener(new SendTimeChangedListener());
+        datePicker.init(mDate.getYear()+1900, mDate.getMonth(), mDate.getDate(), new SendDateChangedListener());
+    }
+
+    
+    public String[] getCurrentTime(){
+        //取得当前的hour minute即可
+        SimpleDateFormat curTimeFormat = new SimpleDateFormat("HH-mm");       
+        String curTime = curTimeFormat.format(new Date());
+        String[] time = new String[2];
+        time = curTime.split("-");
+        return time;
+    }
+    
+    public  String[] getCurrentDate(){
+        //取得当前日期的年月日
+        SimpleDateFormat curDateFormat = new SimpleDateFormat("yyyy-MM-dd");       
+        String curDate = curDateFormat.format(new Date());
+        String[] date = new String[3];
+        date = curDate.split("-");
+        return date;
+    }
+    
+    public void pickSendDate(View view){
+        datePicker.setVisibility(View.VISIBLE);
+        timePicker.setVisibility(View.INVISIBLE);
+        timeButton.setBackgroundResource(R.color.timer_button_bg);
+        dateButton.setBackgroundResource(R.color.timer_button_pressed_bg);
+    }
+    
+    public void pickSendTime(View view){
+        datePicker.setVisibility(View.INVISIBLE);
+        timePicker.setVisibility(View.VISIBLE);
+        timeButton.setBackgroundResource(R.color.timer_button_pressed_bg);
+        dateButton.setBackgroundResource(R.color.timer_button_bg);
+    }
+    
+    public void cancelButtonClick(View view){
+        finish();
+    }
+    
+    public void okButtonClick(View view){
+        long date = mDate.getTime();
+        if (date <= System.currentTimeMillis()) {
+            Toast.makeText(this,
+                    getString(R.string.timer_later_now),
+                    Toast.LENGTH_SHORT).show();
+            return;
+        }
+        Intent intent = new Intent();
+        intent.putExtra("date_sent", date);
+        setResult(RESULT_OK, intent);
+        finish();
+    }
+
+    class SendTimeChangedListener implements OnTimeChangedListener{
+
+        @Override
+        public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
+            //timeButton.setText(hourOfDay+":"+minute);
+//            DateTimePickerActivity.this.hour = hourOfDay;
+//            DateTimePickerActivity.this.minute = minute;
+            mDate.setHours(hourOfDay);
+            mDate.setMinutes(minute);
+            SimpleDateFormat sdf = new SimpleDateFormat( "HH:mm" );
+            timeButton.setText(sdf.format(mDate));
+        }        
+    }
+
+    class SendDateChangedListener implements OnDateChangedListener{
+
+        @Override
+        public void onDateChanged(DatePicker view, int year, int month, int day) {
+            //dateButton.setText(year+"年"+(month+1)+"月"+day+"日");
+//            DateTimePickerActivity.this.year = year;
+//            DateTimePickerActivity.this.month = month;
+//            DateTimePickerActivity.this.day = day;
+            mDate.setYear(year-1900);
+            mDate.setMonth(month);
+            mDate.setDate(day);
+            
+            SimpleDateFormat sdf = new SimpleDateFormat( "yyyy-MM-dd" );
+            dateButton.setText(sdf.format(mDate));
+        }
+    }
+
+}
diff --git a/mediatek/proprietary/packages/apps/Mms/src/com/android/mms/ui/MessageItem.java b/mediatek/proprietary/packages/apps/Mms/src/com/android/mms/ui/MessageItem.java
index 09834f4..016bd99 100644
--- a/mediatek/proprietary/packages/apps/Mms/src/com/android/mms/ui/MessageItem.java
+++ b/mediatek/proprietary/packages/apps/Mms/src/com/android/mms/ui/MessageItem.java
@@ -31,6 +31,7 @@ import android.provider.Telephony.MmsSms;
 import android.provider.Telephony.Sms;
 import android.telephony.SmsManager;
 import android.text.TextUtils;
+import android.text.format.Time;
 import android.util.Log;
 
 import com.android.mms.LogTag;
@@ -459,6 +460,23 @@ public class MessageItem implements IMessageItemCallback {
 
             // Unless the message is currently in the progress of being sent, it gets a time stamp.
             long date = cursor.getLong(columnsMap.mColumnSmsDate);
+            //fangao cyj add start
+            if (isSms() && (mBoxId == Sms.MESSAGE_TYPE_QUEUED)) {
+                mSmsSentDate = cursor.getLong(columnsMap.mColumnSmsDateSent);
+                if (mSmsSentDate != 0) {
+                    Time then = new Time();
+                    then.set(mSmsSentDate);
+                    Time now = new Time();
+                    now.set(date);
+                    if (then.yearDay != now.yearDay) {
+                        mTimestamp = MessageUtils.formatTimeStampString(context, mSmsSentDate, true);
+                    } else {
+                        mTimestamp = MessageUtils.getShortTimeString(context, mSmsSentDate);
+                    }
+                     mSmsDate = mSmsSentDate;
+                }
+            }
+            // fangao cyj add end
             if (!isOutgoingMessage()) {
                 // Set "received" or "sent" time stamp
                 /// M: @{
@@ -481,6 +499,21 @@ public class MessageItem implements IMessageItemCallback {
 //                        mTimestamp = String.format(context.getString(R.string.sent_on),
 //                                MessageUtils.formatTimeStampString(context, date));
                         mTimestamp = MessageUtils.getShortTimeString(context, date);
+                        //fangao cyj add start
+                        mSmsSentDate = cursor.getLong(columnsMap.mColumnSmsDateSent);
+                        if (mSmsSentDate != 0) {
+                            Time then = new Time();
+                            then.set(mSmsSentDate);
+                            Time now = new Time();
+                            now.set(date);
+                            if (then.yearDay != now.yearDay) {
+                                mTimestamp = MessageUtils.formatTimeStampString(context, mSmsSentDate, true);
+                            } else {
+                                mTimestamp = MessageUtils.getShortTimeString(context, mSmsSentDate);
+                            }
+                             mSmsDate = mSmsSentDate;
+                        }
+                        // fangao cyj add end
                     }
                 } else {
                     mTimestamp = "";
diff --git a/mediatek/proprietary/packages/apps/Mms/src/com/android/mms/ui/MessageListItem.java b/mediatek/proprietary/packages/apps/Mms/src/com/android/mms/ui/MessageListItem.java
index 914c28c..39e32d8 100644
--- a/mediatek/proprietary/packages/apps/Mms/src/com/android/mms/ui/MessageListItem.java
+++ b/mediatek/proprietary/packages/apps/Mms/src/com/android/mms/ui/MessageListItem.java
@@ -832,7 +832,7 @@ public class MessageListItem extends LinearLayout implements
         } else {
             mDateView.setVisibility(View.VISIBLE);
             /// M: google jb.mr1 patch, group mms
-            String dateStr = mMessageItem.isSending()
+            String dateStr = mMessageItem.isSending() && mMessageItem.mSmsSentDate==0  // fangao cyj add && mMessageItem.mSmsSentDate==0
                     ? mContext.getResources().getString(R.string.sending_message)
                     : buildTimestampLine(mMessageItem.mTimestamp);
             mDateView.setText(dateStr);
diff --git a/mediatek/proprietary/packages/apps/Mms/src/com/android/mms/ui/MessageUtils.java b/mediatek/proprietary/packages/apps/Mms/src/com/android/mms/ui/MessageUtils.java
index 3b5b40f..a579554 100644
--- a/mediatek/proprietary/packages/apps/Mms/src/com/android/mms/ui/MessageUtils.java
+++ b/mediatek/proprietary/packages/apps/Mms/src/com/android/mms/ui/MessageUtils.java
@@ -2876,7 +2876,7 @@ public class MessageUtils {
             switch (msgItem.mBoxId) {
             case Sms.MESSAGE_TYPE_QUEUED:
             case Sms.MESSAGE_TYPE_OUTBOX:
-                return R.drawable.im_meg_status_sending;
+                return msgItem.mSmsSentDate!=0?R.drawable.ic_timer_date:R.drawable.im_meg_status_sending;//fangao cyj add ic_timer_date
 
             case Sms.MESSAGE_TYPE_SENT:
                 return R.drawable.im_meg_status_out;

效果如下:

基于android原生短信app实现定时发短信功能

基于android原生短信app实现定时发短信功能

基于android原生短信app实现定时发短信功能

基于android原生短信app实现定时发短信功能

基于android原生短信app实现定时发短信功能