diff options
70 files changed, 2019 insertions, 1246 deletions
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 @@ public final class StrictMode { // 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 @@ public final class StrictMode { } /** + * 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 final class StrictMode { 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 @@ public final class StrictMode { 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 @@ public final class StrictMode { numAnimationsRunning = in.readInt(); violationUptimeMillis = in.readLong(); broadcastIntentAction = in.readString(); + tags = in.readStringArray(); } /** @@ -1325,6 +1486,7 @@ public final class StrictMode { dest.writeInt(numAnimationsRunning); dest.writeLong(violationUptimeMillis); dest.writeString(broadcastIntentAction); + dest.writeStringArray(tags); } @@ -1347,6 +1509,12 @@ public final class StrictMode { 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 class View implements Drawable.Callback, KeyEvent.Callback, Accessibility 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 fb760ac..f3f9a6d 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -6529,8 +6529,11 @@ public class WebView extends AbsoluteLayout // 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 org.xmlpull.v1.XmlPullParserException; 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.Log; 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 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener 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 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } - 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; + } + if (webPasswordInputType) { mInputType = (mInputType & ~(EditorInfo.TYPE_MASK_VARIATION)) - | EditorInfo.TYPE_TEXT_VARIATION_PASSWORD; + | EditorInfo.TYPE_TEXT_VARIATION_WEB_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 (selectallonfocus) { @@ -880,7 +888,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener 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 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } 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 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } 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 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } 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 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener */ @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 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener mInputType |= EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE; } } - applySingleLine(singleLine, true); } private void applySingleLine(boolean singleLine, boolean applyTransformation) { @@ -6731,10 +6748,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener 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 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener */ Selection.setSelection((Spannable) mText, selStart, selEnd); } + + if (mSelectAllOnFocus) { + Selection.setSelection((Spannable) mText, 0, mText.length()); + } + mTouchFocusSelected = true; } @@ -7029,12 +7047,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener || 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 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } else { // Stop selection mode if the controller becomes unavailable. - stopSelectionActionMode(); + if (mSelectionModifierCursorController != null) { + stopSelectionActionMode(); + } mSelectionModifierCursorController = null; } } @@ -7053,7 +7073,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * @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 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener 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 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener 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 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener 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 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener 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 @@ the "Downloadable SDK Components" section at left.</p> <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> - -<p>Additionally, the development tools will notify you with debug warnings -if there is dependency that you need to address. </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>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 @@ public class BitmapDrawable extends Drawable { } 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 @@ public class BitmapDrawable extends Drawable { * @see android.graphics.Bitmap#getDensity() */ public void setTargetDensity(DisplayMetrics metrics) { - mTargetDensity = metrics.densityDpi; - if (mBitmap != null) { - computeBitmapSize(); - } + setTargetDensity(metrics.densityDpi); } /** @@ -220,9 +220,12 @@ public class BitmapDrawable extends Drawable { * @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 @@ public class BitmapDrawable extends Drawable { * @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 @@ public class BitmapDrawable extends Drawable { state.mTileModeX = xmode; state.mTileModeY = ymode; mRebuildShader = true; + invalidateSelf(); } } @@ -336,11 +346,13 @@ public class BitmapDrawable extends Drawable { @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 @@ public class ColorDrawable extends Drawable { * @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 @@ public class ColorDrawable extends Drawable { 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 abstract class Drawable { */ 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 class GradientDrawable extends Drawable { public void setCornerRadii(float[] radii) { mGradientState.setCornerRadii(radii); mPathIsDirty = true; + invalidateSelf(); } /** @@ -189,6 +190,7 @@ public class GradientDrawable extends Drawable { public void setCornerRadius(float radius) { mGradientState.setCornerRadius(radius); mPathIsDirty = true; + invalidateSelf(); } /** @@ -214,34 +216,41 @@ public class GradientDrawable extends Drawable { 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 class GradientDrawable extends Drawable { public void setColor(int argb) { mGradientState.setSolidColor(argb); mFillPaint.setColor(argb); + invalidateSelf(); } @Override @@ -443,17 +453,26 @@ public class GradientDrawable extends Drawable { @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 @@ public class NinePatchDrawable extends Drawable { * @see android.graphics.Bitmap#getDensity() */ public void setTargetDensity(DisplayMetrics metrics) { - mTargetDensity = metrics.densityDpi; - if (mNinePatch != null) { - computeBitmapSize(); - } + setTargetDensity(metrics.densityDpi); } /** @@ -147,9 +144,12 @@ public class NinePatchDrawable extends Drawable { * @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 @@ public class NinePatchDrawable extends Drawable { @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 @@ public class PaintDrawable extends ShapeDrawable { } 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 @@ public class ShapeDrawable extends Drawable { } mShapeState.mPadding.set(left, top, right, bottom); } + invalidateSelf(); } /** @@ -144,6 +145,7 @@ public class ShapeDrawable extends Drawable { } mShapeState.mPadding.set(padding); } + invalidateSelf(); } /** @@ -153,6 +155,7 @@ public class ShapeDrawable extends Drawable { */ public void setIntrinsicWidth(int width) { mShapeState.mIntrinsicWidth = width; + invalidateSelf(); } /** @@ -162,6 +165,7 @@ public class ShapeDrawable extends Drawable { */ public void setIntrinsicHeight(int height) { mShapeState.mIntrinsicHeight = height; + invalidateSelf(); } @Override @@ -236,11 +240,13 @@ public class ShapeDrawable extends Drawable { */ @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 @@ public class ShapeDrawable extends Drawable { @Override public void setDither(boolean dither) { mShapeState.mPaint.setDither(dither); + invalidateSelf(); } @Override @@ -344,6 +351,7 @@ public class ShapeDrawable extends Drawable { 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 @@ private: uint32_t flags, Vector<String8> *matchingCodecs); + void restorePatchedDataPointer(BufferInfo *info); + OMXCodec(const OMXCodec &); OMXCodec &operator=(const OMXCodec &); }; @@ -305,6 +307,7 @@ struct CodecProfileLevel { 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 @@ public: 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 @@ private: 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 @@ void OpenGLRenderer::setupColorRect(float left, float top, float right, float bo 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 @@ void SkiaShader::setupProgram(Program* program, const mat4& modelView, const Sna 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 @@ void SkiaBitmapShader::setupProgram(Program* program, const mat4& modelView, 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 @@ void SkiaLinearGradientShader::setupProgram(Program* program, const mat4& modelV 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 @@ void SkiaSweepGradientShader::setupProgram(Program* program, const mat4& modelVi 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 @@ struct SkiaShader { 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 8f583f0..3b2ef84 100644 --- a/libs/surfaceflinger_client/SharedBufferStack.cpp +++ b/libs/surfaceflinger_client/SharedBufferStack.cpp @@ -265,6 +265,14 @@ bool SharedBufferClient::LockCondition::operator()() const { (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 @@ status_t SharedBufferClient::queue(int buf) const nsecs_t now = systemTime(SYSTEM_TIME_THREAD); stack.stats.totalTime = ns2us(now - mDequeueTime[buf]); + return err; } @@ -492,6 +501,7 @@ status_t SharedBufferClient::setBufferCount( if (err == NO_ERROR) { mNumBuffers = bufferCount; queued_head = (stack.head + stack.queued) % mNumBuffers; + tail = computeTail(); } return err; } @@ -606,17 +616,24 @@ uint32_t SharedBufferServer::getTransform(int buf) const */ 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 @@ status_t SharedBufferServer::resize(int newNumBuffers) 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 @@ int Surface::setBufferCount(int bufferCount) 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 @@ int Surface::getBufferIndex(const sp<GraphicBuffer>& buffer) const // 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 @@ void test0(SharedBufferServer& s, SharedBufferClient& c, size_t num, int* list); 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 main(int argc, char** argv) 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 @@ public class MediaFile { 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 @@ void OMXCodec::on_message(const omx_message &msg) { // 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 OMXCodec::freeBuffer(OMX_U32 portIndex, size_t bufIndex) { 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 @@ status_t OMXCodec::freeBuffer(OMX_U32 portIndex, size_t bufIndex) { } info->mMediaBuffer->release(); + info->mMediaBuffer = NULL; } if (err == OK) { @@ -2714,10 +2723,10 @@ void OMXCodec::drainInputBuffer(BufferInfo *info) { 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 @@ status_t QueryCodecs( 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 @@ public final class ActivityManagerService extends ActivityManagerNative 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 @@ bool SensorService::threadLoop() 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 @@ bool SensorService::threadLoop() 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 @@ class SensorService : 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 @@ status_t Layer::setBufferCount(int bufferCount) // 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 @@ Layer::BufferManager::~BufferManager() { } -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 @@ private: 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 @@ void SurfaceFlinger::handleRepaint() { // 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 @@ public class EventSenderImpl { 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 class EventSenderImpl { } 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 class EventSenderImpl { 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 @@ public class EventSenderImpl { /** 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 @@ public class EventSenderImpl { break; case MSG_MOUSE_MOVE_TO: - mMouseX = msg.arg1; - mMouseY = msg.arg2; + mMousePoint = createViewPointFromContentCoordinates(msg.arg1, msg.arg2); break; /** TOUCH */ @@ -208,8 +218,8 @@ public class EventSenderImpl { } 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 @@ public class EventSenderImpl { 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 @@ public class EventSenderImpl { 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 @@ import java.util.Map; * <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 @@ public final class Bridge implements ILayoutBridge { } }; - /** - * 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 @@ public final class Bridge implements ILayoutBridge { 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 @@ public final class Bridge implements ILayoutBridge { 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; - } - - return computeLayout(layoutDescription, projectKey, - screenWidth, screenHeight, DisplayMetrics.DENSITY_DEFAULT, - DisplayMetrics.DENSITY_DEFAULT, DisplayMetrics.DENSITY_DEFAULT, - themeName, isProjectTheme, - projectResources, frameworkResources, customViewLoader, logger); - } + public static void setCached9Patch(String value, NinePatch ninePatch, Object projectKey) { + if (projectKey != null) { + Map<String, SoftReference<NinePatch>> map = sProject9PatchCache.get(projectKey); - /* - * 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 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); - } + if (map == null) { + map = new HashMap<String, SoftReference<NinePatch>>(); + sProject9PatchCache.put(projectKey, map); + } - /* - * 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); + map.put(value, new SoftReference<NinePatch>(ninePatch)); + } else { + sFramework9PatchCache.put(value, new SoftReference<NinePatch>(ninePatch)); + } } - /* - * (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) + /** + * 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 */ - 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(); - } - - // 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; + SceneResult lastResult = SceneResult.SUCCESS; + LayoutSceneImpl scene = null; + synchronized (this) { + try { + scene = new LayoutSceneImpl(params); + + 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 @@ public final class Bridge implements ILayoutBridge { * (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,367 +353,25 @@ public final class Bridge implements ILayoutBridge { return null; } - static Map<String, Integer> getEnumValues(String attributeName) { - if (sEnumValueMap != null) { - return sEnumValueMap.get(attributeName); - } - - return null; - } - - /** - * 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. + * Returns the list of possible enums for a given attribute name. */ - 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); + public static Map<String, Integer> getEnumValues(String attributeName) { + if (sEnumValueMap != null) { + return sEnumValueMap.get(attributeName); } 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 @@ public final class Bridge implements ILayoutBridge { * @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 @@ public final class Bridge implements ILayoutBridge { * @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 @@ public final class Bridge implements ILayoutBridge { 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. - */ - 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); - } + // ---------- OBSOLETE API METHODS ---------- - 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, 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, + 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 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 @@ public class BridgeAssetManager extends AssetManager { * <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 @@ public class BridgeAssetManager extends AssetManager { * 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 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 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 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.Handler; 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.TreeMap; 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 @@ public final class BridgeContext extends Activity { * 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 @@ public final class BridgeContext extends Activity { 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 @@ public final class BridgeContext extends Activity { 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 @@ public final class BridgeContext extends Activity { 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 @@ public final class BridgeContext extends Activity { // 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 @@ public final class BridgeContext extends Activity { // 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 @@ public final class BridgeContext extends Activity { 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 @@ public final class BridgeContext extends Activity { // 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 @@ public final class BridgeContext extends Activity { * @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 @@ public final class BridgeContext extends Activity { * @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 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 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 @@ public final class BridgeResources extends Resources { 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 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.io.FileReader; 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 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 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 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 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 @@ public class NinePatchDrawable extends Drawable { 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 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 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 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 @@ public final class ResourceHelper { * @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 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 @@ class ResourceValue implements IResourceValue { 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 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; |
