/**
   * Makes the SlideView working on MMSConformance Mode. The view will be re-layout to the linear
   * view.
   *
   * <p>This is Chinese requirement about mms conformance. The most popular Mms service in China is
   * newspaper which is MMS conformance, normally it mixes the image and text and has a number of
   * slides. The AbsoluteLayout doesn't have good user experience for this kind of message, for
   * example,
   *
   * <p>1. AbsoluteLayout exactly follows the smil's layout which is not optimized, and actually, no
   * other MMS applications follow the smil's layout, they adjust the layout according their screen
   * size. MMS conformance doc also allows the implementation to adjust the layout.
   *
   * <p>2. The TextView is fixed in the small area of screen, and other part of screen is empty once
   * there is no image in the current slide.
   *
   * <p>3. The TextView is scrollable in a small area of screen and the font size is small which
   * make the user experience bad.
   *
   * <p>The better UI for the MMS conformance message could be putting the image/video and text in a
   * linear layout view and making them scrollable together.
   *
   * <p>Another reason for only applying the LinearLayout to the MMS conformance message is that the
   * AbsoluteLayout has ability to play image and video in a same screen. which shouldn't be broken.
   */
  public void enableMMSConformanceMode(int textLeft, int textTop, int imageLeft, int imageTop) {
    mConformanceMode = true;
    if (mScrollViewPort == null) {
      mScrollViewPort =
          new ScrollView(mContext) {
            private int mBottomY;

            @Override
            protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
              super.onLayout(changed, left, top, right, bottom);
              if (getChildCount() > 0) {
                int childHeight = getChildAt(0).getHeight();
                int height = getHeight();
                mBottomY = height < childHeight ? childHeight - height : 0;
              }
            }

            @Override
            protected void onScrollChanged(int l, int t, int oldl, int oldt) {
              // Shows MediaController when the view is scrolled to the top/bottom of itself.
              if (t == 0 || t >= mBottomY) {
                if (mMediaController != null) {
                  mMediaController.show();
                }
              }
            }
          };
      mScrollViewPort.setScrollBarStyle(SCROLLBARS_OUTSIDE_INSET);
      mViewPort = new LinearLayout(mContext);
      mViewPort.setOrientation(LinearLayout.VERTICAL);
      mViewPort.setGravity(Gravity.CENTER);
      mViewPort.setOnClickListener(
          new OnClickListener() {
            public void onClick(View v) {
              if (mMediaController != null) {
                mMediaController.show();
              }
            }
          });
      mScrollViewPort.addView(
          mViewPort,
          new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
      addView(mScrollViewPort);
    }
    // Layout views to fit the LinearLayout from left to right, then top to
    // bottom.
    TreeMap<Position, View> viewsByPosition =
        new TreeMap<Position, View>(
            new Comparator<Position>() {
              public int compare(Position p1, Position p2) {
                int l1 = p1.mLeft;
                int t1 = p1.mTop;
                int l2 = p2.mLeft;
                int t2 = p2.mTop;
                int res = t1 - t2;
                if (res == 0) {
                  res = l1 - l2;
                }
                if (res == 0) {
                  // A view will be lost if return 0.
                  return -1;
                }
                return res;
              }
            });
    if (textLeft >= 0 && textTop >= 0) {
      mTextView = new TextView(mContext);
      mTextView.setTransformationMethod(HideReturnsTransformationMethod.getInstance());
      mTextView.setTextSize(18);
      mTextView.setPadding(5, 5, 5, 5);
      viewsByPosition.put(new Position(textLeft, textTop), mTextView);
    }

    if (imageLeft >= 0 && imageTop >= 0) {
      mImageView = new ImageView(mContext);
      mImageView.setPadding(0, 5, 0, 5);
      viewsByPosition.put(new Position(imageLeft, imageTop), mImageView);
      // According MMS Conformance Document, the image and video should use the same
      // region. So, put the VideoView below the ImageView.
      mVideoView = new VideoView(mContext);
      viewsByPosition.put(new Position(imageLeft + 1, imageTop), mVideoView);
    }
    for (View view : viewsByPosition.values()) {
      if (view instanceof VideoView) {
        mViewPort.addView(
            view,
            new LinearLayout.LayoutParams(
                LayoutParams.MATCH_PARENT,
                LayoutManager.getInstance().getLayoutParameters().getHeight()));
      } else {
        mViewPort.addView(
            view,
            new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
      }
      view.setVisibility(View.GONE);
    }
  }
  public static SlideshowModel createFromPduBody(Context context, PduBody pb) throws MmsException {
    SMILDocument document = SmilHelper.getDocument(pb);

    // Create root-layout model.
    SMILLayoutElement sle = document.getLayout();
    SMILRootLayoutElement srle = sle.getRootLayout();
    int w = srle.getWidth();
    int h = srle.getHeight();
    if ((w == 0) || (h == 0)) {
      w = LayoutManager.getInstance().getLayoutParameters().getWidth();
      h = LayoutManager.getInstance().getLayoutParameters().getHeight();
      srle.setWidth(w);
      srle.setHeight(h);
    }
    RegionModel rootLayout = new RegionModel(null, 0, 0, w, h);

    // Create region models.
    ArrayList<RegionModel> regions = new ArrayList<RegionModel>();
    NodeList nlRegions = sle.getRegions();
    int regionsNum = nlRegions.getLength();

    for (int i = 0; i < regionsNum; i++) {
      SMILRegionElement sre = (SMILRegionElement) nlRegions.item(i);
      RegionModel r =
          new RegionModel(
              sre.getId(),
              sre.getFit(),
              sre.getLeft(),
              sre.getTop(),
              sre.getWidth(),
              sre.getHeight(),
              sre.getBackgroundColor());
      regions.add(r);
    }
    LayoutModel layouts = new LayoutModel(rootLayout, regions);

    // Create slide models.
    SMILElement docBody = document.getBody();
    NodeList slideNodes = docBody.getChildNodes();
    int slidesNum = slideNodes.getLength();
    ArrayList<SlideModel> slides = new ArrayList<SlideModel>(slidesNum);

    for (int i = 0; i < slidesNum; i++) {
      // FIXME: This is NOT compatible with the SMILDocument which is
      // generated by some other mobile phones.
      SMILParElement par = (SMILParElement) slideNodes.item(i);

      // Create media models for each slide.
      NodeList mediaNodes = par.getChildNodes();
      int mediaNum = mediaNodes.getLength();
      ArrayList<MediaModel> mediaSet = new ArrayList<MediaModel>(mediaNum);

      for (int j = 0; j < mediaNum; j++) {
        SMILMediaElement sme = (SMILMediaElement) mediaNodes.item(j);
        try {
          MediaModel media = MediaModelFactory.getMediaModel(context, sme, layouts, pb);
          SmilHelper.addMediaElementEventListeners((EventTarget) sme, media);
          mediaSet.add(media);
        } catch (DrmException e) {
          Log.e(TAG, e.getMessage(), e);
        } catch (IOException e) {
          Log.e(TAG, e.getMessage(), e);
        } catch (IllegalArgumentException e) {
          Log.e(TAG, e.getMessage(), e);
        }
      }

      SlideModel slide = new SlideModel((int) (par.getDur() * 1000), mediaSet);
      slide.setFill(par.getFill());
      SmilHelper.addParElementEventListeners((EventTarget) par, slide);
      slides.add(slide);
    }

    SlideshowModel slideshow =
        new SlideshowModel(layouts, slides, document, pb, context.getContentResolver());
    slideshow.registerModelChangedObserver(slideshow);
    return slideshow;
  }