summaryrefslogtreecommitdiffstats
path: root/services/java/com/android/server/AssetAtlasService.java
diff options
context:
space:
mode:
Diffstat (limited to 'services/java/com/android/server/AssetAtlasService.java')
-rw-r--r--services/java/com/android/server/AssetAtlasService.java735
1 files changed, 0 insertions, 735 deletions
diff --git a/services/java/com/android/server/AssetAtlasService.java b/services/java/com/android/server/AssetAtlasService.java
deleted file mode 100644
index 26b4652..0000000
--- a/services/java/com/android/server/AssetAtlasService.java
+++ /dev/null
@@ -1,735 +0,0 @@
-/*
- * Copyright (C) 2013 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 com.android.server;
-
-import android.content.Context;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.res.Resources;
-import android.graphics.Atlas;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.PixelFormat;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffXfermode;
-import android.graphics.drawable.Drawable;
-import android.os.Environment;
-import android.os.RemoteException;
-import android.os.SystemProperties;
-import android.util.Log;
-import android.util.LongSparseArray;
-import android.view.GraphicBuffer;
-import android.view.IAssetAtlas;
-
-import java.io.BufferedReader;
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.OutputStreamWriter;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-/**
- * This service is responsible for packing preloaded bitmaps into a single
- * atlas texture. The resulting texture can be shared across processes to
- * reduce overall memory usage.
- *
- * @hide
- */
-public class AssetAtlasService extends IAssetAtlas.Stub {
- /**
- * Name of the <code>AssetAtlasService</code>.
- */
- public static final String ASSET_ATLAS_SERVICE = "assetatlas";
-
- private static final String LOG_TAG = "Atlas";
-
- // Turns debug logs on/off. Debug logs are kept to a minimum and should
- // remain on to diagnose issues
- private static final boolean DEBUG_ATLAS = true;
-
- // When set to true the content of the atlas will be saved to disk
- // in /data/system/atlas.png. The shared GraphicBuffer may be empty
- private static final boolean DEBUG_ATLAS_TEXTURE = false;
-
- // Minimum size in pixels to consider for the resulting texture
- private static final int MIN_SIZE = 768;
- // Maximum size in pixels to consider for the resulting texture
- private static final int MAX_SIZE = 2048;
- // Increment in number of pixels between size variants when looking
- // for the best texture dimensions
- private static final int STEP = 64;
-
- // This percentage of the total number of pixels represents the minimum
- // number of pixels we want to be able to pack in the atlas
- private static final float PACKING_THRESHOLD = 0.8f;
-
- // Defines the number of int fields used to represent a single entry
- // in the atlas map. This number defines the size of the array returned
- // by the getMap(). See the mAtlasMap field for more information
- private static final int ATLAS_MAP_ENTRY_FIELD_COUNT = 4;
-
- // Specifies how our GraphicBuffer will be used. To get proper swizzling
- // the buffer will be written to using OpenGL (from JNI) so we can leave
- // the software flag set to "never"
- private static final int GRAPHIC_BUFFER_USAGE = GraphicBuffer.USAGE_SW_READ_NEVER |
- GraphicBuffer.USAGE_SW_WRITE_NEVER | GraphicBuffer.USAGE_HW_TEXTURE;
-
- // This boolean is set to true if an atlas was successfully
- // computed and rendered
- private final AtomicBoolean mAtlasReady = new AtomicBoolean(false);
-
- private final Context mContext;
-
- // Version name of the current build, used to identify changes to assets list
- private final String mVersionName;
-
- // Holds the atlas' data. This buffer can be mapped to
- // OpenGL using an EGLImage
- private GraphicBuffer mBuffer;
-
- // Describes how bitmaps are placed in the atlas. Each bitmap is
- // represented by several entries in the array:
- // int0: SkBitmap*, the native bitmap object
- // int1: x position
- // int2: y position
- // int3: rotated, 1 if the bitmap must be rotated, 0 otherwise
- // NOTE: This will need to be handled differently to support 64 bit pointers
- private int[] mAtlasMap;
-
- /**
- * Creates a new service. Upon creating, the service will gather the list of
- * assets to consider for packing into the atlas and spawn a new thread to
- * start the packing work.
- *
- * @param context The context giving access to preloaded resources
- */
- public AssetAtlasService(Context context) {
- mContext = context;
- mVersionName = queryVersionName(context);
-
- ArrayList<Bitmap> bitmaps = new ArrayList<Bitmap>(300);
- int totalPixelCount = 0;
-
- // We only care about drawables that hold bitmaps
- final Resources resources = context.getResources();
- final LongSparseArray<Drawable.ConstantState> drawables = resources.getPreloadedDrawables();
-
- final int count = drawables.size();
- for (int i = 0; i < count; i++) {
- final Bitmap bitmap = drawables.valueAt(i).getBitmap();
- if (bitmap != null && bitmap.getConfig() == Bitmap.Config.ARGB_8888) {
- bitmaps.add(bitmap);
- totalPixelCount += bitmap.getWidth() * bitmap.getHeight();
- }
- }
-
- // Our algorithms perform better when the bitmaps are first sorted
- // The comparator will sort the bitmap by width first, then by height
- Collections.sort(bitmaps, new Comparator<Bitmap>() {
- @Override
- public int compare(Bitmap b1, Bitmap b2) {
- if (b1.getWidth() == b2.getWidth()) {
- return b2.getHeight() - b1.getHeight();
- }
- return b2.getWidth() - b1.getWidth();
- }
- });
-
- // Kick off the packing work on a worker thread
- new Thread(new Renderer(bitmaps, totalPixelCount)).start();
- }
-
- /**
- * Queries the version name stored in framework's AndroidManifest.
- * The version name can be used to identify possible changes to
- * framework resources.
- *
- * @see #getBuildIdentifier(String)
- */
- private static String queryVersionName(Context context) {
- try {
- String packageName = context.getPackageName();
- PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0);
- return info.versionName;
- } catch (PackageManager.NameNotFoundException e) {
- Log.w(LOG_TAG, "Could not get package info", e);
- }
- return null;
- }
-
- /**
- * Callback invoked by the server thread to indicate we can now run
- * 3rd party code.
- */
- public void systemRunning() {
- }
-
- /**
- * The renderer does all the work:
- */
- private class Renderer implements Runnable {
- private final ArrayList<Bitmap> mBitmaps;
- private final int mPixelCount;
-
- private int mNativeBitmap;
-
- // Used for debugging only
- private Bitmap mAtlasBitmap;
-
- Renderer(ArrayList<Bitmap> bitmaps, int pixelCount) {
- mBitmaps = bitmaps;
- mPixelCount = pixelCount;
- }
-
- /**
- * 1. On first boot or after every update, brute-force through all the
- * possible atlas configurations and look for the best one (maximimize
- * number of packed assets and minimize texture size)
- * a. If a best configuration was computed, write it out to disk for
- * future use
- * 2. Read best configuration from disk
- * 3. Compute the packing using the best configuration
- * 4. Allocate a GraphicBuffer
- * 5. Render assets in the buffer
- */
- @Override
- public void run() {
- Configuration config = chooseConfiguration(mBitmaps, mPixelCount, mVersionName);
- if (DEBUG_ATLAS) Log.d(LOG_TAG, "Loaded configuration: " + config);
-
- if (config != null) {
- mBuffer = GraphicBuffer.create(config.width, config.height,
- PixelFormat.RGBA_8888, GRAPHIC_BUFFER_USAGE);
-
- if (mBuffer != null) {
- Atlas atlas = new Atlas(config.type, config.width, config.height, config.flags);
- if (renderAtlas(mBuffer, atlas, config.count)) {
- mAtlasReady.set(true);
- }
- }
- }
- }
-
- /**
- * Renders a list of bitmaps into the atlas. The position of each bitmap
- * was decided by the packing algorithm and will be honored by this
- * method. If need be this method will also rotate bitmaps.
- *
- * @param buffer The buffer to render the atlas entries into
- * @param atlas The atlas to pack the bitmaps into
- * @param packCount The number of bitmaps that will be packed in the atlas
- *
- * @return true if the atlas was rendered, false otherwise
- */
- @SuppressWarnings("MismatchedReadAndWriteOfArray")
- private boolean renderAtlas(GraphicBuffer buffer, Atlas atlas, int packCount) {
- // Use a Source blend mode to improve performance, the target bitmap
- // will be zero'd out so there's no need to waste time applying blending
- final Paint paint = new Paint();
- paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
-
- // We always render the atlas into a bitmap. This bitmap is then
- // uploaded into the GraphicBuffer using OpenGL to swizzle the content
- final Canvas canvas = acquireCanvas(buffer.getWidth(), buffer.getHeight());
- if (canvas == null) return false;
-
- final Atlas.Entry entry = new Atlas.Entry();
-
- mAtlasMap = new int[packCount * ATLAS_MAP_ENTRY_FIELD_COUNT];
- int[] atlasMap = mAtlasMap;
- int mapIndex = 0;
-
- boolean result = false;
- try {
- final long startRender = System.nanoTime();
- final int count = mBitmaps.size();
-
- for (int i = 0; i < count; i++) {
- final Bitmap bitmap = mBitmaps.get(i);
- if (atlas.pack(bitmap.getWidth(), bitmap.getHeight(), entry) != null) {
- // We have more bitmaps to pack than the current configuration
- // says, we were most likely not able to detect a change in the
- // list of preloaded drawables, abort and delete the configuration
- if (mapIndex >= mAtlasMap.length) {
- deleteDataFile();
- break;
- }
-
- canvas.save();
- canvas.translate(entry.x, entry.y);
- if (entry.rotated) {
- canvas.translate(bitmap.getHeight(), 0.0f);
- canvas.rotate(90.0f);
- }
- canvas.drawBitmap(bitmap, 0.0f, 0.0f, null);
- canvas.restore();
-
- atlasMap[mapIndex++] = bitmap.mNativeBitmap;
- atlasMap[mapIndex++] = entry.x;
- atlasMap[mapIndex++] = entry.y;
- atlasMap[mapIndex++] = entry.rotated ? 1 : 0;
- }
- }
-
- final long endRender = System.nanoTime();
- if (mNativeBitmap != 0) {
- result = nUploadAtlas(buffer, mNativeBitmap);
- }
-
- final long endUpload = System.nanoTime();
- if (DEBUG_ATLAS) {
- float renderDuration = (endRender - startRender) / 1000.0f / 1000.0f;
- float uploadDuration = (endUpload - endRender) / 1000.0f / 1000.0f;
- Log.d(LOG_TAG, String.format("Rendered atlas in %.2fms (%.2f+%.2fms)",
- renderDuration + uploadDuration, renderDuration, uploadDuration));
- }
-
- } finally {
- releaseCanvas(canvas);
- }
-
- return result;
- }
-
- /**
- * Returns a Canvas for the specified buffer. If {@link #DEBUG_ATLAS_TEXTURE}
- * is turned on, the returned Canvas will render into a local bitmap that
- * will then be saved out to disk for debugging purposes.
- * @param width
- * @param height
- */
- private Canvas acquireCanvas(int width, int height) {
- if (DEBUG_ATLAS_TEXTURE) {
- mAtlasBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
- return new Canvas(mAtlasBitmap);
- } else {
- Canvas canvas = new Canvas();
- mNativeBitmap = nAcquireAtlasCanvas(canvas, width, height);
- return canvas;
- }
- }
-
- /**
- * Releases the canvas used to render into the buffer. Calling this method
- * will release any resource previously acquired. If {@link #DEBUG_ATLAS_TEXTURE}
- * is turend on, calling this method will write the content of the atlas
- * to disk in /data/system/atlas.png for debugging.
- */
- private void releaseCanvas(Canvas canvas) {
- if (DEBUG_ATLAS_TEXTURE) {
- canvas.setBitmap(null);
-
- File systemDirectory = new File(Environment.getDataDirectory(), "system");
- File dataFile = new File(systemDirectory, "atlas.png");
-
- try {
- FileOutputStream out = new FileOutputStream(dataFile);
- mAtlasBitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
- out.close();
- } catch (FileNotFoundException e) {
- // Ignore
- } catch (IOException e) {
- // Ignore
- }
-
- mAtlasBitmap.recycle();
- mAtlasBitmap = null;
- } else {
- nReleaseAtlasCanvas(canvas, mNativeBitmap);
- }
- }
- }
-
- private static native int nAcquireAtlasCanvas(Canvas canvas, int width, int height);
- private static native void nReleaseAtlasCanvas(Canvas canvas, int bitmap);
- private static native boolean nUploadAtlas(GraphicBuffer buffer, int bitmap);
-
- @Override
- public boolean isCompatible(int ppid) {
- return ppid == android.os.Process.myPpid();
- }
-
- @Override
- public GraphicBuffer getBuffer() throws RemoteException {
- return mAtlasReady.get() ? mBuffer : null;
- }
-
- @Override
- public int[] getMap() throws RemoteException {
- return mAtlasReady.get() ? mAtlasMap : null;
- }
-
- /**
- * Finds the best atlas configuration to pack the list of supplied bitmaps.
- * This method takes advantage of multi-core systems by spawning a number
- * of threads equal to the number of available cores.
- */
- private static Configuration computeBestConfiguration(
- ArrayList<Bitmap> bitmaps, int pixelCount) {
- if (DEBUG_ATLAS) Log.d(LOG_TAG, "Computing best atlas configuration...");
-
- long begin = System.nanoTime();
- List<WorkerResult> results = Collections.synchronizedList(new ArrayList<WorkerResult>());
-
- // Don't bother with an extra thread if there's only one processor
- int cpuCount = Runtime.getRuntime().availableProcessors();
- if (cpuCount == 1) {
- new ComputeWorker(MIN_SIZE, MAX_SIZE, STEP, bitmaps, pixelCount, results, null).run();
- } else {
- int start = MIN_SIZE;
- int end = MAX_SIZE - (cpuCount - 1) * STEP;
- int step = STEP * cpuCount;
-
- final CountDownLatch signal = new CountDownLatch(cpuCount);
-
- for (int i = 0; i < cpuCount; i++, start += STEP, end += STEP) {
- ComputeWorker worker = new ComputeWorker(start, end, step,
- bitmaps, pixelCount, results, signal);
- new Thread(worker, "Atlas Worker #" + (i + 1)).start();
- }
-
- try {
- signal.await(10, TimeUnit.SECONDS);
- } catch (InterruptedException e) {
- Log.w(LOG_TAG, "Could not complete configuration computation");
- return null;
- }
- }
-
- // Maximize the number of packed bitmaps, minimize the texture size
- Collections.sort(results, new Comparator<WorkerResult>() {
- @Override
- public int compare(WorkerResult r1, WorkerResult r2) {
- int delta = r2.count - r1.count;
- if (delta != 0) return delta;
- return r1.width * r1.height - r2.width * r2.height;
- }
- });
-
- if (DEBUG_ATLAS) {
- float delay = (System.nanoTime() - begin) / 1000.0f / 1000.0f / 1000.0f;
- Log.d(LOG_TAG, String.format("Found best atlas configuration in %.2fs", delay));
- }
-
- WorkerResult result = results.get(0);
- return new Configuration(result.type, result.width, result.height, result.count);
- }
-
- /**
- * Returns the path to the file containing the best computed
- * atlas configuration.
- */
- private static File getDataFile() {
- File systemDirectory = new File(Environment.getDataDirectory(), "system");
- return new File(systemDirectory, "framework_atlas.config");
- }
-
- private static void deleteDataFile() {
- Log.w(LOG_TAG, "Current configuration inconsistent with assets list");
- if (!getDataFile().delete()) {
- Log.w(LOG_TAG, "Could not delete the current configuration");
- }
- }
-
- private File getFrameworkResourcesFile() {
- return new File(mContext.getApplicationInfo().sourceDir);
- }
-
- /**
- * Returns the best known atlas configuration. This method will either
- * read the configuration from disk or start a brute-force search
- * and save the result out to disk.
- */
- private Configuration chooseConfiguration(ArrayList<Bitmap> bitmaps, int pixelCount,
- String versionName) {
- Configuration config = null;
-
- final File dataFile = getDataFile();
- if (dataFile.exists()) {
- config = readConfiguration(dataFile, versionName);
- }
-
- if (config == null) {
- config = computeBestConfiguration(bitmaps, pixelCount);
- if (config != null) writeConfiguration(config, dataFile, versionName);
- }
-
- return config;
- }
-
- /**
- * Writes the specified atlas configuration to the specified file.
- */
- private void writeConfiguration(Configuration config, File file, String versionName) {
- BufferedWriter writer = null;
- try {
- writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file)));
- writer.write(getBuildIdentifier(versionName));
- writer.newLine();
- writer.write(config.type.toString());
- writer.newLine();
- writer.write(String.valueOf(config.width));
- writer.newLine();
- writer.write(String.valueOf(config.height));
- writer.newLine();
- writer.write(String.valueOf(config.count));
- writer.newLine();
- writer.write(String.valueOf(config.flags));
- writer.newLine();
- } catch (FileNotFoundException e) {
- Log.w(LOG_TAG, "Could not write " + file, e);
- } catch (IOException e) {
- Log.w(LOG_TAG, "Could not write " + file, e);
- } finally {
- if (writer != null) {
- try {
- writer.close();
- } catch (IOException e) {
- // Ignore
- }
- }
- }
- }
-
- /**
- * Reads an atlas configuration from the specified file. This method
- * returns null if an error occurs or if the configuration is invalid.
- */
- private Configuration readConfiguration(File file, String versionName) {
- BufferedReader reader = null;
- Configuration config = null;
- try {
- reader = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
-
- if (checkBuildIdentifier(reader, versionName)) {
- Atlas.Type type = Atlas.Type.valueOf(reader.readLine());
- int width = readInt(reader, MIN_SIZE, MAX_SIZE);
- int height = readInt(reader, MIN_SIZE, MAX_SIZE);
- int count = readInt(reader, 0, Integer.MAX_VALUE);
- int flags = readInt(reader, Integer.MIN_VALUE, Integer.MAX_VALUE);
-
- config = new Configuration(type, width, height, count, flags);
- }
- } catch (IllegalArgumentException e) {
- Log.w(LOG_TAG, "Invalid parameter value in " + file, e);
- } catch (FileNotFoundException e) {
- Log.w(LOG_TAG, "Could not read " + file, e);
- } catch (IOException e) {
- Log.w(LOG_TAG, "Could not read " + file, e);
- } finally {
- if (reader != null) {
- try {
- reader.close();
- } catch (IOException e) {
- // Ignore
- }
- }
- }
- return config;
- }
-
- private static int readInt(BufferedReader reader, int min, int max) throws IOException {
- return Math.max(min, Math.min(max, Integer.parseInt(reader.readLine())));
- }
-
- /**
- * Compares the next line in the specified buffered reader to the current
- * build identifier. Returns whether the two values are equal.
- *
- * @see #getBuildIdentifier(String)
- */
- private boolean checkBuildIdentifier(BufferedReader reader, String versionName)
- throws IOException {
- String deviceBuildId = getBuildIdentifier(versionName);
- String buildId = reader.readLine();
- return deviceBuildId.equals(buildId);
- }
-
- /**
- * Returns an identifier for the current build that can be used to detect
- * likely changes to framework resources. The build identifier is made of
- * several distinct values:
- *
- * build fingerprint/framework version name/file size of framework resources apk
- *
- * Only the build fingerprint should be necessary on user builds but
- * the other values are useful to detect changes on eng builds during
- * development.
- *
- * This identifier does not attempt to be exact: a new identifier does not
- * necessarily mean the preloaded drawables have changed. It is important
- * however that whenever the list of preloaded drawables changes, this
- * identifier changes as well.
- *
- * @see #checkBuildIdentifier(java.io.BufferedReader, String)
- */
- private String getBuildIdentifier(String versionName) {
- return SystemProperties.get("ro.build.fingerprint", "") + '/' + versionName + '/' +
- String.valueOf(getFrameworkResourcesFile().length());
- }
-
- /**
- * Atlas configuration. Specifies the algorithm, dimensions and flags to use.
- */
- private static class Configuration {
- final Atlas.Type type;
- final int width;
- final int height;
- final int count;
- final int flags;
-
- Configuration(Atlas.Type type, int width, int height, int count) {
- this(type, width, height, count, Atlas.FLAG_DEFAULTS);
- }
-
- Configuration(Atlas.Type type, int width, int height, int count, int flags) {
- this.type = type;
- this.width = width;
- this.height = height;
- this.count = count;
- this.flags = flags;
- }
-
- @Override
- public String toString() {
- return type.toString() + " (" + width + "x" + height + ") flags=0x" +
- Integer.toHexString(flags) + " count=" + count;
- }
- }
-
- /**
- * Used during the brute-force search to gather information about each
- * variant of the packing algorithm.
- */
- private static class WorkerResult {
- Atlas.Type type;
- int width;
- int height;
- int count;
-
- WorkerResult(Atlas.Type type, int width, int height, int count) {
- this.type = type;
- this.width = width;
- this.height = height;
- this.count = count;
- }
-
- @Override
- public String toString() {
- return String.format("%s %dx%d", type.toString(), width, height);
- }
- }
-
- /**
- * A compute worker will try a finite number of variations of the packing
- * algorithms and save the results in a supplied list.
- */
- private static class ComputeWorker implements Runnable {
- private final int mStart;
- private final int mEnd;
- private final int mStep;
- private final List<Bitmap> mBitmaps;
- private final List<WorkerResult> mResults;
- private final CountDownLatch mSignal;
- private final int mThreshold;
-
- /**
- * Creates a new compute worker to brute-force through a range of
- * packing algorithms variants.
- *
- * @param start The minimum texture width to try
- * @param end The maximum texture width to try
- * @param step The number of pixels to increment the texture width by at each step
- * @param bitmaps The list of bitmaps to pack in the atlas
- * @param pixelCount The total number of pixels occupied by the list of bitmaps
- * @param results The list of results in which to save the brute-force search results
- * @param signal Latch to decrement when this worker is done, may be null
- */
- ComputeWorker(int start, int end, int step, List<Bitmap> bitmaps, int pixelCount,
- List<WorkerResult> results, CountDownLatch signal) {
- mStart = start;
- mEnd = end;
- mStep = step;
- mBitmaps = bitmaps;
- mResults = results;
- mSignal = signal;
-
- // Minimum number of pixels we want to be able to pack
- int threshold = (int) (pixelCount * PACKING_THRESHOLD);
- // Make sure we can find at least one configuration
- while (threshold > MAX_SIZE * MAX_SIZE) {
- threshold >>= 1;
- }
- mThreshold = threshold;
- }
-
- @Override
- public void run() {
- if (DEBUG_ATLAS) Log.d(LOG_TAG, "Running " + Thread.currentThread().getName());
-
- Atlas.Entry entry = new Atlas.Entry();
- for (Atlas.Type type : Atlas.Type.values()) {
- for (int width = mStart; width < mEnd; width += mStep) {
- for (int height = MIN_SIZE; height < MAX_SIZE; height += STEP) {
- // If the atlas is not big enough, skip it
- if (width * height <= mThreshold) continue;
-
- final int count = packBitmaps(type, width, height, entry);
- if (count > 0) {
- mResults.add(new WorkerResult(type, width, height, count));
- // If we were able to pack everything let's stop here
- // Increasing the height further won't make things better
- if (count == mBitmaps.size()) {
- break;
- }
- }
- }
- }
- }
-
- if (mSignal != null) {
- mSignal.countDown();
- }
- }
-
- private int packBitmaps(Atlas.Type type, int width, int height, Atlas.Entry entry) {
- int total = 0;
- Atlas atlas = new Atlas(type, width, height);
-
- final int count = mBitmaps.size();
- for (int i = 0; i < count; i++) {
- final Bitmap bitmap = mBitmaps.get(i);
- if (atlas.pack(bitmap.getWidth(), bitmap.getHeight(), entry) != null) {
- total++;
- }
- }
-
- return total;
- }
- }
-}