Merge "Fix crash in dump function."
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index 25d868f..22876c0 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -112,6 +112,9 @@
// Only show an annoying dialog at most every 30 seconds
private static final long MIN_DIALOG_INTERVAL_MS = 30000;
+ // How many Span tags (e.g. animations) to report.
+ private static final int MAX_SPAN_TAGS = 20;
+
// How many offending stacks to keep track of (and time) per loop
// of the Looper.
private static final int MAX_OFFENSES_PER_LOOP = 10;
@@ -1217,6 +1220,140 @@
}
/**
+ * A tracked, critical time span. (e.g. during an animation.)
+ *
+ * The object itself is a linked list node, to avoid any allocations
+ * during rapid span entries and exits.
+ *
+ * @hide
+ */
+ public static class Span {
+ private String mName;
+ private long mCreateMillis;
+ private Span mNext;
+ private Span mPrev; // not used when in freeList, only active
+ private final ThreadSpanState mContainerState;
+
+ Span(ThreadSpanState threadState) {
+ mContainerState = threadState;
+ }
+
+ /**
+ * To be called when the critical span is complete (i.e. the
+ * animation is done animating). This can be called on any
+ * thread (even a different one from where the animation was
+ * taking place), but that's only a defensive implementation
+ * measure. It really makes no sense for you to call this on
+ * thread other than that where you created it.
+ *
+ * @hide
+ */
+ public void finish() {
+ ThreadSpanState state = mContainerState;
+ synchronized (state) {
+ if (mName == null) {
+ // Duplicate finish call. Ignore.
+ return;
+ }
+
+ // Remove ourselves from the active list.
+ if (mPrev != null) {
+ mPrev.mNext = mNext;
+ }
+ if (mNext != null) {
+ mNext.mPrev = mPrev;
+ }
+ if (state.mActiveHead == this) {
+ state.mActiveHead = mNext;
+ }
+
+ this.mCreateMillis = -1;
+ this.mName = null;
+ this.mPrev = null;
+ this.mNext = null;
+ state.mActiveSize--;
+
+ // Add ourselves to the freeList, if it's not already
+ // too big.
+ if (state.mFreeListSize < 5) {
+ this.mNext = state.mFreeListHead;
+ state.mFreeListHead = this;
+ state.mFreeListSize++;
+ }
+ }
+ }
+ }
+
+ /**
+ * Linked lists of active spans and a freelist.
+ *
+ * Locking notes: there's one of these structures per thread and
+ * all members of this structure (as well as the Span nodes under
+ * it) are guarded by the ThreadSpanState object instance. While
+ * in theory there'd be no locking required because it's all local
+ * per-thread, the finish() method above is defensive against
+ * people calling it on a different thread from where they created
+ * the Span, hence the locking.
+ */
+ private static class ThreadSpanState {
+ public Span mActiveHead; // doubly-linked list.
+ public int mActiveSize;
+ public Span mFreeListHead; // singly-linked list. only changes at head.
+ public int mFreeListSize;
+ }
+
+ private static final ThreadLocal<ThreadSpanState> sThisThreadSpanState =
+ new ThreadLocal<ThreadSpanState>() {
+ @Override protected ThreadSpanState initialValue() {
+ return new ThreadSpanState();
+ }
+ };
+
+ /**
+ * Enter a named critical span (e.g. an animation)
+ *
+ * <p>The name is an arbitary label (or tag) that will be applied
+ * to any strictmode violation that happens while this span is
+ * active. You must call finish() on the span when done.
+ *
+ * <p>This will never return null, but on devices without debugging
+ * enabled, this may return a dummy object on which the finish()
+ * method is a no-op.
+ *
+ * <p>TODO: add CloseGuard to this, verifying callers call finish.
+ *
+ * @hide
+ */
+ public static Span enterCriticalSpan(String name) {
+ if (name == null || name.isEmpty()) {
+ throw new IllegalArgumentException("name must be non-null and non-empty");
+ }
+ ThreadSpanState state = sThisThreadSpanState.get();
+ Span span = null;
+ synchronized (state) {
+ if (state.mFreeListHead != null) {
+ span = state.mFreeListHead;
+ state.mFreeListHead = span.mNext;
+ state.mFreeListSize--;
+ } else {
+ // Shouldn't have to do this often.
+ span = new Span(state);
+ }
+ span.mName = name;
+ span.mCreateMillis = SystemClock.uptimeMillis();
+ span.mNext = state.mActiveHead;
+ span.mPrev = null;
+ state.mActiveHead = span;
+ state.mActiveSize++;
+ if (span.mNext != null) {
+ span.mNext.mPrev = span;
+ }
+ }
+ return span;
+ }
+
+
+ /**
* Parcelable that gets sent in Binder call headers back to callers
* to report violations that happened during a cross-process call.
*
@@ -1245,6 +1382,12 @@
public int numAnimationsRunning = 0;
/**
+ * List of tags from active Span instances during this
+ * violation, or null for none.
+ */
+ public String[] tags;
+
+ /**
* Which violation number this was (1-based) since the last Looper loop,
* from the perspective of the root caller (if it crossed any processes
* via Binder calls). The value is 0 if the root caller wasn't on a Looper
@@ -1284,6 +1427,23 @@
if (broadcastIntent != null) {
broadcastIntentAction = broadcastIntent.getAction();
}
+ ThreadSpanState state = sThisThreadSpanState.get();
+ synchronized (state) {
+ int spanActiveCount = state.mActiveSize;
+ if (spanActiveCount > MAX_SPAN_TAGS) {
+ spanActiveCount = MAX_SPAN_TAGS;
+ }
+ if (spanActiveCount != 0) {
+ this.tags = new String[spanActiveCount];
+ Span iter = state.mActiveHead;
+ int index = 0;
+ while (iter != null && index < spanActiveCount) {
+ this.tags[index] = iter.mName;
+ index++;
+ iter = iter.mNext;
+ }
+ }
+ }
}
/**
@@ -1312,6 +1472,7 @@
numAnimationsRunning = in.readInt();
violationUptimeMillis = in.readLong();
broadcastIntentAction = in.readString();
+ tags = in.readStringArray();
}
/**
@@ -1325,6 +1486,7 @@
dest.writeInt(numAnimationsRunning);
dest.writeLong(violationUptimeMillis);
dest.writeString(broadcastIntentAction);
+ dest.writeStringArray(tags);
}
@@ -1347,6 +1509,12 @@
if (broadcastIntentAction != null) {
pw.println(prefix + "broadcastIntentAction: " + broadcastIntentAction);
}
+ if (tags != null) {
+ int index = 0;
+ for (String tag : tags) {
+ pw.println(prefix + "tag[" + (index++) + "]: " + tag);
+ }
+ }
}
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 454ef4d..026f1a0 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -8637,7 +8637,6 @@
public void setBackgroundColor(int color) {
if (mBGDrawable instanceof ColorDrawable) {
((ColorDrawable) mBGDrawable).setColor(color);
- invalidate();
} else {
setBackgroundDrawable(new ColorDrawable(color));
}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index fb760ac7..f3f9a6d 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -6529,8 +6529,11 @@
// If the text entry has created more events, ignore
// this one.
} else if (msg.arg2 == mTextGeneration) {
- mWebTextView.setTextAndKeepSelection(
- (String) msg.obj);
+ String text = (String) msg.obj;
+ if (null == text) {
+ text = "";
+ }
+ mWebTextView.setTextAndKeepSelection(text);
}
}
break;
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 3838a02..fdd75d5 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -23,6 +23,7 @@
import android.R;
import android.content.ClipData;
+import android.content.ClipData.Item;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -88,6 +89,7 @@
import android.util.TypedValue;
import android.view.ActionMode;
import android.view.ContextMenu;
+import android.view.DragEvent;
import android.view.Gravity;
import android.view.HapticFeedbackConstants;
import android.view.KeyEvent;
@@ -759,6 +761,13 @@
BufferType bufferType = BufferType.EDITABLE;
+ final int variation =
+ inputType & (EditorInfo.TYPE_MASK_CLASS | EditorInfo.TYPE_MASK_VARIATION);
+ final boolean passwordInputType = variation
+ == (EditorInfo.TYPE_CLASS_TEXT | EditorInfo.TYPE_TEXT_VARIATION_PASSWORD);
+ final boolean webPasswordInputType = variation
+ == (EditorInfo.TYPE_CLASS_TEXT | EditorInfo.TYPE_TEXT_VARIATION_WEB_PASSWORD);
+
if (inputMethod != null) {
Class<?> c;
@@ -854,19 +863,18 @@
}
}
- if (password) {
- // Caller used the deprecated xml attribute "password". Ensure that
- // the inputType is correct.
- boolean normalText = (mInputType & EditorInfo.TYPE_MASK_CLASS)
- == EditorInfo.TYPE_CLASS_TEXT;
- if (normalText && !isPasswordInputType(mInputType)) {
+ // mInputType has been set from inputType, possibly modified by mInputMethod.
+ // Specialize mInputType to [web]password if we have a text class and the original input
+ // type was a password.
+ if ((mInputType & EditorInfo.TYPE_MASK_CLASS) == EditorInfo.TYPE_CLASS_TEXT) {
+ if (password || passwordInputType) {
mInputType = (mInputType & ~(EditorInfo.TYPE_MASK_VARIATION))
- | EditorInfo.TYPE_TEXT_VARIATION_PASSWORD;
+ | EditorInfo.TYPE_TEXT_VARIATION_PASSWORD;
}
- } else if (isPasswordInputType(mInputType)) {
- // Caller did not use the deprecated xml attribute "password", but
- // did set the input properly. Set password to true.
- password = true;
+ if (webPasswordInputType) {
+ mInputType = (mInputType & ~(EditorInfo.TYPE_MASK_VARIATION))
+ | EditorInfo.TYPE_TEXT_VARIATION_WEB_PASSWORD;
+ }
}
if (selectallonfocus) {
@@ -880,7 +888,10 @@
drawableLeft, drawableTop, drawableRight, drawableBottom);
setCompoundDrawablePadding(drawablePadding);
- setSingleLine(singleLine);
+ // Same as setSingleLine, but make sure the transformation method is unchanged.
+ setInputTypeSingleLine(singleLine);
+ applySingleLine(singleLine, false);
+
if (singleLine && mInput == null && ellipsize < 0) {
ellipsize = 3; // END
}
@@ -909,13 +920,11 @@
}
setRawTextSize(textSize);
- if (password) {
+ if (password || passwordInputType || webPasswordInputType) {
setTransformationMethod(PasswordTransformationMethod.getInstance());
typefaceIndex = MONOSPACE;
- } else if ((mInputType&(EditorInfo.TYPE_MASK_CLASS
- |EditorInfo.TYPE_MASK_VARIATION))
- == (EditorInfo.TYPE_CLASS_TEXT
- |EditorInfo.TYPE_TEXT_VARIATION_PASSWORD)) {
+ } else if ((mInputType & (EditorInfo.TYPE_MASK_CLASS | EditorInfo.TYPE_MASK_VARIATION))
+ == (EditorInfo.TYPE_CLASS_TEXT | EditorInfo.TYPE_TEXT_VARIATION_PASSWORD)) {
typefaceIndex = MONOSPACE;
}
@@ -1146,7 +1155,9 @@
} catch (IncompatibleClassChangeError e) {
mInputType = EditorInfo.TYPE_CLASS_TEXT;
}
- setSingleLine(mSingleLine);
+ // Change inputType, without affecting transformation.
+ // No need to applySingleLine since mSingleLine is unchanged.
+ setInputTypeSingleLine(mSingleLine);
} else {
mInputType = EditorInfo.TYPE_NULL;
}
@@ -3049,21 +3060,19 @@
}
private boolean isPasswordInputType(int inputType) {
- final int variation = inputType & (EditorInfo.TYPE_MASK_CLASS
- | EditorInfo.TYPE_MASK_VARIATION);
+ final int variation =
+ inputType & (EditorInfo.TYPE_MASK_CLASS | EditorInfo.TYPE_MASK_VARIATION);
return variation
- == (EditorInfo.TYPE_CLASS_TEXT
- | EditorInfo.TYPE_TEXT_VARIATION_PASSWORD)
- || variation == (EditorInfo.TYPE_CLASS_TEXT
- | EditorInfo.TYPE_TEXT_VARIATION_WEB_PASSWORD);
+ == (EditorInfo.TYPE_CLASS_TEXT | EditorInfo.TYPE_TEXT_VARIATION_PASSWORD)
+ || variation
+ == (EditorInfo.TYPE_CLASS_TEXT | EditorInfo.TYPE_TEXT_VARIATION_WEB_PASSWORD);
}
private boolean isVisiblePasswordInputType(int inputType) {
- final int variation = inputType & (EditorInfo.TYPE_MASK_CLASS
- | EditorInfo.TYPE_MASK_VARIATION);
+ final int variation =
+ inputType & (EditorInfo.TYPE_MASK_CLASS | EditorInfo.TYPE_MASK_VARIATION);
return variation
- == (EditorInfo.TYPE_CLASS_TEXT
- | EditorInfo.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD);
+ == (EditorInfo.TYPE_CLASS_TEXT | EditorInfo.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD);
}
/**
@@ -6073,6 +6082,15 @@
*/
@android.view.RemotableViewMethod
public void setSingleLine(boolean singleLine) {
+ setInputTypeSingleLine(singleLine);
+ applySingleLine(singleLine, true);
+ }
+
+ /**
+ * Adds or remove the EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE on the mInputType.
+ * @param singleLine
+ */
+ private void setInputTypeSingleLine(boolean singleLine) {
if ((mInputType & EditorInfo.TYPE_MASK_CLASS) == EditorInfo.TYPE_CLASS_TEXT) {
if (singleLine) {
mInputType &= ~EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE;
@@ -6080,7 +6098,6 @@
mInputType |= EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE;
}
}
- applySingleLine(singleLine, true);
}
private void applySingleLine(boolean singleLine, boolean applyTransformation) {
@@ -6731,10 +6748,6 @@
mMovement.onTakeFocus(this, (Spannable) mText, direction);
}
- if (mSelectAllOnFocus) {
- Selection.setSelection((Spannable) mText, 0, mText.length());
- }
-
// The DecorView does not have focus when the 'Done' ExtractEditText button is
// pressed. Since it is the ViewRoot's mView, it requests focus before
// ExtractEditText clears focus, which gives focus to the ExtractEditText.
@@ -6753,6 +6766,11 @@
*/
Selection.setSelection((Spannable) mText, selStart, selEnd);
}
+
+ if (mSelectAllOnFocus) {
+ Selection.setSelection((Spannable) mText, 0, mText.length());
+ }
+
mTouchFocusSelected = true;
}
@@ -7029,12 +7047,12 @@
|| windowParams.type > WindowManager.LayoutParams.LAST_SUB_WINDOW;
}
- // TODO Add an extra android:cursorController flag to disable the controller?
- if (windowSupportsHandles && mCursorVisible && mLayout != null) {
+ if (windowSupportsHandles && isTextEditable() && mCursorVisible && mLayout != null) {
if (mInsertionPointCursorController == null) {
mInsertionPointCursorController = new InsertionPointCursorController();
}
} else {
+ hideInsertionPointCursorController();
mInsertionPointCursorController = null;
}
@@ -7044,7 +7062,9 @@
}
} else {
// Stop selection mode if the controller becomes unavailable.
- stopSelectionActionMode();
+ if (mSelectionModifierCursorController != null) {
+ stopSelectionActionMode();
+ }
mSelectionModifierCursorController = null;
}
}
@@ -7053,7 +7073,7 @@
* @return True iff this TextView contains a text that can be edited.
*/
private boolean isTextEditable() {
- return mText instanceof Editable && onCheckIsTextEditor();
+ return mText instanceof Editable && onCheckIsTextEditor() && isEnabled();
}
/**
@@ -7684,13 +7704,53 @@
return packRangeInLong(min, max);
}
+ private DragThumbnailBuilder getTextThumbnailBuilder(CharSequence text) {
+ TextView thumbnail = (TextView) inflate(mContext,
+ com.android.internal.R.layout.text_drag_thumbnail, null);
+
+ if (thumbnail == null) {
+ throw new IllegalArgumentException("Unable to inflate text drag thumbnail");
+ }
+
+ if (text.length() > DRAG_THUMBNAIL_MAX_TEXT_LENGTH) {
+ text = text.subSequence(0, DRAG_THUMBNAIL_MAX_TEXT_LENGTH);
+ }
+ thumbnail.setText(text);
+ thumbnail.setTextColor(getTextColors());
+
+ thumbnail.setTextAppearance(mContext, R.styleable.Theme_textAppearanceLarge);
+ thumbnail.setGravity(Gravity.CENTER);
+
+ thumbnail.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT));
+
+ final int size = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
+ thumbnail.measure(size, size);
+
+ thumbnail.layout(0, 0, thumbnail.getMeasuredWidth(), thumbnail.getMeasuredHeight());
+ thumbnail.invalidate();
+ return new DragThumbnailBuilder(thumbnail);
+ }
+
@Override
public boolean performLongClick() {
if (super.performLongClick()) {
mEatTouchRelease = true;
return true;
}
-
+
+ if (mSelectionActionMode != null && touchPositionIsInSelection()) {
+ final int start = getSelectionStart();
+ final int end = getSelectionEnd();
+ CharSequence selectedText = mTransformed.subSequence(start, end);
+ ClipData data = ClipData.newPlainText(null, null, selectedText);
+ startDrag(data, getTextThumbnailBuilder(selectedText), false);
+ stopSelectionActionMode();
+ performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+ mEatTouchRelease = true;
+ return true;
+ }
+
if (startSelectionActionMode()) {
performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
mEatTouchRelease = true;
@@ -7830,6 +7890,8 @@
if (hasPasswordTransformationMethod()) {
// selectCurrentWord is not available on a password field and would return an
// arbitrary 10-charater selection around pressed position. Select all instead.
+ // Note that cut/copy menu entries are not available for passwords.
+ // This is however useful to delete or paste to replace the entire content.
Selection.setSelection((Spannable) mText, 0, mText.length());
} else {
selectCurrentWord();
@@ -8728,6 +8790,46 @@
return getOffsetForHorizontal(line, x);
}
+ @Override
+ public boolean onDragEvent(DragEvent event) {
+ switch (event.getAction()) {
+ case DragEvent.ACTION_DRAG_STARTED:
+ return mInsertionPointCursorController != null;
+
+ case DragEvent.ACTION_DRAG_ENTERED:
+ TextView.this.requestFocus();
+ return true;
+
+ case DragEvent.ACTION_DRAG_LOCATION: {
+ final int offset = getOffset((int)event.getX(), (int)event.getY());
+ Selection.setSelection((Spannable)mText, offset);
+ return true;
+ }
+
+ case DragEvent.ACTION_DROP: {
+ StringBuilder content = new StringBuilder("");
+ ClipData clipData = event.getClipData();
+ final int itemCount = clipData.getItemCount();
+ for (int i=0; i < itemCount; i++) {
+ Item item = clipData.getItem(i);
+ content.append(item.coerceToText(TextView.this.mContext));
+ }
+ final int offset = getOffset((int) event.getX(), (int) event.getY());
+ long minMax = prepareSpacesAroundPaste(offset, offset, content);
+ int min = extractRangeStartFromLong(minMax);
+ int max = extractRangeEndFromLong(minMax);
+ Selection.setSelection((Spannable) mText, max);
+ ((Editable) mText).replace(min, max, content);
+ return true;
+ }
+
+ case DragEvent.ACTION_DRAG_EXITED:
+ case DragEvent.ACTION_DRAG_ENDED:
+ default:
+ return true;
+ }
+ }
+
@ViewDebug.ExportedProperty(category = "text")
private CharSequence mText;
@@ -8822,4 +8924,5 @@
private static final InputFilter[] NO_FILTERS = new InputFilter[0];
private InputFilter[] mFilters = NO_FILTERS;
private static final Spanned EMPTY_SPANNED = new SpannedString("");
+ private static int DRAG_THUMBNAIL_MAX_TEXT_LENGTH = 20;
}
diff --git a/core/res/res/layout/text_drag_thumbnail.xml b/core/res/res/layout/text_drag_thumbnail.xml
new file mode 100644
index 0000000..63d2c05
--- /dev/null
+++ b/core/res/res/layout/text_drag_thumbnail.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* apps/common/assets/default/default/skins/StatusBar.xml
+**
+** Copyright 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.
+*/
+-->
+<TextView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="@android:style/TextAppearance.Large"
+ android:gravity="center"
+ />
diff --git a/docs/html/sdk/adding-components.jd b/docs/html/sdk/adding-components.jd
index 05be0d6..1f9cb31 100644
--- a/docs/html/sdk/adding-components.jd
+++ b/docs/html/sdk/adding-components.jd
@@ -150,14 +150,19 @@
<p>For example, there may be a dependency between the ADT Plugin for Eclipse and
the SDK Tools component. When you install the SDK Tools
-component, you would then need to upgrade to the required version of ADT (if you
-are developing in Eclipse). In this case, you would find dependencies listed in
-"Revisions" section of the <a href="{@docRoot}sdk/eclipse-adt.html#notes">ADT
-Plugin Notes</a> and <a href="{@docRoot}sdk/tools-notes.html#notes">SDK Tools
-Notes</a> documents. </p>
+component, you should also upgrade to the required version of ADT (if you
+are developing in Eclipse). In this case, the major version number for your ADT plugin should
+always match the revision number of your SDK Tools (for example, ADT 8.x requires SDK Tools r8).
+</p>
-<p>Additionally, the development tools will notify you with debug warnings
-if there is dependency that you need to address. </p>
+<p>Also make sure that, each time you install a new version of the Android platform, you have
+the latest version of the SDK Platform-tools component. The SDK Platform-tools contain
+tools that are backward compatible with all versions of the Android platform and are
+often updated to support new features in the latest version of the Android platform.</p>
+
+<p>The development tools will notify you with debug warnings if there is dependency that you need to
+address. The SDK and AVD Manager also enforces dependencies by requiring that you download any
+components that are needed by those you have selected.</p>
<h2 id="AddingSites">Adding New Sites</h2>
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index 32111e8..032244f 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -174,11 +174,14 @@
}
private void setBitmap(Bitmap bitmap) {
- mBitmap = bitmap;
- if (bitmap != null) {
- computeBitmapSize();
- } else {
- mBitmapWidth = mBitmapHeight = -1;
+ if (bitmap != mBitmap) {
+ mBitmap = bitmap;
+ if (bitmap != null) {
+ computeBitmapSize();
+ } else {
+ mBitmapWidth = mBitmapHeight = -1;
+ }
+ invalidateSelf();
}
}
@@ -205,10 +208,7 @@
* @see android.graphics.Bitmap#getDensity()
*/
public void setTargetDensity(DisplayMetrics metrics) {
- mTargetDensity = metrics.densityDpi;
- if (mBitmap != null) {
- computeBitmapSize();
- }
+ setTargetDensity(metrics.densityDpi);
}
/**
@@ -220,9 +220,12 @@
* @see android.graphics.Bitmap#getDensity()
*/
public void setTargetDensity(int density) {
- mTargetDensity = density == 0 ? DisplayMetrics.DENSITY_DEFAULT : density;
- if (mBitmap != null) {
- computeBitmapSize();
+ if (mTargetDensity != density) {
+ mTargetDensity = density == 0 ? DisplayMetrics.DENSITY_DEFAULT : density;
+ if (mBitmap != null) {
+ computeBitmapSize();
+ }
+ invalidateSelf();
}
}
@@ -239,22 +242,28 @@
* @param gravity the gravity
*/
public void setGravity(int gravity) {
- mBitmapState.mGravity = gravity;
- mApplyGravity = true;
+ if (mBitmapState.mGravity != gravity) {
+ mBitmapState.mGravity = gravity;
+ mApplyGravity = true;
+ invalidateSelf();
+ }
}
public void setAntiAlias(boolean aa) {
mBitmapState.mPaint.setAntiAlias(aa);
+ invalidateSelf();
}
@Override
public void setFilterBitmap(boolean filter) {
mBitmapState.mPaint.setFilterBitmap(filter);
+ invalidateSelf();
}
@Override
public void setDither(boolean dither) {
mBitmapState.mPaint.setDither(dither);
+ invalidateSelf();
}
public Shader.TileMode getTileModeX() {
@@ -280,6 +289,7 @@
state.mTileModeX = xmode;
state.mTileModeY = ymode;
mRebuildShader = true;
+ invalidateSelf();
}
}
@@ -336,11 +346,13 @@
@Override
public void setAlpha(int alpha) {
mBitmapState.mPaint.setAlpha(alpha);
+ invalidateSelf();
}
@Override
public void setColorFilter(ColorFilter cf) {
mBitmapState.mPaint.setColorFilter(cf);
+ invalidateSelf();
}
/**
diff --git a/graphics/java/android/graphics/drawable/ColorDrawable.java b/graphics/java/android/graphics/drawable/ColorDrawable.java
index 289348a..4d560be 100644
--- a/graphics/java/android/graphics/drawable/ColorDrawable.java
+++ b/graphics/java/android/graphics/drawable/ColorDrawable.java
@@ -87,7 +87,10 @@
* @param color The color to draw.
*/
public void setColor(int color) {
- mState.mBaseColor = mState.mUseColor = color;
+ if (mState.mBaseColor != color || mState.mUseColor != color) {
+ invalidateSelf();
+ mState.mBaseColor = mState.mUseColor = color;
+ }
}
/**
@@ -109,6 +112,7 @@
int baseAlpha = mState.mBaseColor >>> 24;
int useAlpha = baseAlpha * alpha >> 8;
mState.mUseColor = (mState.mBaseColor << 8 >>> 8) | (useAlpha << 24);
+ invalidateSelf();
}
/**
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index baa9d62..2f13bef 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -488,7 +488,10 @@
*/
public boolean setVisible(boolean visible, boolean restart) {
boolean changed = mVisible != visible;
- mVisible = visible;
+ if (changed) {
+ mVisible = visible;
+ invalidateSelf();
+ }
return changed;
}
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index c558632..da8bb1b 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -180,6 +180,7 @@
public void setCornerRadii(float[] radii) {
mGradientState.setCornerRadii(radii);
mPathIsDirty = true;
+ invalidateSelf();
}
/**
@@ -189,6 +190,7 @@
public void setCornerRadius(float radius) {
mGradientState.setCornerRadius(radius);
mPathIsDirty = true;
+ invalidateSelf();
}
/**
@@ -214,34 +216,41 @@
e = new DashPathEffect(new float[] { dashWidth, dashGap }, 0);
}
mStrokePaint.setPathEffect(e);
+ invalidateSelf();
}
public void setSize(int width, int height) {
mGradientState.setSize(width, height);
mPathIsDirty = true;
+ invalidateSelf();
}
public void setShape(int shape) {
mRingPath = null;
mPathIsDirty = true;
mGradientState.setShape(shape);
+ invalidateSelf();
}
public void setGradientType(int gradient) {
mGradientState.setGradientType(gradient);
mRectIsDirty = true;
+ invalidateSelf();
}
public void setGradientCenter(float x, float y) {
mGradientState.setGradientCenter(x, y);
+ invalidateSelf();
}
public void setGradientRadius(float gradientRadius) {
mGradientState.setGradientRadius(gradientRadius);
+ invalidateSelf();
}
public void setUseLevel(boolean useLevel) {
mGradientState.mUseLevel = useLevel;
+ invalidateSelf();
}
private int modulateAlpha(int alpha) {
@@ -433,6 +442,7 @@
public void setColor(int argb) {
mGradientState.setSolidColor(argb);
mFillPaint.setColor(argb);
+ invalidateSelf();
}
@Override
@@ -443,17 +453,26 @@
@Override
public void setAlpha(int alpha) {
- mAlpha = alpha;
+ if (alpha != mAlpha) {
+ mAlpha = alpha;
+ invalidateSelf();
+ }
}
@Override
public void setDither(boolean dither) {
- mDither = dither;
+ if (dither != mDither) {
+ mDither = dither;
+ invalidateSelf();
+ }
}
@Override
public void setColorFilter(ColorFilter cf) {
- mColorFilter = cf;
+ if (cf != mColorFilter) {
+ mColorFilter = cf;
+ invalidateSelf();
+ }
}
@Override
diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
index 50b4b75..35b8319 100644
--- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java
+++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
@@ -132,10 +132,7 @@
* @see android.graphics.Bitmap#getDensity()
*/
public void setTargetDensity(DisplayMetrics metrics) {
- mTargetDensity = metrics.densityDpi;
- if (mNinePatch != null) {
- computeBitmapSize();
- }
+ setTargetDensity(metrics.densityDpi);
}
/**
@@ -147,9 +144,12 @@
* @see android.graphics.Bitmap#getDensity()
*/
public void setTargetDensity(int density) {
- mTargetDensity = density == 0 ? DisplayMetrics.DENSITY_DEFAULT : density;
- if (mNinePatch != null) {
- computeBitmapSize();
+ if (density != mTargetDensity) {
+ mTargetDensity = density == 0 ? DisplayMetrics.DENSITY_DEFAULT : density;
+ if (mNinePatch != null) {
+ computeBitmapSize();
+ }
+ invalidateSelf();
}
}
@@ -197,16 +197,19 @@
@Override
public void setAlpha(int alpha) {
getPaint().setAlpha(alpha);
+ invalidateSelf();
}
@Override
public void setColorFilter(ColorFilter cf) {
getPaint().setColorFilter(cf);
+ invalidateSelf();
}
@Override
public void setDither(boolean dither) {
getPaint().setDither(dither);
+ invalidateSelf();
}
@Override
diff --git a/graphics/java/android/graphics/drawable/PaintDrawable.java b/graphics/java/android/graphics/drawable/PaintDrawable.java
index c86fc46..c71cda1 100644
--- a/graphics/java/android/graphics/drawable/PaintDrawable.java
+++ b/graphics/java/android/graphics/drawable/PaintDrawable.java
@@ -66,6 +66,7 @@
} else {
setShape(new RoundRectShape(radii, null, null));
}
+ invalidateSelf();
}
@Override
diff --git a/graphics/java/android/graphics/drawable/ShapeDrawable.java b/graphics/java/android/graphics/drawable/ShapeDrawable.java
index be1892e..92252fc 100644
--- a/graphics/java/android/graphics/drawable/ShapeDrawable.java
+++ b/graphics/java/android/graphics/drawable/ShapeDrawable.java
@@ -129,6 +129,7 @@
}
mShapeState.mPadding.set(left, top, right, bottom);
}
+ invalidateSelf();
}
/**
@@ -144,6 +145,7 @@
}
mShapeState.mPadding.set(padding);
}
+ invalidateSelf();
}
/**
@@ -153,6 +155,7 @@
*/
public void setIntrinsicWidth(int width) {
mShapeState.mIntrinsicWidth = width;
+ invalidateSelf();
}
/**
@@ -162,6 +165,7 @@
*/
public void setIntrinsicHeight(int height) {
mShapeState.mIntrinsicHeight = height;
+ invalidateSelf();
}
@Override
@@ -236,11 +240,13 @@
*/
@Override public void setAlpha(int alpha) {
mShapeState.mAlpha = alpha;
+ invalidateSelf();
}
@Override
public void setColorFilter(ColorFilter cf) {
mShapeState.mPaint.setColorFilter(cf);
+ invalidateSelf();
}
@Override
@@ -264,6 +270,7 @@
@Override
public void setDither(boolean dither) {
mShapeState.mPaint.setDither(dither);
+ invalidateSelf();
}
@Override
@@ -344,6 +351,7 @@
mShapeState.mPaint.setShader(mShapeState.mShaderFactory.resize(w, h));
}
}
+ invalidateSelf();
}
@Override
diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h
index 517868c..0aba347 100644
--- a/include/media/stagefright/OMXCodec.h
+++ b/include/media/stagefright/OMXCodec.h
@@ -293,6 +293,8 @@
uint32_t flags,
Vector<String8> *matchingCodecs);
+ void restorePatchedDataPointer(BufferInfo *info);
+
OMXCodec(const OMXCodec &);
OMXCodec &operator=(const OMXCodec &);
};
@@ -305,6 +307,7 @@
struct CodecCapabilities {
String8 mComponentName;
Vector<CodecProfileLevel> mProfileLevels;
+ Vector<OMX_U32> mColorFormats;
};
// Return a vector of componentNames with supported profile/level pairs
diff --git a/include/private/surfaceflinger/SharedBufferStack.h b/include/private/surfaceflinger/SharedBufferStack.h
index d6ae5e9..9d589cf 100644
--- a/include/private/surfaceflinger/SharedBufferStack.h
+++ b/include/private/surfaceflinger/SharedBufferStack.h
@@ -285,6 +285,8 @@
uint32_t getTransform(int buffer) const;
status_t resize(int newNumBuffers);
+ status_t grow(int newNumBuffers);
+ status_t shrink(int newNumBuffers);
SharedBufferStack::Statistics getStats() const;
@@ -346,6 +348,14 @@
int mNumBuffers;
BufferList mBufferList;
+ struct BuffersAvailableCondition : public ConditionBase {
+ int mNumBuffers;
+ inline BuffersAvailableCondition(SharedBufferServer* sbs,
+ int numBuffers);
+ inline bool operator()() const;
+ inline const char* name() const { return "BuffersAvailableCondition"; }
+ };
+
struct UnlockUpdate : public UpdateBase {
const int lockedBuffer;
inline UnlockUpdate(SharedBufferBase* sbb, int lockedBuffer);
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 540f115..acce1a2 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -1463,7 +1463,9 @@
dirtyLayer(left, top, right, bottom);
}
}
- mCaches.currentProgram->setColor(r, g, b, a);
+ if (!mShader || (mShader && setColor)) {
+ mCaches.currentProgram->setColor(r, g, b, a);
+ }
// Setup attributes and uniforms required by the shaders
if (mShader) {
diff --git a/libs/hwui/SkiaShader.cpp b/libs/hwui/SkiaShader.cpp
index e7e1187..590a9d7 100644
--- a/libs/hwui/SkiaShader.cpp
+++ b/libs/hwui/SkiaShader.cpp
@@ -63,8 +63,7 @@
GLuint* textureUnit) {
}
-void SkiaShader::bindTexture(Texture* texture, GLenum wrapS, GLenum wrapT, GLuint textureUnit) {
- glActiveTexture(gTextureUnitsMap[textureUnit]);
+void SkiaShader::bindTexture(Texture* texture, GLenum wrapS, GLenum wrapT) {
glBindTexture(GL_TEXTURE_2D, texture->id);
if (wrapS != texture->wrapS) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapS);
@@ -132,7 +131,7 @@
computeScreenSpaceMatrix(textureTransform, modelView);
// Uniforms
- bindTexture(texture, mWrapS, mWrapT, textureSlot);
+ bindTexture(texture, mWrapS, mWrapT);
glUniform1i(program->getUniform("bitmapSampler"), textureSlot);
glUniformMatrix4fv(program->getUniform("textureTransform"), 1,
GL_FALSE, &textureTransform.data[0]);
@@ -204,7 +203,7 @@
computeScreenSpaceMatrix(screenSpace, modelView);
// Uniforms
- bindTexture(texture, gTileModes[mTileX], gTileModes[mTileY], textureSlot);
+ bindTexture(texture, gTileModes[mTileX], gTileModes[mTileY]);
glUniform1i(program->getUniform("gradientSampler"), textureSlot);
glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]);
}
@@ -297,7 +296,7 @@
computeScreenSpaceMatrix(screenSpace, modelView);
// Uniforms
- bindTexture(texture, gTileModes[mTileX], gTileModes[mTileY], textureSlot);
+ bindTexture(texture, gTileModes[mTileX], gTileModes[mTileY]);
glUniform1i(program->getUniform("gradientSampler"), textureSlot);
glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]);
}
diff --git a/libs/hwui/SkiaShader.h b/libs/hwui/SkiaShader.h
index 1d884ab..6702129 100644
--- a/libs/hwui/SkiaShader.h
+++ b/libs/hwui/SkiaShader.h
@@ -97,7 +97,11 @@
void computeScreenSpaceMatrix(mat4& screenSpace, const mat4& modelView);
protected:
- inline void bindTexture(Texture* texture, GLenum wrapS, GLenum wrapT, GLuint textureUnit);
+ /**
+ * The appropriate texture unit must have been activated prior to invoking
+ * this method.
+ */
+ inline void bindTexture(Texture* texture, GLenum wrapS, GLenum wrapT);
Type mType;
SkShader* mKey;
diff --git a/libs/surfaceflinger_client/SharedBufferStack.cpp b/libs/surfaceflinger_client/SharedBufferStack.cpp
index 8f583f06..3b2ef84 100644
--- a/libs/surfaceflinger_client/SharedBufferStack.cpp
+++ b/libs/surfaceflinger_client/SharedBufferStack.cpp
@@ -265,6 +265,14 @@
(stack.queued > 0 && stack.inUse != buf));
}
+SharedBufferServer::BuffersAvailableCondition::BuffersAvailableCondition(
+ SharedBufferServer* sbs, int numBuffers) : ConditionBase(sbs),
+ mNumBuffers(numBuffers) {
+}
+bool SharedBufferServer::BuffersAvailableCondition::operator()() const {
+ return stack.available == mNumBuffers;
+}
+
// ----------------------------------------------------------------------------
SharedBufferClient::QueueUpdate::QueueUpdate(SharedBufferBase* sbb)
@@ -448,6 +456,7 @@
const nsecs_t now = systemTime(SYSTEM_TIME_THREAD);
stack.stats.totalTime = ns2us(now - mDequeueTime[buf]);
+
return err;
}
@@ -492,6 +501,7 @@
if (err == NO_ERROR) {
mNumBuffers = bufferCount;
queued_head = (stack.head + stack.queued) % mNumBuffers;
+ tail = computeTail();
}
return err;
}
@@ -606,17 +616,24 @@
*/
status_t SharedBufferServer::resize(int newNumBuffers)
{
- if (uint32_t(newNumBuffers) >= SharedBufferStack::NUM_BUFFER_MAX)
+ if ((unsigned int)(newNumBuffers) < SharedBufferStack::NUM_BUFFER_MIN ||
+ (unsigned int)(newNumBuffers) > SharedBufferStack::NUM_BUFFER_MAX) {
return BAD_VALUE;
+ }
RWLock::AutoWLock _l(mLock);
- // for now we're not supporting shrinking
- const int numBuffers = mNumBuffers;
- if (newNumBuffers < numBuffers)
- return BAD_VALUE;
+ if (newNumBuffers < mNumBuffers) {
+ return shrink(newNumBuffers);
+ } else {
+ return grow(newNumBuffers);
+ }
+}
+status_t SharedBufferServer::grow(int newNumBuffers)
+{
SharedBufferStack& stack( *mSharedStack );
+ const int numBuffers = mNumBuffers;
const int extra = newNumBuffers - numBuffers;
// read the head, make sure it's valid
@@ -650,6 +667,54 @@
return NO_ERROR;
}
+status_t SharedBufferServer::shrink(int newNumBuffers)
+{
+ SharedBufferStack& stack( *mSharedStack );
+
+ // Shrinking is only supported if there are no buffers currently dequeued.
+ int32_t avail = stack.available;
+ int32_t queued = stack.queued;
+ if (avail + queued != mNumBuffers) {
+ return INVALID_OPERATION;
+ }
+
+ // Wait for any queued buffers to be displayed.
+ BuffersAvailableCondition condition(this, mNumBuffers);
+ status_t err = waitForCondition(condition);
+ if (err < 0) {
+ return err;
+ }
+
+ // Reset head to index 0 and make it refer to buffer 0. The same renaming
+ // (head -> 0) is done in the BufferManager.
+ int32_t head = stack.head;
+ int8_t* index = const_cast<int8_t*>(stack.index);
+ for (int8_t i = 0; i < newNumBuffers; i++) {
+ index[i] = i;
+ }
+ stack.head = 0;
+ stack.headBuf = 0;
+
+ // If one of the buffers is in use it must be the head buffer, which we are
+ // renaming to buffer 0.
+ if (stack.inUse > 0) {
+ stack.inUse = 0;
+ }
+
+ // Free the buffers from the end of the list that are no longer needed.
+ for (int i = newNumBuffers; i < mNumBuffers; i++) {
+ mBufferList.remove(i);
+ }
+
+ // Tell the client to reallocate all the buffers.
+ reallocateAll();
+
+ mNumBuffers = newNumBuffers;
+ stack.available = newNumBuffers;
+
+ return NO_ERROR;
+}
+
SharedBufferStack::Statistics SharedBufferServer::getStats() const
{
SharedBufferStack& stack( *mSharedStack );
diff --git a/libs/surfaceflinger_client/Surface.cpp b/libs/surfaceflinger_client/Surface.cpp
index 7af6ce8..9467a4c 100644
--- a/libs/surfaceflinger_client/Surface.cpp
+++ b/libs/surfaceflinger_client/Surface.cpp
@@ -855,6 +855,12 @@
status_t err = mSharedBufferClient->setBufferCount(bufferCount, ipc);
LOGE_IF(err, "ISurface::setBufferCount(%d) returned %s",
bufferCount, strerror(-err));
+
+ if (err == NO_ERROR) {
+ // Clear out any references to the old buffers.
+ mBuffers.clear();
+ }
+
return err;
}
@@ -1029,7 +1035,7 @@
// one of the buffers for which we do know the index. This can happen
// e.g. if GraphicBuffer is used to wrap an android_native_buffer_t that
// was dequeued from an ANativeWindow.
- for (int i = 0; i < mBuffers.size(); i++) {
+ for (size_t i = 0; i < mBuffers.size(); i++) {
if (buffer->handle == mBuffers[i]->handle) {
idx = mBuffers[i]->getIndex();
break;
diff --git a/libs/surfaceflinger_client/tests/SharedBufferStack/SharedBufferStackTest.cpp b/libs/surfaceflinger_client/tests/SharedBufferStack/SharedBufferStackTest.cpp
index f409f48..7ef5926 100644
--- a/libs/surfaceflinger_client/tests/SharedBufferStack/SharedBufferStackTest.cpp
+++ b/libs/surfaceflinger_client/tests/SharedBufferStack/SharedBufferStackTest.cpp
@@ -32,7 +32,8 @@
int main(int argc, char** argv)
{
SharedClient client;
- SharedBufferServer s(&client, 0, 4, 0);
+ sp<SharedBufferServer> ps(new SharedBufferServer(&client, 0, 4, 0));
+ SharedBufferServer& s(*ps);
SharedBufferClient c(&client, 0, 4, 0);
printf("basic test 0\n");
@@ -67,6 +68,10 @@
int list3[6] = {3, 2, 1, 4, 5, 0};
test0(s, c, 6, list3);
+ c.setBufferCount(4, resize);
+ int list4[4] = {1, 2, 3, 0};
+ test0(s, c, 4, list4);
+
return 0;
}
diff --git a/media/java/android/media/MediaFile.java b/media/java/android/media/MediaFile.java
index 532a2df..80c97a0 100644
--- a/media/java/android/media/MediaFile.java
+++ b/media/java/android/media/MediaFile.java
@@ -170,6 +170,7 @@
addFileType("OTA", FILE_TYPE_MID, "audio/midi");
addFileType("MPEG", FILE_TYPE_MP4, "video/mpeg", MtpConstants.FORMAT_MPEG);
+ addFileType("MPG", FILE_TYPE_MP4, "video/mpeg", MtpConstants.FORMAT_MPEG);
addFileType("MP4", FILE_TYPE_MP4, "video/mp4", MtpConstants.FORMAT_MPEG);
addFileType("M4V", FILE_TYPE_M4V, "video/mp4", MtpConstants.FORMAT_MPEG);
addFileType("3GP", FILE_TYPE_3GPP, "video/3gpp", MtpConstants.FORMAT_3GP_CONTAINER);
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 9f9c83a..3d490c9 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -1913,6 +1913,13 @@
// Buffer could not be released until empty buffer done is called.
if (info->mMediaBuffer != NULL) {
+ if (mIsEncoder &&
+ (mQuirks & kAvoidMemcopyInputRecordingFrames)) {
+ // If zero-copy mode is enabled this will send the
+ // input buffer back to the upstream source.
+ restorePatchedDataPointer(info);
+ }
+
info->mMediaBuffer->release();
info->mMediaBuffer = NULL;
}
@@ -2462,6 +2469,7 @@
status_t err = mOMX->freeBuffer(mNode, portIndex, info->mBuffer);
if (err == OK && info->mMediaBuffer != NULL) {
+ CHECK_EQ(portIndex, kPortIndexOutput);
info->mMediaBuffer->setObserver(NULL);
// Make sure nobody but us owns this buffer at this point.
@@ -2474,6 +2482,7 @@
}
info->mMediaBuffer->release();
+ info->mMediaBuffer = NULL;
}
if (err == OK) {
@@ -2714,10 +2723,10 @@
if (mIsEncoder && (mQuirks & kAvoidMemcopyInputRecordingFrames)) {
CHECK(mOMXLivesLocally && offset == 0);
OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *) info->mBuffer;
+ CHECK(header->pBuffer == info->mData);
header->pBuffer = (OMX_U8 *) srcBuffer->data() + srcBuffer->range_offset();
releaseBuffer = false;
info->mMediaBuffer = srcBuffer;
- // FIXME: we are leaking memory
} else {
if (mIsMetaDataStoredInVideoBuffers) {
releaseBuffer = false;
@@ -3997,8 +4006,30 @@
caps->mProfileLevels.push(profileLevel);
}
+ // Color format query
+ OMX_VIDEO_PARAM_PORTFORMATTYPE portFormat;
+ InitOMXParams(&portFormat);
+ portFormat.nPortIndex = queryDecoders ? 1 : 0;
+ for (portFormat.nIndex = 0;; ++portFormat.nIndex) {
+ err = omx->getParameter(
+ node, OMX_IndexParamVideoPortFormat,
+ &portFormat, sizeof(portFormat));
+ if (err != OK) {
+ break;
+ }
+ caps->mColorFormats.push(portFormat.eColorFormat);
+ }
+
CHECK_EQ(omx->freeNode(node), OK);
}
}
+void OMXCodec::restorePatchedDataPointer(BufferInfo *info) {
+ CHECK(mIsEncoder && (mQuirks & kAvoidMemcopyInputRecordingFrames));
+ CHECK(mOMXLivesLocally);
+
+ OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)info->mBuffer;
+ header->pBuffer = (OMX_U8 *)info->mData;
+}
+
} // namespace android
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index ba8d7d2..1ec8a22 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -6702,9 +6702,14 @@
if (info.broadcastIntentAction != null) {
sb.append("Broadcast-Intent-Action: ").append(info.broadcastIntentAction).append("\n");
}
- if (info != null && info.durationMillis != -1) {
+ if (info.durationMillis != -1) {
sb.append("Duration-Millis: ").append(info.durationMillis).append("\n");
}
+ if (info.tags != null) {
+ for (String tag : info.tags) {
+ sb.append("Span-Tag: ").append(tag).append("\n");
+ }
+ }
sb.append("\n");
if (info.crashInfo != null && info.crashInfo.stackTrace != null) {
sb.append(info.crashInfo.stackTrace);
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index c9ab992..b5e73ac 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -218,25 +218,13 @@
break;
}
+ recordLastValue(buffer, count);
+
const SortedVector< wp<SensorEventConnection> > activeConnections(
getActiveConnections());
size_t numConnections = activeConnections.size();
if (numConnections) {
- Mutex::Autolock _l(mLock);
-
- // record the last event for each sensor
- int32_t prev = buffer[0].sensor;
- for (ssize_t i=1 ; i<count ; i++) {
- // record the last event of each sensor type in this buffer
- int32_t curr = buffer[i].sensor;
- if (curr != prev) {
- mLastEventSeen.editValueFor(prev) = buffer[i-1];
- prev = curr;
- }
- }
- mLastEventSeen.editValueFor(prev) = buffer[count-1];
-
for (size_t i=0 ; i<numConnections ; i++) {
sp<SensorEventConnection> connection(activeConnections[i].promote());
if (connection != 0) {
@@ -251,6 +239,24 @@
return false;
}
+void SensorService::recordLastValue(
+ sensors_event_t const * buffer, size_t count)
+{
+ Mutex::Autolock _l(mLock);
+
+ // record the last event for each sensor
+ int32_t prev = buffer[0].sensor;
+ for (size_t i=1 ; i<count ; i++) {
+ // record the last event of each sensor type in this buffer
+ int32_t curr = buffer[i].sensor;
+ if (curr != prev) {
+ mLastEventSeen.editValueFor(prev) = buffer[i-1];
+ prev = curr;
+ }
+ }
+ mLastEventSeen.editValueFor(prev) = buffer[count-1];
+}
+
SortedVector< wp<SensorService::SensorEventConnection> >
SensorService::getActiveConnections() const
{
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index dfb1c0e..b442779 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -111,6 +111,8 @@
String8 getSensorName(int handle) const;
status_t recomputeEventsPeriodLocked(int32_t handle);
+ void recordLastValue(sensors_event_t const * buffer, size_t count);
+
// constants
Vector<Sensor> mSensorList;
struct sensors_poll_device_t* mSensorDevice;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 1b06843..7be58c6 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -340,8 +340,10 @@
// NOTE: lcblk->resize() is protected by an internal lock
status_t err = lcblk->resize(bufferCount);
- if (err == NO_ERROR)
- mBufferManager.resize(bufferCount);
+ if (err == NO_ERROR) {
+ EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay());
+ mBufferManager.resize(bufferCount, mFlinger, dpy);
+ }
return err;
}
@@ -774,9 +776,52 @@
{
}
-status_t Layer::BufferManager::resize(size_t size)
+status_t Layer::BufferManager::resize(size_t size,
+ const sp<SurfaceFlinger>& flinger, EGLDisplay dpy)
{
Mutex::Autolock _l(mLock);
+
+ if (size < mNumBuffers) {
+ // Move the active texture into slot 0
+ BufferData activeBufferData = mBufferData[mActiveBuffer];
+ mBufferData[mActiveBuffer] = mBufferData[0];
+ mBufferData[0] = activeBufferData;
+ mActiveBuffer = 0;
+
+ // Free the buffers that are no longer needed.
+ for (size_t i = size; i < mNumBuffers; i++) {
+ mBufferData[i].buffer = 0;
+
+ // Create a message to destroy the textures on SurfaceFlinger's GL
+ // thread.
+ class MessageDestroyTexture : public MessageBase {
+ Image mTexture;
+ EGLDisplay mDpy;
+ public:
+ MessageDestroyTexture(const Image& texture, EGLDisplay dpy)
+ : mTexture(texture), mDpy(dpy) { }
+ virtual bool handler() {
+ status_t err = Layer::BufferManager::destroyTexture(
+ &mTexture, mDpy);
+ LOGE_IF(err<0, "error destroying texture: %d (%s)",
+ mTexture.name, strerror(-err));
+ return true; // XXX: err == 0; ????
+ }
+ };
+
+ MessageDestroyTexture *msg = new MessageDestroyTexture(
+ mBufferData[i].texture, dpy);
+
+ // Don't allow this texture to be cleaned up by
+ // BufferManager::destroy.
+ mBufferData[i].texture.name = -1U;
+ mBufferData[i].texture.image = EGL_NO_IMAGE_KHR;
+
+ // Post the message to the SurfaceFlinger object.
+ flinger->postMessageAsync(msg);
+ }
+ }
+
mNumBuffers = size;
return NO_ERROR;
}
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index caa6d17..07434cf 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -177,7 +177,8 @@
sp<GraphicBuffer> detachBuffer(size_t index);
status_t attachBuffer(size_t index, const sp<GraphicBuffer>& buffer);
// resize the number of active buffers
- status_t resize(size_t size);
+ status_t resize(size_t size, const sp<SurfaceFlinger>& flinger,
+ EGLDisplay dpy);
// ----------------------------------------------
// must be called from GL thread
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index c59f2fd..2e785aa 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -786,10 +786,6 @@
{
// compute the invalid region
mInvalidRegion.orSelf(mDirtyRegion);
- if (mInvalidRegion.isEmpty()) {
- // nothing to do
- return;
- }
if (UNLIKELY(mDebugRegion)) {
debugFlashRegions();
diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/EventSenderImpl.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/EventSenderImpl.java
index 68bcf11..d425734 100644
--- a/tests/DumpRenderTree2/src/com/android/dumprendertree2/EventSenderImpl.java
+++ b/tests/DumpRenderTree2/src/com/android/dumprendertree2/EventSenderImpl.java
@@ -56,21 +56,38 @@
private static final int MSG_SET_TOUCH_MODIFIER = 16;
private static final int MSG_CANCEL_TOUCH_POINT = 17;
- public static class TouchPoint {
- WebView mWebView;
- private int mId;
+ private static class Point {
private int mX;
private int mY;
+
+ public Point(int x, int y) {
+ mX = x;
+ mY = y;
+ }
+ public int x() {
+ return mX;
+ }
+ public int y() {
+ return mY;
+ }
+ }
+
+ private Point createViewPointFromContentCoordinates(int x, int y) {
+ return new Point((int)(x * mWebView.getScale()) - mWebView.getScrollX(),
+ (int)(y * mWebView.getScale()) - mWebView.getScrollY());
+ }
+
+ public static class TouchPoint {
+ private int mId;
+ private Point mPoint;
private long mDownTime;
private boolean mReleased = false;
private boolean mMoved = false;
private boolean mCancelled = false;
- public TouchPoint(WebView webView, int id, int x, int y) {
- mWebView = webView;
+ public TouchPoint(int id, Point point) {
mId = id;
- mX = scaleX(x);
- mY = scaleY(y);
+ mPoint = point;
}
public int getId() {
@@ -78,20 +95,19 @@
}
public int getX() {
- return mX;
+ return mPoint.x();
}
public int getY() {
- return mY;
+ return mPoint.y();
}
public boolean hasMoved() {
return mMoved;
}
- public void move(int newX, int newY) {
- mX = scaleX(newX);
- mY = scaleY(newY);
+ public void move(Point point) {
+ mPoint = point;
mMoved = true;
}
@@ -122,20 +138,11 @@
public void cancel() {
mCancelled = true;
}
-
- private int scaleX(int x) {
- return (int)(x * mWebView.getScale()) - mWebView.getScrollX();
- }
-
- private int scaleY(int y) {
- return (int)(y * mWebView.getScale()) - mWebView.getScrollY();
- }
}
private List<TouchPoint> mTouchPoints;
private int mTouchMetaState;
- private int mMouseX;
- private int mMouseY;
+ private Point mMousePoint;
private WebView mWebView;
@@ -177,15 +184,19 @@
/** MOUSE */
case MSG_MOUSE_DOWN:
- ts = SystemClock.uptimeMillis();
- event = MotionEvent.obtain(ts, ts, MotionEvent.ACTION_DOWN, mMouseX, mMouseY, 0);
- mWebView.onTouchEvent(event);
+ if (mMousePoint != null) {
+ ts = SystemClock.uptimeMillis();
+ event = MotionEvent.obtain(ts, ts, MotionEvent.ACTION_DOWN, mMousePoint.x(), mMousePoint.y(), 0);
+ mWebView.onTouchEvent(event);
+ }
break;
case MSG_MOUSE_UP:
- ts = SystemClock.uptimeMillis();
- event = MotionEvent.obtain(ts, ts, MotionEvent.ACTION_UP, mMouseX, mMouseY, 0);
- mWebView.onTouchEvent(event);
+ if (mMousePoint != null) {
+ ts = SystemClock.uptimeMillis();
+ event = MotionEvent.obtain(ts, ts, MotionEvent.ACTION_UP, mMousePoint.x(), mMousePoint.y(), 0);
+ mWebView.onTouchEvent(event);
+ }
break;
case MSG_MOUSE_CLICK:
@@ -194,8 +205,7 @@
break;
case MSG_MOUSE_MOVE_TO:
- mMouseX = msg.arg1;
- mMouseY = msg.arg2;
+ mMousePoint = createViewPointFromContentCoordinates(msg.arg1, msg.arg2);
break;
/** TOUCH */
@@ -208,8 +218,8 @@
} else {
id = getTouchPoints().get(numPoints - 1).getId() + 1;
}
- getTouchPoints().add(new TouchPoint(mWebView, id,
- msg.arg1, msg.arg2));
+ getTouchPoints().add(
+ new TouchPoint(id, createViewPointFromContentCoordinates(msg.arg1, msg.arg2)));
break;
case MSG_TOUCH_START:
@@ -232,7 +242,8 @@
break;
}
- getTouchPoints().get(index).move(bundle.getInt("x"), bundle.getInt("y"));
+ getTouchPoints().get(index).move(
+ createViewPointFromContentCoordinates(bundle.getInt("x"), bundle.getInt("y")));
break;
case MSG_TOUCH_MOVE:
@@ -333,8 +344,7 @@
mWebView = webView;
mTouchPoints = null;
mTouchMetaState = 0;
- mMouseX = 0;
- mMouseY = 0;
+ mMousePoint = null;
}
public void enableDOMUIEventLogging(int domNode) {
diff --git a/tools/layoutlib/bridge/.classpath b/tools/layoutlib/bridge/.classpath
index aeeffa6..7204ace 100644
--- a/tools/layoutlib/bridge/.classpath
+++ b/tools/layoutlib/bridge/.classpath
@@ -4,9 +4,9 @@
<classpathentry kind="src" path="tests"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/3"/>
- <classpathentry kind="var" path="ANDROID_SRC/prebuilt/common/layoutlib_api/layoutlib_api-prebuilt.jar"/>
- <classpathentry kind="var" path="ANDROID_SRC/prebuilt/common/kxml2/kxml2-2.3.0.jar" sourcepath="/ANDROID_SRC/dalvik/libcore/xml/src/main/java"/>
- <classpathentry kind="var" path="ANDROID_OUT_FRAMEWORK/ninepatch.jar" sourcepath="/ANDROID_SRC/development/tools/ninepatch/src"/>
+ <classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilt/common/layoutlib_api/layoutlib_api-prebuilt.jar"/>
+ <classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilt/common/kxml2/kxml2-2.3.0.jar" sourcepath="/ANDROID_PLAT_SRC/dalvik/libcore/xml/src/main/java"/>
+ <classpathentry kind="var" path="ANDROID_PLAT_OUT_FRAMEWORK/ninepatch.jar" sourcepath="/ANDROID_PLAT_SRC/development/tools/ninepatch/src"/>
<classpathentry kind="var" path="ANDROID_PLAT_SRC/out/host/common/obj/JAVA_LIBRARIES/temp_layoutlib_intermediates/javalib.jar" sourcepath="/ANDROID_PLAT_SRC/frameworks/base"/>
<classpathentry kind="output" path="bin"/>
</classpath>
diff --git a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
index e97b1e6..392462f 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
@@ -17,7 +17,7 @@
package android.graphics;
import com.android.layoutlib.api.IDensityBasedResourceValue.Density;
-import com.android.layoutlib.bridge.DelegateManager;
+import com.android.layoutlib.bridge.impl.DelegateManager;
import android.graphics.Bitmap.Config;
import android.os.Parcel;
diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
index ce8e960..374bbb4 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
@@ -17,7 +17,7 @@
package android.graphics;
import com.android.layoutlib.api.ILayoutLog;
-import com.android.layoutlib.bridge.DelegateManager;
+import com.android.layoutlib.bridge.impl.DelegateManager;
import android.graphics.Paint_Delegate.FontInfo;
import android.text.TextUtils;
diff --git a/tools/layoutlib/bridge/src/android/graphics/DashPathEffect_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/DashPathEffect_Delegate.java
index 59b6a91..7ee72d8 100644
--- a/tools/layoutlib/bridge/src/android/graphics/DashPathEffect_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/DashPathEffect_Delegate.java
@@ -16,7 +16,7 @@
package android.graphics;
-import com.android.layoutlib.bridge.DelegateManager;
+import com.android.layoutlib.bridge.impl.DelegateManager;
/**
* Delegate implementing the native methods of android.graphics.DashPathEffect
diff --git a/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java
index 405e537..7573dc1 100644
--- a/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java
@@ -16,7 +16,7 @@
package android.graphics;
-import com.android.layoutlib.bridge.DelegateManager;
+import com.android.layoutlib.bridge.impl.DelegateManager;
import android.graphics.Shader.TileMode;
diff --git a/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java
index 0966f39..77de32d 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java
@@ -17,7 +17,7 @@
package android.graphics;
-import com.android.layoutlib.bridge.DelegateManager;
+import com.android.layoutlib.bridge.impl.DelegateManager;
import android.graphics.Matrix.ScaleToFit;
diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
index 6e90bdd..d83a33b 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
@@ -16,7 +16,7 @@
package android.graphics;
-import com.android.layoutlib.bridge.DelegateManager;
+import com.android.layoutlib.bridge.impl.DelegateManager;
import android.graphics.Paint.FontMetrics;
import android.graphics.Paint.FontMetricsInt;
diff --git a/tools/layoutlib/bridge/src/android/graphics/PathEffect_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/PathEffect_Delegate.java
index 6827ae7..ce7eef0 100644
--- a/tools/layoutlib/bridge/src/android/graphics/PathEffect_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/PathEffect_Delegate.java
@@ -16,7 +16,7 @@
package android.graphics;
-import com.android.layoutlib.bridge.DelegateManager;
+import com.android.layoutlib.bridge.impl.DelegateManager;
/**
* Delegate implementing the native methods of android.graphics.PathEffect
diff --git a/tools/layoutlib/bridge/src/android/graphics/PorterDuffXfermode_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/PorterDuffXfermode_Delegate.java
index c242e80..a5885ea 100644
--- a/tools/layoutlib/bridge/src/android/graphics/PorterDuffXfermode_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/PorterDuffXfermode_Delegate.java
@@ -16,7 +16,7 @@
package android.graphics;
-import com.android.layoutlib.bridge.DelegateManager;
+import com.android.layoutlib.bridge.impl.DelegateManager;
/**
* Delegate implementing the native methods of android.graphics.PorterDuffXfermode
diff --git a/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java
index c4e764c..c36ce53 100644
--- a/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java
@@ -16,7 +16,7 @@
package android.graphics;
-import com.android.layoutlib.bridge.DelegateManager;
+import com.android.layoutlib.bridge.impl.DelegateManager;
import android.graphics.Shader.TileMode;
diff --git a/tools/layoutlib/bridge/src/android/graphics/Shader_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Shader_Delegate.java
index 4dcf144..646ac80 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Shader_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Shader_Delegate.java
@@ -16,7 +16,7 @@
package android.graphics;
-import com.android.layoutlib.bridge.DelegateManager;
+import com.android.layoutlib.bridge.impl.DelegateManager;
/**
* Delegate implementing the native methods of android.graphics.Shader
diff --git a/tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java
index 0492e4f..358c3c7 100644
--- a/tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java
@@ -16,7 +16,7 @@
package android.graphics;
-import com.android.layoutlib.bridge.DelegateManager;
+import com.android.layoutlib.bridge.impl.DelegateManager;
import java.awt.Paint;
diff --git a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
index 7e90e7d..0b54a0e 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
@@ -16,8 +16,8 @@
package android.graphics;
-import com.android.layoutlib.bridge.DelegateManager;
-import com.android.layoutlib.bridge.FontLoader;
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.layoutlib.bridge.impl.FontLoader;
import android.content.res.AssetManager;
diff --git a/tools/layoutlib/bridge/src/android/graphics/Xfermode_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Xfermode_Delegate.java
index d4408cf..0c1170d 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Xfermode_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Xfermode_Delegate.java
@@ -16,7 +16,7 @@
package android.graphics;
-import com.android.layoutlib.bridge.DelegateManager;
+import com.android.layoutlib.bridge.impl.DelegateManager;
/**
* Delegate implementing the native methods of android.graphics.Xfermode
diff --git a/tools/layoutlib/bridge/src/android/util/FloatMath_Delegate.java b/tools/layoutlib/bridge/src/android/util/FloatMath_Delegate.java
index ed24e16..9ca1338 100644
--- a/tools/layoutlib/bridge/src/android/util/FloatMath_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/util/FloatMath_Delegate.java
@@ -16,7 +16,7 @@
package android.util;
-import com.android.layoutlib.bridge.DelegateManager;
+import com.android.layoutlib.bridge.impl.DelegateManager;
/**
* Delegate implementing the native methods of android.util.FloatMath
diff --git a/tools/layoutlib/bridge/src/android/view/SurfaceView.java b/tools/layoutlib/bridge/src/android/view/SurfaceView.java
index ce32da9..f7db98a 100644
--- a/tools/layoutlib/bridge/src/android/view/SurfaceView.java
+++ b/tools/layoutlib/bridge/src/android/view/SurfaceView.java
@@ -16,7 +16,7 @@
package android.view;
-import com.android.layoutlib.bridge.MockView;
+import com.android.layoutlib.bridge.android.MockView;
import android.content.Context;
import android.graphics.Canvas;
diff --git a/tools/layoutlib/bridge/src/android/webkit/WebView.java b/tools/layoutlib/bridge/src/android/webkit/WebView.java
index 3b66188..a20a9d1 100644
--- a/tools/layoutlib/bridge/src/android/webkit/WebView.java
+++ b/tools/layoutlib/bridge/src/android/webkit/WebView.java
@@ -16,7 +16,7 @@
package android.webkit;
-import com.android.layoutlib.bridge.MockView;
+import com.android.layoutlib.bridge.android.MockView;
import android.content.Context;
import android.graphics.Bitmap;
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 996a942..d2092d1 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -16,63 +16,26 @@
package com.android.layoutlib.bridge;
-import com.android.internal.util.XmlUtils;
-import com.android.layoutlib.api.ILayoutBridge;
import com.android.layoutlib.api.ILayoutLog;
-import com.android.layoutlib.api.ILayoutResult;
import com.android.layoutlib.api.IProjectCallback;
import com.android.layoutlib.api.IResourceValue;
-import com.android.layoutlib.api.IStyleResourceValue;
import com.android.layoutlib.api.IXmlPullParser;
-import com.android.layoutlib.api.IDensityBasedResourceValue.Density;
-import com.android.layoutlib.api.ILayoutResult.ILayoutViewInfo;
-import com.android.layoutlib.bridge.LayoutResult.LayoutViewInfo;
+import com.android.layoutlib.api.LayoutBridge;
+import com.android.layoutlib.api.SceneParams;
+import com.android.layoutlib.api.SceneResult;
+import com.android.layoutlib.bridge.android.BridgeAssetManager;
+import com.android.layoutlib.bridge.impl.FontLoader;
+import com.android.layoutlib.bridge.impl.LayoutSceneImpl;
import com.android.ninepatch.NinePatch;
import com.android.tools.layoutlib.create.MethodAdapter;
import com.android.tools.layoutlib.create.OverrideMethod;
-import android.app.Fragment_Delegate;
-import android.content.ClipData;
-import android.content.res.Configuration;
import android.graphics.Bitmap;
-import android.graphics.Bitmap_Delegate;
-import android.graphics.Canvas;
-import android.graphics.Canvas_Delegate;
-import android.graphics.Rect;
-import android.graphics.Region;
import android.graphics.Typeface_Delegate;
-import android.graphics.drawable.Drawable;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.ParcelFileDescriptor;
-import android.os.RemoteException;
-import android.util.DisplayMetrics;
-import android.util.TypedValue;
-import android.view.BridgeInflater;
-import android.view.DragEvent;
-import android.view.IWindow;
-import android.view.IWindowSession;
-import android.view.InputChannel;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.Surface;
-import android.view.SurfaceView;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.View.AttachInfo;
-import android.view.View.MeasureSpec;
-import android.view.WindowManager.LayoutParams;
-import android.widget.FrameLayout;
-import android.widget.TabHost;
-import android.widget.TabWidget;
-import java.awt.image.BufferedImage;
import java.lang.ref.SoftReference;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
-import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
@@ -81,10 +44,7 @@
* <p/>To use this bridge, simply instantiate an object of type {@link Bridge} and call
* {@link #computeLayout(IXmlPullParser, Object, int, int, String, boolean, Map, Map, IProjectCallback, ILayoutLog)}.
*/
-public final class Bridge implements ILayoutBridge {
-
- private static final int DEFAULT_TITLE_BAR_HEIGHT = 25;
- private static final int DEFAULT_STATUS_BAR_HEIGHT = 25;
+public final class Bridge extends LayoutBridge {
public static class StaticMethodNotImplementedException extends RuntimeException {
private static final long serialVersionUID = 1L;
@@ -143,34 +103,28 @@
}
};
- /**
- * Logger defined during a compute layout operation.
- * <p/>
- * This logger is generally set to {@link #sDefaultLogger} except during rendering
- * operations when it might be set to a specific provided logger.
- * <p/>
- * To change this value, use a block synchronized on {@link #sDefaultLogger}.
- */
- private static ILayoutLog sLogger = sDefaultLogger;
-
- /*
- * (non-Javadoc)
- * @see com.android.layoutlib.api.ILayoutBridge#getApiLevel()
- */
+ @Override
public int getApiLevel() {
- return API_CURRENT;
+ return LayoutBridge.API_CURRENT;
}
/*
* (non-Javadoc)
* @see com.android.layoutlib.api.ILayoutLibBridge#init(java.lang.String, java.util.Map)
*/
- public boolean init(
- String fontOsLocation, Map<String, Map<String, Integer>> enumValueMap) {
+ @Override
+ public boolean init(String fontOsLocation, Map<String, Map<String, Integer>> enumValueMap) {
+ BridgeAssetManager.initSystem();
return sinit(fontOsLocation, enumValueMap);
}
+ @Override
+ public boolean dispose() {
+ BridgeAssetManager.clearSystem();
+ return true;
+ }
+
private static synchronized boolean sinit(String fontOsLocation,
Map<String, Map<String, Integer>> enumValueMap) {
@@ -189,12 +143,8 @@
OverrideMethod.setDefaultListener(new MethodAdapter() {
@Override
public void onInvokeV(String signature, boolean isNative, Object caller) {
- if (sLogger != null) {
- synchronized (sDefaultLogger) {
- sLogger.error("Missing Stub: " + signature +
- (isNative ? " (native)" : ""));
- }
- }
+ sDefaultLogger.error("Missing Stub: " + signature +
+ (isNative ? " (native)" : ""));
if (debug.equalsIgnoreCase("throw")) {
// Throwing this exception doesn't seem that useful. It breaks
@@ -278,236 +228,82 @@
return true;
}
- /*
- * For compatilibty purposes, we implement the old deprecated version of computeLayout.
- * (non-Javadoc)
- * @see com.android.layoutlib.api.ILayoutBridge#computeLayout(com.android.layoutlib.api.IXmlPullParser, java.lang.Object, int, int, java.lang.String, java.util.Map, java.util.Map, com.android.layoutlib.api.IProjectCallback, com.android.layoutlib.api.ILayoutLog)
+ /**
+ * Sets a 9 patch in a project cache or in the framework cache.
+ * @param value the path of the 9 patch
+ * @param ninePatch the 9 patch object
+ * @param projectKey the key of the project, or null to put the bitmap in the framework cache.
*/
- @Deprecated
- public ILayoutResult computeLayout(IXmlPullParser layoutDescription,
- Object projectKey,
- int screenWidth, int screenHeight, String themeName,
- Map<String, Map<String, IResourceValue>> projectResources,
- Map<String, Map<String, IResourceValue>> frameworkResources,
- IProjectCallback customViewLoader, ILayoutLog logger) {
- boolean isProjectTheme = false;
- if (themeName.charAt(0) == '*') {
- themeName = themeName.substring(1);
- isProjectTheme = true;
- }
+ public static void setCached9Patch(String value, NinePatch ninePatch, Object projectKey) {
+ if (projectKey != null) {
+ Map<String, SoftReference<NinePatch>> map = sProject9PatchCache.get(projectKey);
- return computeLayout(layoutDescription, projectKey,
- screenWidth, screenHeight, DisplayMetrics.DENSITY_DEFAULT,
- DisplayMetrics.DENSITY_DEFAULT, DisplayMetrics.DENSITY_DEFAULT,
- themeName, isProjectTheme,
- projectResources, frameworkResources, customViewLoader, logger);
+ if (map == null) {
+ map = new HashMap<String, SoftReference<NinePatch>>();
+ sProject9PatchCache.put(projectKey, map);
+ }
+
+ map.put(value, new SoftReference<NinePatch>(ninePatch));
+ } else {
+ sFramework9PatchCache.put(value, new SoftReference<NinePatch>(ninePatch));
+ }
}
- /*
- * For compatilibty purposes, we implement the old deprecated version of computeLayout.
- * (non-Javadoc)
- * @see com.android.layoutlib.api.ILayoutBridge#computeLayout(com.android.layoutlib.api.IXmlPullParser, java.lang.Object, int, int, java.lang.String, boolean, java.util.Map, java.util.Map, com.android.layoutlib.api.IProjectCallback, com.android.layoutlib.api.ILayoutLog)
+ /**
+ * Starts a layout session by inflating and rendering it. The method returns a
+ * {@link ILayoutScene} on which further actions can be taken.
+ *
+ * @param layoutDescription the {@link IXmlPullParser} letting the LayoutLib Bridge visit the
+ * layout file.
+ * @param projectKey An Object identifying the project. This is used for the cache mechanism.
+ * @param screenWidth the screen width
+ * @param screenHeight the screen height
+ * @param renderFullSize if true, the rendering will render the full size needed by the
+ * layout. This size is never smaller than <var>screenWidth</var> x <var>screenHeight</var>.
+ * @param density the density factor for the screen.
+ * @param xdpi the screen actual dpi in X
+ * @param ydpi the screen actual dpi in Y
+ * @param themeName The name of the theme to use.
+ * @param isProjectTheme true if the theme is a project theme, false if it is a framework theme.
+ * @param projectResources the resources of the project. The map contains (String, map) pairs
+ * where the string is the type of the resource reference used in the layout file, and the
+ * map contains (String, {@link IResourceValue}) pairs where the key is the resource name,
+ * and the value is the resource value.
+ * @param frameworkResources the framework resources. The map contains (String, map) pairs
+ * where the string is the type of the resource reference used in the layout file, and the map
+ * contains (String, {@link IResourceValue}) pairs where the key is the resource name, and the
+ * value is the resource value.
+ * @param projectCallback The {@link IProjectCallback} object to get information from
+ * the project.
+ * @param logger the object responsible for displaying warning/errors to the user.
+ * @return a new {@link ILayoutScene} object that contains the result of the layout.
+ * @since 5
*/
- @Deprecated
- public ILayoutResult computeLayout(IXmlPullParser layoutDescription, Object projectKey,
- int screenWidth, int screenHeight, String themeName, boolean isProjectTheme,
- Map<String, Map<String, IResourceValue>> projectResources,
- Map<String, Map<String, IResourceValue>> frameworkResources,
- IProjectCallback customViewLoader, ILayoutLog logger) {
- return computeLayout(layoutDescription, projectKey,
- screenWidth, screenHeight, DisplayMetrics.DENSITY_DEFAULT,
- DisplayMetrics.DENSITY_DEFAULT, DisplayMetrics.DENSITY_DEFAULT,
- themeName, isProjectTheme,
- projectResources, frameworkResources, customViewLoader, logger);
- }
-
- /*
- * For compatilibty purposes, we implement the old deprecated version of computeLayout.
- * (non-Javadoc)
- * @see com.android.layoutlib.api.ILayoutBridge#computeLayout(com.android.layoutlib.api.IXmlPullParser, java.lang.Object, int, int, int, float, float, java.lang.String, boolean, java.util.Map, java.util.Map, com.android.layoutlib.api.IProjectCallback, com.android.layoutlib.api.ILayoutLog)
- */
- public ILayoutResult computeLayout(IXmlPullParser layoutDescription, Object projectKey,
- int screenWidth, int screenHeight, int density, float xdpi, float ydpi,
- String themeName, boolean isProjectTheme,
- Map<String, Map<String, IResourceValue>> projectResources,
- Map<String, Map<String, IResourceValue>> frameworkResources,
- IProjectCallback customViewLoader, ILayoutLog logger) {
- return computeLayout(layoutDescription, projectKey,
- screenWidth, screenHeight, false /* renderFullSize */,
- density, xdpi, ydpi, themeName, isProjectTheme,
- projectResources, frameworkResources, customViewLoader, logger);
- }
-
- /*
- * (non-Javadoc)
- * @see com.android.layoutlib.api.ILayoutBridge#computeLayout(com.android.layoutlib.api.IXmlPullParser, java.lang.Object, int, int, boolean, int, float, float, java.lang.String, boolean, java.util.Map, java.util.Map, com.android.layoutlib.api.IProjectCallback, com.android.layoutlib.api.ILayoutLog)
- */
- public ILayoutResult computeLayout(IXmlPullParser layoutDescription, Object projectKey,
- int screenWidth, int screenHeight, boolean renderFullSize,
- int density, float xdpi, float ydpi,
- String themeName, boolean isProjectTheme,
- Map<String, Map<String, IResourceValue>> projectResources,
- Map<String, Map<String, IResourceValue>> frameworkResources,
- IProjectCallback customViewLoader, ILayoutLog logger) {
- if (logger == null) {
- logger = sDefaultLogger;
- }
-
- synchronized (sDefaultLogger) {
- sLogger = logger;
- }
-
- // find the current theme and compute the style inheritance map
- Map<IStyleResourceValue, IStyleResourceValue> styleParentMap =
- new HashMap<IStyleResourceValue, IStyleResourceValue>();
-
- IStyleResourceValue currentTheme = computeStyleMaps(themeName, isProjectTheme,
- projectResources.get(BridgeConstants.RES_STYLE),
- frameworkResources.get(BridgeConstants.RES_STYLE), styleParentMap);
-
- BridgeContext context = null;
+ @Override
+ public BridgeLayoutScene createScene(SceneParams params) {
try {
- // we need to make sure the Looper has been initialized for this thread.
- // this is required for View that creates Handler objects.
- if (Looper.myLooper() == null) {
- Looper.prepare();
- }
+ SceneResult lastResult = SceneResult.SUCCESS;
+ LayoutSceneImpl scene = null;
+ synchronized (this) {
+ try {
+ scene = new LayoutSceneImpl(params);
- // setup the display Metrics.
- DisplayMetrics metrics = new DisplayMetrics();
- metrics.densityDpi = density;
- metrics.density = density / (float) DisplayMetrics.DENSITY_DEFAULT;
- metrics.scaledDensity = metrics.density;
- metrics.widthPixels = screenWidth;
- metrics.heightPixels = screenHeight;
- metrics.xdpi = xdpi;
- metrics.ydpi = ydpi;
-
- context = new BridgeContext(projectKey, metrics, currentTheme, projectResources,
- frameworkResources, styleParentMap, customViewLoader, logger);
- BridgeInflater inflater = new BridgeInflater(context, customViewLoader);
- context.setBridgeInflater(inflater);
- inflater.setFactory2(context);
-
- IResourceValue windowBackground = null;
- int screenOffset = 0;
- if (currentTheme != null) {
- windowBackground = context.findItemInStyle(currentTheme, "windowBackground");
- windowBackground = context.resolveResValue(windowBackground);
-
- screenOffset = getScreenOffset(frameworkResources, currentTheme, context);
- }
-
- BridgeXmlBlockParser parser = new BridgeXmlBlockParser(layoutDescription,
- context, false /* platformResourceFlag */);
-
- ViewGroup root = new FrameLayout(context);
-
- // Sets the project callback (custom view loader) to the fragment delegate so that
- // it can instantiate the custom Fragment.
- Fragment_Delegate.setProjectCallback(customViewLoader);
-
- View view = inflater.inflate(parser, root);
-
- // post-inflate process. For now this supports TabHost/TabWidget
- postInflateProcess(view, customViewLoader);
-
- Fragment_Delegate.setProjectCallback(null);
-
- // set the AttachInfo on the root view.
- AttachInfo info = new AttachInfo(new WindowSession(), new Window(),
- new Handler(), null);
- info.mHasWindowFocus = true;
- info.mWindowVisibility = View.VISIBLE;
- info.mInTouchMode = false; // this is so that we can display selections.
- root.dispatchAttachedToWindow(info, 0);
-
- // get the background drawable
- if (windowBackground != null) {
- Drawable d = ResourceHelper.getDrawable(windowBackground,
- context, true /* isFramework */);
- root.setBackgroundDrawable(d);
- }
-
- // measure the views
- int w_spec, h_spec;
-
- if (renderFullSize) {
- // measure the full size needed by the layout.
- w_spec = MeasureSpec.makeMeasureSpec(screenWidth,
- MeasureSpec.UNSPECIFIED); // this lets us know the actual needed size
- h_spec = MeasureSpec.makeMeasureSpec(screenHeight - screenOffset,
- MeasureSpec.UNSPECIFIED); // this lets us know the actual needed size
- root.measure(w_spec, h_spec);
-
- int neededWidth = root.getChildAt(0).getMeasuredWidth();
- if (neededWidth > screenWidth) {
- screenWidth = neededWidth;
- }
-
- int neededHeight = root.getChildAt(0).getMeasuredHeight();
- if (neededHeight > screenHeight - screenOffset) {
- screenHeight = neededHeight + screenOffset;
+ scene.prepare();
+ lastResult = scene.inflate();
+ if (lastResult == SceneResult.SUCCESS) {
+ lastResult = scene.render();
+ }
+ } finally {
+ if (scene != null) {
+ scene.cleanup();
+ }
}
}
- // remeasure with only the size we need
- // This must always be done before the call to layout
- w_spec = MeasureSpec.makeMeasureSpec(screenWidth, MeasureSpec.EXACTLY);
- h_spec = MeasureSpec.makeMeasureSpec(screenHeight - screenOffset,
- MeasureSpec.EXACTLY);
- root.measure(w_spec, h_spec);
-
- // now do the layout.
- root.layout(0, screenOffset, screenWidth, screenHeight);
-
- // draw the views
- // create the BufferedImage into which the layout will be rendered.
- BufferedImage image = new BufferedImage(screenWidth, screenHeight - screenOffset,
- BufferedImage.TYPE_INT_ARGB);
-
- // create an Android bitmap around the BufferedImage
- Bitmap bitmap = Bitmap_Delegate.createBitmap(image, Density.getEnum(density));
-
- // create a Canvas around the Android bitmap
- Canvas canvas = new Canvas(bitmap);
-
- // to set the logger, get the native delegate
- Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(canvas);
- canvasDelegate.setLogger(logger);
-
- root.draw(canvas);
- canvasDelegate.dispose();
-
- return new LayoutResult(
- visit(((ViewGroup)view).getChildAt(0), context),
- image);
-
- } catch (PostInflateException e) {
- return new LayoutResult(ILayoutResult.ERROR, "Error during post inflation process:\n"
- + e.getMessage());
- } catch (Throwable e) {
- // get the real cause of the exception.
- Throwable t = e;
- while (t.getCause() != null) {
- t = t.getCause();
- }
-
- // log it
- logger.error(t);
-
- // then return with an ERROR status and the message from the real exception
- return new LayoutResult(ILayoutResult.ERROR,
- t.getClass().getSimpleName() + ": " + t.getMessage());
- } finally {
- // Make sure to remove static references, otherwise we could not unload the lib
- BridgeResources.clearSystem();
- BridgeAssetManager.clearSystem();
-
- // Remove the global logger
- synchronized (sDefaultLogger) {
- sLogger = sDefaultLogger;
- }
+ return new BridgeLayoutScene(this, scene, lastResult);
+ } catch (Throwable t) {
+ t.printStackTrace();
+ return new BridgeLayoutScene(this, null, new SceneResult("error!", t));
}
}
@@ -515,6 +311,7 @@
* (non-Javadoc)
* @see com.android.layoutlib.api.ILayoutLibBridge#clearCaches(java.lang.Object)
*/
+ @Override
public void clearCaches(Object projectKey) {
if (projectKey != null) {
sProjectBitmapCache.remove(projectKey);
@@ -556,7 +353,10 @@
return null;
}
- static Map<String, Integer> getEnumValues(String attributeName) {
+ /**
+ * Returns the list of possible enums for a given attribute name.
+ */
+ public static Map<String, Integer> getEnumValues(String attributeName) {
if (sEnumValueMap != null) {
return sEnumValueMap.get(attributeName);
}
@@ -565,358 +365,13 @@
}
/**
- * Visits a View and its children and generate a {@link ILayoutViewInfo} containing the
- * bounds of all the views.
- * @param view the root View
- * @param context the context.
- */
- private ILayoutViewInfo visit(View view, BridgeContext context) {
- if (view == null) {
- return null;
- }
-
- LayoutViewInfo result = new LayoutViewInfo(view.getClass().getName(),
- context.getViewKey(view),
- view.getLeft(), view.getTop(), view.getRight(), view.getBottom());
-
- if (view instanceof ViewGroup) {
- ViewGroup group = ((ViewGroup) view);
- int n = group.getChildCount();
- ILayoutViewInfo[] children = new ILayoutViewInfo[n];
- for (int i = 0; i < group.getChildCount(); i++) {
- children[i] = visit(group.getChildAt(i), context);
- }
- result.setChildren(children);
- }
-
- return result;
- }
-
- /**
- * Compute style information from the given list of style for the project and framework.
- * @param themeName the name of the current theme. In order to differentiate project and
- * platform themes sharing the same name, all project themes must be prepended with
- * a '*' character.
- * @param isProjectTheme Is this a project theme
- * @param inProjectStyleMap the project style map
- * @param inFrameworkStyleMap the framework style map
- * @param outInheritanceMap the map of style inheritance. This is filled by the method
- * @return the {@link IStyleResourceValue} matching <var>themeName</var>
- */
- private IStyleResourceValue computeStyleMaps(
- String themeName, boolean isProjectTheme, Map<String,
- IResourceValue> inProjectStyleMap, Map<String, IResourceValue> inFrameworkStyleMap,
- Map<IStyleResourceValue, IStyleResourceValue> outInheritanceMap) {
-
- if (inProjectStyleMap != null && inFrameworkStyleMap != null) {
- // first, get the theme
- IResourceValue theme = null;
-
- // project theme names have been prepended with a *
- if (isProjectTheme) {
- theme = inProjectStyleMap.get(themeName);
- } else {
- theme = inFrameworkStyleMap.get(themeName);
- }
-
- if (theme instanceof IStyleResourceValue) {
- // compute the inheritance map for both the project and framework styles
- computeStyleInheritance(inProjectStyleMap.values(), inProjectStyleMap,
- inFrameworkStyleMap, outInheritanceMap);
-
- // Compute the style inheritance for the framework styles/themes.
- // Since, for those, the style parent values do not contain 'android:'
- // we want to force looking in the framework style only to avoid using
- // similarly named styles from the project.
- // To do this, we pass null in lieu of the project style map.
- computeStyleInheritance(inFrameworkStyleMap.values(), null /*inProjectStyleMap */,
- inFrameworkStyleMap, outInheritanceMap);
-
- return (IStyleResourceValue)theme;
- }
- }
-
- return null;
- }
-
- /**
- * Compute the parent style for all the styles in a given list.
- * @param styles the styles for which we compute the parent.
- * @param inProjectStyleMap the map of project styles.
- * @param inFrameworkStyleMap the map of framework styles.
- * @param outInheritanceMap the map of style inheritance. This is filled by the method.
- */
- private void computeStyleInheritance(Collection<IResourceValue> styles,
- Map<String, IResourceValue> inProjectStyleMap,
- Map<String, IResourceValue> inFrameworkStyleMap,
- Map<IStyleResourceValue, IStyleResourceValue> outInheritanceMap) {
- for (IResourceValue value : styles) {
- if (value instanceof IStyleResourceValue) {
- IStyleResourceValue style = (IStyleResourceValue)value;
- IStyleResourceValue parentStyle = null;
-
- // first look for a specified parent.
- String parentName = style.getParentStyle();
-
- // no specified parent? try to infer it from the name of the style.
- if (parentName == null) {
- parentName = getParentName(value.getName());
- }
-
- if (parentName != null) {
- parentStyle = getStyle(parentName, inProjectStyleMap, inFrameworkStyleMap);
-
- if (parentStyle != null) {
- outInheritanceMap.put(style, parentStyle);
- }
- }
- }
- }
- }
-
- /**
- * Searches for and returns the {@link IStyleResourceValue} from a given name.
- * <p/>The format of the name can be:
- * <ul>
- * <li>[android:]<name></li>
- * <li>[android:]style/<name></li>
- * <li>@[android:]style/<name></li>
- * </ul>
- * @param parentName the name of the style.
- * @param inProjectStyleMap the project style map. Can be <code>null</code>
- * @param inFrameworkStyleMap the framework style map.
- * @return The matching {@link IStyleResourceValue} object or <code>null</code> if not found.
- */
- private IStyleResourceValue getStyle(String parentName,
- Map<String, IResourceValue> inProjectStyleMap,
- Map<String, IResourceValue> inFrameworkStyleMap) {
- boolean frameworkOnly = false;
-
- String name = parentName;
-
- // remove the useless @ if it's there
- if (name.startsWith(BridgeConstants.PREFIX_RESOURCE_REF)) {
- name = name.substring(BridgeConstants.PREFIX_RESOURCE_REF.length());
- }
-
- // check for framework identifier.
- if (name.startsWith(BridgeConstants.PREFIX_ANDROID)) {
- frameworkOnly = true;
- name = name.substring(BridgeConstants.PREFIX_ANDROID.length());
- }
-
- // at this point we could have the format <type>/<name>. we want only the name as long as
- // the type is style.
- if (name.startsWith(BridgeConstants.REFERENCE_STYLE)) {
- name = name.substring(BridgeConstants.REFERENCE_STYLE.length());
- } else if (name.indexOf('/') != -1) {
- return null;
- }
-
- IResourceValue parent = null;
-
- // if allowed, search in the project resources.
- if (frameworkOnly == false && inProjectStyleMap != null) {
- parent = inProjectStyleMap.get(name);
- }
-
- // if not found, then look in the framework resources.
- if (parent == null) {
- parent = inFrameworkStyleMap.get(name);
- }
-
- // make sure the result is the proper class type and return it.
- if (parent instanceof IStyleResourceValue) {
- return (IStyleResourceValue)parent;
- }
-
- sLogger.error(String.format("Unable to resolve parent style name: %s", parentName));
-
- return null;
- }
-
- /**
- * Computes the name of the parent style, or <code>null</code> if the style is a root style.
- */
- private String getParentName(String styleName) {
- int index = styleName.lastIndexOf('.');
- if (index != -1) {
- return styleName.substring(0, index);
- }
-
- return null;
- }
-
- /**
- * Returns the top screen offset. This depends on whether the current theme defines the user
- * of the title and status bars.
- * @param frameworkResources The framework resources
- * @param currentTheme The current theme
- * @param context The context
- * @return the pixel height offset
- */
- private int getScreenOffset(Map<String, Map<String, IResourceValue>> frameworkResources,
- IStyleResourceValue currentTheme, BridgeContext context) {
- int offset = 0;
-
- // get the title bar flag from the current theme.
- IResourceValue value = context.findItemInStyle(currentTheme, "windowNoTitle");
-
- // because it may reference something else, we resolve it.
- value = context.resolveResValue(value);
-
- // if there's a value and it's true (default is false)
- if (value == null || value.getValue() == null ||
- XmlUtils.convertValueToBoolean(value.getValue(), false /* defValue */) == false) {
- // default size of the window title bar
- int defaultOffset = DEFAULT_TITLE_BAR_HEIGHT;
-
- // get value from the theme.
- value = context.findItemInStyle(currentTheme, "windowTitleSize");
-
- // resolve it
- value = context.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
- defaultOffset = (int)typedValue.getDimension(context.getResources().mMetrics);
- }
- }
-
- offset += defaultOffset;
- }
-
- // get the fullscreen flag from the current theme.
- value = context.findItemInStyle(currentTheme, "windowFullscreen");
-
- // because it may reference something else, we resolve it.
- value = context.resolveResValue(value);
-
- if (value == null || value.getValue() == null ||
- XmlUtils.convertValueToBoolean(value.getValue(), false /* defValue */) == false) {
-
- // default value
- int defaultOffset = DEFAULT_STATUS_BAR_HEIGHT;
-
- // get the real value, first the list of Dimensions from the framework map
- Map<String, IResourceValue> dimens = frameworkResources.get(BridgeConstants.RES_DIMEN);
-
- // now get the value
- value = dimens.get("status_bar_height");
- if (value != null) {
- TypedValue typedValue = ResourceHelper.getValue(value.getValue());
- if (typedValue != null) {
- // compute the pixel value based on the display metrics
- defaultOffset = (int)typedValue.getDimension(context.getResources().mMetrics);
- }
- }
-
- // add the computed offset.
- offset += defaultOffset;
- }
-
- return offset;
- }
-
- /**
- * Post process on a view hierachy that was just inflated.
- * <p/>At the moment this only support TabHost: If {@link TabHost} is detected, look for the
- * {@link TabWidget}, and the corresponding {@link FrameLayout} and make new tabs automatically
- * based on the content of the {@link FrameLayout}.
- * @param view the root view to process.
- * @param projectCallback callback to the project.
- */
- private void postInflateProcess(View view, IProjectCallback projectCallback)
- throws PostInflateException {
- if (view instanceof TabHost) {
- setupTabHost((TabHost)view, projectCallback);
- } else if (view instanceof ViewGroup) {
- ViewGroup group = (ViewGroup)view;
- final int count = group.getChildCount();
- for (int c = 0 ; c < count ; c++) {
- View child = group.getChildAt(c);
- postInflateProcess(child, projectCallback);
- }
- }
- }
-
- /**
- * Sets up a {@link TabHost} object.
- * @param tabHost the TabHost to setup.
- * @param projectCallback The project callback object to access the project R class.
- * @throws PostInflateException
- */
- private void setupTabHost(TabHost tabHost, IProjectCallback projectCallback)
- throws PostInflateException {
- // look for the TabWidget, and the FrameLayout. They have their own specific names
- View v = tabHost.findViewById(android.R.id.tabs);
-
- if (v == null) {
- throw new PostInflateException(
- "TabHost requires a TabWidget with id \"android:id/tabs\".\n");
- }
-
- if ((v instanceof TabWidget) == false) {
- throw new PostInflateException(String.format(
- "TabHost requires a TabWidget with id \"android:id/tabs\".\n" +
- "View found with id 'tabs' is '%s'", v.getClass().getCanonicalName()));
- }
-
- v = tabHost.findViewById(android.R.id.tabcontent);
-
- if (v == null) {
- // TODO: see if we can fake tabs even without the FrameLayout (same below when the framelayout is empty)
- throw new PostInflateException(
- "TabHost requires a FrameLayout with id \"android:id/tabcontent\".");
- }
-
- if ((v instanceof FrameLayout) == false) {
- throw new PostInflateException(String.format(
- "TabHost requires a FrameLayout with id \"android:id/tabcontent\".\n" +
- "View found with id 'tabcontent' is '%s'", v.getClass().getCanonicalName()));
- }
-
- FrameLayout content = (FrameLayout)v;
-
- // now process the content of the framelayout and dynamically create tabs for it.
- final int count = content.getChildCount();
-
- if (count == 0) {
- throw new PostInflateException(
- "The FrameLayout for the TabHost has no content. Rendering failed.\n");
- }
-
- // this must be called before addTab() so that the TabHost searches its TabWidget
- // and FrameLayout.
- tabHost.setup();
-
- // for each child of the framelayout, add a new TabSpec
- for (int i = 0 ; i < count ; i++) {
- View child = content.getChildAt(i);
- String tabSpec = String.format("tab_spec%d", i+1);
- int id = child.getId();
- String[] resource = projectCallback.resolveResourceValue(id);
- String name;
- if (resource != null) {
- name = resource[0]; // 0 is resource name, 1 is resource type.
- } else {
- name = String.format("Tab %d", i+1); // default name if id is unresolved.
- }
- tabHost.addTab(tabHost.newTabSpec(tabSpec).setIndicator(name).setContent(id));
- }
- }
-
- /**
* Returns the bitmap for a specific path, from a specific project cache, or from the
* framework cache.
* @param value the path of the bitmap
* @param projectKey the key of the project, or null to query the framework cache.
* @return the cached Bitmap or null if not found.
*/
- static Bitmap getCachedBitmap(String value, Object projectKey) {
+ public static Bitmap getCachedBitmap(String value, Object projectKey) {
if (projectKey != null) {
Map<String, SoftReference<Bitmap>> map = sProjectBitmapCache.get(projectKey);
if (map != null) {
@@ -941,7 +396,7 @@
* @param bmp the Bitmap object
* @param projectKey the key of the project, or null to put the bitmap in the framework cache.
*/
- static void setCachedBitmap(String value, Bitmap bmp, Object projectKey) {
+ public static void setCachedBitmap(String value, Bitmap bmp, Object projectKey) {
if (projectKey != null) {
Map<String, SoftReference<Bitmap>> map = sProjectBitmapCache.get(projectKey);
@@ -963,7 +418,7 @@
* @param projectKey the key of the project, or null to query the framework cache.
* @return the cached 9 patch or null if not found.
*/
- static NinePatch getCached9Patch(String value, Object projectKey) {
+ public static NinePatch getCached9Patch(String value, Object projectKey) {
if (projectKey != null) {
Map<String, SoftReference<NinePatch>> map = sProject9PatchCache.get(projectKey);
@@ -983,262 +438,69 @@
return null;
}
- /**
- * Sets a 9 patch in a project cache or in the framework cache.
- * @param value the path of the 9 patch
- * @param ninePatch the 9 patch object
- * @param projectKey the key of the project, or null to put the bitmap in the framework cache.
+
+ // ---------- OBSOLETE API METHODS ----------
+
+ /*
+ * For compatilibty purposes, we implement the old deprecated version of computeLayout.
+ * (non-Javadoc)
+ * @see com.android.layoutlib.api.ILayoutBridge#computeLayout(com.android.layoutlib.api.IXmlPullParser, java.lang.Object, int, int, java.lang.String, java.util.Map, java.util.Map, com.android.layoutlib.api.IProjectCallback, com.android.layoutlib.api.ILayoutLog)
*/
- static void setCached9Patch(String value, NinePatch ninePatch, Object projectKey) {
- if (projectKey != null) {
- Map<String, SoftReference<NinePatch>> map = sProject9PatchCache.get(projectKey);
-
- if (map == null) {
- map = new HashMap<String, SoftReference<NinePatch>>();
- sProject9PatchCache.put(projectKey, map);
- }
-
- map.put(value, new SoftReference<NinePatch>(ninePatch));
- } else {
- sFramework9PatchCache.put(value, new SoftReference<NinePatch>(ninePatch));
- }
+ @Deprecated
+ public com.android.layoutlib.api.ILayoutResult computeLayout(IXmlPullParser layoutDescription,
+ Object projectKey,
+ int screenWidth, int screenHeight, String themeName,
+ Map<String, Map<String, IResourceValue>> projectResources,
+ Map<String, Map<String, IResourceValue>> frameworkResources,
+ IProjectCallback customViewLoader, ILayoutLog logger) {
+ throw new UnsupportedOperationException();
}
- private static final class PostInflateException extends Exception {
- private static final long serialVersionUID = 1L;
-
- public PostInflateException(String message) {
- super(message);
- }
+ /*
+ * For compatilibty purposes, we implement the old deprecated version of computeLayout.
+ * (non-Javadoc)
+ * @see com.android.layoutlib.api.ILayoutBridge#computeLayout(com.android.layoutlib.api.IXmlPullParser, java.lang.Object, int, int, java.lang.String, boolean, java.util.Map, java.util.Map, com.android.layoutlib.api.IProjectCallback, com.android.layoutlib.api.ILayoutLog)
+ */
+ @Deprecated
+ public com.android.layoutlib.api.ILayoutResult computeLayout(IXmlPullParser layoutDescription,
+ Object projectKey,
+ int screenWidth, int screenHeight, String themeName, boolean isProjectTheme,
+ Map<String, Map<String, IResourceValue>> projectResources,
+ Map<String, Map<String, IResourceValue>> frameworkResources,
+ IProjectCallback customViewLoader, ILayoutLog logger) {
+ throw new UnsupportedOperationException();
}
- /**
- * Implementation of {@link IWindowSession} so that mSession is not null in
- * the {@link SurfaceView}.
+ /*
+ * For compatilibty purposes, we implement the old deprecated version of computeLayout.
+ * (non-Javadoc)
+ * @see com.android.layoutlib.api.ILayoutBridge#computeLayout(com.android.layoutlib.api.IXmlPullParser, java.lang.Object, int, int, int, float, float, java.lang.String, boolean, java.util.Map, java.util.Map, com.android.layoutlib.api.IProjectCallback, com.android.layoutlib.api.ILayoutLog)
*/
- private static final class WindowSession implements IWindowSession {
-
- @SuppressWarnings("unused")
- public int add(IWindow arg0, LayoutParams arg1, int arg2, Rect arg3,
- InputChannel outInputchannel)
- throws RemoteException {
- // pass for now.
- return 0;
- }
-
- @SuppressWarnings("unused")
- public int addWithoutInputChannel(IWindow arg0, LayoutParams arg1, int arg2, Rect arg3)
- throws RemoteException {
- // pass for now.
- return 0;
- }
-
- @SuppressWarnings("unused")
- public void finishDrawing(IWindow arg0) throws RemoteException {
- // pass for now.
- }
-
- @SuppressWarnings("unused")
- public void finishKey(IWindow arg0) throws RemoteException {
- // pass for now.
- }
-
- @SuppressWarnings("unused")
- public boolean getInTouchMode() throws RemoteException {
- // pass for now.
- return false;
- }
-
- @SuppressWarnings("unused")
- public boolean performHapticFeedback(IWindow window, int effectId, boolean always) {
- // pass for now.
- return false;
- }
-
- @SuppressWarnings("unused")
- public MotionEvent getPendingPointerMove(IWindow arg0) throws RemoteException {
- // pass for now.
- return null;
- }
-
- @SuppressWarnings("unused")
- public MotionEvent getPendingTrackballMove(IWindow arg0) throws RemoteException {
- // pass for now.
- return null;
- }
-
- @SuppressWarnings("unused")
- public int relayout(IWindow arg0, LayoutParams arg1, int arg2, int arg3, int arg4,
- boolean arg4_5, Rect arg5, Rect arg6, Rect arg7, Configuration arg7b, Surface arg8)
- throws RemoteException {
- // pass for now.
- return 0;
- }
-
- public void getDisplayFrame(IWindow window, Rect outDisplayFrame) {
- // pass for now.
- }
-
- @SuppressWarnings("unused")
- public void remove(IWindow arg0) throws RemoteException {
- // pass for now.
- }
-
- @SuppressWarnings("unused")
- public void setInTouchMode(boolean arg0) throws RemoteException {
- // pass for now.
- }
-
- @SuppressWarnings("unused")
- public void setTransparentRegion(IWindow arg0, Region arg1) throws RemoteException {
- // pass for now.
- }
-
- @SuppressWarnings("unused")
- public void setInsets(IWindow window, int touchable, Rect contentInsets,
- Rect visibleInsets) {
- // pass for now.
- }
-
- @SuppressWarnings("unused")
- public IBinder prepareDrag(IWindow window, boolean localOnly,
- int thumbnailWidth, int thumbnailHeight, Surface outSurface)
- throws RemoteException {
- // pass for now
- return null;
- }
-
- @SuppressWarnings("unused")
- public boolean performDrag(IWindow window, IBinder dragToken,
- float touchX, float touchY, float thumbCenterX, float thumbCenterY,
- ClipData data)
- throws RemoteException {
- // pass for now
- return false;
- }
-
- @SuppressWarnings("unused")
- public void reportDropResult(IWindow window, boolean consumed) throws RemoteException {
- // pass for now
- }
-
- @SuppressWarnings("unused")
- public void dragRecipientEntered(IWindow window) throws RemoteException {
- // pass for now
- }
-
- @SuppressWarnings("unused")
- public void dragRecipientExited(IWindow window) throws RemoteException {
- // pass for now
- }
-
- @SuppressWarnings("unused")
- public void setWallpaperPosition(IBinder window, float x, float y,
- float xStep, float yStep) {
- // pass for now.
- }
-
- @SuppressWarnings("unused")
- public void wallpaperOffsetsComplete(IBinder window) {
- // pass for now.
- }
-
- @SuppressWarnings("unused")
- public Bundle sendWallpaperCommand(IBinder window, String action, int x, int y,
- int z, Bundle extras, boolean sync) {
- // pass for now.
- return null;
- }
-
- @SuppressWarnings("unused")
- public void wallpaperCommandComplete(IBinder window, Bundle result) {
- // pass for now.
- }
-
- @SuppressWarnings("unused")
- public void closeSystemDialogs(String reason) {
- // pass for now.
- }
-
- public IBinder asBinder() {
- // pass for now.
- return null;
- }
+ @Deprecated
+ public com.android.layoutlib.api.ILayoutResult computeLayout(IXmlPullParser layoutDescription,
+ Object projectKey,
+ int screenWidth, int screenHeight, int density, float xdpi, float ydpi,
+ String themeName, boolean isProjectTheme,
+ Map<String, Map<String, IResourceValue>> projectResources,
+ Map<String, Map<String, IResourceValue>> frameworkResources,
+ IProjectCallback customViewLoader, ILayoutLog logger) {
+ throw new UnsupportedOperationException();
}
- /**
- * Implementation of {@link IWindow} to pass to the {@link AttachInfo}.
+ /*
+ * (non-Javadoc)
+ * @see com.android.layoutlib.api.ILayoutBridge#computeLayout(com.android.layoutlib.api.IXmlPullParser, java.lang.Object, int, int, boolean, int, float, float, java.lang.String, boolean, java.util.Map, java.util.Map, com.android.layoutlib.api.IProjectCallback, com.android.layoutlib.api.ILayoutLog)
*/
- private static final class Window implements IWindow {
-
- @SuppressWarnings("unused")
- public void dispatchAppVisibility(boolean arg0) throws RemoteException {
- // pass for now.
- }
-
- @SuppressWarnings("unused")
- public void dispatchGetNewSurface() throws RemoteException {
- // pass for now.
- }
-
- @SuppressWarnings("unused")
- public void dispatchKey(KeyEvent arg0) throws RemoteException {
- // pass for now.
- }
-
- @SuppressWarnings("unused")
- public void dispatchPointer(MotionEvent arg0, long arg1, boolean arg2) throws RemoteException {
- // pass for now.
- }
-
- @SuppressWarnings("unused")
- public void dispatchTrackball(MotionEvent arg0, long arg1, boolean arg2) throws RemoteException {
- // pass for now.
- }
-
- @SuppressWarnings("unused")
- public void executeCommand(String arg0, String arg1, ParcelFileDescriptor arg2)
- throws RemoteException {
- // pass for now.
- }
-
- @SuppressWarnings("unused")
- public void resized(int arg0, int arg1, Rect arg2, Rect arg3, boolean arg4, Configuration arg5)
- throws RemoteException {
- // pass for now.
- }
-
- @SuppressWarnings("unused")
- public void windowFocusChanged(boolean arg0, boolean arg1) throws RemoteException {
- // pass for now.
- }
-
- @SuppressWarnings("unused")
- public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep,
- boolean sync) {
- // pass for now.
- }
-
- @SuppressWarnings("unused")
- public void dispatchWallpaperCommand(String action, int x, int y,
- int z, Bundle extras, boolean sync) {
- // pass for now.
- }
-
- @SuppressWarnings("unused")
- public void closeSystemDialogs(String reason) {
- // pass for now.
- }
-
- @SuppressWarnings("unused")
- public void dispatchDragEvent(DragEvent event) {
- // pass for now.
- }
-
- public IBinder asBinder() {
- // pass for now.
- return null;
- }
+ @Deprecated
+ public com.android.layoutlib.api.ILayoutResult computeLayout(IXmlPullParser layoutDescription,
+ Object projectKey,
+ int screenWidth, int screenHeight, boolean renderFullSize,
+ int density, float xdpi, float ydpi,
+ String themeName, boolean isProjectTheme,
+ Map<String, Map<String, IResourceValue>> projectResources,
+ Map<String, Map<String, IResourceValue>> frameworkResources,
+ IProjectCallback customViewLoader, ILayoutLog logger) {
+ throw new UnsupportedOperationException();
}
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeLayoutScene.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeLayoutScene.java
new file mode 100644
index 0000000..5fcb9ff
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeLayoutScene.java
@@ -0,0 +1,80 @@
+/*
+ * 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;
+
+import com.android.layoutlib.api.LayoutScene;
+import com.android.layoutlib.api.SceneResult;
+import com.android.layoutlib.api.ViewInfo;
+import com.android.layoutlib.bridge.impl.LayoutSceneImpl;
+
+import java.awt.image.BufferedImage;
+
+/**
+ * An implementation of {@link LayoutScene}.
+ *
+ * This is a pretty basic class that does almost nothing. All of the work is done in
+ * {@link LayoutSceneImpl}.
+ *
+ */
+public class BridgeLayoutScene extends LayoutScene {
+
+ private final Bridge mBridge;
+ private final LayoutSceneImpl mScene;
+ private SceneResult mLastResult;
+
+ @Override
+ public SceneResult getResult() {
+ return mLastResult;
+ }
+
+ @Override
+ public BufferedImage getImage() {
+ return mScene.getImage();
+ }
+
+ @Override
+ public ViewInfo getRootView() {
+ return mScene.getViewInfo();
+ }
+
+ @Override
+ public SceneResult render() {
+
+ synchronized (mBridge) {
+ try {
+ mScene.prepare();
+ mLastResult = mScene.render();
+ } finally {
+ mScene.cleanup();
+ }
+ }
+
+ return mLastResult;
+ }
+
+ @Override
+ public void dispose() {
+ // TODO Auto-generated method stub
+
+ }
+
+ /*package*/ BridgeLayoutScene(Bridge bridge, LayoutSceneImpl scene, SceneResult lastResult) {
+ mBridge = bridge;
+ mScene = scene;
+ mLastResult = lastResult;
+ }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/LayoutResult.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/LayoutResult.java
deleted file mode 100644
index c4c5225..0000000
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/LayoutResult.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright (C) 2008 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;
-
-import com.android.layoutlib.api.ILayoutResult;
-
-import java.awt.image.BufferedImage;
-
-/**
- * Implementation of {@link ILayoutResult}
- */
-public final class LayoutResult implements ILayoutResult {
-
- private final ILayoutViewInfo mRootView;
- private final BufferedImage mImage;
- private final int mSuccess;
- private final String mErrorMessage;
-
- /**
- * Creates a {@link #SUCCESS} {@link ILayoutResult} with the specified params
- * @param rootView
- * @param image
- */
- public LayoutResult(ILayoutViewInfo rootView, BufferedImage image) {
- mSuccess = SUCCESS;
- mErrorMessage = null;
- mRootView = rootView;
- mImage = image;
- }
-
- /**
- * Creates a LayoutResult with a specific success code and associated message
- * @param code
- * @param message
- */
- public LayoutResult(int code, String message) {
- mSuccess = code;
- mErrorMessage = message;
- mRootView = null;
- mImage = null;
- }
-
- public int getSuccess() {
- return mSuccess;
- }
-
- public String getErrorMessage() {
- return mErrorMessage;
- }
-
- public BufferedImage getImage() {
- return mImage;
- }
-
- public ILayoutViewInfo getRootView() {
- return mRootView;
- }
-
- /**
- * Implementation of {@link ILayoutResult.ILayoutViewInfo}
- */
- public static final class LayoutViewInfo implements ILayoutViewInfo {
- private final Object mKey;
- private final String mName;
- private final int mLeft;
- private final int mRight;
- private final int mTop;
- private final int mBottom;
- private ILayoutViewInfo[] mChildren;
-
- public LayoutViewInfo(String name, Object key, int left, int top, int right, int bottom) {
- mName = name;
- mKey = key;
- mLeft = left;
- mRight = right;
- mTop = top;
- mBottom = bottom;
- }
-
- public void setChildren(ILayoutViewInfo[] children) {
- mChildren = children;
- }
-
- public ILayoutViewInfo[] getChildren() {
- return mChildren;
- }
-
- public Object getViewKey() {
- return mKey;
- }
-
- public String getName() {
- return mName;
- }
-
- public int getLeft() {
- return mLeft;
- }
-
- public int getTop() {
- return mTop;
- }
-
- public int getRight() {
- return mRight;
- }
-
- public int getBottom() {
- return mBottom;
- }
- }
-}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeAssetManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeAssetManager.java
similarity index 89%
rename from tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeAssetManager.java
rename to tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeAssetManager.java
index 71803fc..a825060 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeAssetManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeAssetManager.java
@@ -14,7 +14,9 @@
* limitations under the License.
*/
-package com.android.layoutlib.bridge;
+package com.android.layoutlib.bridge.android;
+
+import com.android.layoutlib.bridge.Bridge;
import android.content.res.AssetManager;
@@ -28,7 +30,7 @@
* <p/>
* {@link Bridge} calls this method after setting up a new bridge.
*/
- /*package*/ static AssetManager initSystem() {
+ /*package*/ public static AssetManager initSystem() {
if (!(AssetManager.sSystem instanceof BridgeAssetManager)) {
// Note that AssetManager() creates a system AssetManager and we override it
// with our BridgeAssetManager.
@@ -42,7 +44,7 @@
* Clears the static {@link AssetManager#sSystem} to make sure we don't leave objects
* around that would prevent us from unloading the library.
*/
- /*package*/ static void clearSystem() {
+ public static void clearSystem() {
AssetManager.sSystem = null;
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContentProvider.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java
similarity index 98%
rename from tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContentProvider.java
rename to tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java
index 9d6dd27..3835378 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContentProvider.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.layoutlib.bridge;
+package com.android.layoutlib.bridge.android;
import android.content.ContentProviderOperation;
import android.content.ContentProviderResult;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContentResolver.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentResolver.java
similarity index 98%
rename from tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContentResolver.java
rename to tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentResolver.java
index e15cb69..0257686 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContentResolver.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentResolver.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.layoutlib.bridge;
+package com.android.layoutlib.bridge.android;
import android.content.ContentResolver;
import android.content.Context;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
similarity index 93%
rename from tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java
rename to tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index b9899b2..2fa97a3 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -14,12 +14,15 @@
* limitations under the License.
*/
-package com.android.layoutlib.bridge;
+package com.android.layoutlib.bridge.android;
import com.android.layoutlib.api.ILayoutLog;
import com.android.layoutlib.api.IProjectCallback;
import com.android.layoutlib.api.IResourceValue;
import com.android.layoutlib.api.IStyleResourceValue;
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.BridgeConstants;
+import com.android.layoutlib.bridge.impl.TempResourceValue;
import android.app.Activity;
import android.app.Fragment;
@@ -50,7 +53,6 @@
import android.os.Looper;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
-import android.view.BridgeInflater;
import android.view.LayoutInflater;
import android.view.View;
@@ -66,15 +68,16 @@
import java.util.Map.Entry;
/**
- * Custom implementation of Context to handle non compiled resources.
+ * Custom implementation of Context/Activity to handle non compiled resources.
*/
public final class BridgeContext extends Activity {
- private final Resources mResources;
- private final Theme mTheme;
+ private Resources mResources;
+ private Theme mTheme;
private final HashMap<View, Object> mViewKeyMap = new HashMap<View, Object>();
private final IStyleResourceValue mThemeValues;
private final Object mProjectKey;
+ private final DisplayMetrics mMetrics;
private final Map<String, Map<String, IResourceValue>> mProjectResources;
private final Map<String, Map<String, IResourceValue>> mFrameworkResources;
private final Map<IStyleResourceValue, IStyleResourceValue> mStyleInheritanceMap;
@@ -105,28 +108,18 @@
* contains (String, {@link IResourceValue}) pairs where the key is the resource name, and the
* value is the resource value.
* @param styleInheritanceMap
- * @param customViewLoader
+ * @param projectCallback
*/
public BridgeContext(Object projectKey, DisplayMetrics metrics,
IStyleResourceValue currentTheme,
Map<String, Map<String, IResourceValue>> projectResources,
Map<String, Map<String, IResourceValue>> frameworkResources,
Map<IStyleResourceValue, IStyleResourceValue> styleInheritanceMap,
- IProjectCallback customViewLoader, ILayoutLog logger) {
+ IProjectCallback projectCallback, ILayoutLog logger) {
mProjectKey = projectKey;
- mProjectCallback = customViewLoader;
+ mMetrics = metrics;
+ mProjectCallback = projectCallback;
mLogger = logger;
- Configuration config = new Configuration();
-
- AssetManager assetManager = BridgeAssetManager.initSystem();
- mResources = BridgeResources.initSystem(
- this,
- assetManager,
- metrics,
- config,
- customViewLoader);
-
- mTheme = mResources.newTheme();
mThemeValues = currentTheme;
mProjectResources = projectResources;
@@ -137,6 +130,32 @@
mFragments.mActivity = this;
}
+ /**
+ * Initializes the {@link Resources} singleton to be linked to this {@link Context}, its
+ * {@link DisplayMetrics}, {@link Configuration}, and {@link IProjectCallback}.
+ *
+ * @see #disposeResources()
+ */
+ public void initResources() {
+ AssetManager assetManager = AssetManager.getSystem();
+ Configuration config = new Configuration();
+
+ mResources = BridgeResources.initSystem(
+ this,
+ assetManager,
+ mMetrics,
+ config,
+ mProjectCallback);
+ mTheme = mResources.newTheme();
+ }
+
+ /**
+ * Disposes the {@link Resources} singleton.
+ */
+ public void disposeResources() {
+ BridgeResources.disposeSystem();
+ }
+
public void setBridgeInflater(BridgeInflater inflater) {
mInflater = inflater;
}
@@ -266,6 +285,15 @@
return null;
}
+ Object key = null;
+ if (parser != null) {
+ key = parser.getViewKey();
+ }
+ if (key != null) {
+ String attrs_name = Bridge.resolveResourceValue(attrs);
+ System.out.println("KEY: " + key.toString() + "(" + attrs_name + ")");
+ }
+
boolean[] frameworkAttributes = new boolean[1];
TreeMap<Integer, String> styleNameMap = searchAttrs(attrs, frameworkAttributes);
@@ -281,6 +309,9 @@
customStyle = parser.getAttributeValue(null /* namespace*/, "style");
}
if (customStyle != null) {
+ if (key != null) {
+ print("style", customStyle, false);
+ }
IResourceValue item = findResValue(customStyle, false /*forceFrameworkOnly*/);
if (item instanceof IStyleResourceValue) {
@@ -292,6 +323,10 @@
// get the name from the int.
String defStyleName = searchAttr(defStyleAttr);
+ if (key != null) {
+ print("style", defStyleName, true);
+ }
+
// look for the style in the current theme, and its parent:
if (mThemeValues != null) {
IResourceValue item = findItemInStyle(mThemeValues, defStyleName);
@@ -350,11 +385,20 @@
// if we found a value, we make sure this doesn't reference another value.
// So we resolve it.
if (resValue != null) {
+ if (key != null) {
+ print(name, resValue.getValue(), true);
+ }
+
resValue = resolveResValue(resValue);
+ } else if (key != null) {
+ print(name, "<unknown>", true);
}
ta.bridgeSetValue(index, name, resValue);
} else {
+ if (key != null) {
+ print(name, value, false);
+ }
// there is a value in the XML, but we need to resolve it in case it's
// referencing another resource or a theme value.
ta.bridgeSetValue(index, name, resolveValue(null, name, value));
@@ -367,6 +411,15 @@
return ta;
}
+ private void print(String name, String value, boolean isDefault) {
+ System.out.print("\t" + name + " : " + value);
+ if (isDefault) {
+ System.out.println(" (default)");
+ } else {
+ System.out.println("");
+ }
+ }
+
@Override
public Looper getMainLooper() {
return Looper.myLooper();
@@ -433,7 +486,7 @@
// if resValue is null, but value is not null, this means it was not a reference.
// we return the name/value wrapper in a IResourceValue
if (resValue == null) {
- return new ResourceValue(type, name, value);
+ return new TempResourceValue(type, name, value);
}
// we resolved a first reference, but we need to make sure this isn't a reference also.
@@ -453,7 +506,7 @@
* @param value the value containing the reference to resolve.
* @return a {@link IResourceValue} object or <code>null</code>
*/
- IResourceValue resolveResValue(IResourceValue value) {
+ public IResourceValue resolveResValue(IResourceValue value) {
if (value == null) {
return null;
}
@@ -661,7 +714,7 @@
* @param itemName the name of the item to search for.
* @return the {@link IResourceValue} object or <code>null</code>
*/
- IResourceValue findItemInStyle(IStyleResourceValue style, String itemName) {
+ public IResourceValue findItemInStyle(IStyleResourceValue style, String itemName) {
IResourceValue item = style.findItem(itemName);
// if we didn't find it, we look in the parent style (if applicable)
diff --git a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeInflater.java
similarity index 97%
rename from tools/layoutlib/bridge/src/android/view/BridgeInflater.java
rename to tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeInflater.java
index 4bc8855..b4a28a6 100644
--- a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeInflater.java
@@ -14,20 +14,22 @@
* limitations under the License.
*/
-package android.view;
+package com.android.layoutlib.bridge.android;
import com.android.layoutlib.api.IProjectCallback;
import com.android.layoutlib.api.IResourceValue;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.BridgeConstants;
-import com.android.layoutlib.bridge.BridgeContext;
-import com.android.layoutlib.bridge.BridgeXmlBlockParser;
import org.kxml2.io.KXmlParser;
import org.xmlpull.v1.XmlPullParser;
import android.content.Context;
import android.util.AttributeSet;
+import android.view.InflateException;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
import java.io.File;
import java.io.FileReader;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeResources.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeResources.java
similarity index 97%
rename from tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeResources.java
rename to tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeResources.java
index 6358abb..46eb776 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeResources.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeResources.java
@@ -14,10 +14,13 @@
* limitations under the License.
*/
-package com.android.layoutlib.bridge;
+package com.android.layoutlib.bridge.android;
import com.android.layoutlib.api.IProjectCallback;
import com.android.layoutlib.api.IResourceValue;
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.BridgeConstants;
+import com.android.layoutlib.bridge.impl.ResourceHelper;
import org.kxml2.io.KXmlParser;
import org.xmlpull.v1.XmlPullParser;
@@ -64,21 +67,18 @@
DisplayMetrics metrics,
Configuration config,
IProjectCallback projectCallback) {
- if (!(Resources.mSystem instanceof BridgeResources)) {
- Resources.mSystem = new BridgeResources(context,
- assets,
- metrics,
- config,
- projectCallback);
- }
- return Resources.mSystem;
+ return Resources.mSystem = new BridgeResources(context,
+ assets,
+ metrics,
+ config,
+ projectCallback);
}
/**
- * Clears the static {@link Resources#mSystem} to make sure we don't leave objects
+ * Disposes the static {@link Resources#mSystem} to make sure we don't leave objects
* around that would prevent us from unloading the library.
*/
- /*package*/ static void clearSystem() {
+ /*package*/ static void disposeSystem() {
if (Resources.mSystem instanceof BridgeResources) {
((BridgeResources)(Resources.mSystem)).mContext = null;
((BridgeResources)(Resources.mSystem)).mProjectCallback = null;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeTypedArray.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java
similarity index 98%
rename from tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeTypedArray.java
rename to tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java
index 70c5bd7..c3ab461 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeTypedArray.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java
@@ -14,11 +14,14 @@
* limitations under the License.
*/
-package com.android.layoutlib.bridge;
+package com.android.layoutlib.bridge.android;
import com.android.internal.util.XmlUtils;
import com.android.layoutlib.api.IResourceValue;
import com.android.layoutlib.api.IStyleResourceValue;
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.BridgeConstants;
+import com.android.layoutlib.bridge.impl.ResourceHelper;
import org.kxml2.io.KXmlParser;
import org.xmlpull.v1.XmlPullParser;
@@ -36,7 +39,7 @@
import java.util.Map;
/**
- * TODO: describe.
+ * Custom implementation of TypedArray to handle non compiled resources.
*/
public final class BridgeTypedArray extends TypedArray {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
new file mode 100644
index 0000000..c04c9e8
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
@@ -0,0 +1,92 @@
+/*
+ * 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.android;
+
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.view.DragEvent;
+import android.view.IWindow;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.View.AttachInfo;
+
+/**
+ * Implementation of {@link IWindow} to pass to the {@link AttachInfo}.
+ */
+public final class BridgeWindow implements IWindow {
+
+ public void dispatchAppVisibility(boolean arg0) throws RemoteException {
+ // pass for now.
+ }
+
+ public void dispatchGetNewSurface() throws RemoteException {
+ // pass for now.
+ }
+
+ public void dispatchKey(KeyEvent arg0) throws RemoteException {
+ // pass for now.
+ }
+
+ public void dispatchPointer(MotionEvent arg0, long arg1, boolean arg2) throws RemoteException {
+ // pass for now.
+ }
+
+ public void dispatchTrackball(MotionEvent arg0, long arg1, boolean arg2) throws RemoteException {
+ // pass for now.
+ }
+
+ public void executeCommand(String arg0, String arg1, ParcelFileDescriptor arg2)
+ throws RemoteException {
+ // pass for now.
+ }
+
+ public void resized(int arg0, int arg1, Rect arg2, Rect arg3, boolean arg4, Configuration arg5)
+ throws RemoteException {
+ // pass for now.
+ }
+
+ public void windowFocusChanged(boolean arg0, boolean arg1) throws RemoteException {
+ // pass for now.
+ }
+
+ public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep,
+ boolean sync) {
+ // pass for now.
+ }
+
+ public void dispatchWallpaperCommand(String action, int x, int y,
+ int z, Bundle extras, boolean sync) {
+ // pass for now.
+ }
+
+ public void closeSystemDialogs(String reason) {
+ // pass for now.
+ }
+
+ public void dispatchDragEvent(DragEvent event) {
+ // pass for now.
+ }
+
+ public IBinder asBinder() {
+ // pass for now.
+ return null;
+ }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
new file mode 100644
index 0000000..74e5a65
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
@@ -0,0 +1,163 @@
+/*
+ * 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.android;
+
+import android.content.ClipData;
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.graphics.Region;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.view.IWindow;
+import android.view.IWindowSession;
+import android.view.InputChannel;
+import android.view.MotionEvent;
+import android.view.Surface;
+import android.view.SurfaceView;
+import android.view.WindowManager.LayoutParams;
+
+/**
+ * Implementation of {@link IWindowSession} so that mSession is not null in
+ * the {@link SurfaceView}.
+ */
+public final class BridgeWindowSession implements IWindowSession {
+
+ public int add(IWindow arg0, LayoutParams arg1, int arg2, Rect arg3,
+ InputChannel outInputchannel)
+ throws RemoteException {
+ // pass for now.
+ return 0;
+ }
+
+ public int addWithoutInputChannel(IWindow arg0, LayoutParams arg1, int arg2, Rect arg3)
+ throws RemoteException {
+ // pass for now.
+ return 0;
+ }
+
+ public void finishDrawing(IWindow arg0) throws RemoteException {
+ // pass for now.
+ }
+
+ public void finishKey(IWindow arg0) throws RemoteException {
+ // pass for now.
+ }
+
+ public boolean getInTouchMode() throws RemoteException {
+ // pass for now.
+ return false;
+ }
+
+ public boolean performHapticFeedback(IWindow window, int effectId, boolean always) {
+ // pass for now.
+ return false;
+ }
+
+ public MotionEvent getPendingPointerMove(IWindow arg0) throws RemoteException {
+ // pass for now.
+ return null;
+ }
+
+ public MotionEvent getPendingTrackballMove(IWindow arg0) throws RemoteException {
+ // pass for now.
+ return null;
+ }
+
+ public int relayout(IWindow arg0, LayoutParams arg1, int arg2, int arg3, int arg4,
+ boolean arg4_5, Rect arg5, Rect arg6, Rect arg7, Configuration arg7b, Surface arg8)
+ throws RemoteException {
+ // pass for now.
+ return 0;
+ }
+
+ public void getDisplayFrame(IWindow window, Rect outDisplayFrame) {
+ // pass for now.
+ }
+
+ public void remove(IWindow arg0) throws RemoteException {
+ // pass for now.
+ }
+
+ public void setInTouchMode(boolean arg0) throws RemoteException {
+ // pass for now.
+ }
+
+ public void setTransparentRegion(IWindow arg0, Region arg1) throws RemoteException {
+ // pass for now.
+ }
+
+ public void setInsets(IWindow window, int touchable, Rect contentInsets,
+ Rect visibleInsets) {
+ // pass for now.
+ }
+
+ public IBinder prepareDrag(IWindow window, boolean localOnly,
+ int thumbnailWidth, int thumbnailHeight, Surface outSurface)
+ throws RemoteException {
+ // pass for now
+ return null;
+ }
+
+ public boolean performDrag(IWindow window, IBinder dragToken,
+ float touchX, float touchY, float thumbCenterX, float thumbCenterY,
+ ClipData data)
+ throws RemoteException {
+ // pass for now
+ return false;
+ }
+
+ public void reportDropResult(IWindow window, boolean consumed) throws RemoteException {
+ // pass for now
+ }
+
+ public void dragRecipientEntered(IWindow window) throws RemoteException {
+ // pass for now
+ }
+
+ public void dragRecipientExited(IWindow window) throws RemoteException {
+ // pass for now
+ }
+
+ public void setWallpaperPosition(IBinder window, float x, float y,
+ float xStep, float yStep) {
+ // pass for now.
+ }
+
+ public void wallpaperOffsetsComplete(IBinder window) {
+ // pass for now.
+ }
+
+ public Bundle sendWallpaperCommand(IBinder window, String action, int x, int y,
+ int z, Bundle extras, boolean sync) {
+ // pass for now.
+ return null;
+ }
+
+ public void wallpaperCommandComplete(IBinder window, Bundle result) {
+ // pass for now.
+ }
+
+ public void closeSystemDialogs(String reason) {
+ // pass for now.
+ }
+
+ public IBinder asBinder() {
+ // pass for now.
+ return null;
+ }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeXmlBlockParser.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParser.java
similarity index 99%
rename from tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeXmlBlockParser.java
rename to tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParser.java
index d842a66..24f61c8 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeXmlBlockParser.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParser.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.layoutlib.bridge;
+package com.android.layoutlib.bridge.android;
import com.android.layoutlib.api.IXmlPullParser;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeXmlPullAttributes.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeXmlPullAttributes.java
similarity index 96%
rename from tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeXmlPullAttributes.java
rename to tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeXmlPullAttributes.java
index d145ff6..c99b70b 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeXmlPullAttributes.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeXmlPullAttributes.java
@@ -14,9 +14,11 @@
* limitations under the License.
*/
-package com.android.layoutlib.bridge;
+package com.android.layoutlib.bridge.android;
import com.android.layoutlib.api.IResourceValue;
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.BridgeConstants;
import org.xmlpull.v1.XmlPullParser;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/MockView.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/MockView.java
similarity index 96%
rename from tools/layoutlib/bridge/src/com/android/layoutlib/bridge/MockView.java
rename to tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/MockView.java
index 1ca3182..e5bddcb 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/MockView.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/MockView.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.layoutlib.bridge;
+package com.android.layoutlib.bridge.android;
import android.content.Context;
import android.graphics.Canvas;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/NinePatchDrawable.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/NinePatchDrawable.java
similarity index 96%
rename from tools/layoutlib/bridge/src/com/android/layoutlib/bridge/NinePatchDrawable.java
rename to tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/NinePatchDrawable.java
index 2c92567..4efa631 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/NinePatchDrawable.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/NinePatchDrawable.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.layoutlib.bridge;
+package com.android.layoutlib.bridge.android;
import com.android.ninepatch.NinePatch;
@@ -28,7 +28,7 @@
private NinePatch m9Patch;
- NinePatchDrawable(NinePatch ninePatch) {
+ public NinePatchDrawable(NinePatch ninePatch) {
m9Patch = ninePatch;
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/DelegateManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/DelegateManager.java
similarity index 98%
rename from tools/layoutlib/bridge/src/com/android/layoutlib/bridge/DelegateManager.java
rename to tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/DelegateManager.java
index 3d9f960..169d751 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/DelegateManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/DelegateManager.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.layoutlib.bridge;
+package com.android.layoutlib.bridge.impl;
import android.util.SparseArray;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/FontLoader.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/FontLoader.java
similarity index 99%
rename from tools/layoutlib/bridge/src/com/android/layoutlib/bridge/FontLoader.java
rename to tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/FontLoader.java
index de89a81..5d56370 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/FontLoader.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/FontLoader.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.layoutlib.bridge;
+package com.android.layoutlib.bridge.impl;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/LayoutSceneImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/LayoutSceneImpl.java
new file mode 100644
index 0000000..2012229
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/LayoutSceneImpl.java
@@ -0,0 +1,689 @@
+/*
+ * 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 com.android.internal.util.XmlUtils;
+import com.android.layoutlib.api.IProjectCallback;
+import com.android.layoutlib.api.IResourceValue;
+import com.android.layoutlib.api.IStyleResourceValue;
+import com.android.layoutlib.api.LayoutBridge;
+import com.android.layoutlib.api.SceneParams;
+import com.android.layoutlib.api.SceneResult;
+import com.android.layoutlib.api.ViewInfo;
+import com.android.layoutlib.api.IDensityBasedResourceValue.Density;
+import com.android.layoutlib.bridge.BridgeConstants;
+import com.android.layoutlib.bridge.android.BridgeContext;
+import com.android.layoutlib.bridge.android.BridgeInflater;
+import com.android.layoutlib.bridge.android.BridgeWindow;
+import com.android.layoutlib.bridge.android.BridgeWindowSession;
+import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
+
+import android.app.Fragment_Delegate;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap_Delegate;
+import android.graphics.Canvas;
+import android.graphics.Canvas_Delegate;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.Looper;
+import android.util.DisplayMetrics;
+import android.util.TypedValue;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.View.AttachInfo;
+import android.view.View.MeasureSpec;
+import android.widget.FrameLayout;
+import android.widget.TabHost;
+import android.widget.TabWidget;
+
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.image.BufferedImage;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Class managing a layout "scene".
+ *
+ * A scene is a stateful representation of a layout file. It is initialized with data coming through
+ * the {@link LayoutBridge} API to inflate the layout. Further actions and rendering can then
+ * be done on the layout.
+ *
+ */
+public class LayoutSceneImpl {
+
+ private static final int DEFAULT_TITLE_BAR_HEIGHT = 25;
+ private static final int DEFAULT_STATUS_BAR_HEIGHT = 25;
+
+ private final SceneParams mParams;
+
+ // scene state
+ private BridgeContext mContext;
+ private BridgeXmlBlockParser mBlockParser;
+ private BridgeInflater mInflater;
+ private IStyleResourceValue mCurrentTheme;
+ private int mScreenOffset;
+ private IResourceValue mWindowBackground;
+ private FrameLayout mViewRoot;
+
+ // information being returned through the API
+ private BufferedImage mImage;
+ private ViewInfo mViewInfo;
+
+ private static final class PostInflateException extends Exception {
+ private static final long serialVersionUID = 1L;
+
+ public PostInflateException(String message) {
+ super(message);
+ }
+ }
+
+ /**
+ * Creates a layout scene with all the information coming from the layout bridge API.
+ *
+ * This also calls {@link LayoutSceneImpl#prepare()}.
+ * <p>
+ * <b>THIS MUST BE INSIDE A SYNCHRONIZED BLOCK on the BRIDGE OBJECT.<b>
+ *
+ * @see LayoutBridge#createScene(com.android.layoutlib.api.SceneParams)
+ */
+ public LayoutSceneImpl(SceneParams params) {
+ // we need to make sure the Looper has been initialized for this thread.
+ // this is required for View that creates Handler objects.
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+
+ // copy the params.
+ mParams = new SceneParams(params);
+
+ // 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();
+
+ // find the current theme and compute the style inheritance map
+ Map<IStyleResourceValue, IStyleResourceValue> styleParentMap =
+ new HashMap<IStyleResourceValue, IStyleResourceValue>();
+
+ mCurrentTheme = computeStyleMaps(mParams.getThemeName(), mParams.getIsProjectTheme(),
+ mParams.getProjectResources().get(BridgeConstants.RES_STYLE),
+ mParams.getFrameworkResources().get(BridgeConstants.RES_STYLE), styleParentMap);
+
+ // build the context
+ mContext = new BridgeContext(mParams.getProjectKey(), metrics, mCurrentTheme,
+ mParams.getProjectResources(), mParams.getFrameworkResources(),
+ styleParentMap, mParams.getProjectCallback(), mParams.getLogger());
+
+ // make sure the Resources object references the context (and other objects) for this
+ // scene
+ mContext.initResources();
+
+ // get the screen offset and window-background resource
+ mWindowBackground = null;
+ mScreenOffset = 0;
+ if (mCurrentTheme != null && mParams.isCustomBackgroundEnabled() == false) {
+ mWindowBackground = mContext.findItemInStyle(mCurrentTheme, "windowBackground");
+ mWindowBackground = mContext.resolveResValue(mWindowBackground);
+
+ mScreenOffset = getScreenOffset(mParams.getFrameworkResources(), mCurrentTheme, mContext);
+ }
+
+ // build the inflater and parser.
+ mInflater = new BridgeInflater(mContext, mParams.getProjectCallback());
+ mContext.setBridgeInflater(mInflater);
+ mInflater.setFactory2(mContext);
+
+ mBlockParser = new BridgeXmlBlockParser(mParams.getLayoutDescription(),
+ mContext, false /* platformResourceFlag */);
+ }
+
+ /**
+ * Prepares the scene for action.
+ * <p>
+ * <b>THIS MUST BE INSIDE A SYNCHRONIZED BLOCK on the BRIDGE OBJECT.<b>
+ */
+ public void prepare() {
+ // we need to make sure the Looper has been initialized for this thread.
+ // this is required for View that creates Handler objects.
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+
+ // make sure the Resources object references the context (and other objects) for this
+ // scene
+ mContext.initResources();
+ }
+
+ /**
+ * Cleans up the scene after an action.
+ * <p>
+ * <b>THIS MUST BE INSIDE A SYNCHRONIZED BLOCK on the BRIDGE OBJECT.<b>
+ */
+ public void cleanup() {
+ // clean up the looper
+ Looper.sThreadLocal.remove();
+
+ // Make sure to remove static references, otherwise we could not unload the lib
+ mContext.disposeResources();
+ }
+
+ /**
+ * Inflates the layout.
+ * <p>
+ * <b>THIS MUST BE INSIDE A SYNCHRONIZED BLOCK on the BRIDGE OBJECT.<b>
+ */
+ public SceneResult inflate() {
+ 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());
+
+ View view = mInflater.inflate(mBlockParser, mViewRoot);
+
+ // post-inflate process. For now this supports TabHost/TabWidget
+ postInflateProcess(view, mParams.getProjectCallback());
+
+ Fragment_Delegate.setProjectCallback(null);
+
+ // 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.
+ mViewRoot.dispatchAttachedToWindow(info, 0);
+
+ // get the background drawable
+ if (mWindowBackground != null) {
+ Drawable d = ResourceHelper.getDrawable(mWindowBackground,
+ mContext, true /* isFramework */);
+ mViewRoot.setBackgroundDrawable(d);
+ }
+
+ return SceneResult.SUCCESS;
+ } catch (PostInflateException e) {
+ return new SceneResult("Error during post inflation process:\n" + e.getMessage());
+ } catch (Throwable e) {
+ // get the real cause of the exception.
+ Throwable t = e;
+ while (t.getCause() != null) {
+ t = t.getCause();
+ }
+
+ // log it
+ mParams.getLogger().error(t);
+
+ return new SceneResult("Unknown error during inflation.", t);
+ }
+ }
+
+ /**
+ * Renders the scene.
+ * <p>
+ * <b>THIS MUST BE INSIDE A SYNCHRONIZED BLOCK on the BRIDGE OBJECT.<b>
+ */
+ public SceneResult render() {
+ try {
+ if (mViewRoot == null) {
+ return new SceneResult("Layout has not been inflated!");
+ }
+ // measure the views
+ int w_spec, h_spec;
+
+ int renderScreenWidth = mParams.getScreenWidth();
+ int renderScreenHeight = mParams.getScreenHeight();
+
+ if (mParams.getRenderFullSize()) {
+ // measure the full size needed by the layout.
+ w_spec = MeasureSpec.makeMeasureSpec(renderScreenWidth,
+ MeasureSpec.UNSPECIFIED); // this lets us know the actual needed size
+ h_spec = MeasureSpec.makeMeasureSpec(renderScreenHeight - mScreenOffset,
+ MeasureSpec.UNSPECIFIED); // this lets us know the actual needed size
+ mViewRoot.measure(w_spec, h_spec);
+
+ int neededWidth = mViewRoot.getChildAt(0).getMeasuredWidth();
+ if (neededWidth > renderScreenWidth) {
+ renderScreenWidth = neededWidth;
+ }
+
+ int neededHeight = mViewRoot.getChildAt(0).getMeasuredHeight();
+ if (neededHeight > renderScreenHeight - mScreenOffset) {
+ renderScreenHeight = neededHeight + mScreenOffset;
+ }
+ }
+
+ // remeasure with the size we need
+ // This must always be done before the call to layout
+ w_spec = MeasureSpec.makeMeasureSpec(renderScreenWidth, MeasureSpec.EXACTLY);
+ h_spec = MeasureSpec.makeMeasureSpec(renderScreenHeight - mScreenOffset,
+ MeasureSpec.EXACTLY);
+ mViewRoot.measure(w_spec, h_spec);
+
+ // now do the layout.
+ mViewRoot.layout(0, mScreenOffset, renderScreenWidth, renderScreenHeight);
+
+ // draw the views
+ // create the BufferedImage into which the layout will be rendered.
+ mImage = new BufferedImage(renderScreenWidth, renderScreenHeight - mScreenOffset,
+ BufferedImage.TYPE_INT_ARGB);
+
+ if (mParams.isCustomBackgroundEnabled()) {
+ Graphics2D gc = mImage.createGraphics();
+ gc.setColor(new Color(mParams.getCustomBackgroundColor()));
+ gc.fillRect(0, 0, renderScreenWidth, renderScreenHeight - mScreenOffset);
+ gc.dispose();
+ }
+
+ // create an Android bitmap around the BufferedImage
+ Bitmap bitmap = Bitmap_Delegate.createBitmap(mImage,
+ Density.getEnum(mParams.getDensity()));
+
+ // create a Canvas around the Android bitmap
+ Canvas canvas = new Canvas(bitmap);
+
+ // to set the logger, get the native delegate
+ Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(canvas);
+ canvasDelegate.setLogger(mParams.getLogger());
+
+ mViewRoot.draw(canvas);
+ canvasDelegate.dispose();
+
+ mViewInfo = visit(((ViewGroup)mViewRoot).getChildAt(0), mContext);
+
+ // success!
+ return SceneResult.SUCCESS;
+ } catch (Throwable e) {
+ // get the real cause of the exception.
+ Throwable t = e;
+ while (t.getCause() != null) {
+ t = t.getCause();
+ }
+
+ // log it
+ mParams.getLogger().error(t);
+
+ return new SceneResult("Unknown error during inflation.", t);
+ }
+ }
+
+ /**
+ * Compute style information from the given list of style for the project and framework.
+ * @param themeName the name of the current theme. In order to differentiate project and
+ * platform themes sharing the same name, all project themes must be prepended with
+ * a '*' character.
+ * @param isProjectTheme Is this a project theme
+ * @param inProjectStyleMap the project style map
+ * @param inFrameworkStyleMap the framework style map
+ * @param outInheritanceMap the map of style inheritance. This is filled by the method
+ * @return the {@link IStyleResourceValue} matching <var>themeName</var>
+ */
+ private IStyleResourceValue computeStyleMaps(
+ String themeName, boolean isProjectTheme, Map<String,
+ IResourceValue> inProjectStyleMap, Map<String, IResourceValue> inFrameworkStyleMap,
+ Map<IStyleResourceValue, IStyleResourceValue> outInheritanceMap) {
+
+ if (inProjectStyleMap != null && inFrameworkStyleMap != null) {
+ // first, get the theme
+ IResourceValue theme = null;
+
+ // project theme names have been prepended with a *
+ if (isProjectTheme) {
+ theme = inProjectStyleMap.get(themeName);
+ } else {
+ theme = inFrameworkStyleMap.get(themeName);
+ }
+
+ if (theme instanceof IStyleResourceValue) {
+ // compute the inheritance map for both the project and framework styles
+ computeStyleInheritance(inProjectStyleMap.values(), inProjectStyleMap,
+ inFrameworkStyleMap, outInheritanceMap);
+
+ // Compute the style inheritance for the framework styles/themes.
+ // Since, for those, the style parent values do not contain 'android:'
+ // we want to force looking in the framework style only to avoid using
+ // similarly named styles from the project.
+ // To do this, we pass null in lieu of the project style map.
+ computeStyleInheritance(inFrameworkStyleMap.values(), null /*inProjectStyleMap */,
+ inFrameworkStyleMap, outInheritanceMap);
+
+ return (IStyleResourceValue)theme;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Compute the parent style for all the styles in a given list.
+ * @param styles the styles for which we compute the parent.
+ * @param inProjectStyleMap the map of project styles.
+ * @param inFrameworkStyleMap the map of framework styles.
+ * @param outInheritanceMap the map of style inheritance. This is filled by the method.
+ */
+ private void computeStyleInheritance(Collection<IResourceValue> styles,
+ Map<String, IResourceValue> inProjectStyleMap,
+ Map<String, IResourceValue> inFrameworkStyleMap,
+ Map<IStyleResourceValue, IStyleResourceValue> outInheritanceMap) {
+ for (IResourceValue value : styles) {
+ if (value instanceof IStyleResourceValue) {
+ IStyleResourceValue style = (IStyleResourceValue)value;
+ IStyleResourceValue parentStyle = null;
+
+ // first look for a specified parent.
+ String parentName = style.getParentStyle();
+
+ // no specified parent? try to infer it from the name of the style.
+ if (parentName == null) {
+ parentName = getParentName(value.getName());
+ }
+
+ if (parentName != null) {
+ parentStyle = getStyle(parentName, inProjectStyleMap, inFrameworkStyleMap);
+
+ if (parentStyle != null) {
+ outInheritanceMap.put(style, parentStyle);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Searches for and returns the {@link IStyleResourceValue} from a given name.
+ * <p/>The format of the name can be:
+ * <ul>
+ * <li>[android:]<name></li>
+ * <li>[android:]style/<name></li>
+ * <li>@[android:]style/<name></li>
+ * </ul>
+ * @param parentName the name of the style.
+ * @param inProjectStyleMap the project style map. Can be <code>null</code>
+ * @param inFrameworkStyleMap the framework style map.
+ * @return The matching {@link IStyleResourceValue} object or <code>null</code> if not found.
+ */
+ private IStyleResourceValue getStyle(String parentName,
+ Map<String, IResourceValue> inProjectStyleMap,
+ Map<String, IResourceValue> inFrameworkStyleMap) {
+ boolean frameworkOnly = false;
+
+ String name = parentName;
+
+ // remove the useless @ if it's there
+ if (name.startsWith(BridgeConstants.PREFIX_RESOURCE_REF)) {
+ name = name.substring(BridgeConstants.PREFIX_RESOURCE_REF.length());
+ }
+
+ // check for framework identifier.
+ if (name.startsWith(BridgeConstants.PREFIX_ANDROID)) {
+ frameworkOnly = true;
+ name = name.substring(BridgeConstants.PREFIX_ANDROID.length());
+ }
+
+ // at this point we could have the format <type>/<name>. we want only the name as long as
+ // the type is style.
+ if (name.startsWith(BridgeConstants.REFERENCE_STYLE)) {
+ name = name.substring(BridgeConstants.REFERENCE_STYLE.length());
+ } else if (name.indexOf('/') != -1) {
+ return null;
+ }
+
+ IResourceValue parent = null;
+
+ // if allowed, search in the project resources.
+ if (frameworkOnly == false && inProjectStyleMap != null) {
+ parent = inProjectStyleMap.get(name);
+ }
+
+ // if not found, then look in the framework resources.
+ if (parent == null) {
+ parent = inFrameworkStyleMap.get(name);
+ }
+
+ // make sure the result is the proper class type and return it.
+ if (parent instanceof IStyleResourceValue) {
+ return (IStyleResourceValue)parent;
+ }
+
+ mParams.getLogger().error(
+ String.format("Unable to resolve parent style name: %s", parentName));
+
+ return null;
+ }
+
+ /**
+ * Computes the name of the parent style, or <code>null</code> if the style is a root style.
+ */
+ private String getParentName(String styleName) {
+ int index = styleName.lastIndexOf('.');
+ if (index != -1) {
+ return styleName.substring(0, index);
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns the top screen offset. This depends on whether the current theme defines the user
+ * of the title and status bars.
+ * @param frameworkResources The framework resources
+ * @param currentTheme The current theme
+ * @param context The context
+ * @return the pixel height offset
+ */
+ private int getScreenOffset(Map<String, Map<String, IResourceValue>> frameworkResources,
+ IStyleResourceValue currentTheme, BridgeContext context) {
+ int offset = 0;
+
+ // get the title bar flag from the current theme.
+ IResourceValue value = context.findItemInStyle(currentTheme, "windowNoTitle");
+
+ // because it may reference something else, we resolve it.
+ value = context.resolveResValue(value);
+
+ // if there's a value and it's true (default is false)
+ if (value == null || value.getValue() == null ||
+ XmlUtils.convertValueToBoolean(value.getValue(), false /* defValue */) == false) {
+ // default size of the window title bar
+ int defaultOffset = DEFAULT_TITLE_BAR_HEIGHT;
+
+ // get value from the theme.
+ value = context.findItemInStyle(currentTheme, "windowTitleSize");
+
+ // resolve it
+ value = context.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
+ defaultOffset = (int)typedValue.getDimension(context.getResources().mMetrics);
+ }
+ }
+
+ offset += defaultOffset;
+ }
+
+ // get the fullscreen flag from the current theme.
+ value = context.findItemInStyle(currentTheme, "windowFullscreen");
+
+ // because it may reference something else, we resolve it.
+ value = context.resolveResValue(value);
+
+ if (value == null || value.getValue() == null ||
+ XmlUtils.convertValueToBoolean(value.getValue(), false /* defValue */) == false) {
+
+ // default value
+ int defaultOffset = DEFAULT_STATUS_BAR_HEIGHT;
+
+ // get the real value, first the list of Dimensions from the framework map
+ Map<String, IResourceValue> dimens = frameworkResources.get(BridgeConstants.RES_DIMEN);
+
+ // now get the value
+ value = dimens.get("status_bar_height");
+ if (value != null) {
+ TypedValue typedValue = ResourceHelper.getValue(value.getValue());
+ if (typedValue != null) {
+ // compute the pixel value based on the display metrics
+ defaultOffset = (int)typedValue.getDimension(context.getResources().mMetrics);
+ }
+ }
+
+ // add the computed offset.
+ offset += defaultOffset;
+ }
+
+ return offset;
+
+ }
+
+ /**
+ * Post process on a view hierachy that was just inflated.
+ * <p/>At the moment this only support TabHost: If {@link TabHost} is detected, look for the
+ * {@link TabWidget}, and the corresponding {@link FrameLayout} and make new tabs automatically
+ * based on the content of the {@link FrameLayout}.
+ * @param view the root view to process.
+ * @param projectCallback callback to the project.
+ */
+ private void postInflateProcess(View view, IProjectCallback projectCallback)
+ throws PostInflateException {
+ if (view instanceof TabHost) {
+ setupTabHost((TabHost)view, projectCallback);
+ } else if (view instanceof ViewGroup) {
+ ViewGroup group = (ViewGroup)view;
+ final int count = group.getChildCount();
+ for (int c = 0 ; c < count ; c++) {
+ View child = group.getChildAt(c);
+ postInflateProcess(child, projectCallback);
+ }
+ }
+ }
+
+ /**
+ * Sets up a {@link TabHost} object.
+ * @param tabHost the TabHost to setup.
+ * @param projectCallback The project callback object to access the project R class.
+ * @throws PostInflateException
+ */
+ private void setupTabHost(TabHost tabHost, IProjectCallback projectCallback)
+ throws PostInflateException {
+ // look for the TabWidget, and the FrameLayout. They have their own specific names
+ View v = tabHost.findViewById(android.R.id.tabs);
+
+ if (v == null) {
+ throw new PostInflateException(
+ "TabHost requires a TabWidget with id \"android:id/tabs\".\n");
+ }
+
+ if ((v instanceof TabWidget) == false) {
+ throw new PostInflateException(String.format(
+ "TabHost requires a TabWidget with id \"android:id/tabs\".\n" +
+ "View found with id 'tabs' is '%s'", v.getClass().getCanonicalName()));
+ }
+
+ v = tabHost.findViewById(android.R.id.tabcontent);
+
+ if (v == null) {
+ // TODO: see if we can fake tabs even without the FrameLayout (same below when the framelayout is empty)
+ throw new PostInflateException(
+ "TabHost requires a FrameLayout with id \"android:id/tabcontent\".");
+ }
+
+ if ((v instanceof FrameLayout) == false) {
+ throw new PostInflateException(String.format(
+ "TabHost requires a FrameLayout with id \"android:id/tabcontent\".\n" +
+ "View found with id 'tabcontent' is '%s'", v.getClass().getCanonicalName()));
+ }
+
+ FrameLayout content = (FrameLayout)v;
+
+ // now process the content of the framelayout and dynamically create tabs for it.
+ final int count = content.getChildCount();
+
+ if (count == 0) {
+ throw new PostInflateException(
+ "The FrameLayout for the TabHost has no content. Rendering failed.\n");
+ }
+
+ // this must be called before addTab() so that the TabHost searches its TabWidget
+ // and FrameLayout.
+ tabHost.setup();
+
+ // for each child of the framelayout, add a new TabSpec
+ for (int i = 0 ; i < count ; i++) {
+ View child = content.getChildAt(i);
+ String tabSpec = String.format("tab_spec%d", i+1);
+ int id = child.getId();
+ String[] resource = projectCallback.resolveResourceValue(id);
+ String name;
+ if (resource != null) {
+ name = resource[0]; // 0 is resource name, 1 is resource type.
+ } else {
+ name = String.format("Tab %d", i+1); // default name if id is unresolved.
+ }
+ tabHost.addTab(tabHost.newTabSpec(tabSpec).setIndicator(name).setContent(id));
+ }
+ }
+
+
+ /**
+ * 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.
+ */
+ private ViewInfo visit(View view, BridgeContext context) {
+ if (view == null) {
+ return null;
+ }
+
+ ViewInfo result = new ViewInfo(view.getClass().getName(),
+ context.getViewKey(view),
+ view.getLeft(), view.getTop(), view.getRight(), view.getBottom());
+
+ if (view instanceof ViewGroup) {
+ ViewGroup group = ((ViewGroup) view);
+ List<ViewInfo> children = new ArrayList<ViewInfo>();
+ for (int i = 0; i < group.getChildCount(); i++) {
+ children.add(visit(group.getChildAt(i), context));
+ }
+ result.setChildren(children);
+ }
+
+ return result;
+ }
+
+ public BufferedImage getImage() {
+ return mImage;
+ }
+
+ public ViewInfo getViewInfo() {
+ return mViewInfo;
+ }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/ResourceHelper.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
similarity index 97%
rename from tools/layoutlib/bridge/src/com/android/layoutlib/bridge/ResourceHelper.java
rename to tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
index f13ecdc..3e506b8 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/ResourceHelper.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
@@ -14,11 +14,15 @@
* limitations under the License.
*/
-package com.android.layoutlib.bridge;
+package com.android.layoutlib.bridge.impl;
import com.android.layoutlib.api.IDensityBasedResourceValue;
import com.android.layoutlib.api.IDensityBasedResourceValue.Density;
import com.android.layoutlib.api.IResourceValue;
+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.android.NinePatchDrawable;
import com.android.ninepatch.NinePatch;
import org.kxml2.io.KXmlParser;
@@ -56,7 +60,7 @@
* @return the color as an int
* @throw NumberFormatException if the conversion failed.
*/
- static int getColor(String value) {
+ public static int getColor(String value) {
if (value != null) {
if (value.startsWith("#") == false) {
throw new NumberFormatException();
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/ResourceValue.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/TempResourceValue.java
similarity index 74%
rename from tools/layoutlib/bridge/src/com/android/layoutlib/bridge/ResourceValue.java
rename to tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/TempResourceValue.java
index 01a4871..4ab98ce 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/ResourceValue.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/TempResourceValue.java
@@ -14,24 +14,24 @@
* limitations under the License.
*/
-package com.android.layoutlib.bridge;
+package com.android.layoutlib.bridge.impl;
+import com.android.layoutlib.api.ILayoutBridge;
import com.android.layoutlib.api.IResourceValue;
/**
- * Basic implementation of IResourceValue.
+ * Basic implementation of IResourceValue for when it is needed to dynamically make a new
+ * {@link IResourceValue} object.
+ *
+ * Most of the time, implementations of IResourceValue come through the {@link ILayoutBridge}
+ * API.
*/
-class ResourceValue implements IResourceValue {
+public class TempResourceValue implements IResourceValue {
private final String mType;
private final String mName;
private String mValue = null;
-
- ResourceValue(String name) {
- mType = null;
- mName = name;
- }
- public ResourceValue(String type, String name, String value) {
+ public TempResourceValue(String type, String name, String value) {
mType = type;
mName = name;
mValue = value;
@@ -44,16 +44,16 @@
public final String getName() {
return mName;
}
-
+
public final String getValue() {
return mValue;
}
-
+
public final void setValue(String value) {
mValue = value;
}
-
- public void replaceWith(ResourceValue value) {
+
+ public void replaceWith(TempResourceValue value) {
mValue = value.mValue;
}
diff --git a/tools/layoutlib/bridge/src/com/google/android/maps/MapView.java b/tools/layoutlib/bridge/src/com/google/android/maps/MapView.java
index 6d013bb..1ec6262 100644
--- a/tools/layoutlib/bridge/src/com/google/android/maps/MapView.java
+++ b/tools/layoutlib/bridge/src/com/google/android/maps/MapView.java
@@ -16,7 +16,7 @@
package com.google.android.maps;
-import com.android.layoutlib.bridge.MockView;
+import com.android.layoutlib.bridge.android.MockView;
import android.content.Context;
import android.os.Bundle;
diff --git a/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/BridgeXmlBlockParserTest.java b/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/android/BridgeXmlBlockParserTest.java
similarity index 96%
rename from tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/BridgeXmlBlockParserTest.java
rename to tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/android/BridgeXmlBlockParserTest.java
index db1262f..3252fb4 100644
--- a/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/BridgeXmlBlockParserTest.java
+++ b/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/android/BridgeXmlBlockParserTest.java
@@ -14,7 +14,9 @@
* limitations under the License.
*/
-package com.android.layoutlib.bridge;
+package com.android.layoutlib.bridge.android;
+
+import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
import org.kxml2.io.KXmlParser;
import org.w3c.dom.Node;