예제 #1
0
  @Override
  @RunsOnMainThread
  public void onGetOrCreateConversationSucceeded(
      final ActionMonitor monitor, final Object data, final String conversationId) {
    Assert.isTrue(monitor == mMonitor);
    Assert.isTrue(conversationId != null);

    mRecipientTextView.setInputType(
        InputType.TYPE_TEXT_FLAG_MULTI_LINE | InputType.TYPE_CLASS_TEXT);
    mHost.onGetOrCreateNewConversation(conversationId);

    mMonitor = null;
  }
예제 #2
0
 @Override
 @RunsOnMainThread
 public void onGetOrCreateConversationFailed(final ActionMonitor monitor, final Object data) {
   Assert.isTrue(monitor == mMonitor);
   LogUtil.e(LogUtil.BUGLE_TAG, "onGetOrCreateConversationFailed");
   mMonitor = null;
 }
예제 #3
0
  @Override
  public boolean onMenuItemClick(final MenuItem menuItem) {
    switch (menuItem.getItemId()) {
      case R.id.action_ime_dialpad_toggle:
        final int baseInputType = InputType.TYPE_TEXT_FLAG_MULTI_LINE;
        if ((mRecipientTextView.getInputType() & InputType.TYPE_CLASS_PHONE)
            != InputType.TYPE_CLASS_PHONE) {
          mRecipientTextView.setInputType(baseInputType | InputType.TYPE_CLASS_PHONE);
          menuItem.setIcon(R.drawable.ic_ime_light);
        } else {
          mRecipientTextView.setInputType(baseInputType | InputType.TYPE_CLASS_TEXT);
          menuItem.setIcon(R.drawable.ic_numeric_dialpad);
        }
        ImeUtil.get().showImeKeyboard(getActivity(), mRecipientTextView);
        return true;

      case R.id.action_add_more_participants:
        mHost.onInitiateAddMoreParticipants();
        return true;

      case R.id.action_confirm_participants:
        maybeGetOrCreateConversation();
        return true;

      case R.id.action_delete_text:
        Assert.equals(MODE_PICK_INITIAL_CONTACT, mContactPickingMode);
        mRecipientTextView.setText("");
        return true;
    }
    return false;
  }
예제 #4
0
 /**
  * {@inheritDoc}
  *
  * <p>Called when the host activity has been created. At this point, the host activity should have
  * set the contact picking mode for us so that we may update our visuals.
  */
 @Override
 public void onActivityCreated(final Bundle savedInstanceState) {
   super.onActivityCreated(savedInstanceState);
   Assert.isTrue(mContactPickingMode != MODE_UNDEFINED);
   updateVisualsForContactPickingMode(false /* animate */);
   mHost.invalidateActionBar();
 }
예제 #5
0
  private void determineLayout(final Iterable<MessagePartData> attachments, final int count) {
    Assert.isTrue(attachments != null);
    final boolean isRtl = AccessibilityUtil.isLayoutRtl(getRootView());
    if (isRtl) {
      mCurrentLayout =
          ATTACHMENT_RTL_LAYOUTS_BY_COUNT[
              Math.min(count, ATTACHMENT_RTL_LAYOUTS_BY_COUNT.length - 1)];
    } else {
      mCurrentLayout =
          ATTACHMENT_LAYOUTS_BY_COUNT[Math.min(count, ATTACHMENT_LAYOUTS_BY_COUNT.length - 1)];
    }

    // We must have a valid layout for the current configuration.
    Assert.notNull(mCurrentLayout);

    mPlusNumber = count - mCurrentLayout.tiles.size();
    Assert.isTrue(mPlusNumber >= 0);
  }
예제 #6
0
  public void setContactPickingMode(final int mode, final boolean animate) {
    if (mContactPickingMode != mode) {
      // Guard against impossible transitions.
      Assert.isTrue(
          // We may start from undefined mode to any mode when we are restoring state.
          (mContactPickingMode == MODE_UNDEFINED)
              || (mContactPickingMode == MODE_PICK_INITIAL_CONTACT && mode == MODE_CHIPS_ONLY)
              || (mContactPickingMode == MODE_CHIPS_ONLY && mode == MODE_PICK_MORE_CONTACTS)
              || (mContactPickingMode == MODE_PICK_MORE_CONTACTS
                  && mode == MODE_PICK_MAX_PARTICIPANTS)
              || (mContactPickingMode == MODE_PICK_MAX_PARTICIPANTS
                  && mode == MODE_PICK_MORE_CONTACTS));

      mContactPickingMode = mode;
      updateVisualsForContactPickingMode(animate);
    }
  }
예제 #7
0
  private void showImeKeyboard() {
    Assert.notNull(mRecipientTextView);
    mRecipientTextView.requestFocus();

    // showImeKeyboard() won't work until the layout is ready, so wait until layout is complete
    // before showing the soft keyboard.
    UiUtils.doOnceAfterLayoutChange(
        mRootView,
        new Runnable() {
          @Override
          public void run() {
            final Activity activity = getActivity();
            if (activity != null) {
              ImeUtil.get().showImeKeyboard(activity, mRecipientTextView);
            }
          }
        });
    mRecipientTextView.invalidate();
  }
예제 #8
0
  /**
   * Watches changes in contact chips to determine possible state transitions (e.g. creating the
   * initial conversation, adding more participants or finish the current conversation)
   */
  @Override
  public void onContactChipsChanged(final int oldCount, final int newCount) {
    Assert.isTrue(oldCount != newCount);
    if (mContactPickingMode == MODE_PICK_INITIAL_CONTACT) {
      // Initial picking mode. Start a conversation once a recipient has been picked.
      maybeGetOrCreateConversation();
    } else if (mContactPickingMode == MODE_CHIPS_ONLY) {
      // oldCount == 0 means we are restoring from savedInstanceState to add the existing
      // chips, don't switch to "add more participants" mode in this case.
      if (oldCount > 0 && mRecipientTextView.isFocused()) {
        // Chips only mode. The user may have picked an additional contact or deleted the
        // only existing contact. Either way, switch to picking more participants mode.
        mHost.onInitiateAddMoreParticipants();
      }
    }
    mHost.onParticipantCountChanged(ContactPickerData.getCanAddMoreParticipants(newCount));

    // Refresh our local copy of the selected chips set to keep it up-to-date.
    mSelectedPhoneNumbers = mRecipientTextView.getSelectedDestinations();
    invalidateContactLists();
  }
예제 #9
0
 // Process different result code from platform MMS service
 public static int getErrorResultStatus(int resultCode, int httpStatusCode) {
   Assert.isFalse(resultCode == Activity.RESULT_OK);
   switch (resultCode) {
     case SmsManager.MMS_ERROR_UNABLE_CONNECT_MMS:
     case SmsManager.MMS_ERROR_IO_ERROR:
       return MmsUtils.MMS_REQUEST_AUTO_RETRY;
     case SmsManager.MMS_ERROR_INVALID_APN:
     case SmsManager.MMS_ERROR_CONFIGURATION_ERROR:
     case SmsManager.MMS_ERROR_NO_DATA_NETWORK:
     case SmsManager.MMS_ERROR_UNSPECIFIED:
       return MmsUtils.MMS_REQUEST_MANUAL_RETRY;
     case SmsManager.MMS_ERROR_HTTP_FAILURE:
       if (httpStatusCode == 404) {
         return MmsUtils.MMS_REQUEST_NO_RETRY;
       } else {
         return MmsUtils.MMS_REQUEST_AUTO_RETRY;
       }
     default:
       return MmsUtils.MMS_REQUEST_MANUAL_RETRY;
   }
 }
예제 #10
0
 /**
  * Process one apn
  *
  * @param apnValues Where we store the parsed apn
  * @throws IOException
  * @throws XmlPullParserException
  */
 private void processApn(ContentValues apnValues) throws IOException, XmlPullParserException {
   Assert.notNull(apnValues);
   apnValues.clear();
   // Collect all the attributes
   for (int i = 0; i < mInputParser.getAttributeCount(); i++) {
     final String key = APN_ATTRIBUTE_MAP.get(mInputParser.getAttributeName(i));
     if (key != null) {
       apnValues.put(key, mInputParser.getAttributeValue(i));
     }
   }
   // Set numeric to be canonicalized mcc/mnc like "310120", always 6 digits
   final String canonicalMccMnc =
       PhoneUtils.canonicalizeMccMnc(
           apnValues.getAsString(Telephony.Carriers.MCC),
           apnValues.getAsString(Telephony.Carriers.MNC));
   apnValues.put(Telephony.Carriers.NUMERIC, canonicalMccMnc);
   // Some of the values should not be string type, converting them to desired types
   final String authType = apnValues.getAsString(Telephony.Carriers.AUTH_TYPE);
   if (authType != null) {
     apnValues.put(Telephony.Carriers.AUTH_TYPE, parseInt(authType, -1, "apn authtype"));
   }
   final String carrierEnabled = apnValues.getAsString(Telephony.Carriers.CARRIER_ENABLED);
   if (carrierEnabled != null) {
     apnValues.put(
         Telephony.Carriers.CARRIER_ENABLED,
         parseBoolean(carrierEnabled, null, "apn carrierEnabled"));
   }
   final String bearer = apnValues.getAsString(Telephony.Carriers.BEARER);
   if (bearer != null) {
     apnValues.put(Telephony.Carriers.BEARER, parseInt(bearer, 0, "apn bearer"));
   }
   // We are at the end tag
   if (mInputParser.next() != XmlPullParser.END_TAG) {
     throw new XmlPullParserException("Apn: expecting end tag @" + xmlParserDebugContext());
   }
   // We are done parsing one APN, call the handler
   if (mApnHandler != null) {
     mApnHandler.process(apnValues);
   }
 }
예제 #11
0
  private void buildViews(
      final Iterable<MessagePartData> attachments,
      final ArrayList<ViewWrapper> previousViews,
      final Rect transitionRect) {
    final LayoutInflater layoutInflater = LayoutInflater.from(getContext());
    final int count = mCurrentLayout.tiles.size();
    int i = 0;
    final Iterator<MessagePartData> iterator = attachments.iterator();
    while (iterator.hasNext() && i < count) {
      final MessagePartData attachment = iterator.next();
      ViewWrapper attachmentWrapper = null;
      // Try to recycle a previous view first
      for (int j = 0; j < previousViews.size(); j++) {
        final ViewWrapper previousView = previousViews.get(j);
        if (previousView.attachment.equals(attachment)
            && !(previousView.attachment instanceof PendingAttachmentData)) {
          attachmentWrapper = previousView;
          previousViews.remove(j);
          break;
        }
      }

      if (attachmentWrapper == null) {
        final View view =
            AttachmentPreviewFactory.createAttachmentPreview(
                layoutInflater,
                attachment,
                this,
                AttachmentPreviewFactory.TYPE_MULTIPLE,
                false /* startImageRequest */,
                mAttachmentClickListener);

        if (view == null) {
          // createAttachmentPreview can return null if something goes wrong (e.g.
          // attachment has unsupported contentType)
          continue;
        }
        if (view instanceof AsyncImageView && mImageViewDelayLoader != null) {
          AsyncImageView asyncImageView = (AsyncImageView) view;
          asyncImageView.setDelayLoader(mImageViewDelayLoader);
        }
        addView(view);
        attachmentWrapper = new ViewWrapper(view, attachment);
        // Help animate from single to multi by copying over the prev location
        if (count == 2 && i == 1 && transitionRect != null) {
          attachmentWrapper.prevLeft = transitionRect.left;
          attachmentWrapper.prevTop = transitionRect.top;
          attachmentWrapper.prevWidth = transitionRect.width();
          attachmentWrapper.prevHeight = transitionRect.height();
        }
      }
      i++;
      Assert.notNull(attachmentWrapper);
      mPreviewViews.add(attachmentWrapper);

      // The first view will animate in using PopupTransitionAnimation, but the remaining
      // views will slide from their previous position to their new position within the
      // layout
      if (i == 0) {
        AttachmentPreview.tryAnimateViewIn(attachment, attachmentWrapper.view);
      }
      attachmentWrapper.needsSlideAnimation = i > 0;
    }

    // Build the plus text view (e.g. "+2") for when there are more attachments than what
    // this layout can display.
    if (mPlusNumber > 0) {
      mPlusTextView =
          (TextView) layoutInflater.inflate(R.layout.attachment_more_text_view, null /* parent */);
      mPlusTextView.setText(getResources().getString(R.string.attachment_more_items, mPlusNumber));
      addView(mPlusTextView);
    }
  }
예제 #12
0
 public static ApnsXmlProcessor get(XmlPullParser parser) {
   Assert.notNull(parser);
   return new ApnsXmlProcessor(parser);
 }
예제 #13
0
 /**
  * Listens for notification that invalid contacts have been removed during resolving them. These
  * contacts were not local contacts, valid email, or valid phone numbers
  */
 @Override
 public void onInvalidContactChipsPruned(final int prunedCount) {
   Assert.isTrue(prunedCount > 0);
   UiUtils.showToast(R.plurals.add_invalid_contact_error, prunedCount);
 }
예제 #14
0
  private void updateVisualsForContactPickingMode(final boolean animate) {
    // Don't update visuals if the visuals haven't been inflated yet.
    if (mRootView != null) {
      final Menu menu = mToolbar.getMenu();
      final MenuItem addMoreParticipantsItem = menu.findItem(R.id.action_add_more_participants);
      final MenuItem confirmParticipantsItem = menu.findItem(R.id.action_confirm_participants);
      switch (mContactPickingMode) {
        case MODE_PICK_INITIAL_CONTACT:
          addMoreParticipantsItem.setVisible(false);
          confirmParticipantsItem.setVisible(false);
          mCustomHeaderViewPager.setVisibility(View.VISIBLE);
          mComposeDivider.setVisibility(View.INVISIBLE);
          mRecipientTextView.setEnabled(true);
          showImeKeyboard();
          break;

        case MODE_CHIPS_ONLY:
          if (animate) {
            if (mPendingExplodeView == null) {
              // The user didn't click on any contact item, so use the toolbar as
              // the view to "explode."
              mPendingExplodeView = mToolbar;
            }
            startExplodeTransitionForContactLists(false /* show */);

            ViewGroupItemVerticalExplodeAnimation.startAnimationForView(
                mCustomHeaderViewPager,
                mPendingExplodeView,
                mRootView,
                true /* snapshotView */,
                UiUtils.COMPOSE_TRANSITION_DURATION);
            showHideContactPagerWithAnimation(false /* show */);
          } else {
            mCustomHeaderViewPager.setVisibility(View.GONE);
          }

          addMoreParticipantsItem.setVisible(true);
          confirmParticipantsItem.setVisible(false);
          mComposeDivider.setVisibility(View.VISIBLE);
          mRecipientTextView.setEnabled(true);
          break;

        case MODE_PICK_MORE_CONTACTS:
          if (animate) {
            // Correctly set the start visibility state for the view pager and
            // individual list items (hidden initially), so that the transition
            // manager can properly track the visibility change for the explode.
            mCustomHeaderViewPager.setVisibility(View.VISIBLE);
            toggleContactListItemsVisibilityForPendingTransition(false /* show */);
            startExplodeTransitionForContactLists(true /* show */);
          }
          addMoreParticipantsItem.setVisible(false);
          confirmParticipantsItem.setVisible(true);
          mCustomHeaderViewPager.setVisibility(View.VISIBLE);
          mComposeDivider.setVisibility(View.INVISIBLE);
          mRecipientTextView.setEnabled(true);
          showImeKeyboard();
          break;

        case MODE_PICK_MAX_PARTICIPANTS:
          addMoreParticipantsItem.setVisible(false);
          confirmParticipantsItem.setVisible(true);
          mCustomHeaderViewPager.setVisibility(View.VISIBLE);
          mComposeDivider.setVisibility(View.INVISIBLE);
          // TODO: Verify that this is okay for accessibility
          mRecipientTextView.setEnabled(false);
          break;

        default:
          Assert.fail("Unsupported contact picker mode!");
          break;
      }
      updateTextInputButtonsVisibility();
    }
  }
 @VisibleForTesting
 public void setDatabaseForTest(final DatabaseWrapper db) {
   Assert.isTrue(BugleApplication.isRunningTests());
   mDatabaseWrapper = db;
 }