content: /*
   * Copyright (C) 2018 The Android Open Source Project
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package androidx.constraintlayout.motion.widget;
  
  import static androidx.constraintlayout.widget.ConstraintSet.BASELINE;
  import static androidx.constraintlayout.widget.ConstraintSet.BOTTOM;
  import static androidx.constraintlayout.widget.ConstraintSet.END;
  import static androidx.constraintlayout.widget.ConstraintSet.HORIZONTAL;
  import static androidx.constraintlayout.widget.ConstraintSet.LEFT;
  import static androidx.constraintlayout.widget.ConstraintSet.RIGHT;
  import static androidx.constraintlayout.widget.ConstraintSet.START;
  import static androidx.constraintlayout.widget.ConstraintSet.TOP;
  import static androidx.constraintlayout.widget.ConstraintSet.VERTICAL;
  import static androidx.constraintlayout.widget.ConstraintSet.WRAP_CONTENT;
  
  import android.util.Log;
  import android.util.Pair;
  import android.view.View;
  import android.view.ViewGroup;
  
  import androidx.constraintlayout.widget.ConstraintSet;
  
  import java.util.HashMap;
  import java.util.Objects;
  
  /**
   * Utility class to manipulate MotionLayout from the layout editor
   *
   *
   */
  public class DesignTool {
  
      static final HashMap<Pair<Integer, Integer>, String> sAllAttributes = new HashMap<>();
      static final HashMap<String, String> sAllMargins = new HashMap<>();
      private static final boolean DEBUG = false;
      private static final boolean DO_NOT_USE = false;
      private static final String TAG = "DesignTool";
  
      static {
          sAllAttributes.put(Pair.create(BOTTOM, BOTTOM), "layout_constraintBottom_toBottomOf");
          sAllAttributes.put(Pair.create(BOTTOM, TOP), "layout_constraintBottom_toTopOf");
          sAllAttributes.put(Pair.create(TOP, BOTTOM), "layout_constraintTop_toBottomOf");
          sAllAttributes.put(Pair.create(TOP, TOP), "layout_constraintTop_toTopOf");
          sAllAttributes.put(Pair.create(START, START), "layout_constraintStart_toStartOf");
          sAllAttributes.put(Pair.create(START, END), "layout_constraintStart_toEndOf");
          sAllAttributes.put(Pair.create(END, START), "layout_constraintEnd_toStartOf");
          sAllAttributes.put(Pair.create(END, END), "layout_constraintEnd_toEndOf");
          sAllAttributes.put(Pair.create(LEFT, LEFT), "layout_constraintLeft_toLeftOf");
          sAllAttributes.put(Pair.create(LEFT, RIGHT), "layout_constraintLeft_toRightOf");
          sAllAttributes.put(Pair.create(RIGHT, RIGHT), "layout_constraintRight_toRightOf");
          sAllAttributes.put(Pair.create(RIGHT, LEFT), "layout_constraintRight_toLeftOf");
          sAllAttributes.put(Pair.create(BASELINE, BASELINE),
                  "layout_constraintBaseline_toBaselineOf");
  
          sAllMargins.put("layout_constraintBottom_toBottomOf", "layout_marginBottom");
          sAllMargins.put("layout_constraintBottom_toTopOf", "layout_marginBottom");
          sAllMargins.put("layout_constraintTop_toBottomOf", "layout_marginTop");
          sAllMargins.put("layout_constraintTop_toTopOf", "layout_marginTop");
          sAllMargins.put("layout_constraintStart_toStartOf", "layout_marginStart");
          sAllMargins.put("layout_constraintStart_toEndOf", "layout_marginStart");
          sAllMargins.put("layout_constraintEnd_toStartOf", "layout_marginEnd");
          sAllMargins.put("layout_constraintEnd_toEndOf", "layout_marginEnd");
          sAllMargins.put("layout_constraintLeft_toLeftOf", "layout_marginLeft");
          sAllMargins.put("layout_constraintLeft_toRightOf", "layout_marginLeft");
          sAllMargins.put("layout_constraintRight_toRightOf", "layout_marginRight");
          sAllMargins.put("layout_constraintRight_toLeftOf", "layout_marginRight");
      }
  
      private final MotionLayout mMotionLayout;
      private MotionScene mSceneCache;
      private String mLastStartState = null;
      private String mLastEndState = null;
      private int mLastStartStateId = -1;
      private int mLastEndStateId = -1;
  
      public DesignTool(MotionLayout motionLayout) {
          mMotionLayout = motionLayout;
      }
  
      private static int getPxFromDp(int dpi, String value) {
          if (value == null) {
              return 0;
          }
          int index = value.indexOf('d');
          if (index == -1) {
              return 0;
          }
          String filteredValue = value.substring(0, index);
          int dpValue = (int) (Integer.valueOf(filteredValue) * dpi / 160f);
          return dpValue;
      }
  
      private static void connect(int dpi,
                                  ConstraintSet set,
                                  View view,
                                  HashMap<String, String> attributes,
                                  int from,
                                  int to) {
          String connection = sAllAttributes.get(Pair.create(from, to));
          String connectionValue = attributes.get(connection);
  
          if (connectionValue != null) {
              int marginValue = 0;
              String margin = sAllMargins.get(connection);
              if (margin != null) {
                  marginValue = getPxFromDp(dpi, attributes.get(margin));
              }
              int id = Integer.parseInt(connectionValue);
              set.connect(view.getId(), from, id, to, marginValue);
          }
      }
  
      private static void setBias(ConstraintSet set,
                                  View view,
                                  HashMap<String, String> attributes,
                                  int type) {
          String bias = "layout_constraintHorizontal_bias";
          if (type == VERTICAL) {
              bias = "layout_constraintVertical_bias";
          }
          String biasValue = attributes.get(bias);
          if (biasValue != null) {
              if (type == HORIZONTAL) {
                  set.setHorizontalBias(view.getId(), Float.parseFloat(biasValue));
              } else if (type == VERTICAL) {
                  set.setVerticalBias(view.getId(), Float.parseFloat(biasValue));
              }
          }
      }
  
      private static void setDimensions(int dpi,
                                        ConstraintSet set,
                                        View view,
                                        HashMap<String, String> attributes,
                                        int type) {
          String dimension = "layout_width";
          if (type == VERTICAL) {
              dimension = "layout_height";
          }
          String dimensionValue = attributes.get(dimension);
          if (dimensionValue != null) {
              int value = WRAP_CONTENT;
              if (!dimensionValue.equalsIgnoreCase("wrap_content")) {
                  value = getPxFromDp(dpi, dimensionValue);
              }
              if (type == HORIZONTAL) {
                  set.constrainWidth(view.getId(), value);
              } else {
                  set.constrainHeight(view.getId(), value);
              }
          }
      }
  
      private static void setAbsolutePositions(int dpi,
                                               ConstraintSet set,
                                               View view,
                                               HashMap<String, String> attributes) {
          String absoluteX = attributes.get("layout_editor_absoluteX");
          if (absoluteX != null) {
              set.setEditorAbsoluteX(view.getId(), getPxFromDp(dpi, absoluteX));
          }
          String absoluteY = attributes.get("layout_editor_absoluteY");
          if (absoluteY != null) {
              set.setEditorAbsoluteY(view.getId(), getPxFromDp(dpi, absoluteY));
          }
      }
  
      /**
       * Get the center point of the animation path of a view
       *
       * @param view view to getMap the animation of
       * @param path array to be filled (x1,y1,x2,y2...)
       * @return -1 if not under and animation 0 if not animated or number of point along animation
       */
      public int getAnimationPath(Object view, float[] path, int len) {
          if (mMotionLayout.mScene == null) {
              return -1;
          }
  
          MotionController motionController = mMotionLayout.mFrameArrayList.get(view);
          if (motionController == null) {
              return 0;
          }
  
          motionController.buildPath(path, len);
          return len;
      }
  
      /**
       * Get the center point of the animation path of a view
       *
       * @param view view to getMap the animation of
       * @param path array to be filled (in groups of 8) (x1,y1,x2,y2...)
       */
      public void getAnimationRectangles(Object view, float[] path) {
          if (mMotionLayout.mScene == null) {
              return;
          }
          int duration = mMotionLayout.mScene.getDuration();
          int frames = duration / 16;
  
          MotionController motionController = mMotionLayout.mFrameArrayList.get(view);
          if (motionController == null) {
              return;
          }
  
          motionController.buildRectangles(path, frames);
      }
  
      /**
       * Get the location of the start end and key frames
       *
       * @param view the view to track
       * @param key  array to be filled
       * @return number of key frames + 2
       */
      public int getAnimationKeyFrames(Object view, float[] key) {
          if (mMotionLayout.mScene == null) {
              return -1;
          }
          int duration = mMotionLayout.mScene.getDuration();
          int frames = duration / 16;
  
          MotionController motionController = mMotionLayout.mFrameArrayList.get(view);
          if (motionController == null) {
              return 0;
          }
  
          motionController.buildKeyFrames(key, null);
          return frames;
      }
  
      /**
       * @param position
       *
       */
      public void setToolPosition(float position) {
          if (mMotionLayout.mScene == null) {
              mMotionLayout.mScene = mSceneCache;
          }
          mMotionLayout.setProgress(position);
          mMotionLayout.evaluate(true);
          mMotionLayout.requestLayout();
          mMotionLayout.invalidate();
      }
  
      // @TODO: add description
  
      /**
       *
       * @return
       */
      public String getStartState() {
          int startId = mMotionLayout.getStartState();
          if (mLastStartStateId == startId) {
              return mLastStartState;
          }
          String last = mMotionLayout.getConstraintSetNames(startId);
  
          if (last != null) {
              mLastStartState = last;
              mLastStartStateId = startId;
          }
          return mMotionLayout.getConstraintSetNames(startId);
      }
  
      // @TODO: add description
  
      /**
       *
       * @return
       */
      public String getEndState() {
          int endId = mMotionLayout.getEndState();
  
          if (mLastEndStateId == endId) {
              return mLastEndState;
          }
          String last = mMotionLayout.getConstraintSetNames(endId);
          if (last != null) {
              mLastEndState = last;
              mLastEndStateId = endId;
          }
          return last;
      }
  
      /**
       * Return the current progress of the current transition
       *
       * @return current transition's progress
       */
      public float getProgress() {
          return mMotionLayout.getProgress();
      }
  
      /**
       * Return the current state (ConstraintSet id) as a string
       *
       * @return the last state set via the design tool bridge
       */
      public String getState() {
          if (mLastStartState != null && mLastEndState != null) {
              float progress = getProgress();
              float epsilon = 0.01f;
              if (progress <= epsilon) {
                  return mLastStartState;
              } else if (progress >= 1 - epsilon) {
                  return mLastEndState;
              }
          }
          return mLastStartState;
      }
  
      /**
       * This sets the constraint set based on a string. (without the "@+id/")
       *
       * @param id
       */
      public void setState(String id) {
          if (id == null) {
              id = "motion_base";
          }
          if (Objects.equals(mLastStartState, id)) {
              return;
          }
  
          if (DEBUG) {
              System.out.println("================================");
              dumpConstraintSet(id);
          }
  
          mLastStartState = id;
          mLastEndState = null;
          if (id == null && DO_NOT_USE) { // going to base layout
              if (mMotionLayout.mScene != null) {
                  mSceneCache = mMotionLayout.mScene;
                  mMotionLayout.mScene = null;
              }
  
              mMotionLayout.setProgress(0);
              mMotionLayout.requestLayout();
          }
  
          if (mMotionLayout.mScene == null) {
              mMotionLayout.mScene = mSceneCache;
          }
  
          int rscId = mMotionLayout.lookUpConstraintId(id);
          mLastStartStateId = rscId;
  
          if (rscId != 0) {
              if (rscId == mMotionLayout.getStartState()) {
                  mMotionLayout.setProgress(0);
              } else if (rscId == mMotionLayout.getEndState()) {
                  mMotionLayout.setProgress(1);
              } else {
                  mMotionLayout.transitionToState(rscId);
                  mMotionLayout.setProgress(1);
              }
          }
          mMotionLayout.requestLayout();
      }
  
      /**
       * Utility method, returns true if we are currently in a transition
       *
       * @return true if in a transition, false otherwise
       */
      public boolean isInTransition() {
          return mLastStartState != null && mLastEndState != null;
      }
  
      /**
       * This sets the constraint set based on a string. (without the "@+id/")
       *
       * @param start
       * @param end
       */
      public void setTransition(String start, String end) {
          if (mMotionLayout.mScene == null) {
              mMotionLayout.mScene = mSceneCache;
          }
          int startId = mMotionLayout.lookUpConstraintId(start);
          int endId = mMotionLayout.lookUpConstraintId(end);
  
          mMotionLayout.setTransition(startId, endId);
          mLastStartStateId = startId;
          mLastEndStateId = endId;
  
          mLastStartState = start;
          mLastEndState = end;
      }
  
      /**
       * this allow disabling autoTransitions to prevent design surface
       * from being in undefined states
       *
       * @param disable
       */
      public void disableAutoTransition(boolean disable) {
          mMotionLayout.disableAutoTransition(disable);
      }
  
      /**
       * Gets the time of the currently set animation.
       *
       * @return time in Milliseconds
       */
      public long getTransitionTimeMs() {
          return mMotionLayout.getTransitionTimeMs();
      }
  
      /**
       * Get the keyFrames for the view controlled by this MotionController.
       * The call is designed to be efficient because it will be called 30x Number of views a second
       *
       * @param view the view to return keyframe positions
       * @param type is pos(0-100) + 1000*mType(1=Attrib, 2=Position, 3=TimeCycle 4=Cycle 5=Trigger
       * @param pos  the x&y position of the keyFrame along the path
       * @return Number of keyFrames found
       */
      public int getKeyFramePositions(Object view, int[] type, float[] pos) {
          MotionController controller = mMotionLayout.mFrameArrayList.get((View) view);
          if (controller == null) {
              return 0;
          }
          return controller.getKeyFramePositions(type, pos);
      }
  
      /**
       * Get the keyFrames for the view controlled by this MotionController.
       * The call is designed to be efficient because it will be called 30x Number of views a second
       *
       * @param view the view to return keyframe positions
       * @param info
       * @return Number of keyFrames found
       */
      public int getKeyFrameInfo(Object view, int type, int[] info) {
          MotionController controller = mMotionLayout.mFrameArrayList.get((View) view);
          if (controller == null) {
              return 0;
          }
          return controller.getKeyFrameInfo(type, info);
      }
  
      /**
       * @param view
       * @param type
       * @param x
       * @param y
       * @return
       *
       */
      public float getKeyFramePosition(Object view, int type, float x, float y) {
          if (!(view instanceof View)) {
              return 0f;
          }
  
          MotionController mc = mMotionLayout.mFrameArrayList.get((View) view);
          if (mc == null) {
              return 0f;
          }
  
          return mc.getKeyFrameParameter(type, x, y);
      }
  
      /**
       * @param view
       * @param position
       * @param name
       * @param value
       *
       */
      public void setKeyFrame(Object view, int position, String name, Object value) {
          if (DEBUG) {
              Log.v(TAG, "setKeyFrame " + position + " <" + name + "> " + value);
          }
          if (mMotionLayout.mScene != null) {
              mMotionLayout.mScene.setKeyframe((View) view, position, name, value);
              mMotionLayout.mTransitionGoalPosition = position / 100f;
              mMotionLayout.mTransitionLastPosition = 0;
              mMotionLayout.rebuildScene();
              mMotionLayout.evaluate(true);
          }
      }
  
      /**
       * Move the widget directly
       *
       * @param view
       * @param position
       * @param type
       * @param x
       * @param y
       * @return
       *
       */
      public boolean setKeyFramePosition(Object view, int position, int type, float x, float y) {
          if (!(view instanceof View)) {
              return false;
          }
  
          if (mMotionLayout.mScene != null) {
              MotionController controller = mMotionLayout.mFrameArrayList.get(view);
              position = (int) (mMotionLayout.mTransitionPosition * 100);
              if (controller != null
                      && mMotionLayout.mScene.hasKeyFramePosition((View) view, position)) {
                  float fx = controller.getKeyFrameParameter(MotionController.HORIZONTAL_PATH_X,
                          x, y);
                  float fy = controller.getKeyFrameParameter(MotionController.VERTICAL_PATH_Y,
                          x, y);
                  // TODO: supports path relative
                  mMotionLayout.mScene.setKeyframe((View) view, position, "motion:percentX", fx);
                  mMotionLayout.mScene.setKeyframe((View) view, position, "motion:percentY", fy);
                  mMotionLayout.rebuildScene();
                  mMotionLayout.evaluate(true);
                  mMotionLayout.invalidate();
                  return true;
              }
          }
          return false;
      }
  
      /**
       * @param view
       * @param debugMode
       *
       */
      public void setViewDebug(Object view, int debugMode) {
          if (!(view instanceof View)) {
              return;
          }
  
          MotionController motionController = mMotionLayout.mFrameArrayList.get(view);
          if (motionController != null) {
              motionController.setDrawPath(debugMode);
              mMotionLayout.invalidate();
          }
      }
  
      /**
       * This is a general access to systems in the  MotionLayout System
       * This provides a series of commands used by the designer to access needed logic
       * It is written this way to minimize the interface between the library and designer.
       * It allows the logic to be kept only in the library not replicated in the gui builder.
       * It also allows us to understand understand the version  of MotionLayout in use
       * commands
       * 0 return the version number
       * 1 Get the center point of the animation path of a view
       * 2 Get the location of the start end and key frames
       *
       * @param cmd        this provide the command needed
       * @param type       support argument for command
       * @param viewObject if this command references a view this provides access
       * @param in         this allows for an array of float to be the input to the system
       * @param inLength   this provides the length of the input
       * @param out        this provide the output array
       * @param outLength  the length of the output array
       * @return command dependent -1 is typically an error (do not understand)
       */
      public int designAccess(int cmd, String type, Object viewObject,
                              float[] in, int inLength, float[] out, int outLength) {
          View view = (View) viewObject;
          MotionController motionController = null;
          if (cmd != 0) {
              if (mMotionLayout.mScene == null) {
                  return -1;
              }
  
              if (view != null) { // Can't find the view
                  motionController = mMotionLayout.mFrameArrayList.get(view);
                  if (motionController == null) {
                      return -1;
                  }
              } else { // currently only cmd  == 0 does not require a motion view
                  return -1;
              }
  
          }
          switch (cmd) {
              case 0: // version
                  return 1;
              case 1: { // get View path
  
                  int duration = mMotionLayout.mScene.getDuration();
                  int frames = duration / 16;
  
                  motionController.buildPath(out, frames);
                  return frames;
              }
              case 2: { // get key frames
  
                  int duration = mMotionLayout.mScene.getDuration();
                  int frames = duration / 16;
  
                  motionController.buildKeyFrames(out, null);
                  return frames;
              }
              case 3: { // get Attribute
  
                  int duration = mMotionLayout.mScene.getDuration();
                  @SuppressWarnings("unused") int frames = duration / 16;
  
                  return motionController.getAttributeValues(type, out, outLength);
              }
  
              default:
                  return -1;
  
          }
      }
  
      // @TODO: add description
  
      /**
       *
       * @param type
       * @param target
       * @param position
       * @return
       */
      public Object getKeyframe(int type, int target, int position) {
          if (mMotionLayout.mScene == null) {
              return null;
          }
          return mMotionLayout.mScene.getKeyFrame(mMotionLayout.getContext(), type, target, position);
      }
  
      // @TODO: add description
  
      /**
       *
       * @param viewObject
       * @param x
       * @param y
       * @return
       */
      public Object getKeyframeAtLocation(Object viewObject, float x, float y) {
          View view = (View) viewObject;
          MotionController motionController = null;
          if (mMotionLayout.mScene == null) {
              return -1;
          }
          if (view != null) { // Can't find the view
              motionController = mMotionLayout.mFrameArrayList.get(view);
              if (motionController == null) {
                  return null;
              }
          } else {
              return null;
          }
          ViewGroup viewGroup = ((ViewGroup) view.getParent());
          int layoutWidth = viewGroup.getWidth();
          int layoutHeight = viewGroup.getHeight();
          return motionController.getPositionKeyframe(layoutWidth, layoutHeight, x, y);
      }
  
      // @TODO: add description
  
      /**
       *
       * @param keyFrame
       * @param view
       * @param x
       * @param y
       * @param attribute
       * @param value
       * @return
       */
      public Boolean getPositionKeyframe(Object keyFrame,
                                         Object view,
                                         float x,
                                         float y,
                                         String[] attribute,
                                         float[] value) {
          if (keyFrame instanceof KeyPositionBase) {
              KeyPositionBase key = (KeyPositionBase) keyFrame;
              MotionController motionController = mMotionLayout.mFrameArrayList.get((View) view);
              motionController.positionKeyframe((View) view, key, x, y, attribute, value);
              mMotionLayout.rebuildScene();
              mMotionLayout.mInTransition = true;
              return true;
          }
          return false;
      }
  
      // @TODO: add description
  
      /**
       *
       * @param view
       * @param type
       * @param position
       * @return
       */
      public Object getKeyframe(Object view, int type, int position) {
          if (mMotionLayout.mScene == null) {
              return null;
          }
          int target = ((View) view).getId();
          return mMotionLayout.mScene.getKeyFrame(mMotionLayout.getContext(), type, target, position);
      }
  
      // @TODO: add description
  
      /**
       *
       * @param keyFrame
       * @param tag
       * @param value
       */
      public void setKeyframe(Object keyFrame, String tag, Object value) {
          if (keyFrame instanceof Key) {
              Key key = (Key) keyFrame;
              key.setValue(tag, value);
              mMotionLayout.rebuildScene();
              mMotionLayout.mInTransition = true;
          }
      }
  
      /**
       * Live setting of attributes on a view
       *
       * @param dpi              dpi used by the application
       * @param constraintSetId  ConstraintSet id
       * @param opaqueView       the Android View we operate on, passed as an Object
       * @param opaqueAttributes the list of attributes (hash<string,string>) we pass to the view
       */
      public void setAttributes(int dpi,
                                String constraintSetId,
                                Object opaqueView,
                                Object opaqueAttributes) {
          View view = (View) opaqueView;
  
          @SuppressWarnings("unchecked")
          HashMap<String, String> attributes = (opaqueAttributes instanceof HashMap) ?
                  (HashMap<String, String>) opaqueAttributes : new HashMap<>();
  
          int rscId = mMotionLayout.lookUpConstraintId(constraintSetId);
          ConstraintSet set = mMotionLayout.mScene.getConstraintSet(rscId);
  
          if (DEBUG) {
              Log.v(TAG, "constraintSetId  = " + constraintSetId + "  " + rscId);
          }
  
          if (set == null) {
              return;
          }
  
          set.clear(view.getId());
  
          setDimensions(dpi, set, view, attributes, HORIZONTAL);
          setDimensions(dpi, set, view, attributes, VERTICAL);
  
          connect(dpi, set, view, attributes, START, START);
          connect(dpi, set, view, attributes, START, END);
          connect(dpi, set, view, attributes, END, END);
          connect(dpi, set, view, attributes, END, START);
          connect(dpi, set, view, attributes, LEFT, LEFT);
          connect(dpi, set, view, attributes, LEFT, RIGHT);
          connect(dpi, set, view, attributes, RIGHT, RIGHT);
          connect(dpi, set, view, attributes, RIGHT, LEFT);
          connect(dpi, set, view, attributes, TOP, TOP);
          connect(dpi, set, view, attributes, TOP, BOTTOM);
          connect(dpi, set, view, attributes, BOTTOM, TOP);
          connect(dpi, set, view, attributes, BOTTOM, BOTTOM);
          connect(dpi, set, view, attributes, BASELINE, BASELINE);
  
          setBias(set, view, attributes, HORIZONTAL);
          setBias(set, view, attributes, VERTICAL);
  
          setAbsolutePositions(dpi, set, view, attributes);
  
          mMotionLayout.updateState(rscId, set);
          mMotionLayout.requestLayout();
      }
  
      // @TODO: add description
  
      /**
       *
       * @param set
       */
      public void dumpConstraintSet(String set) {
          if (mMotionLayout.mScene == null) {
              mMotionLayout.mScene = mSceneCache;
          }
          int setId = mMotionLayout.lookUpConstraintId(set);
          System.out.println(" dumping  " + set + " (" + setId + ")");
          try {
              mMotionLayout.mScene.getConstraintSet(setId).dump(mMotionLayout.mScene);
          } catch (Exception ex) {
              Log.e(TAG, "Error while dumping: " + set + " (" + setId + ")", ex);
          }
      }
  }
  