Example #1
0
 /**
  * Create a new rendering session and test that rendering /layout/activity.xml on nexus 5 doesn't
  * throw any exceptions.
  */
 @Test
 public void testRendering() throws ClassNotFoundException {
   // Create the layout pull parser.
   LayoutPullParser parser = new LayoutPullParser(APP_TEST_RES + "/layout/activity.xml");
   // Create LayoutLibCallback.
   LayoutLibTestCallback layoutLibCallback = new LayoutLibTestCallback(getLogger());
   layoutLibCallback.initResources();
   // TODO: Set up action bar handler properly to test menu rendering.
   // Create session params.
   SessionParams params = getSessionParams(parser, ConfigGenerator.NEXUS_5, layoutLibCallback);
   RenderSession session = mBridge.createSession(params);
   if (!session.getResult().isSuccess()) {
     getLogger().error(session.getResult().getException(), session.getResult().getErrorMessage());
   }
   // Render the session with a timeout of 50s.
   Result renderResult = session.render(50000);
   if (!renderResult.isSuccess()) {
     getLogger().error(session.getResult().getException(), session.getResult().getErrorMessage());
   }
   try {
     String goldenImagePath = APP_TEST_DIR + "/golden/activity.png";
     ImageUtils.requireSimilar(goldenImagePath, session.getImage());
   } catch (IOException e) {
     getLogger().error(e, e.getMessage());
   }
 }
  /**
   * Tear down the session after rendering.
   *
   * <p>The counterpart is {@link #setUp()}.
   */
  private void tearDown() {
    // The context may be null, if there was an error during init().
    if (mContext != null) {
      // Make sure to remove static references, otherwise we could not unload the lib
      mContext.disposeResources();
    }

    if (sCurrentContext != null) {
      // quit HandlerThread created during this session.
      HandlerThread_Delegate.cleanUp(sCurrentContext);
    }

    // clear the stored ViewConfiguration since the map is per density and not per context.
    ViewConfiguration_Accessor.clearConfigurations();

    // remove the InputMethodManager
    InputMethodManager_Accessor.resetInstance();

    sCurrentContext = null;

    Bridge.setLog(null);
    if (mContext != null) {
      mContext.getRenderResources().setFrameworkResourceIdProvider(null);
      mContext.getRenderResources().setLogger(null);
    }
    ParserFactory.setParserFactory(null);
  }
Example #3
0
  /** Initialize the bridge and the resource maps. */
  @Before
  public void setUp() {
    File data_dir = new File(PLATFORM_DIR, "data");
    File res = new File(data_dir, "res");
    mFrameworkRepo = new FrameworkResources(new FolderWrapper(res));
    mFrameworkRepo.loadResources();
    mFrameworkRepo.loadPublicResources(getLogger());

    mProjectResources =
        new ResourceRepository(new FolderWrapper(TEST_RES_DIR + APP_TEST_RES), false) {
          @NonNull
          @Override
          protected ResourceItem createResourceItem(String name) {
            return new ResourceItem(name);
          }
        };
    mProjectResources.loadResources();

    File fontLocation = new File(data_dir, "fonts");
    File buildProp = new File(PLATFORM_DIR, "build.prop");
    File attrs = new File(res, "values" + File.separator + "attrs.xml");
    mBridge = new Bridge();
    mBridge.init(
        ConfigGenerator.loadProperties(buildProp),
        fontLocation,
        ConfigGenerator.getEnumMap(attrs),
        getLayoutLog());
  }
  /**
   * Acquire the lock so that the scene can be acted upon.
   *
   * <p>This returns null if the lock was just acquired, otherwise it returns {@link
   * Result.Status#SUCCESS} if the lock already belonged to that thread, or another instance (see
   * {@link Result#getStatus()}) if an error occurred.
   *
   * @param timeout the time to wait if another rendering is happening.
   * @return null if the lock was just acquire or another result depending on the state.
   * @throws IllegalStateException if the current context is different than the one owned by the
   *     scene.
   */
  private Result acquireLock(long timeout) {
    ReentrantLock lock = Bridge.getLock();
    if (!lock.isHeldByCurrentThread()) {
      try {
        boolean acquired = lock.tryLock(timeout, TimeUnit.MILLISECONDS);

        if (!acquired) {
          return ERROR_TIMEOUT.createResult();
        }
      } catch (InterruptedException e) {
        return ERROR_LOCK_INTERRUPTED.createResult();
      }
    } else {
      // This thread holds the lock already. Checks that this wasn't for a different context.
      // If this is called by init, mContext will be null and so should sCurrentContext
      // anyway
      if (mContext != sCurrentContext) {
        throw new IllegalStateException(
            "Acquiring different scenes from same thread without releases");
      }
      return SUCCESS.createResult();
    }

    return null;
  }
 /**
  * Checks that the lock is owned by the current thread and that the current context is the one
  * from this scene.
  *
  * @throws IllegalStateException if the current context is different than the one owned by the
  *     scene, or if {@link #acquire(long)} was not called.
  */
 protected void checkLock() {
   ReentrantLock lock = Bridge.getLock();
   if (!lock.isHeldByCurrentThread()) {
     throw new IllegalStateException("scene must be acquired first. see #acquire(long)");
   }
   if (sCurrentContext != mContext) {
     throw new IllegalStateException("Thread acquired a scene but is rendering a different one");
   }
 }
  /**
   * Returns a {@link NinePatchChunk} object for the given serialized representation.
   *
   * <p>If the chunk is present in the cache then the object from the cache is returned, otherwise
   * the array is deserialized into a {@link NinePatchChunk} object.
   *
   * @param array the serialized representation of the chunk.
   * @return the NinePatchChunk or null if deserialization failed.
   */
  public static NinePatchChunk getChunk(byte[] array) {
    SoftReference<NinePatchChunk> chunkRef = sChunkCache.get(array);
    NinePatchChunk chunk = chunkRef.get();
    if (chunk == null) {
      ByteArrayInputStream bais = new ByteArrayInputStream(array);
      ObjectInputStream ois = null;
      try {
        ois = new ObjectInputStream(bais);
        chunk = (NinePatchChunk) ois.readObject();

        // put back the chunk in the cache
        if (chunk != null) {
          sChunkCache.put(array, new SoftReference<NinePatchChunk>(chunk));
        }
      } catch (IOException e) {
        Bridge.getLog()
            .error(
                LayoutLog.TAG_BROKEN,
                "Failed to deserialize NinePatchChunk content.",
                e,
                null /*data*/);
        return null;
      } catch (ClassNotFoundException e) {
        Bridge.getLog()
            .error(
                LayoutLog.TAG_BROKEN,
                "Failed to deserialize NinePatchChunk class.",
                e,
                null /*data*/);
        return null;
      } finally {
        if (ois != null) {
          try {
            ois.close();
          } catch (IOException ignored) {
          }
        }
      }
    }

    return chunk;
  }
  /** Cleans up the scene after an action. */
  public void release() {
    ReentrantLock lock = Bridge.getLock();

    // with the use of finally blocks, it is possible to find ourself calling this
    // without a successful call to prepareScene. This test makes sure that unlock() will
    // not throw IllegalMonitorStateException.
    if (lock.isHeldByCurrentThread()) {
      tearDown();
      lock.unlock();
    }
  }
 @LayoutlibDelegate
 /*package*/ static String formatDateInterval(long address, long fromDate, long toDate) {
   DateIntervalFormat_Delegate delegate = sManager.getDelegate((int) address);
   if (delegate == null) {
     Bridge.getLog()
         .error(LayoutLog.TAG_BROKEN, "Unable for find native DateIntervalFormat", null);
     return null;
   }
   DateInterval interval = new DateInterval(fromDate, toDate);
   StringBuffer sb = new StringBuffer();
   FieldPosition pos = new FieldPosition(0);
   delegate.mFormat.format(interval, sb, pos);
   return sb.toString();
 }
  /**
   * Sets up the session for rendering.
   *
   * <p>The counterpart is {@link #tearDown()}.
   */
  private void setUp() {
    // make sure the Resources object references the context (and other objects) for this
    // scene
    mContext.initResources();
    sCurrentContext = mContext;

    // create an InputMethodManager
    InputMethodManager.getInstance();

    LayoutLog currentLog = mParams.getLog();
    Bridge.setLog(currentLog);
    mContext.getRenderResources().setFrameworkResourceIdProvider(this);
    mContext.getRenderResources().setLogger(currentLog);
  }
  /**
   * Serializes the given chunk.
   *
   * @return the serialized data for the chunk.
   */
  public static byte[] serialize(NinePatchChunk chunk) {
    // serialize the chunk to get a byte[]
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ObjectOutputStream oos = null;
    try {
      oos = new ObjectOutputStream(baos);
      oos.writeObject(chunk);
    } catch (IOException e) {
      Bridge.getLog().error(null, "Failed to serialize NinePatchChunk.", e, null /*data*/);
      return null;
    } finally {
      if (oos != null) {
        try {
          oos.close();
        } catch (IOException ignored) {
        }
      }
    }

    // get the array and add it to the cache
    byte[] array = baos.toByteArray();
    sChunkCache.put(array, new SoftReference<NinePatchChunk>(chunk));
    return array;
  }
 @Override
 public Integer getId(ResourceType resType, String resName) {
   return Bridge.getResourceId(resType, resName);
 }