/**
   * This method is used if this is a "replace short message" SMS. We find any existing message that
   * matches the incoming message's originating address and protocol identifier. If there is one, we
   * replace its fields with those of the new message. Otherwise, we store the new message as usual.
   *
   * <p>See TS 23.040 9.2.3.9.
   */
  private Uri replaceMessage(Context context, SmsMessage[] msgs, int error) {
    SmsMessage sms = msgs[0];
    ContentValues values = extractContentValues(sms);
    values.put(Sms.ERROR_CODE, error);
    int pduCount = msgs.length;

    if (pduCount == 1) {
      // There is only one part, so grab the body directly.
      values.put(Inbox.BODY, replaceFormFeeds(sms.getDisplayMessageBody()));
    } else {
      // Build up the body from the parts.
      StringBuilder body = new StringBuilder();
      for (int i = 0; i < pduCount; i++) {
        sms = msgs[i];
        if (sms.mWrappedSmsMessage != null) {
          body.append(sms.getDisplayMessageBody());
        }
      }
      values.put(Inbox.BODY, replaceFormFeeds(body.toString()));
    }

    ContentResolver resolver = context.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(
            context,
            resolver,
            Inbox.CONTENT_URI,
            REPLACE_PROJECTION,
            selection,
            selectionArgs,
            null);

    if (cursor != null) {
      try {
        if (cursor.moveToFirst()) {
          long messageId = cursor.getLong(REPLACE_COLUMN_ID);
          Uri messageUri = ContentUris.withAppendedId(Sms.CONTENT_URI, messageId);

          SqliteWrapper.update(context, resolver, messageUri, values, null, null);
          return messageUri;
        }
      } finally {
        cursor.close();
      }
    }
    return storeMessage(context, msgs, error);
  }
  /// M:Code analyze 011,add for setting the mms being downloading when shutdown to unrecognized
  /// after boot complete again,have to manual download @{
  public static void setNotificationIndUnstarted(final Context context) {
    MmsLog.d(MmsApp.TXN_TAG, "setNotificationIndUnstarted");
    Cursor cursor =
        SqliteWrapper.query(
            context,
            context.getContentResolver(),
            Mms.CONTENT_URI,
            new String[] {Mms._ID, Mms.STATUS},
            Mms.MESSAGE_TYPE + "=" + PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND,
            null,
            null);
    if (cursor != null) {
      try {
        int count = cursor.getCount();
        MmsLog.d(MmsApp.TXN_TAG, "setNotificationIndUnstarted: Message Size=" + count);

        if (count == 0) {
          return;
        }

        ContentValues values = null;
        int id = 0;
        int status = 0;
        while (cursor.moveToNext()) {
          id = cursor.getInt(0);
          status = cursor.getInt(1);
          MmsLog.d(
              MmsApp.TXN_TAG, "setNotificationIndUnstarted: MsgId=" + id + "; status=" + status);

          if (DownloadManager.STATE_DOWNLOADING == (status & ~DownloadManager.DEFERRED_MASK)) {
            values = new ContentValues(1);
            values.put(Mms.STATUS, PduHeaders.STATUS_UNRECOGNIZED);
            SqliteWrapper.update(
                context,
                context.getContentResolver(),
                Mms.CONTENT_URI,
                values,
                Mms._ID + "=" + id,
                null);
          }
        }
      } catch (SQLiteDiskIOException e) {
        // Ignore
        MmsLog.e(
            MmsApp.TXN_TAG, "SQLiteDiskIOException caught while set notification ind unstart", e);
      } finally {
        cursor.close();
      }
    } else {
      MmsLog.d(MmsApp.TXN_TAG, "setNotificationIndUnstarted: no pending messages.");
    }
  }
  public static void setPendingSmsFailed(final Context context) {
    Xlog.d(MmsApp.TXN_TAG, "setPendingSmsFailed");
    Cursor cursor =
        SqliteWrapper.query(
            context,
            context.getContentResolver(),
            Sms.CONTENT_URI,
            new String[] {Sms._ID},
            Sms.TYPE
                + "="
                + Sms.MESSAGE_TYPE_OUTBOX
                + " OR "
                + Sms.TYPE
                + "="
                + Sms.MESSAGE_TYPE_QUEUED,
            null,
            null);
    if (cursor != null) {
      try {
        int count = cursor.getCount();
        Xlog.d(MmsApp.TXN_TAG, "setPendingSmsFailed: Message Size=" + count);

        if (count == 0) {
          return;
        }

        ContentValues values = null;
        int id = 0;
        while (cursor.moveToNext()) {
          id = cursor.getInt(0);
          Xlog.d(MmsApp.TXN_TAG, "setPendingSmsFailed: MsgId=" + id);
          values = new ContentValues(1);
          values.put(Sms.TYPE, Sms.MESSAGE_TYPE_FAILED);
          SqliteWrapper.update(
              context,
              context.getContentResolver(),
              Sms.CONTENT_URI,
              values,
              Sms._ID + "=" + id,
              null);
        }
      } catch (SQLiteDiskIOException e) {
        Xlog.e(MmsApp.TXN_TAG, "SQLiteDiskIOException caught while set sms failed", e);
      } finally {
        cursor.close();
      }
    } else {
      Xlog.d(MmsApp.TXN_TAG, "setPendingSmsFailed: no pending messages.");
    }
  }
 private void startMsgListQuery() {
   try {
     mMsgListView.setVisibility(View.GONE);
     mMessage.setVisibility(View.GONE);
     setTitle(getString(R.string.refreshing));
     setProgressBarIndeterminateVisibility(true);
     if (mManageMode == MessageUtils.FORWARD_MODE) {
       mBackgroundQueryHandler.startQuery(
           0,
           null,
           Sms.CONTENT_URI,
           FORWARD_PROJECTION,
           Conversations.THREAD_ID + "=?",
           new String[] {String.valueOf(mThreadId)},
           SORT_ORDER);
     } else if (mManageMode == MessageUtils.SIM_MESSAGE_MODE) {
       mBackgroundQueryHandler.startQuery(0, null, mIccUri, null, null, null, null);
     } else if (mManageMode == MessageUtils.BATCH_DELETE_MODE) {
       Uri uri = ContentUris.withAppendedId(Threads.CONTENT_URI, mThreadId);
       mBackgroundQueryHandler.startQuery(
           0, null, uri, MessageListAdapter.PROJECTION, null, null, null);
     }
   } catch (SQLiteException e) {
     SqliteWrapper.checkSQLiteException(this, e);
   }
 }
 private static int getDownloadFailedMessageCount(Context context) {
   // Look for any messages in the MMS Inbox that are of the type
   // NOTIFICATION_IND (i.e. not already downloaded) and in the
   // permanent failure state.  If there are none, cancel any
   // failed download notification.
   Cursor c =
       SqliteWrapper.query(
           context,
           context.getContentResolver(),
           Mms.Inbox.CONTENT_URI,
           null,
           Mms.MESSAGE_TYPE
               + "="
               + String.valueOf(PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND)
               + " AND "
               + Mms.STATUS
               + "="
               + String.valueOf(DownloadManager.STATE_PERMANENT_FAILURE),
           null,
           null);
   if (c == null) {
     return 0;
   }
   int count = c.getCount();
   c.close();
   return count;
 }
 private static boolean isDuplicateNotification(Context context, NotificationInd nInd) {
   byte[] rawLocation = nInd.getContentLocation();
   if (rawLocation != null) {
     String location = new String(rawLocation);
     String selection = Mms.CONTENT_LOCATION + " = ?";
     String[] selectionArgs = new String[] {location};
     Cursor cursor =
         SqliteWrapper.query(
             context,
             context.getContentResolver(),
             Mms.CONTENT_URI,
             new String[] {Mms._ID},
             selection,
             selectionArgs,
             null);
     if (cursor != null) {
       try {
         if (cursor.getCount() > 0) {
           cursor.moveToFirst();
           Xlog.d(MmsApp.TXN_TAG, "duplicate, location=" + location + ", id=" + cursor.getLong(0));
           // We already received the same notification before.
           return true;
         }
       } finally {
         cursor.close();
       }
     }
   }
   return false;
 }
Example #7
0
 private void startQuery() {
   try {
     mQueryHandler.startQuery(0, null, ICC_URI, null, null, null, null);
   } catch (SQLiteException e) {
     SqliteWrapper.checkSQLiteException(this, e);
   }
 }
Example #8
0
 private static boolean isDuplicateNotification(Context context, NotificationInd nInd) {
   final byte[] rawLocation = nInd.getContentLocation();
   if (rawLocation != null) {
     String location = new String(rawLocation);
     String[] selectionArgs = new String[] {location};
     Cursor cursor = null;
     try {
       cursor =
           SqliteWrapper.query(
               context,
               context.getContentResolver(),
               Telephony.Mms.CONTENT_URI,
               new String[] {Telephony.Mms._ID},
               LOCATION_SELECTION,
               new String[] {
                 Integer.toString(PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND),
                 new String(rawLocation)
               },
               null /*sortOrder*/);
       if (cursor != null && cursor.getCount() > 0) {
         // We already received the same notification before.
         return true;
       }
     } catch (SQLiteException e) {
       Rlog.e(TAG, "failed to query existing notification ind", e);
     } finally {
       if (cursor != null) {
         cursor.close();
       }
     }
   }
   return false;
 }
  private static final MmsSmsDeliveryInfo getSmsNewDeliveryInfo(Context context) {
    ContentResolver resolver = context.getContentResolver();
    Cursor cursor =
        SqliteWrapper.query(
            context,
            resolver,
            Sms.CONTENT_URI,
            SMS_STATUS_PROJECTION,
            NEW_DELIVERY_SM_CONSTRAINT,
            null,
            Sms.DATE);

    if (cursor == null) return null;

    try {
      if (!cursor.moveToLast()) return null;

      String address = cursor.getString(COLUMN_SMS_ADDRESS);
      long timeMillis = 3000;

      return new MmsSmsDeliveryInfo(
          String.format(context.getString(R.string.delivery_toast_body), address), timeMillis);

    } finally {
      cursor.close();
    }
  }
  /**
   * Query the DB and return the number of undelivered messages (total for both SMS and MMS)
   *
   * @param context The context
   * @param threadIdResult A container to put the result in, according to the following rules:
   *     threadIdResult[0] contains the thread id of the first message. threadIdResult[1] is nonzero
   *     if the thread ids of all the messages are the same. You can pass in null for
   *     threadIdResult. You can pass in a threadIdResult of size 1 to avoid the comparison of each
   *     thread id.
   */
  private static int getUndeliveredMessageCount(Context context, long[] threadIdResult) {
    Cursor undeliveredCursor =
        SqliteWrapper.query(
            context,
            context.getContentResolver(),
            UNDELIVERED_URI,
            new String[] {Mms.THREAD_ID},
            "read=0",
            null,
            null);
    if (undeliveredCursor == null) {
      return 0;
    }
    int count = undeliveredCursor.getCount();
    try {
      if (threadIdResult != null && undeliveredCursor.moveToFirst()) {
        threadIdResult[0] = undeliveredCursor.getLong(0);

        if (threadIdResult.length >= 2) {
          // Test to see if all the undelivered messages belong to the same thread.
          long firstId = threadIdResult[0];
          while (undeliveredCursor.moveToNext()) {
            if (undeliveredCursor.getLong(0) != firstId) {
              firstId = 0;
              break;
            }
          }
          threadIdResult[1] = firstId; // non-zero if all ids are the same
        }
      }
    } finally {
      undeliveredCursor.close();
    }
    return count;
  }
  private static final MmsSmsNotificationInfo getSmsNewMessageNotificationInfo(
      Context context, Set<Long> threads) {
    ContentResolver resolver = context.getContentResolver();
    Cursor cursor =
        SqliteWrapper.query(
            context,
            resolver,
            Sms.CONTENT_URI,
            SMS_STATUS_PROJECTION,
            NEW_INCOMING_SM_CONSTRAINT,
            null,
            Sms.DATE + " desc");

    if (cursor == null) {
      return null;
    }

    try {
      if (!cursor.moveToFirst()) {
        return null;
      }

      String address = cursor.getString(COLUMN_SMS_ADDRESS);
      String body = cursor.getString(COLUMN_SMS_BODY);
      long threadId = cursor.getLong(COLUMN_THREAD_ID);
      long timeMillis = cursor.getLong(COLUMN_DATE);

      if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) {
        Log.d(
            TAG,
            "getSmsNewMessageNotificationInfo: count="
                + cursor.getCount()
                + ", first addr="
                + address
                + ", thread_id="
                + threadId);
      }

      MmsSmsNotificationInfo info =
          getNewMessageNotificationInfo(
              address,
              body,
              context,
              R.drawable.stat_notify_sms,
              null,
              threadId,
              timeMillis,
              cursor.getCount());

      threads.add(threadId);
      while (cursor.moveToNext()) {
        threads.add(cursor.getLong(COLUMN_THREAD_ID));
      }

      return info;
    } finally {
      cursor.close();
    }
  }
  /// M:Code analyze 009,add for setting the pending mms failed,mainly using after boot complete @{
  public static void setPendingMmsFailed(final Context context) {
    MmsLog.d(MmsApp.TXN_TAG, "setPendingMmsFailed");
    Cursor cursor =
        PduPersister.getPduPersister(context)
            .getPendingMessages(Long.MAX_VALUE /*System.currentTimeMillis()*/);
    if (cursor != null) {
      try {
        int count = cursor.getCount();
        MmsLog.d(MmsApp.TXN_TAG, "setPendingMmsFailed: Pending Message Size=" + count);

        if (count == 0) {
          return;
        }
        DefaultRetryScheme scheme = new DefaultRetryScheme(context, 100);
        ContentValues values = null;
        int columnIndex = 0;
        int columnType = 0;
        int id = 0;
        int type = 0;
        while (cursor.moveToNext()) {
          columnIndex = cursor.getColumnIndexOrThrow(PendingMessages._ID);
          id = cursor.getInt(columnIndex);

          columnType = cursor.getColumnIndexOrThrow(PendingMessages.MSG_TYPE);
          type = cursor.getInt(columnType);

          MmsLog.d(MmsApp.TXN_TAG, "setPendingMmsFailed: type=" + type + "; MsgId=" + id);

          if (type == PduHeaders.MESSAGE_TYPE_SEND_REQ) {
            values = new ContentValues(2);
            values.put(PendingMessages.ERROR_TYPE, MmsSms.ERR_TYPE_GENERIC_PERMANENT);
            values.put(PendingMessages.RETRY_INDEX, scheme.getRetryLimit());
            SqliteWrapper.update(
                context,
                context.getContentResolver(),
                PendingMessages.CONTENT_URI,
                values,
                PendingMessages._ID + "=" + id,
                null);
          }
        }
      } catch (SQLiteDiskIOException e) {
        // Ignore
        MmsLog.e(
            MmsApp.TXN_TAG, "SQLiteDiskIOException caught while set pending message failed", e);
      } finally {
        cursor.close();
      }
    } else {
      MmsLog.d(MmsApp.TXN_TAG, "setPendingMmsFailed: no pending MMS.");
    }
  }
  private void deleteMessages() {
    for (String uri : mSelectedUris) {
      if (mIsDeleteLockChecked || !mSelectedLockedUris.contains(uri)) {
        SqliteWrapper.delete(
            ManageMultiSelectAction.this, mContentResolver, Uri.parse(uri), null, null);
      }
    }

    Message msg = Message.obtain();
    msg.what = SHOW_TOAST;
    msg.obj = getString(R.string.operate_success);
    mUiHandler.sendMessage(msg);
  }
Example #14
0
  private void copyToPhoneMemory(Cursor cursor) {
    String address = cursor.getString(cursor.getColumnIndexOrThrow("address"));
    String body = cursor.getString(cursor.getColumnIndexOrThrow("body"));
    Long date = cursor.getLong(cursor.getColumnIndexOrThrow("date"));

    try {
      if (isIncomingMessage(cursor)) {
        Sms.Inbox.addMessage(mContentResolver, address, body, null, date, true /* read */);
      } else {
        Sms.Sent.addMessage(mContentResolver, address, body, null, date);
      }
    } catch (SQLiteException e) {
      SqliteWrapper.checkSQLiteException(this, e);
    }
  }
  /**
   * Move all messages that are in the outbox to the queued state
   *
   * @return The number of messages that were actually moved
   */
  private int moveOutboxMessagesToQueuedBox() {
    ContentValues values = new ContentValues(1);

    values.put(Sms.TYPE, Sms.MESSAGE_TYPE_QUEUED);

    int messageCount =
        SqliteWrapper.update(
            getApplicationContext(),
            getContentResolver(),
            Outbox.CONTENT_URI,
            values,
            "type = " + Sms.MESSAGE_TYPE_OUTBOX,
            null);
    if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE) || LogTag.DEBUG_SEND) {
      Log.v(TAG, "moveOutboxMessagesToQueuedBox messageCount: " + messageCount);
    }
    return messageCount;
  }
  /**
   * Move all messages that are in the outbox to the failed state and set them to unread.
   *
   * @return The number of messages that were actually moved
   */
  private int moveOutboxMessagesToFailedBox() {
    ContentValues values = new ContentValues(3);

    values.put(Sms.TYPE, Sms.MESSAGE_TYPE_FAILED);
    values.put(Sms.ERROR_CODE, SmsManager.RESULT_ERROR_GENERIC_FAILURE);
    values.put(Sms.READ, Integer.valueOf(0));

    int messageCount =
        SqliteWrapper.update(
            getApplicationContext(),
            getContentResolver(),
            Outbox.CONTENT_URI,
            values,
            "type = " + Sms.MESSAGE_TYPE_OUTBOX,
            null);
    if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE) || LogTag.DEBUG_SEND) {
      Log.v(TAG, "moveOutboxMessagesToFailedBox messageCount: " + messageCount);
    }
    return messageCount;
  }
  private static long findThreadId(Context context, GenericPdu pdu, int type) {
    String messageId;

    if (type == MESSAGE_TYPE_DELIVERY_IND) {
      messageId = new String(((DeliveryInd) pdu).getMessageId());
    } else {
      messageId = new String(((ReadOrigInd) pdu).getMessageId());
    }

    StringBuilder sb = new StringBuilder('(');
    sb.append(Mms.MESSAGE_ID);
    sb.append('=');
    sb.append(DatabaseUtils.sqlEscapeString(messageId));
    sb.append(" AND ");
    sb.append(Mms.MESSAGE_TYPE);
    sb.append('=');
    sb.append(PduHeaders.MESSAGE_TYPE_SEND_REQ);
    // TODO ContentResolver.query() appends closing ')' to the selection argument
    // sb.append(')');

    Cursor cursor =
        SqliteWrapper.query(
            context,
            context.getContentResolver(),
            Mms.CONTENT_URI,
            new String[] {Mms.THREAD_ID},
            sb.toString(),
            null,
            null);
    if (cursor != null) {
      try {
        if ((cursor.getCount() == 1) && cursor.moveToFirst()) {
          return cursor.getLong(0);
        }
      } finally {
        cursor.close();
      }
    }

    return -1;
  }
Example #18
0
 private static long getDeliveryOrReadReportThreadId(Context context, GenericPdu pdu) {
   String messageId;
   if (pdu instanceof DeliveryInd) {
     messageId = new String(((DeliveryInd) pdu).getMessageId());
   } else if (pdu instanceof ReadOrigInd) {
     messageId = new String(((ReadOrigInd) pdu).getMessageId());
   } else {
     Rlog.e(
         TAG,
         "WAP Push data is neither delivery or read report type: "
             + pdu.getClass().getCanonicalName());
     return -1L;
   }
   Cursor cursor = null;
   try {
     cursor =
         SqliteWrapper.query(
             context,
             context.getContentResolver(),
             Telephony.Mms.CONTENT_URI,
             new String[] {Telephony.Mms.THREAD_ID},
             THREAD_ID_SELECTION,
             new String[] {
               DatabaseUtils.sqlEscapeString(messageId),
               Integer.toString(PduHeaders.MESSAGE_TYPE_SEND_REQ)
             },
             null /*sortOrder*/);
     if (cursor != null && cursor.moveToFirst()) {
       return cursor.getLong(0);
     }
   } catch (SQLiteException e) {
     Rlog.e(TAG, "Failed to query delivery or read report thread id", e);
   } finally {
     if (cursor != null) {
       cursor.close();
     }
   }
   return -1L;
 }
Example #19
0
  private void writeInboxMessage(long subId, byte[] pushData) {
    final GenericPdu pdu = new PduParser(pushData).parse();
    if (pdu == null) {
      Rlog.e(TAG, "Invalid PUSH PDU");
    }
    final PduPersister persister = PduPersister.getPduPersister(mContext);
    final int type = pdu.getMessageType();
    try {
      switch (type) {
        case MESSAGE_TYPE_DELIVERY_IND:
        case MESSAGE_TYPE_READ_ORIG_IND:
          {
            final long threadId = getDeliveryOrReadReportThreadId(mContext, pdu);
            if (threadId == -1) {
              // The associated SendReq isn't found, therefore skip
              // processing this PDU.
              Rlog.e(TAG, "Failed to find delivery or read report's thread id");
              break;
            }
            final Uri uri =
                persister.persist(
                    pdu,
                    Telephony.Mms.Inbox.CONTENT_URI,
                    true /*createThreadId*/,
                    true /*groupMmsEnabled*/,
                    null /*preOpenedFiles*/);
            if (uri == null) {
              Rlog.e(TAG, "Failed to persist delivery or read report");
              break;
            }
            // Update thread ID for ReadOrigInd & DeliveryInd.
            final ContentValues values = new ContentValues(1);
            values.put(Telephony.Mms.THREAD_ID, threadId);
            if (SqliteWrapper.update(
                    mContext,
                    mContext.getContentResolver(),
                    uri,
                    values,
                    null /*where*/,
                    null /*selectionArgs*/)
                != 1) {
              Rlog.e(TAG, "Failed to update delivery or read report thread id");
            }
            break;
          }
        case MESSAGE_TYPE_NOTIFICATION_IND:
          {
            final NotificationInd nInd = (NotificationInd) pdu;

            Bundle configs = SmsManager.getSmsManagerForSubscriber(subId).getCarrierConfigValues();
            if (configs != null
                && configs.getBoolean(SmsManager.MMS_CONFIG_APPEND_TRANSACTION_ID, false)) {
              final byte[] contentLocation = nInd.getContentLocation();
              if ('=' == contentLocation[contentLocation.length - 1]) {
                byte[] transactionId = nInd.getTransactionId();
                byte[] contentLocationWithId =
                    new byte[contentLocation.length + transactionId.length];
                System.arraycopy(
                    contentLocation, 0, contentLocationWithId, 0, contentLocation.length);
                System.arraycopy(
                    transactionId,
                    0,
                    contentLocationWithId,
                    contentLocation.length,
                    transactionId.length);
                nInd.setContentLocation(contentLocationWithId);
              }
            }
            if (!isDuplicateNotification(mContext, nInd)) {
              final Uri uri =
                  persister.persist(
                      pdu,
                      Telephony.Mms.Inbox.CONTENT_URI,
                      true /*createThreadId*/,
                      true /*groupMmsEnabled*/,
                      null /*preOpenedFiles*/);
              if (uri == null) {
                Rlog.e(TAG, "Failed to save MMS WAP push notification ind");
              }
            } else {
              Rlog.d(
                  TAG,
                  "Skip storing duplicate MMS WAP push notification ind: "
                      + new String(nInd.getContentLocation()));
            }
            break;
          }
        default:
          Log.e(TAG, "Received unrecognized WAP Push PDU.");
      }
    } catch (MmsException e) {
      Log.e(TAG, "Failed to save MMS WAP push data: type=" + type, e);
    } catch (RuntimeException e) {
      Log.e(TAG, "Unexpected RuntimeException in persisting MMS WAP push data", e);
    }
  }
Example #20
0
  private void deleteFromSim(Cursor cursor) {
    String messageIndexString = cursor.getString(cursor.getColumnIndexOrThrow("index_on_icc"));
    Uri simUri = ICC_URI.buildUpon().appendPath(messageIndexString).build();

    SqliteWrapper.delete(this, mContentResolver, simUri, null, null);
  }
  private static final MmsSmsNotificationInfo getMmsNewMessageNotificationInfo(
      Context context, Set<Long> threads) {
    ContentResolver resolver = context.getContentResolver();

    // This query looks like this when logged:
    // I/Database(  147): elapsedTime4Sql|/data/data/com.android.providers.telephony/databases/
    // mmssms.db|0.362 ms|SELECT thread_id, date, _id, sub, sub_cs FROM pdu WHERE ((msg_box=1
    // AND seen=0 AND (m_type=130 OR m_type=132))) ORDER BY date desc

    Cursor cursor =
        SqliteWrapper.query(
            context,
            resolver,
            Mms.CONTENT_URI,
            MMS_STATUS_PROJECTION,
            NEW_INCOMING_MM_CONSTRAINT,
            null,
            Mms.DATE + " desc");

    if (cursor == null) {
      return null;
    }

    try {
      if (!cursor.moveToFirst()) {
        return null;
      }
      long msgId = cursor.getLong(COLUMN_MMS_ID);
      Uri msgUri = Mms.CONTENT_URI.buildUpon().appendPath(Long.toString(msgId)).build();
      String address = AddressUtils.getFrom(context, msgUri);
      String subject =
          getMmsSubject(cursor.getString(COLUMN_SUBJECT), cursor.getInt(COLUMN_SUBJECT_CS));
      long threadId = cursor.getLong(COLUMN_THREAD_ID);
      long timeMillis = cursor.getLong(COLUMN_DATE) * 1000;

      if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) {
        Log.d(
            TAG,
            "getMmsNewMessageNotificationInfo: count="
                + cursor.getCount()
                + ", first addr = "
                + address
                + ", thread_id="
                + threadId);
      }

      MmsSmsNotificationInfo info =
          getNewMessageNotificationInfo(
              address,
              subject,
              context,
              R.drawable.stat_notify_mms,
              null,
              threadId,
              timeMillis,
              cursor.getCount());

      threads.add(threadId);
      while (cursor.moveToNext()) {
        threads.add(cursor.getLong(COLUMN_THREAD_ID));
      }

      return info;
    } finally {
      cursor.close();
    }
  }
  /**
   * Constructor that uses the default settings of the MMS Client.
   *
   * @param context The context of the MMS Client
   */
  public TransactionSettings(Context context, String apnName) {
    if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {
      Log.v(TAG, "TransactionSettings: apnName: " + apnName);
    }
    String selection = Telephony.Carriers.CURRENT + " IS NOT NULL";
    String[] selectionArgs = null;
    if (!TextUtils.isEmpty(apnName)) {
      selection += " AND " + Telephony.Carriers.APN + "=?";
      selectionArgs = new String[] {apnName.trim()};
    }

    Cursor cursor =
        SqliteWrapper.query(
            context,
            context.getContentResolver(),
            Telephony.Carriers.CONTENT_URI,
            APN_PROJECTION,
            selection,
            selectionArgs,
            null);

    if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {
      Log.v(
          TAG,
          "TransactionSettings looking for apn: "
              + selection
              + " returned: "
              + (cursor == null ? "null cursor" : (cursor.getCount() + " hits")));
    }

    if (cursor == null) {
      Log.e(TAG, "Apn is not found in Database!");
      return;
    }

    boolean sawValidApn = false;
    try {
      while (cursor.moveToNext() && TextUtils.isEmpty(mServiceCenter)) {
        // Read values from APN settings
        if (isValidApnType(cursor.getString(COLUMN_TYPE), PhoneConstants.APN_TYPE_MMS)) {
          sawValidApn = true;

          String mmsc = cursor.getString(COLUMN_MMSC);
          if (mmsc == null) {
            continue;
          }

          mServiceCenter = NetworkUtils.trimV4AddrZeros(mmsc.trim());
          mProxyAddress = NetworkUtils.trimV4AddrZeros(cursor.getString(COLUMN_MMSPROXY));
          if (isProxySet()) {
            String portString = cursor.getString(COLUMN_MMSPORT);
            try {
              mProxyPort = Integer.parseInt(portString);
            } catch (NumberFormatException e) {
              if (TextUtils.isEmpty(portString)) {
                Log.w(TAG, "mms port not set!");
              } else {
                Log.e(TAG, "Bad port number format: " + portString, e);
              }
            }
          }
        }
      }
    } finally {
      cursor.close();
    }

    Log.v(TAG, "APN setting: MMSC: " + mServiceCenter + " looked for: " + selection);

    if (sawValidApn && TextUtils.isEmpty(mServiceCenter)) {
      Log.e(TAG, "Invalid APN setting: MMSC is empty");
    }
  }
  public static void handleReadReport(
      final Context context,
      final Collection<Long> threadIds,
      final int status,
      final Runnable callback) {
    StringBuilder selectionBuilder =
        new StringBuilder(
            Mms.MESSAGE_TYPE
                + " = "
                + PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF
                + " AND "
                + Mms.READ
                + " = 0"
                + " AND "
                + Mms.READ_REPORT
                + " = "
                + PduHeaders.VALUE_YES);

    String[] selectionArgs = null;
    if (threadIds != null) {
      String threadIdSelection = null;
      StringBuilder buf = new StringBuilder();
      selectionArgs = new String[threadIds.size()];
      int i = 0;

      for (long threadId : threadIds) {
        if (i > 0) {
          buf.append(" OR ");
        }
        buf.append(Mms.THREAD_ID).append("=?");
        selectionArgs[i++] = Long.toString(threadId);
      }
      threadIdSelection = buf.toString();

      selectionBuilder.append(" AND (" + threadIdSelection + ")");
    }

    final Cursor c =
        SqliteWrapper.query(
            context,
            context.getContentResolver(),
            Mms.Inbox.CONTENT_URI,
            new String[] {Mms._ID, Mms.MESSAGE_ID},
            selectionBuilder.toString(),
            selectionArgs,
            null);

    if (c == null) {
      return;
    }

    final Map<String, String> map = new HashMap<String, String>();
    try {
      if (c.getCount() == 0) {
        if (callback != null) {
          callback.run();
        }
        return;
      }

      while (c.moveToNext()) {
        Uri uri = ContentUris.withAppendedId(Mms.CONTENT_URI, c.getLong(0));
        map.put(c.getString(1), AddressUtils.getFrom(context, uri));
      }
    } finally {
      c.close();
    }

    OnClickListener positiveListener =
        new OnClickListener() {
          @Override
          public void onClick(DialogInterface dialog, int which) {
            for (final Map.Entry<String, String> entry : map.entrySet()) {
              MmsMessageSender.sendReadRec(context, entry.getValue(), entry.getKey(), status);
            }

            if (callback != null) {
              callback.run();
            }
            dialog.dismiss();
          }
        };

    OnClickListener negativeListener =
        new OnClickListener() {
          @Override
          public void onClick(DialogInterface dialog, int which) {
            if (callback != null) {
              callback.run();
            }
            dialog.dismiss();
          }
        };

    OnCancelListener cancelListener =
        new OnCancelListener() {
          @Override
          public void onCancel(DialogInterface dialog) {
            if (callback != null) {
              callback.run();
            }
            dialog.dismiss();
          }
        };

    confirmReadReportDialog(context, positiveListener, negativeListener, cancelListener);
  }
 /**
  * Load APN settings from system
  *
  * @param context
  * @param apnName the optional APN name to match
  */
 public static ApnSettings load(Context context, String apnName, int subId) throws ApnException {
   if (Log.isLoggable(TAG, Log.VERBOSE)) {
     Log.v(TAG, "ApnSettings: apnName " + apnName);
   }
   // TODO: CURRENT semantics is currently broken in telephony. Revive this when it is fixed.
   // String selection = Telephony.Carriers.CURRENT + " IS NOT NULL";
   String selection = null;
   String[] selectionArgs = null;
   apnName = apnName != null ? apnName.trim() : null;
   if (!TextUtils.isEmpty(apnName)) {
     // selection += " AND " + Telephony.Carriers.APN + "=?";
     selection = Telephony.Carriers.APN + "=?";
     selectionArgs = new String[] {apnName};
   }
   Cursor cursor = null;
   try {
     cursor =
         SqliteWrapper.query(
             context,
             context.getContentResolver(),
             Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "/subId/" + subId),
             APN_PROJECTION,
             selection,
             selectionArgs,
             null /*sortOrder*/);
     if (cursor != null) {
       String mmscUrl = null;
       String proxyAddress = null;
       int proxyPort = -1;
       while (cursor.moveToNext()) {
         // Read values from APN settings
         if (isValidApnType(cursor.getString(COLUMN_TYPE), PhoneConstants.APN_TYPE_MMS)) {
           mmscUrl = trimWithNullCheck(cursor.getString(COLUMN_MMSC));
           if (TextUtils.isEmpty(mmscUrl)) {
             continue;
           }
           mmscUrl = NetworkUtils.trimV4AddrZeros(mmscUrl);
           try {
             new URI(mmscUrl);
           } catch (URISyntaxException e) {
             throw new ApnException("Invalid MMSC url " + mmscUrl);
           }
           proxyAddress = trimWithNullCheck(cursor.getString(COLUMN_MMSPROXY));
           if (!TextUtils.isEmpty(proxyAddress)) {
             proxyAddress = NetworkUtils.trimV4AddrZeros(proxyAddress);
             final String portString = trimWithNullCheck(cursor.getString(COLUMN_MMSPORT));
             if (portString != null) {
               try {
                 proxyPort = Integer.parseInt(portString);
               } catch (NumberFormatException e) {
                 Log.e(TAG, "Invalid port " + portString);
                 throw new ApnException("Invalid port " + portString);
               }
             }
           }
           return new ApnSettings(mmscUrl, proxyAddress, proxyPort, getDebugText(cursor));
         }
       }
     }
   } finally {
     if (cursor != null) {
       cursor.close();
     }
   }
   throw new ApnException("Can not find valid APN");
 }
    @Override
    protected Void doInBackground(Intent... intents) {
      Intent intent = intents[0];
      Xlog.d(
          MmsApp.TXN_TAG,
          "do In Background, slotId=" + intent.getIntExtra(Phone.GEMINI_SIM_ID_KEY, 0));
      // Get raw PDU push-data from the message and parse it
      byte[] pushData = intent.getByteArrayExtra("data");
      PduParser parser = new PduParser(pushData);
      GenericPdu pdu = parser.parse();

      if (null == pdu) {
        Log.e(TAG, "Invalid PUSH data");
        return null;
      }

      PduPersister p = PduPersister.getPduPersister(mContext);
      ContentResolver cr = mContext.getContentResolver();
      int type = pdu.getMessageType();
      long threadId = -1;

      try {
        switch (type) {
          case MESSAGE_TYPE_DELIVERY_IND:
            Xlog.d(MmsApp.TXN_TAG, "type=MESSAGE_TYPE_DELIVERY_IND");
          case MESSAGE_TYPE_READ_ORIG_IND:
            {
              if (type == MESSAGE_TYPE_READ_ORIG_IND) {
                Xlog.d(MmsApp.TXN_TAG, "type=MESSAGE_TYPE_READ_ORIG_IND");
              }
              threadId = findThreadId(mContext, pdu, type);
              if (threadId == -1) {
                // The associated SendReq isn't found, therefore skip
                // processing this PDU.
                break;
              }

              Uri uri = p.persist(pdu, Inbox.CONTENT_URI);
              // Update thread ID for ReadOrigInd & DeliveryInd.
              ContentValues values = new ContentValues(1);
              values.put(Mms.THREAD_ID, threadId);
              SqliteWrapper.update(mContext, cr, uri, values, null, null);
              break;
            }
          case MESSAGE_TYPE_NOTIFICATION_IND:
            {
              Xlog.d(MmsApp.TXN_TAG, "type=MESSAGE_TYPE_NOTIFICATION_IND");
              NotificationInd nInd = (NotificationInd) pdu;

              if (MmsConfig.getTransIdEnabled()) {
                byte[] contentLocation = nInd.getContentLocation();
                if ('=' == contentLocation[contentLocation.length - 1]) {
                  byte[] transactionId = nInd.getTransactionId();
                  byte[] contentLocationWithId =
                      new byte[contentLocation.length + transactionId.length];
                  System.arraycopy(
                      contentLocation, 0, contentLocationWithId, 0, contentLocation.length);
                  System.arraycopy(
                      transactionId,
                      0,
                      contentLocationWithId,
                      contentLocation.length,
                      transactionId.length);
                  nInd.setContentLocation(contentLocationWithId);
                }
              }

              if (!isDuplicateNotification(mContext, nInd)) {
                Uri uri = p.persist(pdu, Inbox.CONTENT_URI);
                // add for gemini
                if (FeatureOption.MTK_GEMINI_SUPPORT) {
                  // update pdu
                  ContentValues values = new ContentValues(2);
                  SIMInfo si =
                      SIMInfo.getSIMInfoBySlot(
                          mContext, intent.getIntExtra(Phone.GEMINI_SIM_ID_KEY, -1));
                  if (null == si) {
                    Xlog.e(
                        MmsApp.TXN_TAG,
                        "PushReceiver:SIMInfo is null for slot "
                            + intent.getIntExtra(Phone.GEMINI_SIM_ID_KEY, -1));
                    break;
                  }
                  values.put(Mms.SIM_ID, si.mSimId);
                  values.put(WapPush.SERVICE_ADDR, intent.getStringExtra(WapPush.SERVICE_ADDR));
                  SqliteWrapper.update(mContext, cr, uri, values, null, null);
                  Xlog.d(
                      MmsApp.TXN_TAG,
                      "save notification slotId="
                          + intent.getIntExtra(Phone.GEMINI_SIM_ID_KEY, 0)
                          + "\tsimId="
                          + si.mSimId
                          + "\tsc="
                          + intent.getStringExtra(WapPush.SERVICE_ADDR)
                          + "\taddr="
                          + intent.getStringExtra(WapPush.ADDR));

                  // update pending messages
                  long msgId = 0;
                  Cursor cursor =
                      SqliteWrapper.query(
                          mContext,
                          mContext.getContentResolver(),
                          uri,
                          new String[] {Mms._ID},
                          null,
                          null,
                          null);
                  if (cursor != null && cursor.getCount() == 1 && cursor.moveToFirst()) {
                    try {
                      msgId = cursor.getLong(0);
                      Xlog.d(MmsApp.TXN_TAG, "msg id = " + msgId);
                    } finally {
                      cursor.close();
                    }
                  }

                  Uri.Builder uriBuilder = PendingMessages.CONTENT_URI.buildUpon();
                  uriBuilder.appendQueryParameter("protocol", "mms");
                  uriBuilder.appendQueryParameter("message", String.valueOf(msgId));
                  Cursor pendingCs =
                      SqliteWrapper.query(
                          mContext,
                          mContext.getContentResolver(),
                          uriBuilder.build(),
                          null,
                          null,
                          null,
                          null);
                  if (pendingCs != null) {
                    try {
                      if ((pendingCs.getCount() == 1) && pendingCs.moveToFirst()) {
                        ContentValues valuesforPending = new ContentValues();
                        valuesforPending.put(PendingMessages.SIM_ID, si.mSimId);
                        int columnIndex = pendingCs.getColumnIndexOrThrow(PendingMessages._ID);
                        long id = pendingCs.getLong(columnIndex);
                        SqliteWrapper.update(
                            mContext,
                            mContext.getContentResolver(),
                            PendingMessages.CONTENT_URI,
                            valuesforPending,
                            PendingMessages._ID + "=" + id,
                            null);
                      } else {
                        Xlog.w(
                            MmsApp.TXN_TAG,
                            "can not find message to set pending sim id, msgId=" + msgId);
                      }
                    } finally {
                      pendingCs.close();
                    }
                  }
                } else {
                  ContentValues value = new ContentValues(1);
                  value.put(WapPush.SERVICE_ADDR, intent.getStringExtra(WapPush.SERVICE_ADDR));
                  SqliteWrapper.update(mContext, cr, uri, value, null, null);
                  Xlog.d(
                      MmsApp.TXN_TAG,
                      "save notification,"
                          + "\tsc="
                          + intent.getStringExtra(WapPush.SERVICE_ADDR)
                          + "\taddr="
                          + intent.getStringExtra(WapPush.ADDR));
                }

                // Start service to finish the notification transaction.
                Intent svc = new Intent(mContext, TransactionService.class);
                svc.putExtra(TransactionBundle.URI, uri.toString());
                svc.putExtra(
                    TransactionBundle.TRANSACTION_TYPE, Transaction.NOTIFICATION_TRANSACTION);
                if (FeatureOption.MTK_GEMINI_SUPPORT) {
                  SIMInfo si =
                      SIMInfo.getSIMInfoBySlot(
                          mContext, intent.getIntExtra(Phone.GEMINI_SIM_ID_KEY, -1));
                  if (null == si) {
                    Xlog.e(
                        MmsApp.TXN_TAG,
                        "PushReceiver: SIMInfo is null for slot "
                            + intent.getIntExtra(Phone.GEMINI_SIM_ID_KEY, -1));
                    break;
                  }
                  int simId = (int) si.mSimId;
                  svc.putExtra(Phone.GEMINI_SIM_ID_KEY, simId);
                  // svc.putExtra(Phone.GEMINI_SIM_ID_KEY,
                  // intent.getIntExtra(Phone.GEMINI_SIM_ID_KEY, 0));
                }
                mContext.startService(svc);
              } else if (LOCAL_LOGV) {
                Log.v(
                    TAG,
                    "Skip downloading duplicate message: " + new String(nInd.getContentLocation()));
              }
              break;
            }
          default:
            Log.e(TAG, "Received unrecognized PDU.");
        }
      } catch (MmsException e) {
        Log.e(TAG, "Failed to save the data from PUSH: type=" + type, e);
      } catch (RuntimeException e) {
        Log.e(TAG, "Unexpected RuntimeException.", e);
      } finally {
        raisePriority(mContext, false);
        Xlog.d(MmsApp.TXN_TAG, "Normal priority");
      }

      if (LOCAL_LOGV) {
        Log.v(TAG, "PUSH Intent processed.");
      }

      return null;
    }
  public void run() {
    Xlog.d(MmsApp.TXN_TAG, "NotificationTransaction: run()");
    DownloadManager downloadManager = DownloadManager.getInstance();
    // boolean autoDownload = downloadManager.isAuto();
    // boolean dataSuspended = (MmsApp.getApplication().getTelephonyManager().getDataState() ==
    //        TelephonyManager.DATA_SUSPENDED);
    boolean autoDownload = false;
    boolean dataSuspended = false;
    // add for gemini
    if (FeatureOption.MTK_GEMINI_SUPPORT) {
      autoDownload = downloadManager.isAuto(mSimId);
      int datastate =
          MmsApp.getApplication()
              .getTelephonyManager()
              .getDataStateGemini(SIMInfo.getSlotById(mContext, mSimId));
      dataSuspended =
          (datastate == TelephonyManager.DATA_SUSPENDED
              || datastate == TelephonyManager.DATA_DISCONNECTED);
    } else {
      autoDownload = downloadManager.isAuto();
      dataSuspended =
          (MmsApp.getApplication().getTelephonyManager().getDataState()
              == TelephonyManager.DATA_SUSPENDED);
    }

    try {
      if (LOCAL_LOGV) {
        Log.v(TAG, "Notification transaction launched: " + this);
      }

      // By default, we set status to STATUS_DEFERRED because we
      // should response MMSC with STATUS_DEFERRED when we cannot
      // download a MM immediately.
      int status = STATUS_DEFERRED;

      // Check expiry state
      Date CurrentDate = new Date(System.currentTimeMillis());
      Date ExpiryDate = new Date(mNotificationInd.getExpiry() * 1000);
      Xlog.d(
          MmsApp.TXN_TAG,
          "expiry time="
              + ExpiryDate.toLocaleString()
              + "\t current="
              + CurrentDate.toLocaleString());

      // MTK_OP01_PROTECT_START
      /*
      String optr = SystemProperties.get("ro.operator.optr");
      if (optr.equals("OP01")) {
          // Check Message size
          int msgSize = 0;
          Cursor cursor = SqliteWrapper.query(mContext, mContext.getContentResolver(),
                           mUri, new String[] {Mms.MESSAGE_SIZE}, null, null, null);
          if (cursor != null && cursor.getCount() == 1 && cursor.moveToFirst()) {
              try{
                  msgSize = cursor.getInt(0);
                  Xlog.v(MmsApp.TXN_TAG, "msg Size = " + msgSize);
              }finally{
                  cursor.close();
              }
          }

          String netWorkType = null;
          int slotId = -1;
          if (FeatureOption.MTK_GEMINI_SUPPORT) {
              // convert sim id to slot id
              slotId = SIMInfo.getSlotById(mContext, mSimId);
              netWorkType = SystemProperties.get(slotId == 0 ?
                      TelephonyProperties.PROPERTY_CS_NETWORK_TYPE : TelephonyProperties.PROPERTY_CS_NETWORK_TYPE_2);
          } else {
              netWorkType = SystemProperties.get(TelephonyProperties.PROPERTY_CS_NETWORK_TYPE);
          }

          boolean bTDNetwork = Integer.parseInt(netWorkType) > 2 ? true : false;
          if ((!bTDNetwork && MmsConfig.getReceiveMmsLimitFor2G() < msgSize/1024)
                  || (bTDNetwork && MmsConfig.getReceiveMmsLimitForTD() < msgSize/1024)) {
              Xlog.v(MmsApp.TXN_TAG, "Message size exceed limitation, rejected.");

              status = STATUS_REJECTED;
              sendNotifyRespInd(status);
              return;
          }
      }
      */
      // MTK_OP01_PROTECT_END
      // Don't try to download when data is suspended, as it will fail, so defer download
      if (!autoDownload || dataSuspended) {
        Xlog.d(
            MmsApp.TXN_TAG,
            "Not autoDownload! autoDonwload=" + autoDownload + ", dataSuspended=" + dataSuspended);
        if (FeatureOption.MTK_GEMINI_SUPPORT) {
          downloadManager.markState(mUri, DownloadManager.STATE_UNSTARTED, mSimId);
        } else {
          downloadManager.markState(mUri, DownloadManager.STATE_UNSTARTED);
        }
        sendNotifyRespInd(status);
        return;
      }

      if (FeatureOption.MTK_GEMINI_SUPPORT) {
        downloadManager.markState(mUri, DownloadManager.STATE_DOWNLOADING, mSimId);
      } else {
        downloadManager.markState(mUri, DownloadManager.STATE_DOWNLOADING);
      }

      if (LOCAL_LOGV) {
        Log.v(TAG, "Content-Location: " + mContentLocation);
      }

      byte[] retrieveConfData = null;
      // We should catch exceptions here to response MMSC
      // with STATUS_DEFERRED.
      try {
        Xlog.d(MmsApp.TXN_TAG, "NotificationTransaction: before getpdu");
        retrieveConfData = getPdu(mContentLocation);
        Xlog.d(MmsApp.TXN_TAG, "NotificationTransaction: after getpdu");
      } catch (IOException e) {
        mTransactionState.setState(FAILED);
      }

      if (retrieveConfData != null) {
        GenericPdu pdu = new PduParser(retrieveConfData).parse();
        if ((pdu == null) || (pdu.getMessageType() != MESSAGE_TYPE_RETRIEVE_CONF)) {
          Log.e(TAG, "Invalid M-RETRIEVE.CONF PDU.");
          mTransactionState.setState(FAILED);
          status = STATUS_UNRECOGNIZED;
        } else {
          // Save the received PDU (must be a M-RETRIEVE.CONF).
          PduPersister p = PduPersister.getPduPersister(mContext);
          Uri uri = p.persist(pdu, Inbox.CONTENT_URI);
          Xlog.d(MmsApp.TXN_TAG, "PDU Saved, Uri=" + uri + "\nDelete Notify Ind, Uri=" + mUri);
          // add for gemini
          if (FeatureOption.MTK_GEMINI_SUPPORT) {
            ContentResolver cr = mContext.getContentResolver();
            ContentValues values = new ContentValues(1);
            values.put(Mms.SIM_ID, mSimId);
            SqliteWrapper.update(mContext, cr, uri, values, null, null);
          }

          // set message size
          int messageSize = retrieveConfData.length;
          ContentValues sizeValue = new ContentValues();
          sizeValue.put(Mms.MESSAGE_SIZE, messageSize);
          SqliteWrapper.update(mContext, mContext.getContentResolver(), uri, sizeValue, null, null);

          // We have successfully downloaded the new MM. Delete the
          // M-NotifyResp.ind from Inbox.
          String notifId = mUri.getLastPathSegment();
          String msgId = uri.getLastPathSegment();
          if (!notifId.equals(msgId)) {
            SqliteWrapper.delete(mContext, mContext.getContentResolver(), mUri, null, null);
          }
          // Notify observers with newly received MM.
          mUri = uri;
          status = STATUS_RETRIEVED;
        }
      } else {
        Xlog.e(MmsApp.TXN_TAG, "retrieveConfData is null");
        mTransactionState.setState(FAILED);
        status = STATUS_UNRECOGNIZED;
      }

      // Check the status and update the result state of this Transaction.
      switch (status) {
        case STATUS_RETRIEVED:
          mTransactionState.setState(SUCCESS);
          break;
        case STATUS_DEFERRED:
          // STATUS_DEFERRED, may be a failed immediate retrieval.
          if (mTransactionState.getState() == INITIALIZED) {
            mTransactionState.setState(SUCCESS);
          }
          break;
      }
      // if the status is STATUS_UNRECOGNIZED, this happened when we don't get mms pdu from server,
      // this may be a server problem or network problem.
      // our policy is will retry later, so we must response a deferred status not this one.
      // otherwise the server may delete this mms, and when we retry it, it's another mms created by
      // server to
      // inform us that the old mms is not exist yet.
      if (status == STATUS_UNRECOGNIZED) {
        status = STATUS_DEFERRED;
      }
      sendNotifyRespInd(status);

      // Make sure this thread isn't over the limits in message count.
      Recycler.getMmsRecycler().deleteOldMessagesInSameThreadAsMessage(mContext, mUri);
    } catch (Throwable t) {
      Log.e(TAG, Log.getStackTraceString(t));
      if (null != mUri) {
        Recycler.getMmsRecycler().deleteOldMessagesInSameThreadAsMessage(mContext, mUri);
      }
    } finally {
      mTransactionState.setContentUri(mUri);
      if (!autoDownload /*|| dataSuspended*/ /*comment this case for 81452*/) {
        // Always mark the transaction successful for deferred
        // download since any error here doesn't make sense.
        mTransactionState.setState(SUCCESS);
      }
      if (mTransactionState.getState() != SUCCESS) {
        mTransactionState.setState(FAILED);
        Xlog.w(MmsApp.TXN_TAG, "NotificationTransaction failed.");
      }
      notifyObservers();
    }
  }
Example #27
0
  private void initModelFromUri(Uri uri) throws MmsException {
    ContentResolver cr = mContext.getContentResolver();
    Cursor c = SqliteWrapper.query(mContext, cr, uri, null, null, null, null);

    if (c != null) {
      try {
        if (c.moveToFirst()) {
          String path;
          boolean isFromMms = isMmsUri(uri);

          // FIXME We suppose that there should be only two sources
          // of the audio, one is the media store, the other is
          // our MMS database.
          if (isFromMms) {
            path = c.getString(c.getColumnIndexOrThrow(Part._DATA));
            mContentType = c.getString(c.getColumnIndexOrThrow(Part.CONTENT_TYPE));
          } else {
            path = c.getString(c.getColumnIndexOrThrow(Audio.Media.DATA));
            mContentType = c.getString(c.getColumnIndexOrThrow(Audio.Media.MIME_TYPE));
            // Get more extras information which would be useful
            // to the user.
            String album = c.getString(c.getColumnIndexOrThrow("album"));
            if (!TextUtils.isEmpty(album)) {
              mExtras.put("album", album);
            }

            String artist = c.getString(c.getColumnIndexOrThrow("artist"));
            if (!TextUtils.isEmpty(artist)) {
              mExtras.put("artist", artist);
            }
          }
          if (FeatureOption.MTK_DRM_APP) {
            if (MessageUtils.checkUriContainsDrm(mContext, uri)) {
              path += ".dcf";
            }
          }

          mSrc = path.substring(path.lastIndexOf('/') + 1).replace(' ', '_');
          Log.i(TAG, "path: " + path);
          Log.i(TAG, "mSrc: " + mSrc);

          if (TextUtils.isEmpty(mContentType)) {
            throw new MmsException("Type of media is unknown.");
          }

          if (LOCAL_LOGV) {
            Log.v(
                TAG,
                "New AudioModel created:"
                    + " mSrc="
                    + mSrc
                    + " mContentType="
                    + mContentType
                    + " mUri="
                    + uri
                    + " mExtras="
                    + mExtras);
          }
        } else {
          throw new MmsException("Nothing found: " + uri);
        }
      } finally {
        c.close();
      }
    } else {
      throw new MmsException("Bad URI: " + uri);
    }

    initMediaDuration();
  }
  private Uri storeMessage(Context context, SmsMessage[] msgs, int error) {
    SmsMessage sms = msgs[0];

    // Store the message in the content provider.
    ContentValues values = extractContentValues(sms);
    values.put(Sms.ERROR_CODE, error);
    int pduCount = msgs.length;

    if (pduCount == 1) {
      // There is only one part, so grab the body directly.
      values.put(Inbox.BODY, replaceFormFeeds(sms.getDisplayMessageBody()));
    } else {
      // Build up the body from the parts.
      StringBuilder body = new StringBuilder();
      for (int i = 0; i < pduCount; i++) {
        sms = msgs[i];
        if (sms.mWrappedSmsMessage != null) {
          body.append(sms.getDisplayMessageBody());
        }
      }
      values.put(Inbox.BODY, replaceFormFeeds(body.toString()));
    }

    // Make sure we've got a thread id so after the insert we'll be able to delete
    // excess messages.
    Long threadId = values.getAsLong(Sms.THREAD_ID);
    String address = values.getAsString(Sms.ADDRESS);

    // Code for debugging and easy injection of short codes, non email addresses, etc.
    // See Contact.isAlphaNumber() for further comments and results.
    //        switch (count++ % 8) {
    //            case 0: address = "AB12"; break;
    //            case 1: address = "12"; break;
    //            case 2: address = "Jello123"; break;
    //            case 3: address = "T-Mobile"; break;
    //            case 4: address = "Mobile1"; break;
    //            case 5: address = "Dogs77"; break;
    //            case 6: address = "****1"; break;
    //            case 7: address = "#4#5#6#"; break;
    //        }

    if (!TextUtils.isEmpty(address)) {
      Contact cacheContact = Contact.get(address, true);
      if (cacheContact != null) {
        address = cacheContact.getNumber();
      }
    } else {
      address = getString(R.string.unknown_sender);
      values.put(Sms.ADDRESS, address);
    }

    if (((threadId == null) || (threadId == 0)) && (address != null)) {
      threadId = Conversation.getOrCreateThreadId(context, address);
      values.put(Sms.THREAD_ID, threadId);
    }

    ContentResolver resolver = context.getContentResolver();

    Uri insertedUri = SqliteWrapper.insert(context, resolver, Inbox.CONTENT_URI, values);

    // Now make sure we're not over the limit in stored messages
    Recycler.getSmsRecycler().deleteOldMessagesByThreadId(context, threadId);
    MmsWidgetProvider.notifyDatasetChanged(context);

    return insertedUri;
  }
  /** Does the actual work of rebuilding the draft cache. */
  private synchronized void rebuildCache() {
    if (Log.isLoggable(LogTag.APP, Log.DEBUG)) {
      log("rebuildCache");
    }

    HashSet<Long> oldDraftSet = mDraftSet;
    HashSet<Long> newDraftSet = new HashSet<Long>(oldDraftSet.size());

    Cursor cursor =
        SqliteWrapper.query(
            mContext,
            mContext.getContentResolver(),
            MmsSms.CONTENT_DRAFT_URI,
            DRAFT_PROJECTION,
            null,
            null,
            null);

    if (cursor != null) {
      try {
        if (cursor.moveToFirst()) {
          for (; !cursor.isAfterLast(); cursor.moveToNext()) {
            long threadId = cursor.getLong(COLUMN_DRAFT_THREAD_ID);
            newDraftSet.add(threadId);
            if (Log.isLoggable(LogTag.APP, Log.DEBUG)) {
              log("rebuildCache: add tid=" + threadId);
            }
          }
        }
      } finally {
        cursor.close();
      }
    }
    mDraftSet = newDraftSet;

    if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) {
      dump();
    }

    // If nobody's interested in finding out about changes,
    // just bail out early.
    if (mChangeListeners.size() < 1) {
      return;
    }

    // Find out which drafts were removed and added and notify
    // listeners.
    Set<Long> added = new HashSet<Long>(newDraftSet);
    added.removeAll(oldDraftSet);
    Set<Long> removed = new HashSet<Long>(oldDraftSet);
    removed.removeAll(newDraftSet);

    for (OnDraftChangedListener l : mChangeListeners) {
      for (long threadId : added) {
        l.onDraftChanged(threadId, true);
      }
      for (long threadId : removed) {
        l.onDraftChanged(threadId, false);
      }
    }
  }
  public synchronized void sendFirstQueuedMessage() {
    boolean success = true;
    // get all the queued messages from the database
    final Uri uri = Uri.parse("content://sms/queued");
    ContentResolver resolver = getContentResolver();
    Cursor c =
        SqliteWrapper.query(
            this,
            resolver,
            uri,
            SEND_PROJECTION,
            null,
            null,
            "date ASC"); // date ASC so we send out in
    // same order the user tried
    // to send messages.
    if (c != null) {
      try {
        if (c.moveToFirst()) {
          String msgText = c.getString(SEND_COLUMN_BODY);
          String address = c.getString(SEND_COLUMN_ADDRESS);
          int threadId = c.getInt(SEND_COLUMN_THREAD_ID);
          int status = c.getInt(SEND_COLUMN_STATUS);

          int msgId = c.getInt(SEND_COLUMN_ID);
          Uri msgUri = ContentUris.withAppendedId(Sms.CONTENT_URI, msgId);

          SmsMessageSender sender =
              new SmsSingleRecipientSender(
                  this, address, msgText, threadId, status == Sms.STATUS_PENDING, msgUri);

          if (LogTag.DEBUG_SEND
              || LogTag.VERBOSE
              || Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {
            Log.v(
                TAG,
                "sendFirstQueuedMessage "
                    + msgUri
                    + ", address: "
                    + address
                    + ", threadId: "
                    + threadId);
          }

          try {
            sender.sendMessage(SendingProgressTokenManager.NO_TOKEN);
            ;
            mSending = true;
          } catch (MmsException e) {
            Log.e(TAG, "sendFirstQueuedMessage: failed to send message " + msgUri + ", caught ", e);
            mSending = false;
            messageFailedToSend(msgUri, SmsManager.RESULT_ERROR_GENERIC_FAILURE);
            success = false;
            // Sending current message fails. Try to send more pending messages
            // if there is any.
            sendBroadcast(
                new Intent(SmsReceiverService.ACTION_SEND_MESSAGE, null, this, SmsReceiver.class));
          }
        }
      } finally {
        c.close();
      }
    }
    if (success) {
      // We successfully sent all the messages in the queue. We don't need to
      // be notified of any service changes any longer.
      unRegisterForServiceStateChanges();
    }
  }