Merge "Fixed 3423072 Imported 1080x720 video clips present distorted view" into honeycomb
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index ac3df79..13ea13f 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -500,7 +500,7 @@
choosehtv, fm, hasTabOrEmoji,
needMultiply, paraStart, chdirs, dir, easy,
paraEnd == bufend, includepad, trackpad,
- chs, widths, here - paraStart,
+ chs, widths, paraStart,
ellipsize, ellipsizedWidth, w, paint);
}
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 @@
mDialog.setOnDismissListener(new OnDismissListener() {
public void onDismiss(DialogInterface dialog) {
mActiveStreamType = -1;
+ mAudioManager.forceVolumeControlStream(mActiveStreamType);
}
});
// Change some window properties
@@ -483,6 +484,7 @@
}
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 @@
}
}
- 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 @@
@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 @@
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 @@
<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>, <code>GT</code>, <code>GR</code></td>
<td><em>Allow access according to Policy constraints.</em></td>
@@ -2201,6 +2201,17 @@
</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 @@
<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 @@
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—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—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 @@
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 @@
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 @@
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 @@
}
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 @@
Vector<SkPaint*> mPaints;
Vector<SkPath*> mPaths;
+ Vector<SkPath*> mOriginalPaths;
Vector<SkMatrix*> mMatrices;
Vector<SkiaShader*> mShaders;
@@ -293,6 +294,10 @@
return mPaths;
}
+ const Vector<SkPath*>& getOriginalPaths() const {
+ return mOriginalPaths;
+ }
+
const Vector<SkMatrix*>& getMatrices() const {
return mMatrices;
}
@@ -371,6 +376,9 @@
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 @@
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 @@
#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 @@
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 @@
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::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 @@
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 @@
kBitmap,
kShader,
kColorFilter,
+ kPath,
};
class ResourceReference {
@@ -53,15 +54,18 @@
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/hwui/Snapshot.h b/libs/hwui/Snapshot.h
index 595ad4e..bd70319 100644
--- a/libs/hwui/Snapshot.h
+++ b/libs/hwui/Snapshot.h
@@ -150,6 +150,10 @@
break;
case SkRegion::kIntersect_Op:
clipped = clipRect->intersect(r);
+ if (!clipped) {
+ clipRect->setEmpty();
+ clipped = true;
+ }
break;
case SkRegion::kUnion_Op:
clipped = clipRect->unionWith(r);
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 @@
{ "__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 @@
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 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 @@
* 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 @@
* 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 @@
}
/**
+ * 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 @@
(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 @@
/** @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 @@
// 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 @@
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/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 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..d3505849 100755
--- a/media/java/android/media/videoeditor/MediaVideoItem.java
+++ b/media/java/android/media/videoeditor/MediaVideoItem.java
@@ -139,6 +139,11 @@
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/jni/mediaeditor/Android.mk b/media/jni/mediaeditor/Android.mk
index 9c21e5e..6a7116c 100755
--- a/media/jni/mediaeditor/Android.mk
+++ b/media/jni/mediaeditor/Android.mk
@@ -66,8 +66,7 @@
-DUSE_STAGEFRIGHT_AUDIOENC \
-DUSE_STAGEFRIGHT_VIDEOENC \
-DUSE_STAGEFRIGHT_READERS \
- -DUSE_STAGEFRIGHT_3GPP_READER \
- -DUSE_SOFTWARE_DECODER
+ -DUSE_STAGEFRIGHT_3GPP_READER
LOCAL_LDFLAGS += -fuse-ld=bfd
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
index 76c05d2..bb326fe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
@@ -20,11 +20,13 @@
import android.app.Notification;
import android.app.NotificationManager;
+import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.location.LocationManager;
+import android.provider.Settings;
import android.util.Slog;
import android.view.View;
import android.widget.ImageView;
@@ -83,10 +85,15 @@
try {
if (visible) {
+ Intent gpsIntent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
+ gpsIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, gpsIntent, 0);
+
Notification n = new Notification.Builder(mContext)
.setSmallIcon(iconId)
.setContentTitle(mContext.getText(textResId))
.setOngoing(true)
+ .setContentIntent(pendingIntent)
.getNotification();
// Notification.Builder will helpfully fill these out for you no matter what you do
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 @@
boolean changed = setRotationUncheckedLocked(
WindowManagerPolicy.USE_LAST_ROTATION, 0, false);
if (changed) {
- sendNewConfiguration();
+ mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
}
}
@@ -11075,7 +11075,7 @@
boolean changed = setRotationUncheckedLocked(
WindowManagerPolicy.USE_LAST_ROTATION, 0, false);
if (changed) {
- sendNewConfiguration();
+ mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
}
}
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index 3535809..f72de127 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -32,6 +32,15 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
+
+ <activity
+ android:name="MarqueeActivity"
+ android:label="_Marquee">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
<activity
android:name="ShapesActivity"
diff --git a/tests/HwAccelerationTest/res/anim/accelerate_interpolator_2.xml b/tests/HwAccelerationTest/res/anim/accelerate_interpolator_2.xml
new file mode 100644
index 0000000..e4a8d48
--- /dev/null
+++ b/tests/HwAccelerationTest/res/anim/accelerate_interpolator_2.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+-->
+
+<accelerateInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:factor="2.0"/>
diff --git a/tests/HwAccelerationTest/res/anim/slide_off_left.xml b/tests/HwAccelerationTest/res/anim/slide_off_left.xml
new file mode 100644
index 0000000..f05de39
--- /dev/null
+++ b/tests/HwAccelerationTest/res/anim/slide_off_left.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<translate xmlns:android="http://schemas.android.com/apk/res/android"
+ android:fromXDelta="0%"
+ android:toXDelta="-100%"
+ android:interpolator="@anim/accelerate_interpolator_2"
+ android:duration="600"/>
\ No newline at end of file
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/MarqueeActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/MarqueeActivity.java
new file mode 100644
index 0000000..715cdbb
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/MarqueeActivity.java
@@ -0,0 +1,68 @@
+/*
+ * 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.test.hwui;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.view.View;
+import android.view.animation.Animation;
+import android.view.animation.AnimationUtils;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+@SuppressWarnings({"UnusedDeclaration"})
+public class MarqueeActivity extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ final LinearLayout linearLayout = new LinearLayout(this);
+ linearLayout.setOrientation(LinearLayout.VERTICAL);
+
+ final TextView text1 = new TextView(this);
+ text1.setText("This is a marquee inside a TextView");
+ text1.setSingleLine(true);
+ text1.setHorizontalFadingEdgeEnabled(true);
+ text1.setEllipsize(TextUtils.TruncateAt.MARQUEE);
+ linearLayout.addView(text1, new LinearLayout.LayoutParams(
+ 100, LinearLayout.LayoutParams.WRAP_CONTENT));
+
+ final TextView text2 = new TextView(this);
+ text2.setText("This is a marquee inside a TextView");
+ text2.setSingleLine(true);
+ text2.setHorizontalFadingEdgeEnabled(true);
+ text2.setEllipsize(TextUtils.TruncateAt.MARQUEE);
+ LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
+ 100, LinearLayout.LayoutParams.WRAP_CONTENT);
+ linearLayout.addView(text2, params);
+
+ setContentView(linearLayout);
+
+ getWindow().getDecorView().postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ text2.setVisibility(View.INVISIBLE);
+ Animation animation = AnimationUtils.loadAnimation(text2.getContext(),
+ R.anim.slide_off_left);
+ animation.setFillEnabled(true);
+ animation.setFillAfter(true);
+ text2.startAnimation(animation);
+ }
+ }, 1000);
+ }
+}
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 @@
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
index 993c305..ee60eb4 100644
--- a/tools/layoutlib/bridge/src/android/graphics/BitmapFactory.java
+++ b/tools/layoutlib/bridge/src/android/graphics/BitmapFactory.java
@@ -18,6 +18,9 @@
import com.android.ide.common.rendering.api.LayoutLog;
import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.android.BridgeResources.NinePatchInputStream;
+import com.android.ninepatch.NinePatch;
+import com.android.ninepatch.NinePatchChunk;
import com.android.resources.Density;
import android.content.res.AssetManager;
@@ -438,6 +441,8 @@
return null;
}
+ boolean isNinePatch = is instanceof NinePatchInputStream;
+
// we need mark/reset to work properly
if (!is.markSupported()) {
@@ -466,7 +471,29 @@
if (opts != null) {
density = Density.getEnum(opts.inDensity);
}
- bm = Bitmap_Delegate.createBitmap(is, true, density);
+
+ if (isNinePatch) {
+ // load the bitmap as a nine patch
+ NinePatch ninePatch = NinePatch.load(is, 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[] padding = chunk.getPadding();
+ outPadding.left = padding[0];
+ outPadding.top = padding[1];
+ outPadding.right = padding[2];
+ outPadding.bottom = padding[3];
+ } else {
+ // load the bitmap directly.
+ bm = Bitmap_Delegate.createBitmap(is, true, density);
+ }
} catch (IOException e) {
return null;
}
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..65f6bed 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -21,7 +21,7 @@
import com.android.ide.common.rendering.api.Capability;
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.RenderSession;
import com.android.ide.common.rendering.api.Result;
import com.android.layoutlib.bridge.android.BridgeAssetManager;
@@ -293,15 +293,15 @@
/**
* 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 RenderParams} 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(RenderParams params) {
try {
Result lastResult = SUCCESS.createResult();
RenderSessionImpl scene = new RenderSessionImpl(params);
@@ -331,10 +331,6 @@
}
}
- /*
- * (non-Javadoc)
- * @see com.android.layoutlib.api.ILayoutLibBridge#clearCaches(java.lang.Object)
- */
@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 @@
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 @@
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 @@
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 @@
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 @@
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/BridgeResources.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeResources.java
index 5ea0a8d..d31fcc8 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.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,18 @@
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 {
+ public NinePatchInputStream(File file) throws FileNotFoundException {
+ super(file);
+ }
+ }
+
+ /**
* This initializes the static field {@link Resources#mSystem} which is used
* by methods who get global resources using {@link Resources#getSystem()}.
* <p/>
@@ -129,7 +142,7 @@
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 +178,9 @@
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 +540,19 @@
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 +574,17 @@
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 @@
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/RenderSessionImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
index c8ad1d6..0aa2e6d 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
@@ -29,14 +29,13 @@
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.ViewInfo;
-import com.android.ide.common.rendering.api.Params.RenderingMode;
+import com.android.ide.common.rendering.api.RenderParams.RenderingMode;
import com.android.ide.common.rendering.api.RenderResources.FrameworkResourceIdProvider;
import com.android.ide.common.rendering.api.Result.Status;
import com.android.internal.util.XmlUtils;
@@ -47,11 +46,16 @@
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;
@@ -105,7 +109,7 @@
*/
private static BridgeContext sCurrentContext = null;
- private final Params mParams;
+ private final RenderParams mParams;
// scene state
private RenderSession mScene;
@@ -113,17 +117,18 @@
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 +151,9 @@
*
* @see LayoutBridge#createScene(com.android.layoutlib.api.SceneParams)
*/
- public RenderSessionImpl(Params params) {
+ public RenderSessionImpl(RenderParams params) {
// copy the params.
- mParams = new Params(params);
+ mParams = new RenderParams(params);
}
/**
@@ -172,8 +177,8 @@
// setup the display Metrics.
DisplayMetrics metrics = new DisplayMetrics();
- metrics.densityDpi = mParams.getDensity();
- metrics.density = mParams.getDensity() / (float) DisplayMetrics.DENSITY_DEFAULT;
+ 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();
@@ -190,17 +195,16 @@
mIsAlphaChannelImage = getBooleanThemeValue(resources,
"windowIsFloating", true /*defaultValue*/);
+ mWindowIsFloating = getBooleanThemeValue(resources, "windowIsFloating",
+ true /*defaultValue*/);
setUp();
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);
@@ -353,13 +357,100 @@
try {
- mViewRoot = new FrameLayout(mContext);
+ if (mWindowIsFloating || mParams.isForceNoDecor()) {
+ mViewRoot = mContentRoot = new FrameLayout(mContext);
+ } 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(mContext);
+ mViewRoot = topLayout;
+ topLayout.setOrientation(LinearLayout.VERTICAL);
+
+ if (mStatusBarSize > 0) {
+ // system bar
+ try {
+ PhoneSystemBar systemBar = new PhoneSystemBar(mContext,
+ mParams.getDensity());
+ systemBar.setLayoutParams(
+ new LinearLayout.LayoutParams(
+ LayoutParams.MATCH_PARENT, mStatusBarSize));
+ topLayout.addView(systemBar);
+ } catch (XmlPullParserException e) {
+
+ }
+ }
+
+ // if the theme says no title/action bar, then the size will be 0
+ if (mActionBarSize > 0) {
+ try {
+ FakeActionBar actionBar = new FakeActionBar(mContext,
+ mParams.getDensity(),
+ mParams.getAppLabel(), mParams.getAppIcon());
+ actionBar.setLayoutParams(
+ new LinearLayout.LayoutParams(
+ LayoutParams.MATCH_PARENT, mActionBarSize));
+ topLayout.addView(actionBar);
+ } catch (XmlPullParserException e) {
+
+ }
+ } else if (mTitleBarSize > 0) {
+ try {
+ TitleBar titleBar = new TitleBar(mContext,
+ mParams.getDensity(), mParams.getAppLabel());
+ titleBar.setLayoutParams(
+ new LinearLayout.LayoutParams(
+ LayoutParams.MATCH_PARENT, mTitleBarSize));
+ topLayout.addView(titleBar);
+ } catch (XmlPullParserException e) {
+
+ }
+ }
+
+
+ // content frame
+ mContentRoot = new FrameLayout(mContext);
+ LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
+ LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
+ params.weight = 1;
+ mContentRoot.setLayoutParams(params);
+ topLayout.addView(mContentRoot);
+
+ if (mSystemBarSize > 0) {
+ // system bar
+ try {
+ TabletSystemBar systemBar = new TabletSystemBar(mContext,
+ mParams.getDensity());
+ systemBar.setLayoutParams(
+ new LinearLayout.LayoutParams(
+ LayoutParams.MATCH_PARENT, mSystemBarSize));
+ topLayout.addView(systemBar);
+ } catch (XmlPullParserException e) {
+
+ }
+ }
+
+ }
+
// Sets the project callback (custom view loader) to the fragment delegate so that
// it can instantiate the custom Fragment.
Fragment_Delegate.setProjectCallback(mParams.getProjectCallback());
- View view = mInflater.inflate(mBlockParser, mViewRoot);
+ View view = mInflater.inflate(mBlockParser, mContentRoot);
Fragment_Delegate.setProjectCallback(null);
@@ -377,9 +468,8 @@
// get the background drawable
if (mWindowBackground != null) {
- Drawable d = ResourceHelper.getDrawable(mWindowBackground,
- mContext, true /* isFramework */);
- mViewRoot.setBackgroundDrawable(d);
+ Drawable d = ResourceHelper.getDrawable(mWindowBackground, mContext);
+ mContentRoot.setBackgroundDrawable(d);
}
return SUCCESS.createResult();
@@ -408,8 +498,8 @@
* @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();
@@ -428,7 +518,7 @@
if (mMeasuredScreenWidth == -1) {
newRenderSize = true;
mMeasuredScreenWidth = mParams.getScreenWidth();
- mMeasuredScreenHeight = mParams.getScreenHeight() - mTotalBarSize;
+ mMeasuredScreenHeight = mParams.getScreenHeight();
if (renderingMode != RenderingMode.NORMAL) {
// measure the full size needed by the layout.
@@ -476,11 +566,11 @@
if (mParams.getImageFactory() != null) {
mImage = mParams.getImageFactory().getImage(
mMeasuredScreenWidth,
- mMeasuredScreenHeight + mTotalBarSize);
+ mMeasuredScreenHeight);
} else {
mImage = new BufferedImage(
mMeasuredScreenWidth,
- mMeasuredScreenHeight + mTotalBarSize,
+ mMeasuredScreenHeight,
BufferedImage.TYPE_INT_ARGB);
newImage = true;
}
@@ -491,46 +581,26 @@
Graphics2D gc = mImage.createGraphics();
gc.setColor(new Color(mParams.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*/, mParams.getDensity());
// create a Canvas around the Android bitmap
mCanvas = new Canvas(bitmap);
- mCanvas.setDensity(mParams.getDensity());
- mCanvas.translate(0, mTopOffset);
+ mCanvas.setDensity(mParams.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 +608,7 @@
mViewRoot.draw(mCanvas);
- mViewInfoList = visitAllChildren((ViewGroup)mViewRoot, mContext, mTopOffset);
+ mViewInfoList = startVisitingViews(mViewRoot, 0);
// success!
return SUCCESS.createResult();
@@ -561,7 +631,7 @@
* @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) {
@@ -617,7 +687,7 @@
* @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) {
@@ -696,7 +766,7 @@
* @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 +962,7 @@
* @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();
@@ -989,40 +1059,12 @@
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;
- }
-
private void findStatusBar(RenderResources resources, DisplayMetrics metrics) {
if (isTabletUi() == false) {
boolean windowFullscreen = getBooleanThemeValue(resources,
"windowFullscreen", false /*defaultValue*/);
- if (windowFullscreen == false) {
+ if (windowFullscreen == false && mWindowIsFloating == false) {
// default value
mStatusBarSize = DEFAULT_STATUS_BAR_HEIGHT;
@@ -1041,20 +1083,11 @@
}
}
- 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;
+ }
+
boolean windowActionBar = getBooleanThemeValue(resources,
"windowActionBar", true /*defaultValue*/);
@@ -1062,7 +1095,7 @@
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 +1108,43 @@
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,
@@ -1244,40 +1276,71 @@
}
}
+ 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),
+ mContext.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;
}
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 @@
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 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 @@
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 @@
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 @@
chunk = ninePatch.getChunk();
Bridge.setCached9Patch(stringValue, chunk,
- isFramework ? null : context.getProjectKey());
+ value.isFramework() ? null : context.getProjectKey());
}
if (bitmap == null) {
@@ -158,7 +205,7 @@
density);
Bridge.setCachedBitmap(stringValue, bitmap,
- isFramework ? null : context.getProjectKey());
+ value.isFramework() ? null : context.getProjectKey());
}
}
} catch (MalformedURLException e) {
@@ -192,7 +239,7 @@
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 @@
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 @@
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);