summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/java/android/view/VolumePanel.java2
-rw-r--r--core/java/android/webkit/CookieManager.java16
-rw-r--r--core/java/com/android/internal/service/wallpaper/ImageWallpaper.java2
-rw-r--r--core/jni/android/graphics/Path.cpp3
-rw-r--r--data/sounds/effects/ogg/Effect_Tick.oggbin4825 -> 4348 bytes
-rw-r--r--data/sounds/effects/ogg/KeypressSpacebar.oggbin4204 -> 7470 bytes
-rw-r--r--data/sounds/effects/ogg/KeypressStandard.oggbin4196 -> 6442 bytes
-rw-r--r--data/sounds/effects/ogg/Lock.oggbin26740 -> 20013 bytes
-rw-r--r--data/sounds/effects/ogg/Unlock.oggbin29712 -> 21885 bytes
-rw-r--r--docs/html/guide/publishing/licensing.jd13
-rw-r--r--docs/html/guide/topics/fundamentals/index.jd45
-rw-r--r--libs/gui/SurfaceTexture.cpp3
-rw-r--r--libs/hwui/DisplayListRenderer.cpp17
-rw-r--r--libs/hwui/DisplayListRenderer.h9
-rw-r--r--libs/hwui/OpenGLRenderer.cpp13
-rw-r--r--libs/hwui/ResourceCache.cpp35
-rw-r--r--libs/hwui/ResourceCache.h4
-rw-r--r--libs/rs/rsScriptC_Lib.cpp2
-rw-r--r--media/java/android/media/AudioManager.java34
-rw-r--r--media/java/android/media/AudioService.java16
-rw-r--r--media/java/android/media/videoeditor/MediaArtistNativeHelper.java53
-rwxr-xr-xmedia/java/android/media/videoeditor/MediaProperties.java5
-rwxr-xr-xmedia/java/android/media/videoeditor/MediaVideoItem.java5
-rwxr-xr-xmedia/java/android/media/videoeditor/Transition.java20
-rwxr-xr-xmedia/jni/mediaeditor/VideoEditorPropertiesMain.cpp24
-rw-r--r--services/java/com/android/server/WindowManagerService.java4
-rw-r--r--tools/layoutlib/bridge/Android.mk2
-rw-r--r--tools/layoutlib/bridge/resources/bars/action_bar.xml11
-rw-r--r--tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_back_default.pngbin0 -> 3900 bytes
-rw-r--r--tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_home_default.pngbin0 -> 3991 bytes
-rw-r--r--tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_recent_default.pngbin0 -> 3140 bytes
-rw-r--r--tools/layoutlib/bridge/resources/bars/mdpi/stat_sys_wifi_signal_4_fully.pngbin0 -> 885 bytes
-rw-r--r--tools/layoutlib/bridge/resources/bars/phone_system_bar.xml12
-rw-r--r--tools/layoutlib/bridge/resources/bars/tablet_system_bar.xml20
-rw-r--r--tools/layoutlib/bridge/resources/bars/title_bar.xml7
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/BitmapFactory.java578
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/BitmapFactory_Delegate.java117
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java1
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java43
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java10
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java4
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeResources.java95
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java2
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java212
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/FakeActionBar.java47
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/PhoneSystemBar.java42
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/TabletSystemBar.java45
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/TitleBar.java46
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java285
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java141
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java569
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java71
-rw-r--r--tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java2
53 files changed, 1622 insertions, 1065 deletions
diff --git a/core/java/android/view/VolumePanel.java b/core/java/android/view/VolumePanel.java
index 2aa94dc..3bab29f 100644
--- a/core/java/android/view/VolumePanel.java
+++ b/core/java/android/view/VolumePanel.java
@@ -190,6 +190,7 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie
mDialog.setOnDismissListener(new OnDismissListener() {
public void onDismiss(DialogInterface dialog) {
mActiveStreamType = -1;
+ mAudioManager.forceVolumeControlStream(mActiveStreamType);
}
});
// Change some window properties
@@ -483,6 +484,7 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie
}
if (!mDialog.isShowing()) {
+ mAudioManager.forceVolumeControlStream(streamType);
mDialog.setContentView(mView);
// Showing dialog - use collapsed state
collapse();
diff --git a/core/java/android/webkit/CookieManager.java b/core/java/android/webkit/CookieManager.java
index 1fea65a..9b0d4e0 100644
--- a/core/java/android/webkit/CookieManager.java
+++ b/core/java/android/webkit/CookieManager.java
@@ -519,11 +519,17 @@ public final class CookieManager {
}
}
- synchronized void waitForCookieOperationsToComplete() {
- while (pendingCookieOperations > 0) {
- try {
- wait();
- } catch (InterruptedException e) { }
+ /**
+ * Waits for pending operations to completed.
+ * {@hide} Too late to release publically.
+ */
+ public void waitForCookieOperationsToComplete() {
+ synchronized (this) {
+ while (pendingCookieOperations > 0) {
+ try {
+ wait();
+ } catch (InterruptedException e) { }
+ }
}
}
diff --git a/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java b/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java
index 38ec9c8..85095cf 100644
--- a/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java
+++ b/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java
@@ -129,7 +129,7 @@ public class ImageWallpaper extends WallpaperService {
@Override
public void onDesiredSizeChanged(int desiredWidth, int desiredHeight) {
- onDesiredSizeChanged(desiredWidth, desiredHeight);
+ super.onDesiredSizeChanged(desiredWidth, desiredHeight);
SurfaceHolder surfaceHolder = getSurfaceHolder();
if (surfaceHolder != null) {
updateSurfaceSize(surfaceHolder);
diff --git a/core/jni/android/graphics/Path.cpp b/core/jni/android/graphics/Path.cpp
index 90c4dd4..eb9e004 100644
--- a/core/jni/android/graphics/Path.cpp
+++ b/core/jni/android/graphics/Path.cpp
@@ -36,7 +36,8 @@ public:
static void finalizer(JNIEnv* env, jobject clazz, SkPath* obj) {
#ifdef USE_OPENGL_RENDERER
if (android::uirenderer::Caches::hasInstance()) {
- android::uirenderer::Caches::getInstance().pathCache.removeDeferred(obj);
+ android::uirenderer::Caches::getInstance().resourceCache.destructor(obj);
+ return;
}
#endif
delete obj;
diff --git a/data/sounds/effects/ogg/Effect_Tick.ogg b/data/sounds/effects/ogg/Effect_Tick.ogg
index b379019..a997fe1 100644
--- a/data/sounds/effects/ogg/Effect_Tick.ogg
+++ b/data/sounds/effects/ogg/Effect_Tick.ogg
Binary files differ
diff --git a/data/sounds/effects/ogg/KeypressSpacebar.ogg b/data/sounds/effects/ogg/KeypressSpacebar.ogg
index 1776762..0d0fbf1 100644
--- a/data/sounds/effects/ogg/KeypressSpacebar.ogg
+++ b/data/sounds/effects/ogg/KeypressSpacebar.ogg
Binary files differ
diff --git a/data/sounds/effects/ogg/KeypressStandard.ogg b/data/sounds/effects/ogg/KeypressStandard.ogg
index a261975..5878135 100644
--- a/data/sounds/effects/ogg/KeypressStandard.ogg
+++ b/data/sounds/effects/ogg/KeypressStandard.ogg
Binary files differ
diff --git a/data/sounds/effects/ogg/Lock.ogg b/data/sounds/effects/ogg/Lock.ogg
index a24df3d..2e57d9e 100644
--- a/data/sounds/effects/ogg/Lock.ogg
+++ b/data/sounds/effects/ogg/Lock.ogg
Binary files differ
diff --git a/data/sounds/effects/ogg/Unlock.ogg b/data/sounds/effects/ogg/Unlock.ogg
index 114df93..490f98e 100644
--- a/data/sounds/effects/ogg/Unlock.ogg
+++ b/data/sounds/effects/ogg/Unlock.ogg
Binary files differ
diff --git a/docs/html/guide/publishing/licensing.jd b/docs/html/guide/publishing/licensing.jd
index e099413..5551384 100644
--- a/docs/html/guide/publishing/licensing.jd
+++ b/docs/html/guide/publishing/licensing.jd
@@ -2123,7 +2123,7 @@ returned by the Android Market server in a license response.</p>
<tr>
<td>LICENSED</td>
<td>The application is licensed to the user. The user has purchased the
-application or the application is free.</td>
+application or the application only exists as a draft.</td>
<td>Yes</td>
<td><code>VT</code>,&nbsp;<code>GT</code>, <code>GR</code></td>
<td><em>Allow access according to Policy constraints.</em></td>
@@ -2201,6 +2201,17 @@ implementation.</p>
</table>
+<p class="note"><strong>Note:</strong> As documented in <a href="#test-env">
+Setting Up The Testing Environment</a>, the response code can be manually
+overridden for the application developer and any registered test users via the
+Android Market publisher site.
+<br/><br/>
+Additionally, as noted above, applications that are in draft mode (in other
+words, applicaitons that have been uploaded but have <em>never</em> been
+published) will return LICENSED for all users, even if not listed as a test
+user. Since the application has never been offered for download, it is assumed
+that any users running it must have obtained it from an authorized channel for
+testing purposes.</p>
<h2 id="extras">Server Response Extras</h2>
diff --git a/docs/html/guide/topics/fundamentals/index.jd b/docs/html/guide/topics/fundamentals/index.jd
index de2e312..f427a92 100644
--- a/docs/html/guide/topics/fundamentals/index.jd
+++ b/docs/html/guide/topics/fundamentals/index.jd
@@ -180,9 +180,7 @@ instance, it might initiate a service to perform some work based on the event.
<p>A broadcast receiver is implemented as a subclass of {@link android.content.BroadcastReceiver}
and each broadcast is delivered as an {@link android.content.Intent} object. For more information,
-see the <a
-href="{@docRoot}guide/topics/intents/intents-filters.html">Intents and Intent Filters</a>
-developer guide.</p>
+see the {@link android.content.BroadcastReceiver} class.</p>
</dd>
</dl>
@@ -220,35 +218,56 @@ Intents bind individual components to each other at runtime (you can think of th
as the messengers that request an action from other components), whether the component belongs
to your application or another.</p>
-<p>An intent is defined by an {@link android.content.Intent} object, which defines a message to
+<p>An intent is created with an {@link android.content.Intent} object, which defines a message to
activate either a specific component or a specific <em>type</em> of component&mdash;an intent
can be either explicit or implicit, respectively.</p>
<p>For activities and services, an intent defines the action to perform (for example, to "view" or
"send" something) and may specify the URI of the data to act on (among other things that the
component being started might need to know). For example, an intent might convey a request for an
-activity to present an image to the user or to open a web page. In some cases, you can start a
-component in order to receive a result, in which case, the component that is started also returns
-the result in an {@link android.content.Intent} object (for example, you can issue an intent to let
+activity to show an image or to open a web page. In some cases, you can start an
+activity to receive a result, in which case, the activity also returns
+the result in an {@link android.content.Intent} (for example, you can issue an intent to let
the user pick a personal contact and have it returned to you&mdash;the return intent includes a
-URI pointing to the chosen contact). For broadcast receivers, the intent simply defines the
+URI pointing to the chosen contact).</p>
+
+<p>For broadcast receivers, the intent simply defines the
announcement being broadcast (for example, a broadcast to indicate the device battery is low
includes only a known action string that indicates "battery is low").</p>
-<p>The remaining type of component, content provider, is not activated by intents. Rather, it is
+<p>The other component type, content provider, is not activated by intents. Rather, it is
activated when targeted by a request from a {@link android.content.ContentResolver}. The content
resolver handles all direct transactions with the content provider so that the component that's
performing transactions with the provider doesn't need to and instead calls methods on the {@link
android.content.ContentResolver} object. This leaves a layer of abstraction between the content
provider and the component requesting information (for security).</p>
+<p>There are separate methods for activiting each type of component:</p>
+<ul>
+ <li>You can start an activity (or give it something new to do) by
+passing an {@link android.content.Intent} to {@link android.content.Context#startActivity
+startActivity()} or {@link android.app.Activity#startActivityForResult startActivityForResult()}
+(when you want the activity to return a result).</li>
+ <li>You can start a service (or give new instructions to an ongoing service) by
+passing an {@link android.content.Intent} to {@link android.content.Context#startService
+startService()}. Or you can bind to the service by passing an {@link android.content.Intent} to
+{@link android.content.Context#bindService bindService()}.</li>
+ <li>You can initiate a broadcast by passing an {@link android.content.Intent} to methods like
+{@link android.content.Context#sendBroadcast(Intent) sendBroadcast()}, {@link
+android.content.Context#sendOrderedBroadcast(Intent, String) sendOrderedBroadcast()}, or {@link
+android.content.Context#sendStickyBroadcast sendStickyBroadcast()}.</li>
+ <li>You can perform a query to a content provider by calling {@link
+android.content.ContentProvider#query query()} on a {@link android.content.ContentResolver}.</li>
+</ul>
+
<p>For more information about using intents, see the <a
href="{@docRoot}guide/topics/intents/intents-filters.html">Intents and
Intent Filters</a> document. More information about activating specific components is also provided
-in the <a href="{@docRoot}guide/topics/fundamentals/activities.html">Activities</a>, <a
-href="{@docRoot}guide/topics/fundamentals/services.html">Services</a>, and <a
-href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a> developer
-guides.</p>
+in the following documents: <a
+href="{@docRoot}guide/topics/fundamentals/activities.html">Activities</a>, <a
+href="{@docRoot}guide/topics/fundamentals/services.html">Services</a>, {@link
+android.content.BroadcastReceiver} and <a
+href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a>.</p>
<h2 id="Manifest">The Manifest File</h2>
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index 3c4b565..d6cc8ce 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -77,7 +77,8 @@ static void mtxMul(float out[16], const float a[16], const float b[16]);
SurfaceTexture::SurfaceTexture(GLuint tex) :
mBufferCount(MIN_BUFFER_SLOTS), mCurrentTexture(INVALID_BUFFER_SLOT),
- mLastQueued(INVALID_BUFFER_SLOT), mTexName(tex) {
+ mCurrentTransform(0), mLastQueued(INVALID_BUFFER_SLOT),
+ mLastQueuedTransform(0), mNextTransform(0), mTexName(tex) {
LOGV("SurfaceTexture::SurfaceTexture");
for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
mSlots[i].mEglImage = EGL_NO_IMAGE_KHR;
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 2df52ae..d5d2ba0 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -95,6 +95,10 @@ void DisplayList::clearResources() {
delete mPaths.itemAt(i);
}
mPaths.clear();
+ for (size_t i = 0; i < mOriginalPaths.size(); i++) {
+ caches.resourceCache.decrementRefcount(mOriginalPaths.itemAt(i));
+ }
+ mOriginalPaths.clear();
for (size_t i = 0; i < mMatrices.size(); i++) {
delete mMatrices.itemAt(i);
@@ -146,6 +150,13 @@ void DisplayList::initFromDisplayListRenderer(const DisplayListRenderer& recorde
mPaths.add(paths.itemAt(i));
}
+ const Vector<SkPath*> &originalPaths = recorder.getOriginalPaths();
+ for (size_t i = 0; i < originalPaths.size(); i++) {
+ SkPath* path = originalPaths.itemAt(i);
+ mOriginalPaths.add(path);
+ caches.resourceCache.incrementRefcount(path);
+ }
+
const Vector<SkMatrix*> &matrices = recorder.getMatrices();
for (size_t i = 0; i < matrices.size(); i++) {
mMatrices.add(matrices.itemAt(i));
@@ -519,6 +530,12 @@ void DisplayListRenderer::reset() {
}
mBitmapResources.clear();
+ for (size_t i = 0; i < mOriginalPaths.size(); i++) {
+ SkPath* resource = mOriginalPaths.itemAt(i);
+ caches.resourceCache.decrementRefcount(resource);
+ }
+ mOriginalPaths.clear();
+
for (size_t i = 0; i < mShaders.size(); i++) {
caches.resourceCache.decrementRefcount(mShaders.itemAt(i));
}
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 2d0e30a..f39f37f 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -190,6 +190,7 @@ private:
Vector<SkPaint*> mPaints;
Vector<SkPath*> mPaths;
+ Vector<SkPath*> mOriginalPaths;
Vector<SkMatrix*> mMatrices;
Vector<SkiaShader*> mShaders;
@@ -293,6 +294,10 @@ public:
return mPaths;
}
+ const Vector<SkPath*>& getOriginalPaths() const {
+ return mOriginalPaths;
+ }
+
const Vector<SkMatrix*>& getMatrices() const {
return mMatrices;
}
@@ -371,6 +376,9 @@ private:
if (pathCopy == NULL || pathCopy->getGenerationID() != path->getGenerationID()) {
if (pathCopy == NULL) {
pathCopy = path;
+ mOriginalPaths.add(path);
+ Caches& caches = Caches::getInstance();
+ caches.resourceCache.incrementRefcount(path);
} else {
pathCopy = new SkPath(*path);
mPaths.add(pathCopy);
@@ -452,6 +460,7 @@ private:
Vector<SkPaint*> mPaints;
DefaultKeyedVector<SkPaint*, SkPaint*> mPaintMap;
+ Vector<SkPath*> mOriginalPaths;
Vector<SkPath*> mPaths;
DefaultKeyedVector<SkPath*, SkPath*> mPathMap;
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 90d6ea1..8ee7ec3 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -1217,17 +1217,18 @@ void OpenGLRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int
#if RENDER_LAYERS_AS_REGIONS
// Mark the current layer dirty where we are going to draw the patch
if (hasLayer() && mesh->hasEmptyQuads) {
+ const float offsetX = left + mSnapshot->transform->getTranslateX();
+ const float offsetY = top + mSnapshot->transform->getTranslateY();
const size_t count = mesh->quads.size();
for (size_t i = 0; i < count; i++) {
const Rect& bounds = mesh->quads.itemAt(i);
if (pureTranslate) {
- const float x = (int) floorf(bounds.left + 0.5f);
- const float y = (int) floorf(bounds.top + 0.5f);
- dirtyLayer(x, y, x + bounds.getWidth(), y + bounds.getHeight(),
- *mSnapshot->transform);
+ const float x = (int) floorf(bounds.left + offsetX + 0.5f);
+ const float y = (int) floorf(bounds.top + offsetY + 0.5f);
+ dirtyLayer(x, y, x + bounds.getWidth(), y + bounds.getHeight());
} else {
- dirtyLayer(bounds.left, bounds.top, bounds.right, bounds.bottom,
- *mSnapshot->transform);
+ dirtyLayer(left + bounds.left, top + bounds.top,
+ left + bounds.right, top + bounds.bottom, *mSnapshot->transform);
}
}
}
diff --git a/libs/hwui/ResourceCache.cpp b/libs/hwui/ResourceCache.cpp
index 70d117a..87fdfb5 100644
--- a/libs/hwui/ResourceCache.cpp
+++ b/libs/hwui/ResourceCache.cpp
@@ -65,6 +65,10 @@ void ResourceCache::incrementRefcount(SkBitmap* bitmapResource) {
incrementRefcount((void*)bitmapResource, kBitmap);
}
+void ResourceCache::incrementRefcount(SkPath* pathResource) {
+ incrementRefcount((void*)pathResource, kPath);
+}
+
void ResourceCache::incrementRefcount(SkiaShader* shaderResource) {
shaderResource->getSkShader()->safeRef();
incrementRefcount((void*) shaderResource, kShader);
@@ -94,6 +98,10 @@ void ResourceCache::decrementRefcount(SkBitmap* bitmapResource) {
decrementRefcount((void*) bitmapResource);
}
+void ResourceCache::decrementRefcount(SkPath* pathResource) {
+ decrementRefcount((void*) pathResource);
+}
+
void ResourceCache::decrementRefcount(SkiaShader* shaderResource) {
shaderResource->getSkShader()->safeUnref();
decrementRefcount((void*) shaderResource);
@@ -122,6 +130,24 @@ void ResourceCache::recycle(SkBitmap* resource) {
}
}
+void ResourceCache::destructor(SkPath* resource) {
+ Mutex::Autolock _l(mLock);
+ ResourceReference* ref = mCache->indexOfKey(resource) >= 0 ? mCache->valueFor(resource) : NULL;
+ if (ref == NULL) {
+ // If we're not tracking this resource, just delete it
+ if (Caches::hasInstance()) {
+ Caches::getInstance().pathCache.removeDeferred(resource);
+ }
+ delete resource;
+ return;
+ }
+ ref->destroyed = true;
+ if (ref->refCount == 0) {
+ deleteResourceReference(resource, ref);
+ return;
+ }
+}
+
void ResourceCache::destructor(SkBitmap* resource) {
Mutex::Autolock _l(mLock);
ResourceReference* ref = mCache->indexOfKey(resource) >= 0 ? mCache->valueFor(resource) : NULL;
@@ -192,6 +218,15 @@ void ResourceCache::deleteResourceReference(void* resource, ResourceReference* r
delete bitmap;
}
break;
+ case kPath:
+ {
+ SkPath* path = (SkPath*)resource;
+ if (Caches::hasInstance()) {
+ Caches::getInstance().pathCache.removeDeferred(path);
+ }
+ delete path;
+ }
+ break;
case kShader:
{
SkiaShader* shader = (SkiaShader*)resource;
diff --git a/libs/hwui/ResourceCache.h b/libs/hwui/ResourceCache.h
index 1bb4390..2a38910 100644
--- a/libs/hwui/ResourceCache.h
+++ b/libs/hwui/ResourceCache.h
@@ -32,6 +32,7 @@ enum ResourceType {
kBitmap,
kShader,
kColorFilter,
+ kPath,
};
class ResourceReference {
@@ -53,15 +54,18 @@ class ResourceCache {
public:
ResourceCache();
~ResourceCache();
+ void incrementRefcount(SkPath* resource);
void incrementRefcount(SkBitmap* resource);
void incrementRefcount(SkiaShader* resource);
void incrementRefcount(SkiaColorFilter* resource);
void incrementRefcount(const void* resource, ResourceType resourceType);
void decrementRefcount(void* resource);
void decrementRefcount(SkBitmap* resource);
+ void decrementRefcount(SkPath* resource);
void decrementRefcount(SkiaShader* resource);
void decrementRefcount(SkiaColorFilter* resource);
void recycle(SkBitmap* resource);
+ void destructor(SkPath* resource);
void destructor(SkBitmap* resource);
void destructor(SkiaShader* resource);
void destructor(SkiaColorFilter* resource);
diff --git a/libs/rs/rsScriptC_Lib.cpp b/libs/rs/rsScriptC_Lib.cpp
index 8a85f6e..80da8ae 100644
--- a/libs/rs/rsScriptC_Lib.cpp
+++ b/libs/rs/rsScriptC_Lib.cpp
@@ -856,6 +856,8 @@ static ScriptCState::SymbolTable_t gSyms[] = {
{ "__modsi3", (void *)&SC_modsi3, true },
{ "__udivsi3", (void *)&SC_udivsi3, true },
{ "__umodsi3", (void *)&SC_umodsi3, true },
+ { "memset", (void *)&memset, true },
+ { "memcpy", (void *)&memcpy, true },
// allocation
{ "_Z19rsAllocationGetDimX13rs_allocation", (void *)&SC_allocGetDimX, true },
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 051a0fc..5a59ef6 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -48,7 +48,7 @@ public class AudioManager {
private final Context mContext;
private final Handler mHandler;
private long mVolumeKeyUpTime;
-
+ private int mVolumeControlStream = -1;
private static String TAG = "AudioManager";
private static boolean DEBUG = false;
private static boolean localLOGV = DEBUG || android.util.Config.LOGV;
@@ -263,6 +263,13 @@ public class AudioManager {
public static final int FLAG_VIBRATE = 1 << 4;
/**
+ * forces use of specified stream
+ * @hide
+ */
+ public static final int FLAG_FORCE_STREAM = 1 << 5;
+
+
+ /**
* Ringer mode that will be silent and will not vibrate. (This overrides the
* vibrate setting.)
*
@@ -392,12 +399,17 @@ public class AudioManager {
* Adjust the volume in on key down since it is more
* responsive to the user.
*/
+ int flags = FLAG_SHOW_UI | FLAG_VIBRATE;
+ if (mVolumeControlStream != -1) {
+ stream = mVolumeControlStream;
+ flags |= FLAG_FORCE_STREAM;
+ }
adjustSuggestedStreamVolume(
keyCode == KeyEvent.KEYCODE_VOLUME_UP
? ADJUST_RAISE
: ADJUST_LOWER,
stream,
- FLAG_SHOW_UI | FLAG_VIBRATE);
+ flags);
break;
case KeyEvent.KEYCODE_VOLUME_MUTE:
// TODO: Actually handle MUTE.
@@ -416,10 +428,15 @@ public class AudioManager {
* Play a sound. This is done on key up since we don't want the
* sound to play when a user holds down volume down to mute.
*/
+ int flags = FLAG_PLAY_SOUND;
+ if (mVolumeControlStream != -1) {
+ stream = mVolumeControlStream;
+ flags |= FLAG_FORCE_STREAM;
+ }
adjustSuggestedStreamVolume(
ADJUST_SAME,
stream,
- FLAG_PLAY_SOUND);
+ flags);
mVolumeKeyUpTime = SystemClock.uptimeMillis();
break;
@@ -683,6 +700,17 @@ public class AudioManager {
}
/**
+ * forces the stream controlled by hard volume keys
+ * specifying streamType == -1 releases control to the
+ * logic.
+ *
+ * @hide
+ */
+ public void forceVolumeControlStream(int streamType) {
+ mVolumeControlStream = streamType;
+ }
+
+ /**
* Returns whether a particular type should vibrate according to user
* settings and the current ringer mode.
* <p>
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index e18220a..6c85490 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -417,6 +417,9 @@ public class AudioService extends IAudioService.Stub {
(1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED)|
(1 << AudioSystem.STREAM_MUSIC)));
+ if (!mVoiceCapable) {
+ mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_MUSIC);
+ }
mMuteAffectedStreams = System.getInt(cr,
System.MUTE_STREAMS_AFFECTED,
((1 << AudioSystem.STREAM_MUSIC)|(1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_SYSTEM)));
@@ -461,7 +464,12 @@ public class AudioService extends IAudioService.Stub {
/** @see AudioManager#adjustVolume(int, int, int) */
public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags) {
- int streamType = getActiveStreamType(suggestedStreamType);
+ int streamType;
+ if ((flags & AudioManager.FLAG_FORCE_STREAM) != 0) {
+ streamType = suggestedStreamType;
+ } else {
+ streamType = getActiveStreamType(suggestedStreamType);
+ }
// Don't play sound on other streams
if (streamType != AudioSystem.STREAM_RING && (flags & AudioManager.FLAG_PLAY_SOUND) != 0) {
@@ -1940,7 +1948,7 @@ public class AudioService extends IAudioService.Stub {
// Force creation of new IAudioflinger interface
if (!mMediaServerOk) {
Log.e(TAG, "Media server died.");
- AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0);
+ AudioSystem.isMicrophoneMuted();
sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SHARED_MSG, SENDMSG_NOOP, 0, 0,
null, 500);
}
@@ -2025,6 +2033,10 @@ public class AudioService extends IAudioService.Stub {
int ringerModeAffectedStreams = Settings.System.getInt(mContentResolver,
Settings.System.MODE_RINGER_STREAMS_AFFECTED,
0);
+ if (!mVoiceCapable) {
+ ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_MUSIC);
+ }
+
if (ringerModeAffectedStreams != mRingerModeAffectedStreams) {
/*
* Ensure all stream types that should be affected by ringer mode
diff --git a/media/java/android/media/videoeditor/MediaArtistNativeHelper.java b/media/java/android/media/videoeditor/MediaArtistNativeHelper.java
index 6b3f223..8214e7f 100644
--- a/media/java/android/media/videoeditor/MediaArtistNativeHelper.java
+++ b/media/java/android/media/videoeditor/MediaArtistNativeHelper.java
@@ -2555,6 +2555,14 @@ class MediaArtistNativeHelper {
final List<Effect> effects = m.getAllEffects();
final List<Overlay> overlays = m.getAllOverlays();
+
+ for (Overlay overlay : overlays) {
+ effectSettings[i] = getOverlaySettings((OverlayFrame)overlay);
+ adjustEffectsStartTimeAndDuration(effectSettings[i], beginCutTime, endCutTime);
+ effectSettings[i].startTime += storyBoardTime;
+ i++;
+ }
+
for (Effect effect : effects) {
if (effect instanceof EffectColor) {
effectSettings[i] = getEffectSettings((EffectColor)effect);
@@ -2564,12 +2572,6 @@ class MediaArtistNativeHelper {
}
}
- for (Overlay overlay : overlays) {
- effectSettings[i] = getOverlaySettings((OverlayFrame)overlay);
- adjustEffectsStartTimeAndDuration(effectSettings[i], beginCutTime, endCutTime);
- effectSettings[i].startTime += storyBoardTime;
- i++;
- }
return i;
}
@@ -2984,27 +2986,28 @@ class MediaArtistNativeHelper {
}
}
}
- }
- if (!mErrorFlagSet) {
- mPreviewEditSettings.videoFrameSize = findVideoResolution(mVideoEditor
- .getAspectRatio(), maxHeight);
- populateBackgroundMusicProperties(mediaBGMList);
- /** call to native populate settings */
- try {
- nativePopulateSettings(mPreviewEditSettings, mClipProperties, mAudioSettings);
- } catch (IllegalArgumentException ex) {
- Log.e(TAG, "Illegal argument exception in nativePopulateSettings");
- throw ex;
- } catch (IllegalStateException ex) {
- Log.e(TAG, "Illegal state exception in nativePopulateSettings");
- throw ex;
- } catch (RuntimeException ex) {
- Log.e(TAG, "Runtime exception in nativePopulateSettings");
- throw ex;
+ if (!mErrorFlagSet) {
+ mPreviewEditSettings.videoFrameSize = findVideoResolution(mVideoEditor
+ .getAspectRatio(), maxHeight);
+ populateBackgroundMusicProperties(mediaBGMList);
+
+ /** call to native populate settings */
+ try {
+ nativePopulateSettings(mPreviewEditSettings, mClipProperties, mAudioSettings);
+ } catch (IllegalArgumentException ex) {
+ Log.e(TAG, "Illegal argument exception in nativePopulateSettings");
+ throw ex;
+ } catch (IllegalStateException ex) {
+ Log.e(TAG, "Illegal state exception in nativePopulateSettings");
+ throw ex;
+ } catch (RuntimeException ex) {
+ Log.e(TAG, "Runtime exception in nativePopulateSettings");
+ throw ex;
+ }
+ mInvalidatePreviewArray = false;
+ mProcessingState = PROCESSING_NONE;
}
- mInvalidatePreviewArray = false;
- mProcessingState = PROCESSING_NONE;
}
if (mErrorFlagSet) {
mErrorFlagSet = false;
diff --git a/media/java/android/media/videoeditor/MediaProperties.java b/media/java/android/media/videoeditor/MediaProperties.java
index a2e01f6..34186e9 100755
--- a/media/java/android/media/videoeditor/MediaProperties.java
+++ b/media/java/android/media/videoeditor/MediaProperties.java
@@ -198,6 +198,11 @@ public class MediaProperties {
public static final int FILE_UNSUPPORTED = 255;
/**
+ * Undefined video codec profiles
+ */
+ public static final int UNDEFINED_VIDEO_PROFILE = 255;
+
+ /**
* The array of the supported file formats
*/
private static final int[] SUPPORTED_VIDEO_FILE_FORMATS = new int[] {
diff --git a/media/java/android/media/videoeditor/MediaVideoItem.java b/media/java/android/media/videoeditor/MediaVideoItem.java
index bbadd62..d350584 100755
--- a/media/java/android/media/videoeditor/MediaVideoItem.java
+++ b/media/java/android/media/videoeditor/MediaVideoItem.java
@@ -139,6 +139,11 @@ public class MediaVideoItem extends MediaItem {
throw new IllegalArgumentException("Unsupported Video Codec Format in Input File");
}
+ /* Check if the profile is unsupported. */
+ if (properties.profileAndLevel == MediaProperties.UNDEFINED_VIDEO_PROFILE) {
+ throw new IllegalArgumentException("Unsupported Video Codec Profile in Input File");
+ }
+
mWidth = properties.width;
mHeight = properties.height;
mAspectRatio = mMANativeHelper.getAspectRatio(properties.width,
diff --git a/media/java/android/media/videoeditor/Transition.java b/media/java/android/media/videoeditor/Transition.java
index 4d1bafb..95f002c 100755
--- a/media/java/android/media/videoeditor/Transition.java
+++ b/media/java/android/media/videoeditor/Transition.java
@@ -288,6 +288,16 @@ public abstract class Transition {
List<EffectSettings> effectSettings = new ArrayList<EffectSettings>();
EffectSettings tmpEffectSettings;
+ overlays = m.getAllOverlays();
+ for (Overlay overlay : overlays) {
+ tmpEffectSettings = mNativeHelper.getOverlaySettings((OverlayFrame)overlay);
+ mNativeHelper.adjustEffectsStartTimeAndDuration(tmpEffectSettings,
+ clipSettings.beginCutTime, clipSettings.endCutTime);
+ if (tmpEffectSettings.duration != 0) {
+ effectSettings.add(tmpEffectSettings);
+ }
+ }
+
effects = m.getAllEffects();
for (Effect effect : effects) {
if (effect instanceof EffectColor) {
@@ -303,15 +313,7 @@ public abstract class Transition {
}
}
}
- overlays = m.getAllOverlays();
- for (Overlay overlay : overlays) {
- tmpEffectSettings = mNativeHelper.getOverlaySettings((OverlayFrame)overlay);
- mNativeHelper.adjustEffectsStartTimeAndDuration(tmpEffectSettings,
- clipSettings.beginCutTime, clipSettings.endCutTime);
- if (tmpEffectSettings.duration != 0) {
- effectSettings.add(tmpEffectSettings);
- }
- }
+
return effectSettings;
}
diff --git a/media/jni/mediaeditor/VideoEditorPropertiesMain.cpp b/media/jni/mediaeditor/VideoEditorPropertiesMain.cpp
index 35c14b6..014cd95 100755
--- a/media/jni/mediaeditor/VideoEditorPropertiesMain.cpp
+++ b/media/jni/mediaeditor/VideoEditorPropertiesMain.cpp
@@ -195,13 +195,31 @@ jobject videoEditProp_getProperties(
&gotten, pEnv,(M4NO_ERROR != result),
"Invalid File or File not found");
- if (pClipProperties->uiVideoWidth >= 1920)
+ /**
+ * Max resolution supported is 1280 x 720.
+ */
+ if ( (pClipProperties->uiVideoWidth > 1280)
+ || (pClipProperties->uiVideoHeight > 720) )
{
- result = M4MCS_ERR_INPUT_FILE_CONTAINS_NO_SUPPORTED_STREAM;
+ result = M4MCS_ERR_INVALID_INPUT_VIDEO_FRAME_SIZE;
videoEditJava_checkAndThrowIllegalArgumentException(
&gotten, pEnv, (M4NO_ERROR != result),
- "HD Content (1080p) is not supported");
+ "Unsupported input video frame size");
}
+
+#ifdef USE_SOFTWARE_DECODER
+ /**
+ * Input clip with non-multiples of 16 is not supported.
+ */
+ if ( (pClipProperties->uiVideoWidth %16)
+ || (pClipProperties->uiVideoHeight %16) )
+ {
+ result = M4MCS_ERR_INPUT_VIDEO_SIZE_NON_X16;
+ videoEditJava_checkAndThrowIllegalArgumentException(
+ &gotten, pEnv, (M4NO_ERROR != result),
+ "non x16 input video frame size is not supported");
+ }
+#endif /* USE_SOFTWARE_DECODER */
}
// Check if the properties could be retrieved.
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index d144dba..2efb444 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -692,7 +692,7 @@ public class WindowManagerService extends IWindowManager.Stub
boolean changed = setRotationUncheckedLocked(
WindowManagerPolicy.USE_LAST_ROTATION, 0, false);
if (changed) {
- sendNewConfiguration();
+ mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
}
}
@@ -11075,7 +11075,7 @@ public class WindowManagerService extends IWindowManager.Stub
boolean changed = setRotationUncheckedLocked(
WindowManagerPolicy.USE_LAST_ROTATION, 0, false);
if (changed) {
- sendNewConfiguration();
+ mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
}
}
diff --git a/tools/layoutlib/bridge/Android.mk b/tools/layoutlib/bridge/Android.mk
index 3d4c76a..ca7db8c 100644
--- a/tools/layoutlib/bridge/Android.mk
+++ b/tools/layoutlib/bridge/Android.mk
@@ -17,6 +17,8 @@ LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(call all-java-files-under,src)
+LOCAL_JAVA_RESOURCE_DIRS := resources
+
LOCAL_JAVA_LIBRARIES := \
kxml2-2.3.0 \
diff --git a/tools/layoutlib/bridge/resources/bars/action_bar.xml b/tools/layoutlib/bridge/resources/bars/action_bar.xml
new file mode 100644
index 0000000..cd99a09
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/action_bar.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+ <ImageView
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_gravity="center"/>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"/>
+</merge>
diff --git a/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_back_default.png b/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_back_default.png
new file mode 100644
index 0000000..4bcd2be
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_back_default.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_home_default.png b/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_home_default.png
new file mode 100644
index 0000000..cfeba3e
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_home_default.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_recent_default.png b/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_recent_default.png
new file mode 100644
index 0000000..1d97e05
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_recent_default.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/mdpi/stat_sys_wifi_signal_4_fully.png b/tools/layoutlib/bridge/resources/bars/mdpi/stat_sys_wifi_signal_4_fully.png
new file mode 100644
index 0000000..c629387
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/mdpi/stat_sys_wifi_signal_4_fully.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/phone_system_bar.xml b/tools/layoutlib/bridge/resources/bars/phone_system_bar.xml
new file mode 100644
index 0000000..29df909
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/phone_system_bar.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text=" "/>
+ <ImageView
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_gravity="center"/>
+</merge>
diff --git a/tools/layoutlib/bridge/resources/bars/tablet_system_bar.xml b/tools/layoutlib/bridge/resources/bars/tablet_system_bar.xml
new file mode 100644
index 0000000..8a3b87a
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/tablet_system_bar.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+ <ImageView
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"/>
+ <ImageView
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"/>
+ <ImageView
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"/>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"/>
+ <ImageView
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_gravity="center"/>
+</merge>
diff --git a/tools/layoutlib/bridge/resources/bars/title_bar.xml b/tools/layoutlib/bridge/resources/bars/title_bar.xml
new file mode 100644
index 0000000..29fcc4b
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/title_bar.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"/>
+</merge>
diff --git a/tools/layoutlib/bridge/src/android/graphics/BitmapFactory.java b/tools/layoutlib/bridge/src/android/graphics/BitmapFactory.java
deleted file mode 100644
index 993c305..0000000
--- a/tools/layoutlib/bridge/src/android/graphics/BitmapFactory.java
+++ /dev/null
@@ -1,578 +0,0 @@
-/*
- * Copyright (C) 2010 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 android.graphics;
-
-import com.android.ide.common.rendering.api.LayoutLog;
-import com.android.layoutlib.bridge.Bridge;
-import com.android.resources.Density;
-
-import android.content.res.AssetManager;
-import android.content.res.Resources;
-import android.util.DisplayMetrics;
-import android.util.TypedValue;
-
-import java.io.BufferedInputStream;
-import java.io.FileDescriptor;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * Creates Bitmap objects from various sources, including files, streams,
- * and byte-arrays.
- */
-public class BitmapFactory {
- public static class Options {
- /**
- * Create a default Options object, which if left unchanged will give
- * the same result from the decoder as if null were passed.
- */
- public Options() {
- inDither = true;
- inScaled = true;
- }
-
- /**
- * If set to true, the decoder will return null (no bitmap), but
- * the out... fields will still be set, allowing the caller to query
- * the bitmap without having to allocate the memory for its pixels.
- */
- public boolean inJustDecodeBounds;
-
- /**
- * If set to a value > 1, requests the decoder to subsample the original
- * image, returning a smaller image to save memory. The sample size is
- * the number of pixels in either dimension that correspond to a single
- * pixel in the decoded bitmap. For example, inSampleSize == 4 returns
- * an image that is 1/4 the width/height of the original, and 1/16 the
- * number of pixels. Any value <= 1 is treated the same as 1. Note: the
- * decoder will try to fulfill this request, but the resulting bitmap
- * may have different dimensions that precisely what has been requested.
- * Also, powers of 2 are often faster/easier for the decoder to honor.
- */
- public int inSampleSize;
-
- /**
- * If this is non-null, the decoder will try to decode into this
- * internal configuration. If it is null, or the request cannot be met,
- * the decoder will try to pick the best matching config based on the
- * system's screen depth, and characteristics of the original image such
- * as if it has per-pixel alpha (requiring a config that also does).
- */
- public Bitmap.Config inPreferredConfig;
-
- /**
- * If dither is true, the decoder will attempt to dither the decoded
- * image.
- */
- public boolean inDither;
-
- /**
- * The pixel density to use for the bitmap. This will always result
- * in the returned bitmap having a density set for it (see
- * {@link Bitmap#setDensity(int) Bitmap.setDensity(int)). In addition,
- * if {@link #inScaled} is set (which it is by default} and this
- * density does not match {@link #inTargetDensity}, then the bitmap
- * will be scaled to the target density before being returned.
- *
- * <p>If this is 0,
- * {@link BitmapFactory#decodeResource(Resources, int)},
- * {@link BitmapFactory#decodeResource(Resources, int, android.graphics.BitmapFactory.Options)},
- * and {@link BitmapFactory#decodeResourceStream}
- * will fill in the density associated with the resource. The other
- * functions will leave it as-is and no density will be applied.
- *
- * @see #inTargetDensity
- * @see #inScreenDensity
- * @see #inScaled
- * @see Bitmap#setDensity(int)
- * @see android.util.DisplayMetrics#densityDpi
- */
- public int inDensity;
-
- /**
- * The pixel density of the destination this bitmap will be drawn to.
- * This is used in conjunction with {@link #inDensity} and
- * {@link #inScaled} to determine if and how to scale the bitmap before
- * returning it.
- *
- * <p>If this is 0,
- * {@link BitmapFactory#decodeResource(Resources, int)},
- * {@link BitmapFactory#decodeResource(Resources, int, android.graphics.BitmapFactory.Options)},
- * and {@link BitmapFactory#decodeResourceStream}
- * will fill in the density associated the Resources object's
- * DisplayMetrics. The other
- * functions will leave it as-is and no scaling for density will be
- * performed.
- *
- * @see #inDensity
- * @see #inScreenDensity
- * @see #inScaled
- * @see android.util.DisplayMetrics#densityDpi
- */
- public int inTargetDensity;
-
- /**
- * The pixel density of the actual screen that is being used. This is
- * purely for applications running in density compatibility code, where
- * {@link #inTargetDensity} is actually the density the application
- * sees rather than the real screen density.
- *
- * <p>By setting this, you
- * allow the loading code to avoid scaling a bitmap that is currently
- * in the screen density up/down to the compatibility density. Instead,
- * if {@link #inDensity} is the same as {@link #inScreenDensity}, the
- * bitmap will be left as-is. Anything using the resulting bitmap
- * must also used {@link Bitmap#getScaledWidth(int)
- * Bitmap.getScaledWidth} and {@link Bitmap#getScaledHeight
- * Bitmap.getScaledHeight} to account for any different between the
- * bitmap's density and the target's density.
- *
- * <p>This is never set automatically for the caller by
- * {@link BitmapFactory} itself. It must be explicitly set, since the
- * caller must deal with the resulting bitmap in a density-aware way.
- *
- * @see #inDensity
- * @see #inTargetDensity
- * @see #inScaled
- * @see android.util.DisplayMetrics#densityDpi
- */
- public int inScreenDensity;
-
- /**
- * When this flag is set, if {@link #inDensity} and
- * {@link #inTargetDensity} are not 0, the
- * bitmap will be scaled to match {@link #inTargetDensity} when loaded,
- * rather than relying on the graphics system scaling it each time it
- * is drawn to a Canvas.
- *
- * <p>This flag is turned on by default and should be turned off if you need
- * a non-scaled version of the bitmap. Nine-patch bitmaps ignore this
- * flag and are always scaled.
- */
- public boolean inScaled;
-
- /**
- * If this is set to true, then the resulting bitmap will allocate its
- * pixels such that they can be purged if the system needs to reclaim
- * memory. In that instance, when the pixels need to be accessed again
- * (e.g. the bitmap is drawn, getPixels() is called), they will be
- * automatically re-decoded.
- *
- * For the re-decode to happen, the bitmap must have access to the
- * encoded data, either by sharing a reference to the input
- * or by making a copy of it. This distinction is controlled by
- * inInputShareable. If this is true, then the bitmap may keep a shallow
- * reference to the input. If this is false, then the bitmap will
- * explicitly make a copy of the input data, and keep that. Even if
- * sharing is allowed, the implementation may still decide to make a
- * deep copy of the input data.
- */
- public boolean inPurgeable;
-
- /**
- * This field works in conjuction with inPurgeable. If inPurgeable is
- * false, then this field is ignored. If inPurgeable is true, then this
- * field determines whether the bitmap can share a reference to the
- * input data (inputstream, array, etc.) or if it must make a deep copy.
- */
- public boolean inInputShareable;
-
- /**
- * Normally bitmap allocations count against the dalvik heap, which
- * means they help trigger GCs when a lot have been allocated. However,
- * in rare cases, the caller may want to allocate the bitmap outside of
- * that heap. To request that, set inNativeAlloc to true. In these
- * rare instances, it is solely up to the caller to ensure that OOM is
- * managed explicitly by calling bitmap.recycle() as soon as such a
- * bitmap is no longer needed.
- *
- * @hide pending API council approval
- */
- public boolean inNativeAlloc;
-
- /**
- * The resulting width of the bitmap, set independent of the state of
- * inJustDecodeBounds. However, if there is an error trying to decode,
- * outWidth will be set to -1.
- */
- public int outWidth;
-
- /**
- * The resulting height of the bitmap, set independent of the state of
- * inJustDecodeBounds. However, if there is an error trying to decode,
- * outHeight will be set to -1.
- */
- public int outHeight;
-
- /**
- * If known, this string is set to the mimetype of the decoded image.
- * If not know, or there is an error, it is set to null.
- */
- public String outMimeType;
-
- /**
- * Temp storage to use for decoding. Suggest 16K or so.
- */
- public byte[] inTempStorage;
-
- private native void requestCancel();
-
- /**
- * Flag to indicate that cancel has been called on this object. This
- * is useful if there's an intermediary that wants to first decode the
- * bounds and then decode the image. In that case the intermediary
- * can check, inbetween the bounds decode and the image decode, to see
- * if the operation is canceled.
- */
- public boolean mCancel;
-
- /**
- * This can be called from another thread while this options object is
- * inside a decode... call. Calling this will notify the decoder that
- * it should cancel its operation. This is not guaranteed to cancel
- * the decode, but if it does, the decoder... operation will return
- * null, or if inJustDecodeBounds is true, will set outWidth/outHeight
- * to -1
- */
- public void requestCancelDecode() {
- mCancel = true;
- requestCancel();
- }
- }
-
- /**
- * Decode a file path into a bitmap. If the specified file name is null,
- * or cannot be decoded into a bitmap, the function returns null.
- *
- * @param pathName complete path name for the file to be decoded.
- * @param opts null-ok; Options that control downsampling and whether the
- * image should be completely decoded, or just is size returned.
- * @return The decoded bitmap, or null if the image data could not be
- * decoded, or, if opts is non-null, if opts requested only the
- * size be returned (in opts.outWidth and opts.outHeight)
- */
- public static Bitmap decodeFile(String pathName, Options opts) {
- Bitmap bm = null;
- InputStream stream = null;
- try {
- stream = new FileInputStream(pathName);
- bm = decodeStream(stream, null, opts);
- } catch (Exception e) {
- /* do nothing.
- If the exception happened on open, bm will be null.
- */
- } finally {
- if (stream != null) {
- try {
- stream.close();
- } catch (IOException e) {
- // do nothing here
- }
- }
- }
- return bm;
- }
-
- /**
- * Decode a file path into a bitmap. If the specified file name is null,
- * or cannot be decoded into a bitmap, the function returns null.
- *
- * @param pathName complete path name for the file to be decoded.
- * @return the resulting decoded bitmap, or null if it could not be decoded.
- */
- public static Bitmap decodeFile(String pathName) {
- return decodeFile(pathName, null);
- }
-
- /**
- * Decode a new Bitmap from an InputStream. This InputStream was obtained from
- * resources, which we pass to be able to scale the bitmap accordingly.
- */
- public static Bitmap decodeResourceStream(Resources res, TypedValue value,
- InputStream is, Rect pad, Options opts) {
-
- if (opts == null) {
- opts = new Options();
- }
-
- if (opts.inDensity == 0 && value != null) {
- final int density = value.density;
- if (density == TypedValue.DENSITY_DEFAULT) {
- opts.inDensity = DisplayMetrics.DENSITY_DEFAULT;
- } else if (density != TypedValue.DENSITY_NONE) {
- opts.inDensity = density;
- }
- }
-
- if (opts.inTargetDensity == 0 && res != null) {
- opts.inTargetDensity = res.getDisplayMetrics().densityDpi;
- }
-
- return decodeStream(is, pad, opts);
- }
-
- /**
- * Synonym for opening the given resource and calling
- * {@link #decodeResourceStream}.
- *
- * @param res The resources object containing the image data
- * @param id The resource id of the image data
- * @param opts null-ok; Options that control downsampling and whether the
- * image should be completely decoded, or just is size returned.
- * @return The decoded bitmap, or null if the image data could not be
- * decoded, or, if opts is non-null, if opts requested only the
- * size be returned (in opts.outWidth and opts.outHeight)
- */
- public static Bitmap decodeResource(Resources res, int id, Options opts) {
- Bitmap bm = null;
- InputStream is = null;
-
- try {
- final TypedValue value = new TypedValue();
- is = res.openRawResource(id, value);
-
- bm = decodeResourceStream(res, value, is, null, opts);
- } catch (Exception e) {
- /* do nothing.
- If the exception happened on open, bm will be null.
- If it happened on close, bm is still valid.
- */
- Bridge.getLog().error(LayoutLog.TAG_RESOURCES_READ,
- String.format("Error decoding bitmap of id 0x%x", id), e, null /*data*/);
- } finally {
- try {
- if (is != null) is.close();
- } catch (IOException e) {
- // Ignore
- }
- }
-
- return bm;
- }
-
- /**
- * Synonym for {@link #decodeResource(Resources, int, android.graphics.BitmapFactory.Options)}
- * will null Options.
- *
- * @param res The resources object containing the image data
- * @param id The resource id of the image data
- * @return The decoded bitmap, or null if the image could not be decode.
- */
- public static Bitmap decodeResource(Resources res, int id) {
- return decodeResource(res, id, null);
- }
-
- /**
- * Decode an immutable bitmap from the specified byte array.
- *
- * @param data byte array of compressed image data
- * @param offset offset into imageData for where the decoder should begin
- * parsing.
- * @param length the number of bytes, beginning at offset, to parse
- * @param opts null-ok; Options that control downsampling and whether the
- * image should be completely decoded, or just is size returned.
- * @return The decoded bitmap, or null if the image data could not be
- * decoded, or, if opts is non-null, if opts requested only the
- * size be returned (in opts.outWidth and opts.outHeight)
- */
- public static Bitmap decodeByteArray(byte[] data, int offset, int length, Options opts) {
- if ((offset | length) < 0 || data.length < offset + length) {
- throw new ArrayIndexOutOfBoundsException();
- }
-
- // FIXME: implement as needed, but it's unlikely that this is needed in the context of the bridge.
- return null;
- //return nativeDecodeByteArray(data, offset, length, opts);
- }
-
- /**
- * Decode an immutable bitmap from the specified byte array.
- *
- * @param data byte array of compressed image data
- * @param offset offset into imageData for where the decoder should begin
- * parsing.
- * @param length the number of bytes, beginning at offset, to parse
- * @return The decoded bitmap, or null if the image could not be decode.
- */
- public static Bitmap decodeByteArray(byte[] data, int offset, int length) {
- return decodeByteArray(data, offset, length, null);
- }
-
- /**
- * Decode an input stream into a bitmap. If the input stream is null, or
- * cannot be used to decode a bitmap, the function returns null.
- * The stream's position will be where ever it was after the encoded data
- * was read.
- *
- * @param is The input stream that holds the raw data to be decoded into a
- * bitmap.
- * @param outPadding If not null, return the padding rect for the bitmap if
- * it exists, otherwise set padding to [-1,-1,-1,-1]. If
- * no bitmap is returned (null) then padding is
- * unchanged.
- * @param opts null-ok; Options that control downsampling and whether the
- * image should be completely decoded, or just is size returned.
- * @return The decoded bitmap, or null if the image data could not be
- * decoded, or, if opts is non-null, if opts requested only the
- * size be returned (in opts.outWidth and opts.outHeight)
- */
- public static Bitmap decodeStream(InputStream is, Rect outPadding, Options opts) {
- // we don't throw in this case, thus allowing the caller to only check
- // the cache, and not force the image to be decoded.
- if (is == null) {
- return null;
- }
-
- // we need mark/reset to work properly
-
- if (!is.markSupported()) {
- is = new BufferedInputStream(is, 16 * 1024);
- }
-
- // so we can call reset() if a given codec gives up after reading up to
- // this many bytes. FIXME: need to find out from the codecs what this
- // value should be.
- is.mark(1024);
-
- Bitmap bm;
-
- if (is instanceof AssetManager.AssetInputStream) {
- Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED,
- "Bitmap.decodeStream: " +
- "InputStream is unsupported (AssetManager.AssetInputStream)", null /*data*/);
- return null;
- } else {
- // pass some temp storage down to the native code. 1024 is made up,
- // but should be large enough to avoid too many small calls back
- // into is.read(...) This number is not related to the value passed
- // to mark(...) above.
- try {
- Density density = Density.MEDIUM;
- if (opts != null) {
- density = Density.getEnum(opts.inDensity);
- }
- bm = Bitmap_Delegate.createBitmap(is, true, density);
- } catch (IOException e) {
- return null;
- }
- }
-
- return finishDecode(bm, outPadding, opts);
- }
-
- private static Bitmap finishDecode(Bitmap bm, Rect outPadding, Options opts) {
- if (bm == null || opts == null) {
- return bm;
- }
-
- final int density = opts.inDensity;
- if (density == 0) {
- return bm;
- }
-
- bm.setDensity(density);
- final int targetDensity = opts.inTargetDensity;
- if (targetDensity == 0 || density == targetDensity
- || density == opts.inScreenDensity) {
- return bm;
- }
-
- byte[] np = bm.getNinePatchChunk();
- final boolean isNinePatch = false; //np != null && NinePatch.isNinePatchChunk(np);
- if (opts.inScaled || isNinePatch) {
- float scale = targetDensity / (float)density;
- // TODO: This is very inefficient and should be done in native by Skia
- final Bitmap oldBitmap = bm;
- bm = Bitmap.createScaledBitmap(oldBitmap, (int) (bm.getWidth() * scale + 0.5f),
- (int) (bm.getHeight() * scale + 0.5f), true);
- oldBitmap.recycle();
-
- if (isNinePatch) {
- //np = nativeScaleNinePatch(np, scale, outPadding);
- bm.setNinePatchChunk(np);
- }
- bm.setDensity(targetDensity);
- }
-
- return bm;
- }
-
- /**
- * Decode an input stream into a bitmap. If the input stream is null, or
- * cannot be used to decode a bitmap, the function returns null.
- * The stream's position will be where ever it was after the encoded data
- * was read.
- *
- * @param is The input stream that holds the raw data to be decoded into a
- * bitmap.
- * @return The decoded bitmap, or null if the image data could not be
- * decoded, or, if opts is non-null, if opts requested only the
- * size be returned (in opts.outWidth and opts.outHeight)
- */
- public static Bitmap decodeStream(InputStream is) {
- return decodeStream(is, null, null);
- }
-
- /**
- * Decode a bitmap from the file descriptor. If the bitmap cannot be decoded
- * return null. The position within the descriptor will not be changed when
- * this returns, so the descriptor can be used again as-is.
- *
- * @param fd The file descriptor containing the bitmap data to decode
- * @param outPadding If not null, return the padding rect for the bitmap if
- * it exists, otherwise set padding to [-1,-1,-1,-1]. If
- * no bitmap is returned (null) then padding is
- * unchanged.
- * @param opts null-ok; Options that control downsampling and whether the
- * image should be completely decoded, or just is size returned.
- * @return the decoded bitmap, or null
- */
- public static Bitmap decodeFileDescriptor(FileDescriptor fd, Rect outPadding, Options opts) {
- return null;
-
- /* FIXME: implement as needed
- try {
- if (MemoryFile.isMemoryFile(fd)) {
- int mappedlength = MemoryFile.getMappedSize(fd);
- MemoryFile file = new MemoryFile(fd, mappedlength, "r");
- InputStream is = file.getInputStream();
- Bitmap bm = decodeStream(is, outPadding, opts);
- return finishDecode(bm, outPadding, opts);
- }
- } catch (IOException ex) {
- // invalid filedescriptor, no need to call nativeDecodeFileDescriptor()
- return null;
- }
- //Bitmap bm = nativeDecodeFileDescriptor(fd, outPadding, opts);
- //return finishDecode(bm, outPadding, opts);
- */
- }
-
- /**
- * Decode a bitmap from the file descriptor. If the bitmap cannot be decoded
- * return null. The position within the descriptor will not be changed when
- * this returns, so the descriptor can be used again as is.
- *
- * @param fd The file descriptor containing the bitmap data to decode
- * @return the decoded bitmap, or null
- */
- public static Bitmap decodeFileDescriptor(FileDescriptor fd) {
- return decodeFileDescriptor(fd, null, null);
- }
-}
-
diff --git a/tools/layoutlib/bridge/src/android/graphics/BitmapFactory_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/BitmapFactory_Delegate.java
new file mode 100644
index 0000000..44b14dc
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/BitmapFactory_Delegate.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2011 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 android.graphics;
+
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.android.BridgeResources.NinePatchInputStream;
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.ninepatch.NinePatchChunk;
+import com.android.resources.Density;
+
+import android.graphics.BitmapFactory.Options;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Delegate implementing the native methods of android.graphics.BitmapFactory
+ *
+ * Through the layoutlib_create tool, the original native methods of BitmapFactory have been
+ * replaced by calls to methods of the same name in this delegate class.
+ *
+ * Because it's a stateless class to start with, there's no need to keep a {@link DelegateManager}
+ * around to map int to instance of the delegate.
+ *
+ */
+/*package*/ class BitmapFactory_Delegate {
+
+ // ------ Native Delegates ------
+
+ /*package*/ static void nativeSetDefaultConfig(int nativeConfig) {
+ // pass
+ }
+
+ /*package*/ static Bitmap nativeDecodeStream(InputStream is, byte[] storage,
+ Rect padding, Options opts) {
+ Bitmap bm = null;
+
+ Density density = Density.MEDIUM;
+ if (opts != null) {
+ density = Density.getEnum(opts.inDensity);
+ }
+
+ try {
+ if (is instanceof NinePatchInputStream) {
+ NinePatchInputStream npis = (NinePatchInputStream) is;
+ npis.disableFakeMarkSupport();
+
+ // load the bitmap as a nine patch
+ com.android.ninepatch.NinePatch ninePatch = com.android.ninepatch.NinePatch.load(
+ npis, true /*is9Patch*/, false /*convert*/);
+
+ // get the bitmap and chunk objects.
+ bm = Bitmap_Delegate.createBitmap(ninePatch.getImage(), true /*isMutable*/,
+ density);
+ NinePatchChunk chunk = ninePatch.getChunk();
+
+ // put the chunk in the bitmap
+ bm.setNinePatchChunk(NinePatch_Delegate.serialize(chunk));
+
+ // read the padding
+ int[] paddingarray = chunk.getPadding();
+ padding.left = paddingarray[0];
+ padding.top = paddingarray[1];
+ padding.right = paddingarray[2];
+ padding.bottom = paddingarray[3];
+ } else {
+ // load the bitmap directly.
+ bm = Bitmap_Delegate.createBitmap(is, true, density);
+ }
+ } catch (IOException e) {
+ Bridge.getLog().error(null,"Failed to load image" , e, null);
+ }
+
+ return bm;
+ }
+
+ /*package*/ static Bitmap nativeDecodeFileDescriptor(FileDescriptor fd,
+ Rect padding, Options opts) {
+ opts.inBitmap = null;
+ return null;
+ }
+
+ /*package*/ static Bitmap nativeDecodeAsset(int asset, Rect padding, Options opts) {
+ opts.inBitmap = null;
+ return null;
+ }
+
+ /*package*/ static Bitmap nativeDecodeByteArray(byte[] data, int offset,
+ int length, Options opts) {
+ opts.inBitmap = null;
+ return null;
+ }
+
+ /*package*/ static byte[] nativeScaleNinePatch(byte[] chunk, float scale, Rect pad) {
+ // don't scale for now.
+ return chunk;
+ }
+
+ /*package*/ static boolean nativeIsSeekable(FileDescriptor fd) {
+ return true;
+ }
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
index efe6955..3e80614 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
@@ -21,6 +21,7 @@ import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.impl.DelegateManager;
import com.android.resources.Density;
+import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.os.Parcel;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
index 93c81d1..c01962d 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -20,12 +20,14 @@ import static com.android.ide.common.rendering.api.Result.Status.ERROR_UNKNOWN;
import static com.android.ide.common.rendering.api.Result.Status.SUCCESS;
import com.android.ide.common.rendering.api.Capability;
+import com.android.ide.common.rendering.api.DrawableParams;
import com.android.ide.common.rendering.api.LayoutLog;
-import com.android.ide.common.rendering.api.Params;
import com.android.ide.common.rendering.api.RenderSession;
import com.android.ide.common.rendering.api.Result;
+import com.android.ide.common.rendering.api.SessionParams;
import com.android.layoutlib.bridge.android.BridgeAssetManager;
import com.android.layoutlib.bridge.impl.FontLoader;
+import com.android.layoutlib.bridge.impl.RenderDrawable;
import com.android.layoutlib.bridge.impl.RenderSessionImpl;
import com.android.ninepatch.NinePatchChunk;
import com.android.resources.ResourceType;
@@ -293,15 +295,15 @@ public final class Bridge extends com.android.ide.common.rendering.api.Bridge {
/**
* Starts a layout session by inflating and rendering it. The method returns a
- * {@link ILayoutScene} on which further actions can be taken.
+ * {@link RenderSession} on which further actions can be taken.
*
- * @param params the {@link SceneParams} object with all the information necessary to create
+ * @param params the {@link SessionParams} object with all the information necessary to create
* the scene.
- * @return a new {@link ILayoutScene} object that contains the result of the layout.
+ * @return a new {@link RenderSession} object that contains the result of the layout.
* @since 5
*/
@Override
- public RenderSession createSession(Params params) {
+ public RenderSession createSession(SessionParams params) {
try {
Result lastResult = SUCCESS.createResult();
RenderSessionImpl scene = new RenderSessionImpl(params);
@@ -331,10 +333,33 @@ public final class Bridge extends com.android.ide.common.rendering.api.Bridge {
}
}
- /*
- * (non-Javadoc)
- * @see com.android.layoutlib.api.ILayoutLibBridge#clearCaches(java.lang.Object)
- */
+ @Override
+ public Result renderDrawable(DrawableParams params) {
+ try {
+ Result lastResult = SUCCESS.createResult();
+ RenderDrawable action = new RenderDrawable(params);
+ try {
+ prepareThread();
+ lastResult = action.init(params.getTimeout());
+ if (lastResult.isSuccess()) {
+ lastResult = action.render();
+ }
+ } finally {
+ action.release();
+ cleanupThread();
+ }
+
+ return lastResult;
+ } catch (Throwable t) {
+ // get the real cause of the exception.
+ Throwable t2 = t;
+ while (t2.getCause() != null) {
+ t2 = t.getCause();
+ }
+ return ERROR_UNKNOWN.createResult(t2.getMessage(), t);
+ }
+ }
+
@Override
public void clearCaches(Object projectKey) {
if (projectKey != null) {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java
index 0c6fa20..765fd99 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java
@@ -18,7 +18,7 @@ package com.android.layoutlib.bridge;
import com.android.ide.common.rendering.api.IAnimationListener;
import com.android.ide.common.rendering.api.ILayoutPullParser;
-import com.android.ide.common.rendering.api.Params;
+import com.android.ide.common.rendering.api.RenderParams;
import com.android.ide.common.rendering.api.RenderSession;
import com.android.ide.common.rendering.api.Result;
import com.android.ide.common.rendering.api.ViewInfo;
@@ -128,7 +128,7 @@ public class BridgeRenderSession extends RenderSession {
boolean isFrameworkAnimation, IAnimationListener listener) {
try {
Bridge.prepareThread();
- mLastResult = mSession.acquire(Params.DEFAULT_TIMEOUT);
+ mLastResult = mSession.acquire(RenderParams.DEFAULT_TIMEOUT);
if (mLastResult.isSuccess()) {
mLastResult = mSession.animate(targetObject, animationName, isFrameworkAnimation,
listener);
@@ -150,7 +150,7 @@ public class BridgeRenderSession extends RenderSession {
try {
Bridge.prepareThread();
- mLastResult = mSession.acquire(Params.DEFAULT_TIMEOUT);
+ mLastResult = mSession.acquire(RenderParams.DEFAULT_TIMEOUT);
if (mLastResult.isSuccess()) {
mLastResult = mSession.insertChild((ViewGroup) parentView, childXml, index,
listener);
@@ -176,7 +176,7 @@ public class BridgeRenderSession extends RenderSession {
try {
Bridge.prepareThread();
- mLastResult = mSession.acquire(Params.DEFAULT_TIMEOUT);
+ mLastResult = mSession.acquire(RenderParams.DEFAULT_TIMEOUT);
if (mLastResult.isSuccess()) {
mLastResult = mSession.moveChild((ViewGroup) parentView, (View) childView, index,
layoutParams, listener);
@@ -197,7 +197,7 @@ public class BridgeRenderSession extends RenderSession {
try {
Bridge.prepareThread();
- mLastResult = mSession.acquire(Params.DEFAULT_TIMEOUT);
+ mLastResult = mSession.acquire(RenderParams.DEFAULT_TIMEOUT);
if (mLastResult.isSuccess()) {
mLastResult = mSession.removeChild((View) childView, listener);
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index bb4c56c..33dd214 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -176,6 +176,10 @@ public final class BridgeContext extends Activity {
return mProjectKey;
}
+ public DisplayMetrics getMetrics() {
+ return mMetrics;
+ }
+
public IProjectCallback getProjectCallback() {
return mProjectCallback;
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeResources.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeResources.java
index 5ea0a8d..5e5aeb1 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeResources.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeResources.java
@@ -22,6 +22,7 @@ import com.android.ide.common.rendering.api.ResourceValue;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.BridgeConstants;
import com.android.layoutlib.bridge.impl.ResourceHelper;
+import com.android.ninepatch.NinePatch;
import com.android.resources.ResourceType;
import com.android.util.Pair;
@@ -58,6 +59,35 @@ public final class BridgeResources extends Resources {
private boolean[] mPlatformResourceFlag = new boolean[1];
/**
+ * Simpler wrapper around FileInputStream. This is used when the input stream represent
+ * not a normal bitmap but a nine patch.
+ * This is useful when the InputStream is created in a method but used in another that needs
+ * to know whether this is 9-patch or not, such as BitmapFactory.
+ */
+ public class NinePatchInputStream extends FileInputStream {
+ private boolean mFakeMarkSupport = true;
+ public NinePatchInputStream(File file) throws FileNotFoundException {
+ super(file);
+ }
+
+ @Override
+ public boolean markSupported() {
+ if (mFakeMarkSupport) {
+ // this is needed so that BitmapFactory doesn't wrap this in a BufferedInputStream.
+ return true;
+ }
+
+ return super.markSupported();
+ }
+
+ public void disableFakeMarkSupport() {
+ // disable fake mark support so that in case codec actually try to use them
+ // we don't lie to them.
+ mFakeMarkSupport = false;
+ }
+ }
+
+ /**
* This initializes the static field {@link Resources#mSystem} which is used
* by methods who get global resources using {@link Resources#getSystem()}.
* <p/>
@@ -129,7 +159,7 @@ public final class BridgeResources extends Resources {
ResourceValue value = getResourceValue(id, mPlatformResourceFlag);
if (value != null) {
- return ResourceHelper.getDrawable(value, mContext, value.isFramework());
+ return ResourceHelper.getDrawable(value, mContext);
}
// id was not found or not resolved. Throw a NotFoundException.
@@ -165,44 +195,9 @@ public final class BridgeResources extends Resources {
ResourceValue resValue = getResourceValue(id, mPlatformResourceFlag);
if (resValue != null) {
- String value = resValue.getValue();
- if (value != null) {
- // first check if the value is a file (xml most likely)
- File f = new File(value);
- if (f.isFile()) {
- try {
- // let the framework inflate the ColorStateList from the XML file, by
- // providing an XmlPullParser
- KXmlParser parser = new KXmlParser();
- parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
- parser.setInput(new FileReader(f));
-
- return ColorStateList.createFromXml(this,
- new BridgeXmlBlockParser(parser, mContext, resValue.isFramework()));
- } catch (XmlPullParserException e) {
- Bridge.getLog().error(LayoutLog.TAG_BROKEN,
- "Failed to configure parser for " + value, e, null /*data*/);
- // we'll return null below.
- } catch (Exception e) {
- // this is an error and not warning since the file existence is
- // checked before attempting to parse it.
- Bridge.getLog().error(LayoutLog.TAG_RESOURCES_READ,
- "Failed to parse file " + value, e, null /*data*/);
-
- return null;
- }
- } else {
- // try to load the color state list from an int
- try {
- int color = ResourceHelper.getColor(value);
- return ColorStateList.valueOf(color);
- } catch (NumberFormatException e) {
- Bridge.getLog().error(LayoutLog.TAG_RESOURCES_FORMAT,
- "Failed to convert " + value + " into a ColorStateList", e,
- null /*data*/);
- return null;
- }
- }
+ ColorStateList stateList = ResourceHelper.getColorStateList(resValue, mContext);
+ if (stateList != null) {
+ return stateList;
}
}
@@ -562,13 +557,19 @@ public final class BridgeResources extends Resources {
ResourceValue value = getResourceValue(id, mPlatformResourceFlag);
if (value != null) {
- String v = value.getValue();
+ String path = value.getValue();
- if (v != null) {
+ if (path != null) {
// check this is a file
- File f = new File(value.getValue());
+ File f = new File(path);
if (f.isFile()) {
try {
+ // if it's a nine-patch return a custom input stream so that
+ // other methods (mainly bitmap factory) can detect it's a 9-patch
+ // and actually load it as a 9-patch instead of a normal bitmap
+ if (path.toLowerCase().endsWith(NinePatch.EXTENSION_9PATCH)) {
+ return new NinePatchInputStream(f);
+ }
return new FileInputStream(f);
} catch (FileNotFoundException e) {
NotFoundException newE = new NotFoundException();
@@ -590,9 +591,17 @@ public final class BridgeResources extends Resources {
public InputStream openRawResource(int id, TypedValue value) throws NotFoundException {
getValue(id, value, true);
- File f = new File(value.string.toString());
+ String path = value.string.toString();
+
+ File f = new File(path);
if (f.isFile()) {
try {
+ // if it's a nine-patch return a custom input stream so that
+ // other methods (mainly bitmap factory) can detect it's a 9-patch
+ // and actually load it as a 9-patch instead of a normal bitmap
+ if (path.toLowerCase().endsWith(NinePatch.EXTENSION_9PATCH)) {
+ return new NinePatchInputStream(f);
+ }
return new FileInputStream(f);
} catch (FileNotFoundException e) {
NotFoundException exception = new NotFoundException();
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java
index cf2c0ff..c226b8b 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java
@@ -690,7 +690,7 @@ public final class BridgeTypedArray extends TypedArray {
return null;
}
- return ResourceHelper.getDrawable(value, mContext, mResourceData[index].isFramework());
+ return ResourceHelper.getDrawable(value, mContext);
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
new file mode 100644
index 0000000..f039994
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2011 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.layoutlib.bridge.bars;
+
+import com.android.ide.common.rendering.api.RenderResources;
+import com.android.ide.common.rendering.api.ResourceValue;
+import com.android.ide.common.rendering.api.StyleResourceValue;
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.android.BridgeContext;
+import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
+import com.android.layoutlib.bridge.impl.ResourceHelper;
+import com.android.resources.Density;
+
+import org.kxml2.io.KXmlParser;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap_Delegate;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.util.TypedValue;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Base "bar" class for the window decor around the the edited layout.
+ * This is basically an horizontal layout that loads a given layout on creation (it is read
+ * through {@link Class#getResourceAsStream(String)}).
+ *
+ * The given layout should be a merge layout so that all the children belong to this class directly.
+ *
+ * It also provides a few utility methods to configure the content of the layout.
+ */
+abstract class CustomBar extends LinearLayout {
+
+ protected abstract TextView getStyleableTextView();
+
+ protected CustomBar(Context context, Density density, String layoutPath)
+ throws XmlPullParserException {
+ super(context);
+ setOrientation(LinearLayout.HORIZONTAL);
+ setBackgroundColor(0xFF000000);
+
+ LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
+
+ KXmlParser parser = new KXmlParser();
+ parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
+ parser.setInput(
+ getClass().getResourceAsStream(layoutPath),
+ "UTF8");
+
+ BridgeXmlBlockParser bridgeParser = new BridgeXmlBlockParser(
+ parser, (BridgeContext) context, false);
+
+ inflater.inflate(bridgeParser, this, true);
+ }
+
+ protected void loadIcon(int index, String iconName, Density density) {
+ View child = getChildAt(index);
+ if (child instanceof ImageView) {
+ ImageView imageView = (ImageView) child;
+
+ // bitmap url relative to this class
+ String path = "/bars/" + density.getResourceValue() + "/" + iconName;
+
+ // create a bitmap
+ Bitmap bitmap = Bridge.getCachedBitmap(path, true /*isFramework*/);
+
+ if (bitmap == null) {
+ InputStream stream = getClass().getResourceAsStream(path);
+
+ if (stream != null) {
+ try {
+ bitmap = Bitmap_Delegate.createBitmap(stream, false /*isMutable*/, density);
+ Bridge.setCachedBitmap(path, bitmap, true /*isFramework*/);
+ } catch (IOException e) {
+ return;
+ }
+ }
+ }
+
+ if (bitmap != null) {
+ BitmapDrawable drawable = new BitmapDrawable(getContext().getResources(), bitmap);
+ imageView.setBackgroundDrawable(drawable);
+ }
+ }
+ }
+
+ protected void loadIcon(int index, String iconReference) {
+ ResourceValue value = getResourceValue(iconReference);
+ if (value != null) {
+ View child = getChildAt(index);
+ if (child instanceof ImageView) {
+ ImageView imageView = (ImageView) child;
+
+ Drawable drawable = ResourceHelper.getDrawable(
+ value, (BridgeContext) mContext);
+ if (drawable != null) {
+ imageView.setBackgroundDrawable(drawable);
+ }
+ }
+ }
+ }
+
+ protected TextView setText(int index, String stringReference) {
+ View child = getChildAt(index);
+ if (child instanceof TextView) {
+ TextView textView = (TextView) child;
+ ResourceValue value = getResourceValue(stringReference);
+ if (value != null) {
+ textView.setText(value.getValue());
+ } else {
+ textView.setText(stringReference);
+ }
+ return textView;
+ }
+
+ return null;
+ }
+
+ protected void setStyle(String themeEntryName) {
+
+ BridgeContext bridgeContext = (BridgeContext) mContext;
+ RenderResources res = bridgeContext.getRenderResources();
+
+ ResourceValue value = res.findItemInTheme(themeEntryName);
+ value = res.resolveResValue(value);
+
+ if (value instanceof StyleResourceValue == false) {
+ return;
+ }
+
+ StyleResourceValue style = (StyleResourceValue) value;
+
+ // get the background
+ ResourceValue backgroundValue = res.findItemInStyle(style, "background");
+ backgroundValue = res.resolveResValue(backgroundValue);
+ if (backgroundValue != null) {
+ Drawable d = ResourceHelper.getDrawable(backgroundValue, bridgeContext);
+ if (d != null) {
+ setBackgroundDrawable(d);
+ }
+ }
+
+ TextView textView = getStyleableTextView();
+ if (textView != null) {
+ // get the text style
+ ResourceValue textStyleValue = res.findItemInStyle(style, "titleTextStyle");
+ textStyleValue = res.resolveResValue(textStyleValue);
+ if (textStyleValue instanceof StyleResourceValue) {
+ StyleResourceValue textStyle = (StyleResourceValue) textStyleValue;
+
+ ResourceValue textSize = res.findItemInStyle(textStyle, "textSize");
+ textSize = res.resolveResValue(textSize);
+
+ if (textSize != null) {
+ TypedValue out = new TypedValue();
+ if (ResourceHelper.stringToFloat(textSize.getValue(), out)) {
+ textView.setTextSize(
+ out.getDimension(bridgeContext.getResources().mMetrics));
+ }
+ }
+
+
+ ResourceValue textColor = res.findItemInStyle(textStyle, "textColor");
+ textColor = res.resolveResValue(textColor);
+ if (textColor != null) {
+ ColorStateList stateList = ResourceHelper.getColorStateList(
+ textColor, bridgeContext);
+ if (stateList != null) {
+ textView.setTextColor(stateList);
+ }
+ }
+ }
+ }
+ }
+
+ private ResourceValue getResourceValue(String reference) {
+ BridgeContext bridgeContext = (BridgeContext) mContext;
+ RenderResources res = bridgeContext.getRenderResources();
+
+ // find the resource
+ ResourceValue value = res.findResValue(reference, false /*isFramework*/);
+
+ // resolve it if needed
+ return res.resolveResValue(value);
+ }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/FakeActionBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/FakeActionBar.java
new file mode 100644
index 0000000..3af4e3a
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/FakeActionBar.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2011 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.layoutlib.bridge.bars;
+
+import com.android.resources.Density;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.content.Context;
+import android.widget.TextView;
+
+public class FakeActionBar extends CustomBar {
+
+ private TextView mTextView;
+
+ public FakeActionBar(Context context, Density density, String label, String icon)
+ throws XmlPullParserException {
+ super(context, density, "/bars/action_bar.xml");
+
+ // Cannot access the inside items through id because no R.id values have been
+ // created for them.
+ // We do know the order though.
+ loadIcon(0, icon);
+ mTextView = setText(1, label);
+
+ setStyle("actionBarStyle");
+ }
+
+ @Override
+ protected TextView getStyleableTextView() {
+ return mTextView;
+ }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/PhoneSystemBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/PhoneSystemBar.java
new file mode 100644
index 0000000..92615dc
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/PhoneSystemBar.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2011 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.layoutlib.bridge.bars;
+
+import com.android.resources.Density;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.content.Context;
+import android.widget.TextView;
+
+public class PhoneSystemBar extends CustomBar {
+
+ public PhoneSystemBar(Context context, Density density) throws XmlPullParserException {
+ super(context, density, "/bars/tablet_system_bar.xml");
+
+ // Cannot access the inside items through id because no R.id values have been
+ // created for them.
+ // We do know the order though.
+ // 0 is the spacer
+ loadIcon(1, "stat_sys_wifi_signal_4_fully.png", density);
+ }
+
+ @Override
+ protected TextView getStyleableTextView() {
+ return null;
+ }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/TabletSystemBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/TabletSystemBar.java
new file mode 100644
index 0000000..bc61799
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/TabletSystemBar.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2011 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.layoutlib.bridge.bars;
+
+import com.android.resources.Density;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.content.Context;
+import android.widget.TextView;
+
+public class TabletSystemBar extends CustomBar {
+
+ public TabletSystemBar(Context context, Density density) throws XmlPullParserException {
+ super(context, density, "/bars/tablet_system_bar.xml");
+
+ // Cannot access the inside items through id because no R.id values have been
+ // created for them.
+ // We do know the order though.
+ loadIcon(0, "ic_sysbar_back_default.png", density);
+ loadIcon(1, "ic_sysbar_home_default.png", density);
+ loadIcon(2, "ic_sysbar_recent_default.png", density);
+ // 3 is the spacer
+ loadIcon(4, "stat_sys_wifi_signal_4_fully.png", density);
+ }
+
+ @Override
+ protected TextView getStyleableTextView() {
+ return null;
+ }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/TitleBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/TitleBar.java
new file mode 100644
index 0000000..d7401d9
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/TitleBar.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2011 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.layoutlib.bridge.bars;
+
+import com.android.resources.Density;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.content.Context;
+import android.widget.TextView;
+
+public class TitleBar extends CustomBar {
+
+ private TextView mTextView;
+
+ public TitleBar(Context context, Density density, String label)
+ throws XmlPullParserException {
+ super(context, density, "/bars/title_bar.xml");
+
+ // Cannot access the inside items through id because no R.id values have been
+ // created for them.
+ // We do know the order though.
+ mTextView = setText(0, label);
+
+ setStyle("windowTitleBackgroundStyle");
+ }
+
+ @Override
+ protected TextView getStyleableTextView() {
+ return mTextView;
+ }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
new file mode 100644
index 0000000..8e80c21
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
@@ -0,0 +1,285 @@
+/*
+ * Copyright (C) 2010 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.layoutlib.bridge.impl;
+
+import static com.android.ide.common.rendering.api.Result.Status.ERROR_LOCK_INTERRUPTED;
+import static com.android.ide.common.rendering.api.Result.Status.ERROR_TIMEOUT;
+import static com.android.ide.common.rendering.api.Result.Status.SUCCESS;
+
+import com.android.ide.common.rendering.api.LayoutLog;
+import com.android.ide.common.rendering.api.RenderParams;
+import com.android.ide.common.rendering.api.RenderResources;
+import com.android.ide.common.rendering.api.Result;
+import com.android.ide.common.rendering.api.RenderResources.FrameworkResourceIdProvider;
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.android.BridgeContext;
+import com.android.resources.ResourceType;
+
+import android.util.DisplayMetrics;
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * Base class for rendering action.
+ *
+ * It provides life-cycle methods to init and stop the rendering.
+ * The most important methods are:
+ * {@link #init(long)} and {@link #acquire(long)} to start a rendering and {@link #release()}
+ * after the rendering.
+ *
+ *
+ * @param <T> the {@link RenderParams} implementation
+ *
+ */
+public abstract class RenderAction<T extends RenderParams> extends FrameworkResourceIdProvider {
+
+ /**
+ * The current context being rendered. This is set through {@link #acquire(long)} and
+ * {@link #init(long)}, and unset in {@link #release()}.
+ */
+ private static BridgeContext sCurrentContext = null;
+
+ private final T mParams;
+
+ private BridgeContext mContext;
+
+ /**
+ * Creates a renderAction.
+ * <p>
+ * This <b>must</b> be followed by a call to {@link RenderAction#init()}, which act as a
+ * call to {@link RenderAction#acquire(long)}
+ *
+ * @param params the RenderParams. This must be a copy that the action can keep
+ *
+ */
+ protected RenderAction(T params) {
+ mParams = params;
+ }
+
+ /**
+ * Initializes and acquires the scene, creating various Android objects such as context,
+ * inflater, and parser.
+ *
+ * @param timeout the time to wait if another rendering is happening.
+ *
+ * @return whether the scene was prepared
+ *
+ * @see #acquire(long)
+ * @see #release()
+ */
+ public Result init(long timeout) {
+ // acquire the lock. if the result is null, lock was just acquired, otherwise, return
+ // the result.
+ Result result = acquireLock(timeout);
+ if (result != null) {
+ return result;
+ }
+
+ // setup the display Metrics.
+ DisplayMetrics metrics = new DisplayMetrics();
+ metrics.densityDpi = mParams.getDensity().getDpiValue();
+ metrics.density = metrics.densityDpi / (float) DisplayMetrics.DENSITY_DEFAULT;
+ metrics.scaledDensity = metrics.density;
+ metrics.widthPixels = mParams.getScreenWidth();
+ metrics.heightPixels = mParams.getScreenHeight();
+ metrics.xdpi = mParams.getXdpi();
+ metrics.ydpi = mParams.getYdpi();
+
+ RenderResources resources = mParams.getResources();
+
+ // build the context
+ mContext = new BridgeContext(mParams.getProjectKey(), metrics, resources,
+ mParams.getProjectCallback(), mParams.getTargetSdkVersion());
+
+ setUp();
+
+ return SUCCESS.createResult();
+ }
+
+ /**
+ * Prepares the scene for action.
+ * <p>
+ * This call is blocking if another rendering/inflating is currently happening, and will return
+ * whether the preparation worked.
+ *
+ * The preparation can fail if another rendering took too long and the timeout was elapsed.
+ *
+ * More than one call to this from the same thread will have no effect and will return
+ * {@link Result#SUCCESS}.
+ *
+ * After scene actions have taken place, only one call to {@link #release()} must be
+ * done.
+ *
+ * @param timeout the time to wait if another rendering is happening.
+ *
+ * @return whether the scene was prepared
+ *
+ * @see #release()
+ *
+ * @throws IllegalStateException if {@link #init(long)} was never called.
+ */
+ public Result acquire(long timeout) {
+ if (mContext == null) {
+ throw new IllegalStateException("After scene creation, #init() must be called");
+ }
+
+ // acquire the lock. if the result is null, lock was just acquired, otherwise, return
+ // the result.
+ Result result = acquireLock(timeout);
+ if (result != null) {
+ return result;
+ }
+
+ setUp();
+
+ return SUCCESS.createResult();
+ }
+
+ /**
+ * 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#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() == false) {
+ try {
+ boolean acquired = lock.tryLock(timeout, TimeUnit.MILLISECONDS);
+
+ if (acquired == false) {
+ 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;
+ }
+
+ /**
+ * 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();
+ }
+ }
+
+ /**
+ * 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;
+
+ LayoutLog currentLog = mParams.getLog();
+ Bridge.setLog(currentLog);
+ mContext.getRenderResources().setFrameworkResourceIdProvider(this);
+ mContext.getRenderResources().setLogger(currentLog);
+ }
+
+ /**
+ * Tear down the session after rendering.
+ * <p/>
+ * The counterpart is {@link #setUp()}.
+ */
+ private void tearDown() {
+ // Make sure to remove static references, otherwise we could not unload the lib
+ mContext.disposeResources();
+ sCurrentContext = null;
+
+ Bridge.setLog(null);
+ mContext.getRenderResources().setFrameworkResourceIdProvider(null);
+ mContext.getRenderResources().setLogger(null);
+ }
+
+ public static BridgeContext getCurrentContext() {
+ return sCurrentContext;
+ }
+
+ protected T getParams() {
+ return mParams;
+ }
+
+ protected BridgeContext getContext() {
+ return mContext;
+ }
+
+ /**
+ * Returns the log associated with the session.
+ * @return the log or null if there are none.
+ */
+ public LayoutLog getLog() {
+ if (mParams != null) {
+ return mParams.getLog();
+ }
+
+ 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() == false) {
+ 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");
+ }
+ }
+
+ // --- FrameworkResourceIdProvider methods
+
+ @Override
+ public Integer getId(ResourceType resType, String resName) {
+ return Bridge.getResourceId(resType, resName);
+ }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java
new file mode 100644
index 0000000..953d8cf
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2011 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.layoutlib.bridge.impl;
+
+import static com.android.ide.common.rendering.api.Result.Status.ERROR_UNKNOWN;
+
+import com.android.ide.common.rendering.api.DrawableParams;
+import com.android.ide.common.rendering.api.ResourceValue;
+import com.android.ide.common.rendering.api.Result;
+import com.android.ide.common.rendering.api.Result.Status;
+import com.android.layoutlib.bridge.android.BridgeContext;
+import com.android.layoutlib.bridge.android.BridgeWindow;
+import com.android.layoutlib.bridge.android.BridgeWindowSession;
+import com.android.resources.ResourceType;
+
+import android.graphics.Bitmap;
+import android.graphics.Bitmap_Delegate;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.view.View;
+import android.view.View.AttachInfo;
+import android.view.View.MeasureSpec;
+import android.widget.FrameLayout;
+
+import java.awt.AlphaComposite;
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+
+/**
+ * Action to render a given Drawable provided through {@link DrawableParams#getDrawable()}.
+ *
+ * The class only provides a simple {@link #render()} method, but the full life-cycle of the
+ * action must be respected.
+ *
+ * @see RenderAction
+ *
+ */
+public class RenderDrawable extends RenderAction<DrawableParams> {
+
+ public RenderDrawable(DrawableParams params) {
+ super(new DrawableParams(params));
+ }
+
+ public Result render() {
+ checkLock();
+ try {
+ // get the drawable resource value
+ DrawableParams params = getParams();
+ ResourceValue drawableResource = params.getDrawable();
+
+ // resolve it
+ BridgeContext context = getContext();
+ drawableResource = context.getRenderResources().resolveResValue(drawableResource);
+
+ if (drawableResource == null ||
+ drawableResource.getResourceType() != ResourceType.DRAWABLE) {
+ return Status.ERROR_NOT_A_DRAWABLE.createResult();
+ }
+
+ // create a simple FrameLayout
+ FrameLayout content = new FrameLayout(context);
+
+ // get the actual Drawable object to draw
+ Drawable d = ResourceHelper.getDrawable(drawableResource, context);
+ content.setBackgroundDrawable(d);
+
+ // set the AttachInfo on the root view.
+ AttachInfo info = new AttachInfo(new BridgeWindowSession(), new BridgeWindow(),
+ new Handler(), null);
+ info.mHasWindowFocus = true;
+ info.mWindowVisibility = View.VISIBLE;
+ info.mInTouchMode = false; // this is so that we can display selections.
+ info.mHardwareAccelerated = false;
+ content.dispatchAttachedToWindow(info, 0);
+
+
+ // measure
+ int w = params.getScreenWidth();
+ int h = params.getScreenHeight();
+ int w_spec = MeasureSpec.makeMeasureSpec(w, MeasureSpec.EXACTLY);
+ int h_spec = MeasureSpec.makeMeasureSpec(h, MeasureSpec.EXACTLY);
+ content.measure(w_spec, h_spec);
+
+ // now do the layout.
+ content.layout(0, 0, w, h);
+
+ // preDraw setup
+ content.mAttachInfo.mTreeObserver.dispatchOnPreDraw();
+
+ // draw into a new image
+ BufferedImage image = getImage(w, h);
+
+ // create an Android bitmap around the BufferedImage
+ Bitmap bitmap = Bitmap_Delegate.createBitmap(image,
+ true /*isMutable*/, params.getDensity());
+
+ // create a Canvas around the Android bitmap
+ Canvas canvas = new Canvas(bitmap);
+ canvas.setDensity(params.getDensity().getDpiValue());
+
+ // and draw
+ content.draw(canvas);
+
+ return Status.SUCCESS.createResult(image);
+ } catch (IOException e) {
+ return ERROR_UNKNOWN.createResult(e.getMessage(), e);
+ }
+ }
+
+ protected BufferedImage getImage(int w, int h) {
+ BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
+ Graphics2D gc = image.createGraphics();
+ gc.setComposite(AlphaComposite.Src);
+
+ gc.setColor(new Color(0x00000000, true));
+ gc.fillRect(0, 0, w, h);
+
+ // done
+ gc.dispose();
+
+ return image;
+ }
+
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
index c8ad1d6..3e5127e 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
@@ -18,9 +18,7 @@ package com.android.layoutlib.bridge.impl;
import static com.android.ide.common.rendering.api.Result.Status.ERROR_ANIM_NOT_FOUND;
import static com.android.ide.common.rendering.api.Result.Status.ERROR_INFLATION;
-import static com.android.ide.common.rendering.api.Result.Status.ERROR_LOCK_INTERRUPTED;
import static com.android.ide.common.rendering.api.Result.Status.ERROR_NOT_INFLATED;
-import static com.android.ide.common.rendering.api.Result.Status.ERROR_TIMEOUT;
import static com.android.ide.common.rendering.api.Result.Status.ERROR_UNKNOWN;
import static com.android.ide.common.rendering.api.Result.Status.ERROR_VIEWGROUP_NO_CHILDREN;
import static com.android.ide.common.rendering.api.Result.Status.SUCCESS;
@@ -28,17 +26,15 @@ import static com.android.ide.common.rendering.api.Result.Status.SUCCESS;
import com.android.ide.common.rendering.api.IAnimationListener;
import com.android.ide.common.rendering.api.ILayoutPullParser;
import com.android.ide.common.rendering.api.IProjectCallback;
-import com.android.ide.common.rendering.api.LayoutLog;
-import com.android.ide.common.rendering.api.Params;
+import com.android.ide.common.rendering.api.RenderParams;
import com.android.ide.common.rendering.api.RenderResources;
import com.android.ide.common.rendering.api.RenderSession;
import com.android.ide.common.rendering.api.ResourceValue;
import com.android.ide.common.rendering.api.Result;
-import com.android.ide.common.rendering.api.StyleResourceValue;
+import com.android.ide.common.rendering.api.SessionParams;
import com.android.ide.common.rendering.api.ViewInfo;
-import com.android.ide.common.rendering.api.Params.RenderingMode;
-import com.android.ide.common.rendering.api.RenderResources.FrameworkResourceIdProvider;
import com.android.ide.common.rendering.api.Result.Status;
+import com.android.ide.common.rendering.api.SessionParams.RenderingMode;
import com.android.internal.util.XmlUtils;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.android.BridgeContext;
@@ -47,11 +43,16 @@ import com.android.layoutlib.bridge.android.BridgeLayoutParamsMapAttributes;
import com.android.layoutlib.bridge.android.BridgeWindow;
import com.android.layoutlib.bridge.android.BridgeWindowSession;
import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
-import com.android.resources.Density;
+import com.android.layoutlib.bridge.bars.FakeActionBar;
+import com.android.layoutlib.bridge.bars.PhoneSystemBar;
+import com.android.layoutlib.bridge.bars.TabletSystemBar;
+import com.android.layoutlib.bridge.bars.TitleBar;
import com.android.resources.ResourceType;
import com.android.resources.ScreenSize;
import com.android.util.Pair;
+import org.xmlpull.v1.XmlPullParserException;
+
import android.animation.Animator;
import android.animation.AnimatorInflater;
import android.animation.LayoutTransition;
@@ -83,8 +84,6 @@ import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.locks.ReentrantLock;
/**
* Class implementing the render session.
@@ -94,36 +93,28 @@ import java.util.concurrent.locks.ReentrantLock;
* be done on the layout.
*
*/
-public class RenderSessionImpl extends FrameworkResourceIdProvider {
+public class RenderSessionImpl extends RenderAction<SessionParams> {
private static final int DEFAULT_TITLE_BAR_HEIGHT = 25;
private static final int DEFAULT_STATUS_BAR_HEIGHT = 25;
- /**
- * The current context being rendered. This is set through {@link #acquire(long)} and
- * {@link #init(long)}, and unset in {@link #release()}.
- */
- private static BridgeContext sCurrentContext = null;
-
- private final Params mParams;
-
// scene state
private RenderSession mScene;
- private BridgeContext mContext;
private BridgeXmlBlockParser mBlockParser;
private BridgeInflater mInflater;
private ResourceValue mWindowBackground;
- private FrameLayout mViewRoot;
+ private ViewGroup mViewRoot;
+ private FrameLayout mContentRoot;
private Canvas mCanvas;
private int mMeasuredScreenWidth = -1;
private int mMeasuredScreenHeight = -1;
- private boolean mIsAlphaChannelImage = true;
+ private boolean mIsAlphaChannelImage;
+ private boolean mWindowIsFloating;
private int mStatusBarSize;
- private int mTopBarSize;
private int mSystemBarSize;
- private int mTopOffset;
- private int mTotalBarSize;
+ private int mTitleBarSize;
+ private int mActionBarSize;
// information being returned through the API
@@ -146,9 +137,8 @@ public class RenderSessionImpl extends FrameworkResourceIdProvider {
*
* @see LayoutBridge#createScene(com.android.layoutlib.api.SceneParams)
*/
- public RenderSessionImpl(Params params) {
- // copy the params.
- mParams = new Params(params);
+ public RenderSessionImpl(SessionParams params) {
+ super(new SessionParams(params));
}
/**
@@ -162,204 +152,152 @@ public class RenderSessionImpl extends FrameworkResourceIdProvider {
* @see #acquire(long)
* @see #release()
*/
+ @Override
public Result init(long timeout) {
- // acquire the lock. if the result is null, lock was just acquired, otherwise, return
- // the result.
- Result result = acquireLock(timeout);
- if (result != null) {
+ Result result = super.init(timeout);
+ if (result.isSuccess() == false) {
return result;
}
- // setup the display Metrics.
- DisplayMetrics metrics = new DisplayMetrics();
- metrics.densityDpi = mParams.getDensity();
- metrics.density = mParams.getDensity() / (float) DisplayMetrics.DENSITY_DEFAULT;
- metrics.scaledDensity = metrics.density;
- metrics.widthPixels = mParams.getScreenWidth();
- metrics.heightPixels = mParams.getScreenHeight();
- metrics.xdpi = mParams.getXdpi();
- metrics.ydpi = mParams.getYdpi();
-
- RenderResources resources = mParams.getResources();
+ SessionParams params = getParams();
+ BridgeContext context = getContext();
- // build the context
- mContext = new BridgeContext(mParams.getProjectKey(), metrics, resources,
- mParams.getProjectCallback(), mParams.getTargetSdkVersion());
+ RenderResources resources = getParams().getResources();
+ DisplayMetrics metrics = getContext().getMetrics();
// use default of true in case it's not found to use alpha by default
mIsAlphaChannelImage = getBooleanThemeValue(resources,
"windowIsFloating", true /*defaultValue*/);
-
- setUp();
+ mWindowIsFloating = getBooleanThemeValue(resources, "windowIsFloating",
+ true /*defaultValue*/);
findBackground(resources);
findStatusBar(resources, metrics);
- findTopBar(resources, metrics);
+ findActionBar(resources, metrics);
findSystemBar(resources, metrics);
- mTopOffset = mStatusBarSize + mTopBarSize;
- mTotalBarSize = mTopOffset + mSystemBarSize;
-
// build the inflater and parser.
- mInflater = new BridgeInflater(mContext, mParams.getProjectCallback());
- mContext.setBridgeInflater(mInflater);
- mInflater.setFactory2(mContext);
+ mInflater = new BridgeInflater(context, params.getProjectCallback());
+ context.setBridgeInflater(mInflater);
+ mInflater.setFactory2(context);
- mBlockParser = new BridgeXmlBlockParser(mParams.getLayoutDescription(),
- mContext, false /* platformResourceFlag */);
+ mBlockParser = new BridgeXmlBlockParser(params.getLayoutDescription(),
+ context, false /* platformResourceFlag */);
return SUCCESS.createResult();
}
/**
- * Prepares the scene for action.
+ * Inflates the layout.
* <p>
- * This call is blocking if another rendering/inflating is currently happening, and will return
- * whether the preparation worked.
- *
- * The preparation can fail if another rendering took too long and the timeout was elapsed.
- *
- * More than one call to this from the same thread will have no effect and will return
- * {@link Result#SUCCESS}.
- *
- * After scene actions have taken place, only one call to {@link #release()} must be
- * done.
- *
- * @param timeout the time to wait if another rendering is happening.
- *
- * @return whether the scene was prepared
- *
- * @see #release()
+ * {@link #acquire(long)} must have been called before this.
*
- * @throws IllegalStateException if {@link #init(long)} was never called.
+ * @throws IllegalStateException if the current context is different than the one owned by
+ * the scene, or if {@link #init(long)} was not called.
*/
- public Result acquire(long timeout) {
- if (mContext == null) {
- throw new IllegalStateException("After scene creation, #init() must be called");
- }
+ public Result inflate() {
+ checkLock();
- // acquire the lock. if the result is null, lock was just acquired, otherwise, return
- // the result.
- Result result = acquireLock(timeout);
- if (result != null) {
- return result;
- }
+ try {
- setUp();
+ SessionParams params = getParams();
+ BridgeContext context = getContext();
- return SUCCESS.createResult();
- }
+ if (mWindowIsFloating || params.isForceNoDecor()) {
+ mViewRoot = mContentRoot = new FrameLayout(context);
+ } else {
+ /*
+ * we're creating the following layout
+ *
+ +-------------------------------------------------+
+ | System bar (only in phone UI) |
+ +-------------------------------------------------+
+ | Title/Action bar (optional) |
+ +-------------------------------------------------+
+ | Content, vertical extending |
+ | |
+ +-------------------------------------------------+
+ | System bar (only in tablet UI) |
+ +-------------------------------------------------+
+
+ */
+
+ LinearLayout topLayout = new LinearLayout(context);
+ mViewRoot = topLayout;
+ topLayout.setOrientation(LinearLayout.VERTICAL);
- /**
- * 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#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() == false) {
- try {
- boolean acquired = lock.tryLock(timeout, TimeUnit.MILLISECONDS);
+ if (mStatusBarSize > 0) {
+ // system bar
+ try {
+ PhoneSystemBar systemBar = new PhoneSystemBar(context,
+ params.getDensity());
+ systemBar.setLayoutParams(
+ new LinearLayout.LayoutParams(
+ LayoutParams.MATCH_PARENT, mStatusBarSize));
+ topLayout.addView(systemBar);
+ } catch (XmlPullParserException e) {
- if (acquired == false) {
- 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;
- }
+ // if the theme says no title/action bar, then the size will be 0
+ if (mActionBarSize > 0) {
+ try {
+ FakeActionBar actionBar = new FakeActionBar(context,
+ params.getDensity(),
+ params.getAppLabel(), params.getAppIcon());
+ actionBar.setLayoutParams(
+ new LinearLayout.LayoutParams(
+ LayoutParams.MATCH_PARENT, mActionBarSize));
+ topLayout.addView(actionBar);
+ } catch (XmlPullParserException e) {
- /**
- * 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();
- }
- }
+ }
+ } else if (mTitleBarSize > 0) {
+ try {
+ TitleBar titleBar = new TitleBar(context,
+ params.getDensity(), params.getAppLabel());
+ titleBar.setLayoutParams(
+ new LinearLayout.LayoutParams(
+ LayoutParams.MATCH_PARENT, mTitleBarSize));
+ topLayout.addView(titleBar);
+ } catch (XmlPullParserException e) {
- /**
- * 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;
-
- LayoutLog currentLog = mParams.getLog();
- Bridge.setLog(currentLog);
- mContext.getRenderResources().setFrameworkResourceIdProvider(this);
- mContext.getRenderResources().setLogger(currentLog);
- }
+ }
+ }
- /**
- * Tear down the session after rendering.
- * <p/>
- * The counterpart is {@link #setUp()}.
- */
- private void tearDown() {
- // Make sure to remove static references, otherwise we could not unload the lib
- mContext.disposeResources();
- sCurrentContext = null;
-
- Bridge.setLog(null);
- mContext.getRenderResources().setFrameworkResourceIdProvider(null);
- mContext.getRenderResources().setLogger(null);
- }
- public static BridgeContext getCurrentContext() {
- return sCurrentContext;
- }
+ // content frame
+ mContentRoot = new FrameLayout(context);
+ LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
+ LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
+ layoutParams.weight = 1;
+ mContentRoot.setLayoutParams(layoutParams);
+ topLayout.addView(mContentRoot);
- /**
- * Inflates the layout.
- * <p>
- * {@link #acquire(long)} must have been called before this.
- *
- * @throws IllegalStateException if the current context is different than the one owned by
- * the scene, or if {@link #init(long)} was not called.
- */
- public Result inflate() {
- checkLock();
+ if (mSystemBarSize > 0) {
+ // system bar
+ try {
+ TabletSystemBar systemBar = new TabletSystemBar(context,
+ params.getDensity());
+ systemBar.setLayoutParams(
+ new LinearLayout.LayoutParams(
+ LayoutParams.MATCH_PARENT, mSystemBarSize));
+ topLayout.addView(systemBar);
+ } catch (XmlPullParserException e) {
- try {
+ }
+ }
+
+ }
- mViewRoot = new FrameLayout(mContext);
// Sets the project callback (custom view loader) to the fragment delegate so that
// it can instantiate the custom Fragment.
- Fragment_Delegate.setProjectCallback(mParams.getProjectCallback());
+ Fragment_Delegate.setProjectCallback(params.getProjectCallback());
- View view = mInflater.inflate(mBlockParser, mViewRoot);
+ View view = mInflater.inflate(mBlockParser, mContentRoot);
Fragment_Delegate.setProjectCallback(null);
@@ -373,13 +311,12 @@ public class RenderSessionImpl extends FrameworkResourceIdProvider {
mViewRoot.dispatchAttachedToWindow(info, 0);
// post-inflate process. For now this supports TabHost/TabWidget
- postInflateProcess(view, mParams.getProjectCallback());
+ postInflateProcess(view, params.getProjectCallback());
// get the background drawable
if (mWindowBackground != null) {
- Drawable d = ResourceHelper.getDrawable(mWindowBackground,
- mContext, true /* isFramework */);
- mViewRoot.setBackgroundDrawable(d);
+ Drawable d = ResourceHelper.getDrawable(mWindowBackground, context);
+ mContentRoot.setBackgroundDrawable(d);
}
return SUCCESS.createResult();
@@ -408,12 +345,14 @@ public class RenderSessionImpl extends FrameworkResourceIdProvider {
* @throws IllegalStateException if the current context is different than the one owned by
* the scene, or if {@link #acquire(long)} was not called.
*
- * @see SceneParams#getRenderingMode()
- * @see LayoutScene#render(long)
+ * @see RenderParams#getRenderingMode()
+ * @see RenderSession#render(long)
*/
public Result render(boolean freshRender) {
checkLock();
+ SessionParams params = getParams();
+
try {
if (mViewRoot == null) {
return ERROR_NOT_INFLATED.createResult();
@@ -421,14 +360,14 @@ public class RenderSessionImpl extends FrameworkResourceIdProvider {
// measure the views
int w_spec, h_spec;
- RenderingMode renderingMode = mParams.getRenderingMode();
+ RenderingMode renderingMode = params.getRenderingMode();
// only do the screen measure when needed.
boolean newRenderSize = false;
if (mMeasuredScreenWidth == -1) {
newRenderSize = true;
- mMeasuredScreenWidth = mParams.getScreenWidth();
- mMeasuredScreenHeight = mParams.getScreenHeight() - mTotalBarSize;
+ mMeasuredScreenWidth = params.getScreenWidth();
+ mMeasuredScreenHeight = params.getScreenHeight();
if (renderingMode != RenderingMode.NORMAL) {
// measure the full size needed by the layout.
@@ -473,64 +412,44 @@ public class RenderSessionImpl extends FrameworkResourceIdProvider {
// create the BufferedImage into which the layout will be rendered.
boolean newImage = false;
if (newRenderSize || mCanvas == null) {
- if (mParams.getImageFactory() != null) {
- mImage = mParams.getImageFactory().getImage(
+ if (params.getImageFactory() != null) {
+ mImage = params.getImageFactory().getImage(
mMeasuredScreenWidth,
- mMeasuredScreenHeight + mTotalBarSize);
+ mMeasuredScreenHeight);
} else {
mImage = new BufferedImage(
mMeasuredScreenWidth,
- mMeasuredScreenHeight + mTotalBarSize,
+ mMeasuredScreenHeight,
BufferedImage.TYPE_INT_ARGB);
newImage = true;
}
- if (mParams.isBgColorOverridden()) {
+ if (params.isBgColorOverridden()) {
// since we override the content, it's the same as if it was a new image.
newImage = true;
Graphics2D gc = mImage.createGraphics();
- gc.setColor(new Color(mParams.getOverrideBgColor(), true));
+ gc.setColor(new Color(params.getOverrideBgColor(), true));
gc.setComposite(AlphaComposite.Src);
- gc.fillRect(0, 0, mMeasuredScreenWidth,
- mMeasuredScreenHeight + mTotalBarSize);
+ gc.fillRect(0, 0, mMeasuredScreenWidth, mMeasuredScreenHeight);
gc.dispose();
}
// create an Android bitmap around the BufferedImage
Bitmap bitmap = Bitmap_Delegate.createBitmap(mImage,
- true /*isMutable*/,
- Density.getEnum(mParams.getDensity()));
+ true /*isMutable*/, params.getDensity());
// create a Canvas around the Android bitmap
mCanvas = new Canvas(bitmap);
- mCanvas.setDensity(mParams.getDensity());
- mCanvas.translate(0, mTopOffset);
+ mCanvas.setDensity(params.getDensity().getDpiValue());
}
if (freshRender && newImage == false) {
Graphics2D gc = mImage.createGraphics();
gc.setComposite(AlphaComposite.Src);
- if (mStatusBarSize > 0) {
- gc.setColor(new Color(0xFF3C3C3C, true));
- gc.fillRect(0, 0, mMeasuredScreenWidth, mStatusBarSize);
- }
-
- if (mTopBarSize > 0) {
- gc.setColor(new Color(0xFF7F7F7F, true));
- gc.fillRect(0, mStatusBarSize, mMeasuredScreenWidth, mTopOffset);
- }
-
- // erase the rest
gc.setColor(new Color(0x00000000, true));
- gc.fillRect(0, mTopOffset,
- mMeasuredScreenWidth, mMeasuredScreenHeight + mTopOffset);
-
- if (mSystemBarSize > 0) {
- gc.setColor(new Color(0xFF3C3C3C, true));
- gc.fillRect(0, mMeasuredScreenHeight + mTopOffset,
- mMeasuredScreenWidth, mMeasuredScreenHeight + mTotalBarSize);
- }
+ gc.fillRect(0, 0,
+ mMeasuredScreenWidth, mMeasuredScreenHeight);
// done
gc.dispose();
@@ -538,7 +457,7 @@ public class RenderSessionImpl extends FrameworkResourceIdProvider {
mViewRoot.draw(mCanvas);
- mViewInfoList = visitAllChildren((ViewGroup)mViewRoot, mContext, mTopOffset);
+ mViewInfoList = startVisitingViews(mViewRoot, 0);
// success!
return SUCCESS.createResult();
@@ -561,33 +480,35 @@ public class RenderSessionImpl extends FrameworkResourceIdProvider {
* @throws IllegalStateException if the current context is different than the one owned by
* the scene, or if {@link #acquire(long)} was not called.
*
- * @see LayoutScene#animate(Object, String, boolean, IAnimationListener)
+ * @see RenderSession#animate(Object, String, boolean, IAnimationListener)
*/
public Result animate(Object targetObject, String animationName,
boolean isFrameworkAnimation, IAnimationListener listener) {
checkLock();
+ BridgeContext context = getContext();
+
// find the animation file.
ResourceValue animationResource = null;
int animationId = 0;
if (isFrameworkAnimation) {
- animationResource = mContext.getRenderResources().getFrameworkResource(
+ animationResource = context.getRenderResources().getFrameworkResource(
ResourceType.ANIMATOR, animationName);
if (animationResource != null) {
animationId = Bridge.getResourceId(ResourceType.ANIMATOR, animationName);
}
} else {
- animationResource = mContext.getRenderResources().getProjectResource(
+ animationResource = context.getRenderResources().getProjectResource(
ResourceType.ANIMATOR, animationName);
if (animationResource != null) {
- animationId = mContext.getProjectCallback().getResourceId(
+ animationId = context.getProjectCallback().getResourceId(
ResourceType.ANIMATOR, animationName);
}
}
if (animationResource != null) {
try {
- Animator anim = AnimatorInflater.loadAnimator(mContext, animationId);
+ Animator anim = AnimatorInflater.loadAnimator(context, animationId);
if (anim != null) {
anim.setTarget(targetObject);
@@ -617,14 +538,16 @@ public class RenderSessionImpl extends FrameworkResourceIdProvider {
* @throws IllegalStateException if the current context is different than the one owned by
* the scene, or if {@link #acquire(long)} was not called.
*
- * @see LayoutScene#insertChild(Object, ILayoutPullParser, int, IAnimationListener)
+ * @see RenderSession#insertChild(Object, ILayoutPullParser, int, IAnimationListener)
*/
public Result insertChild(final ViewGroup parentView, ILayoutPullParser childXml,
final int index, IAnimationListener listener) {
checkLock();
+ BridgeContext context = getContext();
+
// create a block parser for the XML
- BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(childXml, mContext,
+ BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(childXml, context,
false /* platformResourceFlag */);
// inflate the child without adding it to the root since we want to control where it'll
@@ -696,7 +619,7 @@ public class RenderSessionImpl extends FrameworkResourceIdProvider {
* @throws IllegalStateException if the current context is different than the one owned by
* the scene, or if {@link #acquire(long)} was not called.
*
- * @see LayoutScene#moveChild(Object, Object, int, Map, IAnimationListener)
+ * @see RenderSession#moveChild(Object, Object, int, Map, IAnimationListener)
*/
public Result moveChild(final ViewGroup newParentView, final View childView, final int index,
Map<String, String> layoutParamsMap, final IAnimationListener listener) {
@@ -892,7 +815,7 @@ public class RenderSessionImpl extends FrameworkResourceIdProvider {
* @throws IllegalStateException if the current context is different than the one owned by
* the scene, or if {@link #acquire(long)} was not called.
*
- * @see LayoutScene#removeChild(Object, IAnimationListener)
+ * @see RenderSession#removeChild(Object, IAnimationListener)
*/
public Result removeChild(final View childView, IAnimationListener listener) {
checkLock();
@@ -947,37 +870,9 @@ public class RenderSessionImpl extends FrameworkResourceIdProvider {
}
}
- /**
- * Returns the log associated with the session.
- * @return the log or null if there are none.
- */
- public LayoutLog getLog() {
- if (mParams != null) {
- return mParams.getLog();
- }
-
- 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.
- */
- private void checkLock() {
- ReentrantLock lock = Bridge.getLock();
- if (lock.isHeldByCurrentThread() == false) {
- 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");
- }
- }
private void findBackground(RenderResources resources) {
- if (mParams.isBgColorOverridden() == false) {
+ if (getParams().isBgColorOverridden() == false) {
mWindowBackground = resources.findItemInTheme("windowBackground");
if (mWindowBackground != null) {
mWindowBackground = resources.resolveResValue(mWindowBackground);
@@ -986,35 +881,7 @@ public class RenderSessionImpl extends FrameworkResourceIdProvider {
}
private boolean isTabletUi() {
- return mParams.getConfigScreenSize() == ScreenSize.XLARGE;
- }
-
- private boolean isHCApp() {
- RenderResources resources = mContext.getRenderResources();
-
- // the app must say it targets 11+ and the theme name must extend Theme.Holo or
- // Theme.Holo.Light (which does not extend Theme.Holo, but Theme.Light)
- if (mParams.getTargetSdkVersion() < 11) {
- return false;
- }
-
- StyleResourceValue currentTheme = resources.getCurrentTheme();
- StyleResourceValue holoTheme = resources.getTheme("Theme.Holo", true /*frameworkTheme*/);
-
- if (currentTheme == holoTheme ||
- resources.themeIsParentOf(holoTheme, currentTheme)) {
- return true;
- }
-
- StyleResourceValue holoLightTheme = resources.getTheme("Theme.Holo.Light",
- true /*frameworkTheme*/);
-
- if (currentTheme == holoLightTheme ||
- resources.themeIsParentOf(holoLightTheme, currentTheme)) {
- return true;
- }
-
- return false;
+ return getParams().getConfigScreenSize() == ScreenSize.XLARGE;
}
private void findStatusBar(RenderResources resources, DisplayMetrics metrics) {
@@ -1022,7 +889,7 @@ public class RenderSessionImpl extends FrameworkResourceIdProvider {
boolean windowFullscreen = getBooleanThemeValue(resources,
"windowFullscreen", false /*defaultValue*/);
- if (windowFullscreen == false) {
+ if (windowFullscreen == false && mWindowIsFloating == false) {
// default value
mStatusBarSize = DEFAULT_STATUS_BAR_HEIGHT;
@@ -1041,20 +908,11 @@ public class RenderSessionImpl extends FrameworkResourceIdProvider {
}
}
- private void findTopBar(RenderResources resources, DisplayMetrics metrics) {
- boolean windowIsFloating = getBooleanThemeValue(resources,
- "windowIsFloating", true /*defaultValue*/);
-
- if (windowIsFloating == false) {
- if (isHCApp()) {
- findActionBar(resources, metrics);
- } else {
- findTitleBar(resources, metrics);
- }
+ private void findActionBar(RenderResources resources, DisplayMetrics metrics) {
+ if (mWindowIsFloating) {
+ return;
}
- }
- private void findActionBar(RenderResources resources, DisplayMetrics metrics) {
boolean windowActionBar = getBooleanThemeValue(resources,
"windowActionBar", true /*defaultValue*/);
@@ -1062,7 +920,7 @@ public class RenderSessionImpl extends FrameworkResourceIdProvider {
if (windowActionBar) {
// default size of the window title bar
- mTopBarSize = DEFAULT_TITLE_BAR_HEIGHT;
+ mActionBarSize = DEFAULT_TITLE_BAR_HEIGHT;
// get value from the theme.
ResourceValue value = resources.findItemInTheme("actionBarSize");
@@ -1075,44 +933,43 @@ public class RenderSessionImpl extends FrameworkResourceIdProvider {
TypedValue typedValue = ResourceHelper.getValue(value.getValue());
if (typedValue != null) {
// compute the pixel value based on the display metrics
- mTopBarSize = (int)typedValue.getDimension(metrics);
+ mActionBarSize = (int)typedValue.getDimension(metrics);
}
}
- }
- }
+ } else {
+ // action bar overrides title bar so only look for this one if action bar is hidden
+ boolean windowNoTitle = getBooleanThemeValue(resources,
+ "windowNoTitle", false /*defaultValue*/);
- private void findTitleBar(RenderResources resources, DisplayMetrics metrics) {
- boolean windowNoTitle = getBooleanThemeValue(resources,
- "windowNoTitle", false /*defaultValue*/);
+ if (windowNoTitle == false) {
- if (windowNoTitle == false) {
+ // default size of the window title bar
+ mTitleBarSize = DEFAULT_TITLE_BAR_HEIGHT;
- // default size of the window title bar
- mTopBarSize = DEFAULT_TITLE_BAR_HEIGHT;
+ // get value from the theme.
+ ResourceValue value = resources.findItemInTheme("windowTitleSize");
- // get value from the theme.
- ResourceValue value = resources.findItemInTheme("windowTitleSize");
+ // resolve it
+ value = resources.resolveResValue(value);
- // resolve it
- value = resources.resolveResValue(value);
-
- if (value != null) {
- // get the numerical value, if available
- TypedValue typedValue = ResourceHelper.getValue(value.getValue());
- if (typedValue != null) {
- // compute the pixel value based on the display metrics
- mTopBarSize = (int)typedValue.getDimension(metrics);
+ if (value != null) {
+ // get the numerical value, if available
+ TypedValue typedValue = ResourceHelper.getValue(value.getValue());
+ if (typedValue != null) {
+ // compute the pixel value based on the display metrics
+ mTitleBarSize = (int)typedValue.getDimension(metrics);
+ }
}
}
+
}
}
private void findSystemBar(RenderResources resources, DisplayMetrics metrics) {
- if (isTabletUi() && getBooleanThemeValue(
- resources, "windowIsFloating", true /*defaultValue*/) == false) {
+ if (isTabletUi() && mWindowIsFloating == false) {
// default value
- mSystemBarSize = 56; // ??
+ mSystemBarSize = 48; // ??
// get the real value
ResourceValue value = resources.getFrameworkResource(ResourceType.DIMEN,
@@ -1221,7 +1078,7 @@ public class RenderSessionImpl extends FrameworkResourceIdProvider {
tabHost.getResources().getDrawable(android.R.drawable.ic_menu_info_details))
.setContent(new TabHost.TabContentFactory() {
public View createTabContent(String tag) {
- return new LinearLayout(mContext);
+ return new LinearLayout(getContext());
}
});
tabHost.addTab(spec);
@@ -1244,40 +1101,71 @@ public class RenderSessionImpl extends FrameworkResourceIdProvider {
}
}
+ private List<ViewInfo> startVisitingViews(View view, int offset) {
+ if (view == null) {
+ return null;
+ }
+
+ // adjust the offset to this view.
+ offset += view.getTop();
+
+ if (view == mContentRoot) {
+ return visitAllChildren(mContentRoot, offset);
+ }
+
+ // otherwise, look for mContentRoot in the children
+ if (view instanceof ViewGroup) {
+ ViewGroup group = ((ViewGroup) view);
+
+ for (int i = 0; i < group.getChildCount(); i++) {
+ List<ViewInfo> list = startVisitingViews(group.getChildAt(i), offset);
+ if (list != null) {
+ return list;
+ }
+ }
+ }
+
+ return null;
+ }
/**
* Visits a View and its children and generate a {@link ViewInfo} containing the
* bounds of all the views.
* @param view the root View
- * @param context the context.
+ * @param offset an offset for the view bounds.
*/
- private ViewInfo visit(View view, BridgeContext context, int offset) {
+ private ViewInfo visit(View view, int offset) {
if (view == null) {
return null;
}
ViewInfo result = new ViewInfo(view.getClass().getName(),
- context.getViewKey(view),
+ getContext().getViewKey(view),
view.getLeft(), view.getTop() + offset, view.getRight(), view.getBottom() + offset,
view, view.getLayoutParams());
if (view instanceof ViewGroup) {
ViewGroup group = ((ViewGroup) view);
- result.setChildren(visitAllChildren(group, context, 0 /*offset*/));
+ result.setChildren(visitAllChildren(group, 0 /*offset*/));
}
return result;
}
- private List<ViewInfo> visitAllChildren(ViewGroup viewGroup, BridgeContext context,
- int offset) {
+ /**
+ * Visits all the children of a given ViewGroup generate a list of {@link ViewInfo}
+ * containing the bounds of all the views.
+ * @param view the root View
+ * @param offset an offset for the view bounds.
+ */
+ private List<ViewInfo> visitAllChildren(ViewGroup viewGroup, int offset) {
if (viewGroup == null) {
return null;
}
List<ViewInfo> children = new ArrayList<ViewInfo>();
for (int i = 0; i < viewGroup.getChildCount(); i++) {
- children.add(visit(viewGroup.getChildAt(i), context, offset));
+ children.add(visit(viewGroup.getChildAt(i), offset));
}
return children;
}
@@ -1300,7 +1188,7 @@ public class RenderSessionImpl extends FrameworkResourceIdProvider {
}
public Map<String, String> getDefaultProperties(Object viewObject) {
- return mContext.getDefaultPropMap(viewObject);
+ return getContext().getDefaultPropMap(viewObject);
}
public void setScene(RenderSession session) {
@@ -1310,11 +1198,4 @@ public class RenderSessionImpl extends FrameworkResourceIdProvider {
public RenderSession getSession() {
return mScene;
}
-
- // --- FrameworkResourceIdProvider methods
-
- @Override
- public Integer getId(ResourceType resType, String resName) {
- return Bridge.getResourceId(resType, resName);
- }
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
index 25bb81c..cea7cf3 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
@@ -18,6 +18,7 @@ package com.android.layoutlib.bridge.impl;
import com.android.ide.common.rendering.api.DensityBasedResourceValue;
import com.android.ide.common.rendering.api.LayoutLog;
+import com.android.ide.common.rendering.api.RenderResources;
import com.android.ide.common.rendering.api.ResourceValue;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.android.BridgeContext;
@@ -28,7 +29,9 @@ import com.android.resources.Density;
import org.kxml2.io.KXmlParser;
import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import android.content.res.ColorStateList;
import android.graphics.Bitmap;
import android.graphics.Bitmap_Delegate;
import android.graphics.NinePatch_Delegate;
@@ -108,19 +111,63 @@ public final class ResourceHelper {
throw new NumberFormatException();
}
+ public static ColorStateList getColorStateList(ResourceValue resValue, BridgeContext context) {
+ String value = resValue.getValue();
+ if (value != null) {
+ // first check if the value is a file (xml most likely)
+ File f = new File(value);
+ if (f.isFile()) {
+ try {
+ // let the framework inflate the ColorStateList from the XML file, by
+ // providing an XmlPullParser
+ KXmlParser parser = new KXmlParser();
+ parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
+ parser.setInput(new FileReader(f));
+
+ return ColorStateList.createFromXml(context.getResources(),
+ new BridgeXmlBlockParser(parser, context, resValue.isFramework()));
+ } catch (XmlPullParserException e) {
+ Bridge.getLog().error(LayoutLog.TAG_BROKEN,
+ "Failed to configure parser for " + value, e, null /*data*/);
+ // we'll return null below.
+ } catch (Exception e) {
+ // this is an error and not warning since the file existence is
+ // checked before attempting to parse it.
+ Bridge.getLog().error(LayoutLog.TAG_RESOURCES_READ,
+ "Failed to parse file " + value, e, null /*data*/);
+
+ return null;
+ }
+ } else {
+ // try to load the color state list from an int
+ try {
+ int color = ResourceHelper.getColor(value);
+ return ColorStateList.valueOf(color);
+ } catch (NumberFormatException e) {
+ Bridge.getLog().error(LayoutLog.TAG_RESOURCES_FORMAT,
+ "Failed to convert " + value + " into a ColorStateList", e,
+ null /*data*/);
+ return null;
+ }
+ }
+ }
+
+ return null;
+ }
+
/**
* Returns a drawable from the given value.
* @param value The value that contains a path to a 9 patch, a bitmap or a xml based drawable,
* or an hexadecimal color
- * @param context
- * @param isFramework indicates whether the resource is a framework resources.
- * Framework resources are cached, and loaded only once.
+ * @param context the current context
*/
- public static Drawable getDrawable(ResourceValue value, BridgeContext context,
- boolean isFramework) {
+ public static Drawable getDrawable(ResourceValue value, BridgeContext context) {
Drawable d = null;
String stringValue = value.getValue();
+ if (RenderResources.REFERENCE_NULL.equals(stringValue)) {
+ return null;
+ }
String lowerCaseValue = stringValue.toLowerCase();
@@ -129,9 +176,9 @@ public final class ResourceHelper {
if (file.isFile()) {
// see if we still have both the chunk and the bitmap in the caches
NinePatchChunk chunk = Bridge.getCached9Patch(stringValue,
- isFramework ? null : context.getProjectKey());
+ value.isFramework() ? null : context.getProjectKey());
Bitmap bitmap = Bridge.getCachedBitmap(stringValue,
- isFramework ? null : context.getProjectKey());
+ value.isFramework() ? null : context.getProjectKey());
// if either chunk or bitmap is null, then we reload the 9-patch file.
if (chunk == null || bitmap == null) {
@@ -143,7 +190,7 @@ public final class ResourceHelper {
chunk = ninePatch.getChunk();
Bridge.setCached9Patch(stringValue, chunk,
- isFramework ? null : context.getProjectKey());
+ value.isFramework() ? null : context.getProjectKey());
}
if (bitmap == null) {
@@ -158,7 +205,7 @@ public final class ResourceHelper {
density);
Bridge.setCachedBitmap(stringValue, bitmap,
- isFramework ? null : context.getProjectKey());
+ value.isFramework() ? null : context.getProjectKey());
}
}
} catch (MalformedURLException e) {
@@ -192,7 +239,7 @@ public final class ResourceHelper {
parser.setInput(new FileReader(f));
d = Drawable.createFromXml(context.getResources(),
- new BridgeXmlBlockParser(parser, context, isFramework));
+ new BridgeXmlBlockParser(parser, context, value.isFramework()));
return d;
} catch (Exception e) {
// this is an error and not warning since the file existence is checked before
@@ -212,7 +259,7 @@ public final class ResourceHelper {
if (bmpFile.isFile()) {
try {
Bitmap bitmap = Bridge.getCachedBitmap(stringValue,
- isFramework ? null : context.getProjectKey());
+ value.isFramework() ? null : context.getProjectKey());
if (bitmap == null) {
Density density = Density.MEDIUM;
@@ -223,7 +270,7 @@ public final class ResourceHelper {
bitmap = Bitmap_Delegate.createBitmap(bmpFile, false /*isMutable*/,
density);
Bridge.setCachedBitmap(stringValue, bitmap,
- isFramework ? null : context.getProjectKey());
+ value.isFramework() ? null : context.getProjectKey());
}
return new BitmapDrawable(context.getResources(), bitmap);
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index 291f076..fb215ab 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -112,6 +112,7 @@ public final class CreateInfo implements ICreateInfo {
"android.animation.PropertyValuesHolder",
"android.graphics.AvoidXfermode",
"android.graphics.Bitmap",
+ "android.graphics.BitmapFactory",
"android.graphics.BitmapShader",
"android.graphics.BlurMaskFilter",
"android.graphics.Canvas",
@@ -164,7 +165,6 @@ public final class CreateInfo implements ICreateInfo {
*/
private final static String[] RENAMED_CLASSES =
new String[] {
- "android.graphics.BitmapFactory", "android.graphics._Original_BitmapFactory",
"android.os.ServiceManager", "android.os._Original_ServiceManager",
"android.view.SurfaceView", "android.view._Original_SurfaceView",
"android.view.accessibility.AccessibilityManager", "android.view.accessibility._Original_AccessibilityManager",