diff options
51 files changed, 1076 insertions, 302 deletions
diff --git a/api/current.txt b/api/current.txt index ebf3893..c76627f 100644 --- a/api/current.txt +++ b/api/current.txt @@ -17115,14 +17115,32 @@ package android.speech { package android.speech.tts { + public abstract class SynthesisRequest { + ctor public SynthesisRequest(java.lang.String); + method public abstract int audioAvailable(byte[], int, int); + method public abstract int completeAudioAvailable(int, int, int, byte[], int, int); + method public abstract int done(); + method public abstract void error(); + method public java.lang.String getCountry(); + method public java.lang.String getLanguage(); + method public abstract int getMaxBufferSize(); + method public int getPitch(); + method public int getSpeechRate(); + method public java.lang.String getText(); + method public java.lang.String getVariant(); + method public abstract int start(int, int, int); + } + public class TextToSpeech { ctor public TextToSpeech(android.content.Context, android.speech.tts.TextToSpeech.OnInitListener); + ctor public TextToSpeech(android.content.Context, android.speech.tts.TextToSpeech.OnInitListener, java.lang.String); method public int addEarcon(java.lang.String, java.lang.String, int); method public int addEarcon(java.lang.String, java.lang.String); method public int addSpeech(java.lang.String, java.lang.String, int); method public int addSpeech(java.lang.String, java.lang.String); method public boolean areDefaultsEnforced(); method public java.lang.String getDefaultEngine(); + method public java.util.List<android.speech.tts.TextToSpeech.EngineInfo> getEngines(); method public java.util.Locale getLanguage(); method public int isLanguageAvailable(java.util.Locale); method public boolean isSpeaking(); @@ -17167,12 +17185,20 @@ package android.speech.tts { field public static final java.lang.String EXTRA_VOICE_DATA_FILES = "dataFiles"; field public static final java.lang.String EXTRA_VOICE_DATA_FILES_INFO = "dataFilesInfo"; field public static final java.lang.String EXTRA_VOICE_DATA_ROOT_DIRECTORY = "dataRoot"; + field public static final java.lang.String INTENT_ACTION_TTS_SERVICE = "android.intent.action.TTS_SERVICE"; field public static final java.lang.String KEY_PARAM_PAN = "pan"; field public static final java.lang.String KEY_PARAM_STREAM = "streamType"; field public static final java.lang.String KEY_PARAM_UTTERANCE_ID = "utteranceId"; field public static final java.lang.String KEY_PARAM_VOLUME = "volume"; } + public static class TextToSpeech.EngineInfo { + ctor public TextToSpeech.EngineInfo(); + field public int icon; + field public java.lang.String label; + field public java.lang.String name; + } + public static abstract interface TextToSpeech.OnInitListener { method public abstract void onInit(int); } @@ -17181,6 +17207,16 @@ package android.speech.tts { method public abstract void onUtteranceCompleted(java.lang.String); } + public abstract class TextToSpeechService extends android.app.Service { + ctor public TextToSpeechService(); + method public android.os.IBinder onBind(android.content.Intent); + method protected abstract java.lang.String[] onGetLanguage(); + method protected abstract int onIsLanguageAvailable(java.lang.String, java.lang.String, java.lang.String); + method protected abstract int onLoadLanguage(java.lang.String, java.lang.String, java.lang.String); + method protected abstract void onStop(); + method protected abstract void onSynthesizeText(android.speech.tts.SynthesisRequest); + } + } package android.telephony { diff --git a/core/java/android/speech/tts/SynthesisRequest.java b/core/java/android/speech/tts/SynthesisRequest.java index 515218b..6df9af2 100644 --- a/core/java/android/speech/tts/SynthesisRequest.java +++ b/core/java/android/speech/tts/SynthesisRequest.java @@ -24,8 +24,6 @@ package android.speech.tts; * * Alternatively, the engine can provide all the audio at once, by using * {@link #completeAudioAvailable}. - * - * @hide Pending approval */ public abstract class SynthesisRequest { @@ -92,16 +90,14 @@ public abstract class SynthesisRequest { } /** - * Gets the speech rate to use. {@link TextToSpeech.Engine#DEFAULT_RATE} (100) - * is the normal rate. + * Gets the speech rate to use. The normal rate is 100. */ public int getSpeechRate() { return mSpeechRate; } /** - * Gets the pitch to use. {@link TextToSpeech.Engine#DEFAULT_PITCH} (100) - * is the normal pitch. + * Gets the pitch to use. The normal pitch is 100. */ public int getPitch() { return mPitch; diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java index e247df8..1d26c22 100755 --- a/core/java/android/speech/tts/TextToSpeech.java +++ b/core/java/android/speech/tts/TextToSpeech.java @@ -220,8 +220,6 @@ public class TextToSpeech { * extend {@link TextToSpeechService}. Normal applications should not use this intent * directly, instead they should talk to the TTS service using the the methods in this * class. - * - * @hide Pending API council approval */ @SdkConstant(SdkConstantType.SERVICE_ACTION) public static final String INTENT_ACTION_TTS_SERVICE = @@ -428,7 +426,7 @@ public class TextToSpeech { private final Bundle mParams = new Bundle(); /** - * The constructor for the TextToSpeech class. + * The constructor for the TextToSpeech class, using the default TTS engine. * This will also initialize the associated TextToSpeech engine if it isn't already running. * * @param context @@ -442,7 +440,15 @@ public class TextToSpeech { } /** - * @hide pending approval + * The constructor for the TextToSpeech class, using the given TTS engine. + * This will also initialize the associated TextToSpeech engine if it isn't already running. + * + * @param context + * The context this instance is running in. + * @param listener + * The {@link TextToSpeech.OnInitListener} that will be called when the + * TextToSpeech engine has initialized. + * @param engine Package name of the TTS engine to use. */ public TextToSpeech(Context context, OnInitListener listener, String engine) { mContext = context; @@ -1060,8 +1066,6 @@ public class TextToSpeech { * Gets a list of all installed TTS engines. * * @return A list of engine info objects. The list can be empty, but will never by {@code null}. - * - * @hide Pending approval */ public List<EngineInfo> getEngines() { PackageManager pm = mContext.getPackageManager(); @@ -1144,7 +1148,6 @@ public class TextToSpeech { * Information about an installed text-to-speech engine. * * @see TextToSpeech#getEngines - * @hide Pending approval */ public static class EngineInfo { /** diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java index da97fb4..590e2ef 100644 --- a/core/java/android/speech/tts/TextToSpeechService.java +++ b/core/java/android/speech/tts/TextToSpeechService.java @@ -41,8 +41,6 @@ import java.util.Locale; /** * Abstract base class for TTS engine implementations. - * - * @hide Pending approval */ public abstract class TextToSpeechService extends Service { diff --git a/core/java/android/text/style/TextAppearanceSpan.java b/core/java/android/text/style/TextAppearanceSpan.java index de929e3..deed713 100644 --- a/core/java/android/text/style/TextAppearanceSpan.java +++ b/core/java/android/text/style/TextAppearanceSpan.java @@ -51,10 +51,9 @@ public class TextAppearanceSpan extends MetricAffectingSpan implements Parcelabl * to determine the color. The <code>appearance</code> should be, * for example, <code>android.R.style.TextAppearance_Small</code>, * and the <code>colorList</code> should be, for example, - * <code>android.R.styleable.Theme_textColorDim</code>. + * <code>android.R.styleable.Theme_textColorPrimary</code>. */ - public TextAppearanceSpan(Context context, int appearance, - int colorList) { + public TextAppearanceSpan(Context context, int appearance, int colorList) { ColorStateList textColor; TypedArray a = diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 7b404b4..1a84175 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -2203,10 +2203,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } /** - * Perform dispatching of a {@link #saveHierarchyState freeze()} to only this view, - * not to its children. For use when overriding - * {@link #dispatchSaveInstanceState dispatchFreeze()} to allow subclasses to freeze - * their own state but not the state of their children. + * Perform dispatching of a {@link #saveHierarchyState(android.util.SparseArray)} freeze()} + * to only this view, not to its children. For use when overriding + * {@link #dispatchSaveInstanceState(android.util.SparseArray)} dispatchFreeze()} to allow + * subclasses to freeze their own state but not the state of their children. * * @param container the container */ diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java index f02daba..20503b7 100644 --- a/core/java/android/view/ViewRoot.java +++ b/core/java/android/view/ViewRoot.java @@ -1926,6 +1926,7 @@ public final class ViewRoot extends Handler implements ViewParent, void dispatchDetachedFromWindow() { if (mView != null && mView.mAttachInfo != null) { mView.dispatchDetachedFromWindow(); + mAttached = false; } mView = null; diff --git a/core/java/android/view/inputmethod/InputMethodSubtype.java b/core/java/android/view/inputmethod/InputMethodSubtype.java index 25f2229..807f6ce 100644 --- a/core/java/android/view/inputmethod/InputMethodSubtype.java +++ b/core/java/android/view/inputmethod/InputMethodSubtype.java @@ -60,8 +60,7 @@ public final class InputMethodSubtype implements Parcelable { mSubtypeLocale = locale != null ? locale : ""; mSubtypeMode = mode != null ? mode : ""; mSubtypeExtraValue = extraValue != null ? extraValue : ""; - mSubtypeHashCode = hashCodeInternal(mSubtypeNameResId, mSubtypeIconResId, mSubtypeLocale, - mSubtypeMode, mSubtypeExtraValue); + mSubtypeHashCode = hashCodeInternal(mSubtypeLocale, mSubtypeMode, mSubtypeExtraValue); } InputMethodSubtype(Parcel source) { @@ -74,8 +73,7 @@ public final class InputMethodSubtype implements Parcelable { mSubtypeMode = s != null ? s : ""; s = source.readString(); mSubtypeExtraValue = s != null ? s : ""; - mSubtypeHashCode = hashCodeInternal(mSubtypeNameResId, mSubtypeIconResId, mSubtypeLocale, - mSubtypeMode, mSubtypeExtraValue); + mSubtypeHashCode = hashCodeInternal(mSubtypeLocale, mSubtypeMode, mSubtypeExtraValue); } /** @@ -195,9 +193,8 @@ public final class InputMethodSubtype implements Parcelable { } }; - private static int hashCodeInternal(int nameResId, int iconResId, String locale, - String mode, String extraValue) { - return Arrays.hashCode(new Object[] {nameResId, iconResId, locale, mode, extraValue}); + private static int hashCodeInternal(String locale, String mode, String extraValue) { + return Arrays.hashCode(new Object[] {locale, mode, extraValue}); } /** diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java index 71d6080..3e11197 100644 --- a/core/java/android/webkit/WebSettings.java +++ b/core/java/android/webkit/WebSettings.java @@ -219,6 +219,7 @@ public class WebSettings { private boolean mAllowContentAccess = true; private boolean mLoadWithOverviewMode = false; private boolean mEnableSmoothTransition = false; + private boolean mForceUserScalable = false; // AutoFill Profile data /** @@ -1658,6 +1659,23 @@ public class WebSettings { } } + /** + * Returns whether the viewport metatag can disable zooming + * @hide + */ + public boolean forceUserScalable() { + return mForceUserScalable; + } + + /** + * Sets whether viewport metatag can disable zooming. + * @param flag Whether or not to forceably enable user scalable. + * @hide + */ + public synchronized void setForceUserScalable(boolean flag) { + mForceUserScalable = flag; + } + synchronized void setSyntheticLinksEnabled(boolean flag) { if (mSyntheticLinksEnabled != flag) { mSyntheticLinksEnabled = flag; diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java index 0271695..09205a5 100644 --- a/core/java/android/webkit/WebViewCore.java +++ b/core/java/android/webkit/WebViewCore.java @@ -2253,6 +2253,27 @@ final class WebViewCore { // set the viewport settings from WebKit setViewportSettingsFromNative(); + if (mSettings.forceUserScalable()) { + mViewportUserScalable = true; + if (mViewportInitialScale > 0) { + if (mViewportMinimumScale > 0) { + mViewportMinimumScale = Math.min(mViewportMinimumScale, + mViewportInitialScale / 2); + } + if (mViewportMaximumScale > 0) { + mViewportMaximumScale = Math.max(mViewportMaximumScale, + mViewportInitialScale * 2); + } + } else { + if (mViewportMinimumScale > 0) { + mViewportMinimumScale = Math.min(mViewportMinimumScale, 50); + } + if (mViewportMaximumScale > 0) { + mViewportMaximumScale = Math.max(mViewportMaximumScale, 200); + } + } + } + // adjust the default scale to match the densityDpi float adjust = 1.0f; if (mViewportDensityDpi == -1) { @@ -2589,11 +2610,11 @@ final class WebViewCore { // called by JNI private Class<?> getPluginClass(String libName, String clsName) { - + if (mWebView == null) { return null; } - + PluginManager pluginManager = PluginManager.getInstance(null); String pkgName = pluginManager.getPluginsAPKName(libName); @@ -2601,7 +2622,7 @@ final class WebViewCore { Log.w(LOGTAG, "Unable to resolve " + libName + " to a plugin APK"); return null; } - + try { return pluginManager.getPluginClass(pkgName, clsName); } catch (NameNotFoundException e) { @@ -2656,7 +2677,7 @@ final class WebViewCore { view.mView = pluginView; return view; } - + // called by JNI. PluginWidget functions for creating an embedded View for // the surface drawing model. private ViewManager.ChildView addSurface(View pluginView, int x, int y, diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java index 1fe6f4b..d8068f9 100644 --- a/core/java/android/widget/ImageView.java +++ b/core/java/android/widget/ImageView.java @@ -218,15 +218,16 @@ public class ImageView extends View { /** * An optional argument to supply a maximum width for this view. Only valid if - * {@link #setAdjustViewBounds} has been set to true. To set an image to be a maximum of 100 x - * 100 while preserving the original aspect ratio, do the following: 1) set adjustViewBounds to - * true 2) set maxWidth and maxHeight to 100 3) set the height and width layout params to - * WRAP_CONTENT. + * {@link #setAdjustViewBounds(boolean)} has been set to true. To set an image to be a maximum + * of 100 x 100 while preserving the original aspect ratio, do the following: 1) set + * adjustViewBounds to true 2) set maxWidth and maxHeight to 100 3) set the height and width + * layout params to WRAP_CONTENT. * * <p> * Note that this view could be still smaller than 100 x 100 using this approach if the original * image is small. To set an image to a fixed size, specify that size in the layout params and - * then use {@link #setScaleType} to determine how to fit the image within the bounds. + * then use {@link #setScaleType(android.widget.ImageView.ScaleType)} to determine how to fit + * the image within the bounds. * </p> * * @param maxWidth maximum width for this view @@ -240,15 +241,16 @@ public class ImageView extends View { /** * An optional argument to supply a maximum height for this view. Only valid if - * {@link #setAdjustViewBounds} has been set to true. To set an image to be a maximum of 100 x - * 100 while preserving the original aspect ratio, do the following: 1) set adjustViewBounds to - * true 2) set maxWidth and maxHeight to 100 3) set the height and width layout params to - * WRAP_CONTENT. + * {@link #setAdjustViewBounds(boolean)} has been set to true. To set an image to be a + * maximum of 100 x 100 while preserving the original aspect ratio, do the following: 1) set + * adjustViewBounds to true 2) set maxWidth and maxHeight to 100 3) set the height and width + * layout params to WRAP_CONTENT. * * <p> * Note that this view could be still smaller than 100 x 100 using this approach if the original * image is small. To set an image to a fixed size, specify that size in the layout params and - * then use {@link #setScaleType} to determine how to fit the image within the bounds. + * then use {@link #setScaleType(android.widget.ImageView.ScaleType)} to determine how to fit + * the image within the bounds. * </p> * * @param maxHeight maximum height for this view @@ -272,8 +274,8 @@ public class ImageView extends View { * * <p class="note">This does Bitmap reading and decoding on the UI * thread, which can cause a latency hiccup. If that's a concern, - * consider using {@link #setImageDrawable} or - * {@link #setImageBitmap} and + * consider using {@link #setImageDrawable(android.graphics.drawable.Drawable)} or + * {@link #setImageBitmap(android.graphics.Bitmap)} and * {@link android.graphics.BitmapFactory} instead.</p> * * @param resId the resource identifier of the the drawable @@ -297,8 +299,8 @@ public class ImageView extends View { * * <p class="note">This does Bitmap reading and decoding on the UI * thread, which can cause a latency hiccup. If that's a concern, - * consider using {@link #setImageDrawable} or - * {@link #setImageBitmap} and + * consider using {@link #setImageDrawable(android.graphics.drawable.Drawable)} or + * {@link #setImageBitmap(android.graphics.Bitmap)} and * {@link android.graphics.BitmapFactory} instead.</p> * * @param uri The Uri of an image @@ -902,12 +904,12 @@ public class ImageView extends View { /** * <p>Set the offset of the widget's text baseline from the widget's top - * boundary. This value is overridden by the {@link #setBaselineAlignBottom} + * boundary. This value is overridden by the {@link #setBaselineAlignBottom(boolean)} * property.</p> * * @param baseline The baseline to use, or -1 if none is to be provided. * - * @see #setBaseline + * @see #setBaseline(int) * @attr ref android.R.styleable#ImageView_baseline */ public void setBaseline(int baseline) { diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 4d3aa68..6c5d117 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -60,6 +60,7 @@ import android.text.Selection; import android.text.SpanWatcher; import android.text.Spannable; import android.text.SpannableString; +import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.SpannedString; import android.text.StaticLayout; @@ -80,10 +81,13 @@ import android.text.method.SingleLineTransformationMethod; import android.text.method.TextKeyListener; import android.text.method.TimeKeyListener; import android.text.method.TransformationMethod; +import android.text.method.WordIterator; import android.text.style.ClickableSpan; import android.text.style.ParagraphStyle; import android.text.style.SuggestionSpan; +import android.text.style.TextAppearanceSpan; import android.text.style.URLSpan; +import android.text.style.UnderlineSpan; import android.text.style.UpdateAppearance; import android.text.util.Linkify; import android.util.AttributeSet; @@ -127,6 +131,7 @@ import android.widget.RemoteViews.RemoteView; import java.io.IOException; import java.lang.ref.WeakReference; +import java.text.BreakIterator; import java.util.ArrayList; /** @@ -314,6 +319,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private int mTextEditSuggestionsBottomWindowLayout, mTextEditSuggestionsTopWindowLayout; private int mTextEditSuggestionItemLayout; private SuggestionsPopupWindow mSuggestionsPopupWindow; + private SuggestionRangeSpan mSuggestionRangeSpan; private int mCursorDrawableRes; private final Drawable[] mCursorDrawable = new Drawable[2]; @@ -8225,13 +8231,20 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return ((minOffset >= selectionStart) && (maxOffset < selectionEnd)); } + private static class SuggestionRangeSpan extends UnderlineSpan { + // TODO themable, would be nice to make it a child class of TextAppearanceSpan, but + // there is no way to have underline and TextAppearanceSpan. + } + private class SuggestionsPopupWindow implements OnClickListener { private static final int MAX_NUMBER_SUGGESTIONS = 5; - private static final long NO_SUGGESTIONS = -1L; + private static final int NO_SUGGESTIONS = -1; private final PopupWindow mContainer; private final ViewGroup[] mSuggestionViews = new ViewGroup[2]; private final int[] mSuggestionViewLayouts = new int[] { mTextEditSuggestionsBottomWindowLayout, mTextEditSuggestionsTopWindowLayout}; + private WordIterator mWordIterator; + private TextAppearanceSpan[] mHighlightSpans = new TextAppearanceSpan[0]; public SuggestionsPopupWindow() { mContainer = new PopupWindow(TextView.this.mContext, null, @@ -8244,6 +8257,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener mContainer.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT); } + private class SuggestionInfo { + int suggestionStart, suggestionEnd; // range of suggestion item with replacement text + int spanStart, spanEnd; // range in TextView where text should be inserted + } + private ViewGroup getViewGroup(boolean under) { final int viewIndex = under ? 0 : 1; ViewGroup viewGroup = mSuggestionViews[viewIndex]; @@ -8277,6 +8295,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener "Inflated TextEdit suggestion item is not a TextView: " + childView); } + childView.setTag(new SuggestionInfo()); viewGroup.addView(childView); childView.setOnClickListener(this); } @@ -8299,21 +8318,28 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener mContainer.setContentView(viewGroup); int totalNbSuggestions = 0; + int spanUnionStart = mText.length(); + int spanUnionEnd = 0; + for (int spanIndex = 0; spanIndex < nbSpans; spanIndex++) { SuggestionSpan suggestionSpan = suggestionSpans[spanIndex]; final int spanStart = spannable.getSpanStart(suggestionSpan); final int spanEnd = spannable.getSpanEnd(suggestionSpan); - final Long spanRange = packRangeInLong(spanStart, spanEnd); + spanUnionStart = Math.min(spanStart, spanUnionStart); + spanUnionEnd = Math.max(spanEnd, spanUnionEnd); String[] suggestions = suggestionSpan.getSuggestions(); int nbSuggestions = suggestions.length; for (int suggestionIndex = 0; suggestionIndex < nbSuggestions; suggestionIndex++) { TextView textView = (TextView) viewGroup.getChildAt(totalNbSuggestions); textView.setText(suggestions[suggestionIndex]); - textView.setTag(spanRange); + SuggestionInfo suggestionInfo = (SuggestionInfo) textView.getTag(); + suggestionInfo.spanStart = spanStart; + suggestionInfo.spanEnd = spanEnd; totalNbSuggestions++; - if (totalNbSuggestions == MAX_NUMBER_SUGGESTIONS) { + if (totalNbSuggestions > MAX_NUMBER_SUGGESTIONS) { + // Also end outer for loop spanIndex = nbSpans; break; } @@ -8324,8 +8350,18 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener // TODO Replace by final text, use a dedicated layout, add a fade out timer... TextView textView = (TextView) viewGroup.getChildAt(0); textView.setText("No suggestions available"); - textView.setTag(NO_SUGGESTIONS); + SuggestionInfo suggestionInfo = (SuggestionInfo) textView.getTag(); + suggestionInfo.spanStart = NO_SUGGESTIONS; totalNbSuggestions++; + } else { + if (mSuggestionRangeSpan == null) mSuggestionRangeSpan = new SuggestionRangeSpan(); + ((Editable) mText).setSpan(mSuggestionRangeSpan, spanUnionStart, spanUnionEnd, + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + + for (int i = 0; i < totalNbSuggestions; i++) { + final TextView textView = (TextView) viewGroup.getChildAt(i); + highlightTextDifferences(textView, spanUnionStart, spanUnionEnd); + } } for (int i = 0; i < MAX_NUMBER_SUGGESTIONS; i++) { @@ -8338,7 +8374,158 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener positionAtCursor(); } + private long[] getWordLimits(CharSequence text) { + if (mWordIterator == null) mWordIterator = new WordIterator(); // TODO locale + mWordIterator.setCharSequence(text); + + // First pass will simply count the number of words to be able to create an array + // Not too expensive since previous break positions are cached by the BreakIterator + int nbWords = 0; + int position = mWordIterator.following(0); + while (position != BreakIterator.DONE) { + nbWords++; + position = mWordIterator.following(position); + } + + int index = 0; + long[] result = new long[nbWords]; + + position = mWordIterator.following(0); + while (position != BreakIterator.DONE) { + int wordStart = mWordIterator.getBeginning(position); + result[index++] = packRangeInLong(wordStart, position); + position = mWordIterator.following(position); + } + + return result; + } + + private TextAppearanceSpan highlightSpan(int index) { + final int length = mHighlightSpans.length; + if (index < length) { + return mHighlightSpans[index]; + } + + // Assumes indexes are requested in sequence: simply append one more item + TextAppearanceSpan[] newArray = new TextAppearanceSpan[length + 1]; + System.arraycopy(mHighlightSpans, 0, newArray, 0, length); + TextAppearanceSpan highlightSpan = new TextAppearanceSpan(mContext, + android.R.style.TextAppearance_SuggestionHighlight); + newArray[length] = highlightSpan; + mHighlightSpans = newArray; + return highlightSpan; + } + + private void highlightTextDifferences(TextView textView, int unionStart, int unionEnd) { + SuggestionInfo suggestionInfo = (SuggestionInfo) textView.getTag(); + final int spanStart = suggestionInfo.spanStart; + final int spanEnd = suggestionInfo.spanEnd; + + // Remove all text formating by converting to Strings + final String text = textView.getText().toString(); + final String sourceText = mText.subSequence(spanStart, spanEnd).toString(); + + long[] sourceWordLimits = getWordLimits(sourceText); + long[] wordLimits = getWordLimits(text); + + SpannableStringBuilder ssb = new SpannableStringBuilder(); + // span [spanStart, spanEnd] is included in union [spanUnionStart, int spanUnionEnd] + // The final result is made of 3 parts: the text before, between and after the span + // This is the text before, provided for context + ssb.append(mText.subSequence(unionStart, spanStart).toString()); + + // shift is used to offset spans positions wrt span's beginning + final int shift = spanStart - unionStart; + suggestionInfo.suggestionStart = shift; + suggestionInfo.suggestionEnd = shift + text.length(); + + // This is the actual suggestion text, which will be highlighted by the following code + ssb.append(text); + + String[] words = new String[wordLimits.length]; + for (int i = 0; i < wordLimits.length; i++) { + int wordStart = extractRangeStartFromLong(wordLimits[i]); + int wordEnd = extractRangeEndFromLong(wordLimits[i]); + words[i] = text.substring(wordStart, wordEnd); + } + + // Highlighted word algorithm is bases on word matching between source and text + // Matching words are found from left to right. TODO: change for RTL languages + // Characters between matching words are highlighted + int previousCommonWordIndex = -1; + int nbHighlightSpans = 0; + for (int i = 0; i < sourceWordLimits.length; i++) { + int wordStart = extractRangeStartFromLong(sourceWordLimits[i]); + int wordEnd = extractRangeEndFromLong(sourceWordLimits[i]); + String sourceWord = sourceText.substring(wordStart, wordEnd); + + for (int j = previousCommonWordIndex + 1; j < words.length; j++) { + if (sourceWord.equals(words[j])) { + if (j != previousCommonWordIndex + 1) { + int firstDifferentPosition = previousCommonWordIndex < 0 ? 0 : + extractRangeEndFromLong(wordLimits[previousCommonWordIndex]); + int lastDifferentPosition = extractRangeStartFromLong(wordLimits[j]); + ssb.setSpan(highlightSpan(nbHighlightSpans++), + shift + firstDifferentPosition, shift + lastDifferentPosition, + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } else { + // Compare characters between words + int previousSourceWordEnd = i == 0 ? 0 : + extractRangeEndFromLong(sourceWordLimits[i - 1]); + int sourceWordStart = extractRangeStartFromLong(sourceWordLimits[i]); + String sourceSpaces = sourceText.substring(previousSourceWordEnd, + sourceWordStart); + + int previousWordEnd = j == 0 ? 0 : + extractRangeEndFromLong(wordLimits[j - 1]); + int currentWordStart = extractRangeStartFromLong(wordLimits[j]); + String textSpaces = text.substring(previousWordEnd, currentWordStart); + + if (!sourceSpaces.equals(textSpaces)) { + ssb.setSpan(highlightSpan(nbHighlightSpans++), + shift + previousWordEnd, shift + currentWordStart, + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + } + previousCommonWordIndex = j; + break; + } + } + } + + // Finally, compare ends of Strings + if (previousCommonWordIndex < words.length - 1) { + int firstDifferentPosition = previousCommonWordIndex < 0 ? 0 : + extractRangeEndFromLong(wordLimits[previousCommonWordIndex]); + int lastDifferentPosition = textView.length(); + ssb.setSpan(highlightSpan(nbHighlightSpans++), + shift + firstDifferentPosition, shift + lastDifferentPosition, + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } else { + int lastSourceWordEnd = sourceWordLimits.length == 0 ? 0 : + extractRangeEndFromLong(sourceWordLimits[sourceWordLimits.length - 1]); + String sourceSpaces = sourceText.substring(lastSourceWordEnd, sourceText.length()); + + int lastCommonTextWordEnd = previousCommonWordIndex < 0 ? 0 : + extractRangeEndFromLong(wordLimits[previousCommonWordIndex]); + String textSpaces = text.substring(lastCommonTextWordEnd, textView.length()); + + if (!sourceSpaces.equals(textSpaces) && textSpaces.length() > 0) { + ssb.setSpan(highlightSpan(nbHighlightSpans++), + shift + lastCommonTextWordEnd, shift + textView.length(), + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + } + + // Final part, text after the current suggestion range. + ssb.append(mText.subSequence(spanEnd, unionEnd).toString()); + textView.setText(ssb); + } + public void hide() { + if ((mText instanceof Editable) && mSuggestionRangeSpan != null) { + ((Editable) mText).removeSpan(mSuggestionRangeSpan); + } mContainer.dismiss(); } @@ -8346,11 +8533,15 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener public void onClick(View view) { if (view instanceof TextView) { TextView textView = (TextView) view; - Long range = ((Long) view.getTag()); - if (range != NO_SUGGESTIONS) { - final int spanStart = extractRangeStartFromLong(range); - final int spanEnd = extractRangeEndFromLong(range); - ((Editable) mText).replace(spanStart, spanEnd, textView.getText()); + SuggestionInfo suggestionInfo = (SuggestionInfo) textView.getTag(); + final int spanStart = suggestionInfo.spanStart; + final int spanEnd = suggestionInfo.spanEnd; + if (spanStart != NO_SUGGESTIONS) { + final int suggestionStart = suggestionInfo.suggestionStart; + final int suggestionEnd = suggestionInfo.suggestionEnd; + final String suggestion = textView.getText().subSequence( + suggestionStart, suggestionEnd).toString(); + ((Editable) mText).replace(spanStart, spanEnd, suggestion); } } hide(); diff --git a/core/res/res/drawable-hdpi/text_edit_suggestions_bottom_window.9.png b/core/res/res/drawable-hdpi/text_edit_suggestions_bottom_window.9.png Binary files differnew file mode 100644 index 0000000..c97514f --- /dev/null +++ b/core/res/res/drawable-hdpi/text_edit_suggestions_bottom_window.9.png diff --git a/core/res/res/drawable-hdpi/text_edit_suggestions_top_window.9.png b/core/res/res/drawable-hdpi/text_edit_suggestions_top_window.9.png Binary files differnew file mode 100644 index 0000000..ff6b34a --- /dev/null +++ b/core/res/res/drawable-hdpi/text_edit_suggestions_top_window.9.png diff --git a/core/res/res/layout/text_edit_suggestion_item.xml b/core/res/res/layout/text_edit_suggestion_item.xml index a54cad2..ef537d9 100644 --- a/core/res/res/layout/text_edit_suggestion_item.xml +++ b/core/res/res/layout/text_edit_suggestion_item.xml @@ -21,7 +21,7 @@ android:paddingRight="16dip" android:paddingTop="8dip" android:paddingBottom="8dip" - android:layout_gravity="center" + android:layout_gravity="left|center_vertical" android:textAppearance="?android:attr/textAppearanceMedium" - android:textColor="@android:color/black" /> + android:textColor="@android:color/dim_foreground_light" /> diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml index 9c59cb6..39d2329 100644 --- a/core/res/res/values/colors.xml +++ b/core/res/res/values/colors.xml @@ -60,6 +60,7 @@ <color name="highlighted_text_light">#9983CC39</color> <color name="link_text_dark">#5c5cff</color> <color name="link_text_light">#0000ee</color> + <color name="suggestion_highlight_text">#177bbd</color> <drawable name="stat_notify_sync_noanim">@drawable/stat_notify_sync_anim0</drawable> <drawable name="stat_sys_download_done">@drawable/stat_sys_download_anim0</drawable> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 778d934..501d478 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -1659,6 +1659,7 @@ <public type="attr" name="stopWithTask" /> <public type="style" name="Theme.Holo.Light.NoActionBar" /> + <public type="style" name="TextAppearance.SuggestionHighlight" /> <public type="attr" name="textSuggestionsWindowStyle" /> <public type="attr" name="textEditSuggestionsBottomWindowLayout" /> diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml index 8ce35f8..e666698 100644 --- a/core/res/res/values/styles.xml +++ b/core/res/res/values/styles.xml @@ -876,6 +876,13 @@ <item name="android:textSize">30sp</item> </style> + <!-- @hide --> + <style name="TextAppearance.SuggestionHighlight"> + <item name="android:textSize">18sp</item> + <item name="android:textColor">@android:color/suggestion_highlight_text</item> + <item name="android:textStyle">bold</item> + </style> + <!-- Preference Styles --> <style name="Preference"> diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml index 4be6995..010e3c3 100644 --- a/core/tests/coretests/AndroidManifest.xml +++ b/core/tests/coretests/AndroidManifest.xml @@ -100,6 +100,12 @@ <application android:theme="@style/Theme"> <uses-library android:name="android.test.runner" /> + <activity android:name="android.view.ViewAttachTestActivity" android:label="View Attach Test"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" /> + </intent-filter> + </activity> <activity android:name="StubTestBrowserActivity" android:label="Stubbed Test Browser"> <intent-filter> <action android:name="android.intent.action.MAIN"/> diff --git a/core/tests/coretests/res/layout/attach_view_test.xml b/core/tests/coretests/res/layout/attach_view_test.xml new file mode 100644 index 0000000..42841cb --- /dev/null +++ b/core/tests/coretests/res/layout/attach_view_test.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_width="fill_parent" + android:layout_height="fill_parent"> + <android.view.ViewAttachView + android:id="@+id/view_attach_view" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:keepScreenOn="true"/> +</LinearLayout> diff --git a/core/tests/coretests/src/android/view/ViewAttachTest.java b/core/tests/coretests/src/android/view/ViewAttachTest.java new file mode 100644 index 0000000..cff66e4 --- /dev/null +++ b/core/tests/coretests/src/android/view/ViewAttachTest.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view; + +import android.content.pm.ActivityInfo; +import android.os.SystemClock; +import android.test.ActivityInstrumentationTestCase2; + +public class ViewAttachTest extends + ActivityInstrumentationTestCase2<ViewAttachTestActivity> { + + public ViewAttachTest() { + super(ViewAttachTestActivity.class); + } + + /** + * Make sure that onAttachedToWindow and onDetachedToWindow is called in the + * correct order The ViewAttachTestActivity contains a view that will throw + * an RuntimeException if onDetachedToWindow and onAttachedToWindow is + * called in the wrong order. + * + * 1. Initiate the activity 2. Perform a series of orientation changes to + * the activity (this will force the View hierarchy to be rebuild, + * generating onAttachedToWindow and onDetachedToWindow) + * + * Expected result: No RuntimeException is thrown from the TestView in + * ViewFlipperTestActivity. + * + * @throws Throwable + */ + public void testAttached() throws Throwable { + final ViewAttachTestActivity activity = getActivity(); + for (int i = 0; i < 20; i++) { + activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); + SystemClock.sleep(250); + activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); + SystemClock.sleep(250); + } + } +} diff --git a/core/tests/coretests/src/android/view/ViewAttachTestActivity.java b/core/tests/coretests/src/android/view/ViewAttachTestActivity.java new file mode 100644 index 0000000..59e25ae --- /dev/null +++ b/core/tests/coretests/src/android/view/ViewAttachTestActivity.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view; + +import com.android.frameworks.coretests.R; + +import android.app.Activity; +import android.os.Bundle; + +public class ViewAttachTestActivity extends Activity { + public static final String TAG = "OnAttachedTest"; + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.attach_view_test); + } +} diff --git a/core/tests/coretests/src/android/view/ViewAttachView.java b/core/tests/coretests/src/android/view/ViewAttachView.java new file mode 100644 index 0000000..5af2d8f --- /dev/null +++ b/core/tests/coretests/src/android/view/ViewAttachView.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.os.SystemClock; +import android.util.AttributeSet; +import android.util.Log; +import android.view.View; + +/** + * A View that will throw a RuntimeException if onAttachedToWindow and + * onDetachedFromWindow is called in the wrong order for ViewAttachTest + */ +public class ViewAttachView extends View { + public static final String TAG = "OnAttachedTest"; + private boolean attached; + + public ViewAttachView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(attrs, defStyle); + } + + public ViewAttachView(Context context, AttributeSet attrs) { + super(context, attrs); + init(attrs, 0); + } + + public ViewAttachView(Context context) { + super(context); + init(null, 0); + } + + private void init(AttributeSet attrs, int defStyle) { + SystemClock.sleep(2000); + } + + @Override + protected void onAttachedToWindow() { + Log.d(TAG, "onAttachedToWindow"); + super.onAttachedToWindow(); + if (attached) { + throw new RuntimeException("OnAttachedToWindow called more than once in a row"); + } + attached = true; + } + + @Override + protected void onDetachedFromWindow() { + Log.d(TAG, "onDetachedFromWindow"); + super.onDetachedFromWindow(); + if (!attached) { + throw new RuntimeException( + "onDetachedFromWindowcalled without prior call to OnAttachedToWindow"); + } + attached = false; + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + canvas.drawColor(Color.BLUE); + } +} diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp index b752850..c3f2360 100644 --- a/graphics/jni/android_renderscript_RenderScript.cpp +++ b/graphics/jni/android_renderscript_RenderScript.cpp @@ -237,7 +237,11 @@ nContextGetErrorMessage(JNIEnv *_env, jobject _this, RsContext con) size_t receiveLen; uint32_t subID; - int id = rsContextGetMessage(con, buf, &receiveLen, &subID, sizeof(buf), true); + int id = rsContextGetMessage(con, + buf, sizeof(buf), + &receiveLen, sizeof(receiveLen), + &subID, sizeof(subID), + true); if (!id && receiveLen) { LOGV("message receive buffer too small. %i", receiveLen); } @@ -252,7 +256,11 @@ nContextGetUserMessage(JNIEnv *_env, jobject _this, RsContext con, jintArray dat jint *ptr = _env->GetIntArrayElements(data, NULL); size_t receiveLen; uint32_t subID; - int id = rsContextGetMessage(con, ptr, &receiveLen, &subID, len * 4, true); + int id = rsContextGetMessage(con, + ptr, len * 4, + &receiveLen, sizeof(receiveLen), + &subID, sizeof(subID), + true); if (!id && receiveLen) { LOGV("message receive buffer too small. %i", receiveLen); } @@ -266,7 +274,8 @@ nContextPeekMessage(JNIEnv *_env, jobject _this, RsContext con, jintArray auxDat jint *auxDataPtr = _env->GetIntArrayElements(auxData, NULL); size_t receiveLen; uint32_t subID; - int id = rsContextPeekMessage(con, &receiveLen, &subID, wait); + int id = rsContextPeekMessage(con, &receiveLen, sizeof(receiveLen), + &subID, sizeof(subID), wait); auxDataPtr[0] = (jint)subID; auxDataPtr[1] = (jint)receiveLen; _env->ReleaseIntArrayElements(auxData, auxDataPtr, 0); @@ -426,7 +435,9 @@ nAllocationCreateFromBitmap(JNIEnv *_env, jobject _this, RsContext con, jint typ bitmap.lockPixels(); const void* ptr = bitmap.getPixels(); - jint id = (jint)rsaAllocationCreateFromBitmap(con, (RsType)type, (RsAllocationMipmapControl)mip, ptr, usage); + jint id = (jint)rsaAllocationCreateFromBitmap(con, + (RsType)type, (RsAllocationMipmapControl)mip, + ptr, bitmap.getSize(), usage); bitmap.unlockPixels(); return id; } @@ -440,7 +451,9 @@ nAllocationCubeCreateFromBitmap(JNIEnv *_env, jobject _this, RsContext con, jint bitmap.lockPixels(); const void* ptr = bitmap.getPixels(); - jint id = (jint)rsaAllocationCubeCreateFromBitmap(con, (RsType)type, (RsAllocationMipmapControl)mip, ptr, usage); + jint id = (jint)rsaAllocationCubeCreateFromBitmap(con, + (RsType)type, (RsAllocationMipmapControl)mip, + ptr, bitmap.getSize(), usage); bitmap.unlockPixels(); return id; } diff --git a/include/media/stagefright/MediaErrors.h b/include/media/stagefright/MediaErrors.h index 6df4d86..1a6d548 100644 --- a/include/media/stagefright/MediaErrors.h +++ b/include/media/stagefright/MediaErrors.h @@ -42,6 +42,17 @@ enum { INFO_DISCONTINUITY = MEDIA_ERROR_BASE - 13, ERROR_NO_LICENSE = MEDIA_ERROR_BASE - 14, + + // Heartbeat Error Codes + HEARTBEAT_ERROR_BASE = -3000, + + ERROR_HEARTBEAT_AUTHENTICATION_FAILURE = HEARTBEAT_ERROR_BASE, + ERROR_HEARTBEAT_NO_ACTIVE_PURCHASE_AGREEMENT = HEARTBEAT_ERROR_BASE - 1, + ERROR_HEARTBEAT_CONCURRENT_PLAYBACK = HEARTBEAT_ERROR_BASE - 2, + ERROR_HEARTBEAT_UNUSUAL_ACTIVITY = HEARTBEAT_ERROR_BASE - 3, + ERROR_HEARTBEAT_STREAMING_UNAVAILABLE = HEARTBEAT_ERROR_BASE - 4, + ERROR_HEARTBEAT_CANNOT_ACTIVATE_RENTAL = HEARTBEAT_ERROR_BASE - 5, + ERROR_HEARTBEAT_TERMINATE_REQUESTED = HEARTBEAT_ERROR_BASE - 6, }; } // namespace android diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h index 26e240f..6c4a2a9 100644 --- a/libs/hwui/Layer.h +++ b/libs/hwui/Layer.h @@ -53,6 +53,23 @@ struct Layer { } /** + * Sets this layer's region to a rectangle. Computes the appropriate + * texture coordinates. + */ + void setRegionAsRect() { + const android::Rect& bounds = region.getBounds(); + regionRect.set(bounds.leftTop().x, bounds.leftTop().y, + bounds.rightBottom().x, bounds.rightBottom().y); + + const float texX = 1.0f / float(width); + const float texY = 1.0f / float(height); + const float height = layer.getHeight(); + texCoords.set( + regionRect.left * texX, (height - regionRect.top) * texY, + regionRect.right * texX, (height - regionRect.bottom) * texY); + } + + /** * Bounds of the layer. */ Rect layer; diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp index ba110ec..ca1e7ae 100644 --- a/libs/hwui/LayerRenderer.cpp +++ b/libs/hwui/LayerRenderer.cpp @@ -102,19 +102,7 @@ void LayerRenderer::generateMesh() { mLayer->meshElementCount = 0; } - const android::Rect& bounds = mLayer->region.getBounds(); - mLayer->regionRect.set(bounds.leftTop().x, bounds.leftTop().y, - bounds.rightBottom().x, bounds.rightBottom().y); - - const float texX = 1.0f / float(mLayer->width); - const float texY = 1.0f / float(mLayer->height); - const float height = mLayer->layer.getHeight(); - mLayer->texCoords.set( - mLayer->regionRect.left * texX, - (height - mLayer->regionRect.top) * texY, - mLayer->regionRect.right * texX, - (height - mLayer->regionRect.bottom) * texY); - + mLayer->setRegionAsRect(); return; } diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index dd0cca2..ea42838 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -647,10 +647,10 @@ void OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect, bool swap) void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) { #if RENDER_LAYERS_AS_REGIONS if (layer->region.isRect()) { - const android::Rect& bounds = layer->region.getBounds(); - layer->regionRect.set(bounds.leftTop().x, bounds.leftTop().y, - bounds.rightBottom().x, bounds.rightBottom().y); + layer->setRegionAsRect(); + composeLayerRect(layer, layer->regionRect); + layer->region.clear(); return; } @@ -979,8 +979,8 @@ void OpenGLRenderer::setupDrawModelViewTranslate(float left, float top, float ri } } -void OpenGLRenderer::setupDrawModelViewIdentity() { - mCaches.currentProgram->set(mOrthoMatrix, mIdentity, *mSnapshot->transform); +void OpenGLRenderer::setupDrawModelViewIdentity(bool offset) { + mCaches.currentProgram->set(mOrthoMatrix, mIdentity, *mSnapshot->transform, offset); } void OpenGLRenderer::setupDrawModelView(float left, float top, float right, float bottom, @@ -1389,13 +1389,46 @@ void OpenGLRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int } } -void OpenGLRenderer::drawLinesAsQuads(float *points, int count, bool isAA, bool isHairline, - float strokeWidth) { +void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) { + if (mSnapshot->isIgnored()) return; + + const bool isAA = paint->isAntiAlias(); + float strokeWidth = paint->getStrokeWidth() * 0.5f; + // A stroke width of 0 has a special meaning in Skia: + // it draws a line 1 px wide regardless of current transform + bool isHairLine = paint->getStrokeWidth() == 0.0f; + int alpha; + SkXfermode::Mode mode; + int generatedVerticesCount = 0; int verticesCount = count; if (count > 4) { // Polyline: account for extra vertices needed for continous tri-strip verticesCount += (count -4); } + + getAlphaAndMode(paint, &alpha, &mode); + setupDraw(); + if (isAA) { + setupDrawAALine(); + } + setupDrawColor(paint->getColor(), alpha); + setupDrawColorFilter(); + setupDrawShader(); + if (isAA) { + setupDrawBlending(true, mode); + } else { + setupDrawBlending(mode); + } + setupDrawProgram(); + setupDrawModelViewIdentity(true); + setupDrawColorUniforms(); + setupDrawColorFilterUniforms(); + setupDrawShaderIdentityUniforms(); + + if (isHairLine) { + // Set a real stroke width to be used in quad construction + strokeWidth = .5; + } if (isAA) { // Expand boundary to enable AA calculations on the quad border strokeWidth += .5f; @@ -1407,25 +1440,22 @@ void OpenGLRenderer::drawLinesAsQuads(float *points, int count, bool isAA, bool if (!isAA) { setupDrawVertices(vertices); } else { - AlphaVertex* alphaCoords = aaVertices + gVertexAlphaOffset; + void* alphaCoords = ((GLbyte*) aaVertices) + gVertexAlphaOffset; // innerProportion is the ratio of the inner (non-AA) port of the line to the total // AA stroke width (the base stroke width expanded by a half pixel on either side). // This value is used in the fragment shader to determine how to fill fragments. float innerProportion = fmax(strokeWidth - 1.0f, 0) / (strokeWidth + .5f); - setupDrawAALine((void*) aaVertices, (void*) alphaCoords, innerProportion); + setupDrawAALine((void*) aaVertices, alphaCoords, innerProportion); } - int generatedVerticesCount = 0; AlphaVertex *prevAAVertex = NULL; Vertex *prevVertex = NULL; float inverseScaleX = 1.0f; float inverseScaleY = 1.0f; - if (isHairline) { + if (isHairLine) { // The quad that we use for AA hairlines needs to account for scaling because the line // should always be one pixel wide regardless of scale. - inverseScaleX = 1.0f; - inverseScaleY = 1.0f; if (!mSnapshot->transform->isPureTranslate()) { Matrix4 *mat = mSnapshot->transform; float m00 = mat->data[Matrix4::kScaleX]; @@ -1446,22 +1476,19 @@ void OpenGLRenderer::drawLinesAsQuads(float *points, int count, bool isAA, bool vec2 a(points[i], points[i + 1]); vec2 b(points[i + 2], points[i + 3]); - // Bias to snap to the same pixels as Skia - a += 0.375; - b += 0.375; - // Find the normal to the line vec2 n = (b - a).copyNormalized() * strokeWidth; - if (isHairline) { - float wideningFactor; - if (fabs(n.x) >= fabs(n.y)) { - wideningFactor = fabs(1.0f / n.x); - } else { - wideningFactor = fabs(1.0f / n.y); + if (isHairLine) { + n *= inverseScaleX; + if (isAA) { + float wideningFactor; + if (fabs(n.x) >= fabs(n.y)) { + wideningFactor = fabs(1.0f / n.x); + } else { + wideningFactor = fabs(1.0f / n.y); + } + n *= wideningFactor; } - n.x *= inverseScaleX; - n.y *= inverseScaleY; - n *= wideningFactor; } float x = n.x; n.x = -n.y; @@ -1525,69 +1552,6 @@ void OpenGLRenderer::drawLinesAsQuads(float *points, int count, bool isAA, bool } } -void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) { - if (mSnapshot->isIgnored()) return; - - const bool isAA = paint->isAntiAlias(); - const float strokeWidth = paint->getStrokeWidth() * 0.5f; - // A stroke width of 0 has a special meaning in Skia: - // it draws a line 1 px wide regardless of current transform - bool isHairLine = paint->getStrokeWidth() == 0.0f; - - int alpha; - SkXfermode::Mode mode; - getAlphaAndMode(paint, &alpha, &mode); - int generatedVerticesCount = 0; - - setupDraw(); - if (isAA) { - setupDrawAALine(); - } - setupDrawColor(paint->getColor(), alpha); - setupDrawColorFilter(); - setupDrawShader(); - if (isAA) { - setupDrawBlending(true, mode); - } else { - setupDrawBlending(mode); - } - setupDrawProgram(); - setupDrawModelViewIdentity(); - setupDrawColorUniforms(); - setupDrawColorFilterUniforms(); - setupDrawShaderIdentityUniforms(); - - if (!isHairLine) { - drawLinesAsQuads(points, count, isAA, isHairLine, strokeWidth); - } else { - if (isAA) { - drawLinesAsQuads(points, count, isAA, isHairLine, .5f); - } else { - int verticesCount = count >> 1; - Vertex lines[verticesCount]; - Vertex* vertices = &lines[0]; - setupDrawVertices(vertices); - for (int i = 0; i < count; i += 4) { - - const float left = fmin(points[i], points[i + 2]); - const float right = fmax(points[i], points[i + 2]); - const float top = fmin(points[i + 1], points[i + 3]); - const float bottom = fmax(points[i + 1], points[i + 3]); - - Vertex::set(vertices++, points[i], points[i + 1]); - Vertex::set(vertices++, points[i + 2], points[i + 3]); - generatedVerticesCount += 2; - dirtyLayer(left, top, - right == left ? left + 1 : right, bottom == top ? top + 1 : bottom, - *mSnapshot->transform); - } - - glLineWidth(1.0f); - glDrawArrays(GL_LINES, 0, generatedVerticesCount); - } - } -} - void OpenGLRenderer::drawPoints(float* points, int count, SkPaint* paint) { if (mSnapshot->isIgnored()) return; @@ -1596,8 +1560,13 @@ void OpenGLRenderer::drawPoints(float* points, int count, SkPaint* paint) { // A stroke width of 0 has a special meaning in Skia: // it draws an unscaled 1px point + float strokeWidth = paint->getStrokeWidth(); const bool isHairLine = paint->getStrokeWidth() == 0.0f; - + if (isHairLine) { + // Now that we know it's hairline, we can set the effective width, to be used later + strokeWidth = 1.0f; + } + const float halfWidth = strokeWidth / 2; int alpha; SkXfermode::Mode mode; getAlphaAndMode(paint, &alpha, &mode); @@ -1609,13 +1578,13 @@ void OpenGLRenderer::drawPoints(float* points, int count, SkPaint* paint) { TextureVertex* vertex = &pointsData[0]; setupDraw(); - setupDrawPoint(isHairLine ? 1.0f : paint->getStrokeWidth()); + setupDrawPoint(strokeWidth); setupDrawColor(paint->getColor(), alpha); setupDrawColorFilter(); setupDrawShader(); setupDrawBlending(mode); setupDrawProgram(); - setupDrawModelViewIdentity(); + setupDrawModelViewIdentity(true); setupDrawColorUniforms(); setupDrawColorFilterUniforms(); setupDrawPointUniforms(); @@ -1625,6 +1594,11 @@ void OpenGLRenderer::drawPoints(float* points, int count, SkPaint* paint) { for (int i = 0; i < count; i += 2) { TextureVertex::set(vertex++, points[i], points[i + 1], 0.0f, 0.0f); generatedVerticesCount++; + float left = points[i] - halfWidth; + float right = points[i] + halfWidth; + float top = points[i + 1] - halfWidth; + float bottom = points [i + 1] + halfWidth; + dirtyLayer(left, top, right, bottom, *mSnapshot->transform); } glDrawArrays(GL_POINTS, 0, generatedVerticesCount); diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index 0276095..918e1fb 100644 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -283,19 +283,6 @@ private: void drawAlphaBitmap(Texture* texture, float left, float top, SkPaint* paint); /** - * Draws a line as a quad. Called by drawLines() for all cases except hairline without AA. - * - * @param points The vertices of the lines. Every four entries specifies the x/y points - * of a single line segment. - * @param count The number of entries in the points array. - * @param isAA Whether the line is anti-aliased - * @param isHairline Whether the line has strokeWidth==0, which results in the line being - * one pixel wide on the display regardless of scale. - */ - void drawLinesAsQuads(float *points, int count, bool isAA, bool isHairline, - float strokeWidth); - - /** * Draws a textured rectangle with the specified texture. The specified coordinates * are transformed by the current snapshot's transform matrix. * @@ -453,7 +440,7 @@ private: bool swapSrcDst = false); void setupDrawProgram(); void setupDrawDirtyRegionsDisabled(); - void setupDrawModelViewIdentity(); + void setupDrawModelViewIdentity(bool offset = false); void setupDrawModelView(float left, float top, float right, float bottom, bool ignoreTransform = false, bool ignoreModelView = false); void setupDrawModelViewTranslate(float left, float top, float right, float bottom, diff --git a/libs/hwui/Program.cpp b/libs/hwui/Program.cpp index 2187f24..972dd87 100644 --- a/libs/hwui/Program.cpp +++ b/libs/hwui/Program.cpp @@ -124,8 +124,15 @@ GLuint Program::buildShader(const char* source, GLenum type) { } void Program::set(const mat4& projectionMatrix, const mat4& modelViewMatrix, - const mat4& transformMatrix) { + const mat4& transformMatrix, bool offset) { mat4 t(projectionMatrix); + if (offset) { + // offset screenspace xy by an amount that compensates for typical precision issues + // in GPU hardware that tends to paint hor/vert lines in pixels shifted up and to the left. + // This offset value is based on an assumption that some hardware may use as little + // as 12.4 precision, so we offset by slightly more than 1/16. + t.translate(.375, .375, 0); + } t.multiply(transformMatrix); t.multiply(modelViewMatrix); diff --git a/libs/hwui/Program.h b/libs/hwui/Program.h index afc6f3d..764cb05 100644 --- a/libs/hwui/Program.h +++ b/libs/hwui/Program.h @@ -81,7 +81,7 @@ public: * transform matrices. */ void set(const mat4& projectionMatrix, const mat4& modelViewMatrix, - const mat4& transformMatrix); + const mat4& transformMatrix, bool offset = false); /** * Sets the color associated with this shader. diff --git a/libs/rs/RenderScript.h b/libs/rs/RenderScript.h index cb6d7e0..f4e3f57 100644 --- a/libs/rs/RenderScript.h +++ b/libs/rs/RenderScript.h @@ -26,20 +26,6 @@ extern "C" { #include "RenderScriptDefines.h" -RsDevice rsDeviceCreate(); -void rsDeviceDestroy(RsDevice); -void rsDeviceSetConfig(RsDevice, RsDeviceParam, int32_t value); - -RsContext rsContextCreate(RsDevice, uint32_t version); -RsContext rsContextCreateGL(RsDevice, uint32_t version, - RsSurfaceConfig sc, uint32_t dpi); -void rsContextDestroy(RsContext); - -RsMessageToClientType rsContextGetMessage(RsContext vrsc, void *data, size_t *receiveLen, uint32_t *subID, size_t bufferLen, bool wait); -RsMessageToClientType rsContextPeekMessage(RsContext vrsc, size_t *receiveLen, uint32_t *subID, bool wait); -void rsContextInitToClient(RsContext); -void rsContextDeinitToClient(RsContext); - // // A3D loading and object update code. // Should only be called at object creation, not thread safe @@ -63,18 +49,8 @@ void rsaTypeGetNativeData(RsContext, RsType, uint32_t *typeData, uint32_t typeDa void rsaElementGetNativeData(RsContext, RsElement, uint32_t *elemData, uint32_t elemDataSize); void rsaElementGetSubElements(RsContext, RsElement, uint32_t *ids, const char **names, uint32_t dataSize); -// Async commands for returning new IDS -RsType rsaTypeCreate(RsContext, RsElement, uint32_t dimX, uint32_t dimY, - uint32_t dimZ, bool mips, bool faces); -RsAllocation rsaAllocationCreateTyped(RsContext rsc, RsType vtype, - RsAllocationMipmapControl mips, - uint32_t usages); -RsAllocation rsaAllocationCreateFromBitmap(RsContext con, RsType vtype, - RsAllocationMipmapControl mips, - const void *data, uint32_t usages); -RsAllocation rsaAllocationCubeCreateFromBitmap(RsContext con, RsType vtype, - RsAllocationMipmapControl mips, - const void *data, uint32_t usages); + + #ifdef ANDROID_RS_SERIALIZE #define NO_RS_FUNCS #endif diff --git a/libs/rs/rs.spec b/libs/rs/rs.spec index dac5cec..998296b 100644 --- a/libs/rs/rs.spec +++ b/libs/rs/rs.spec @@ -1,4 +1,110 @@ +DeviceCreate { + direct + nocontext + ret RsDevice +} + +DeviceDestroy { + direct + nocontext + param RsDevice dev +} + +DeviceSetConfig { + direct + nocontext + param RsDevice dev + param RsDeviceParam p + param int32_t value +} + +ContextCreate { + direct + nocontext + param RsDevice dev + param uint32_t version + ret RsContext +} + +ContextCreateGL { + direct + nocontext + param RsDevice dev + param uint32_t version + param RsSurfaceConfig sc + param uint32_t dpi + ret RsContext +} + +ContextDestroy { + direct +} + +ContextGetMessage { + direct + param void *data + param size_t *receiveLen + param uint32_t *subID + param bool wait + ret RsMessageToClientType +} + +ContextPeekMessage { + direct + param size_t *receiveLen + param uint32_t *subID + param bool wait + ret RsMessageToClientType +} + +ContextInitToClient { + direct +} + +ContextDeinitToClient { + direct +} + +aTypeCreate { + direct + param RsElement e + param uint32_t dimX + param uint32_t dimY + param uint32_t dimZ + param bool mips + param bool faces + ret RsType +} + +aAllocationCreateTyped { + direct + param RsType vtype + param RsAllocationMipmapControl mips + param uint32_t usages + ret RsAllocation +} + +aAllocationCreateFromBitmap { + direct + param RsType vtype + param RsAllocationMipmapControl mips + param const void *data + param uint32_t usages + ret RsAllocation +} + +aAllocationCubeCreateFromBitmap { + direct + param RsType vtype + param RsAllocationMipmapControl mips + param const void *data + param uint32_t usages + ret RsAllocation +} + + + ContextFinish { handcodeApi } @@ -82,23 +188,21 @@ AllocationCopyToBitmap { Allocation1DData { + handcodeApi param RsAllocation va param uint32_t xoff param uint32_t lod param uint32_t count param const void *data - handcodeApi - togglePlay } Allocation1DElementData { + handcodeApi param RsAllocation va param uint32_t x param uint32_t lod param const void *data param uint32_t comp_offset - handcodeApi - togglePlay } Allocation2DData { @@ -186,11 +290,10 @@ ScriptInvoke { } ScriptInvokeV { + handcodeApi param RsScript s param uint32_t slot param const void * data - handcodeApi - togglePlay } ScriptSetVarI { @@ -224,11 +327,10 @@ ScriptSetVarD { } ScriptSetVarV { + handcodeApi param RsScript s param uint32_t slot param const void * data - handcodeApi - togglePlay } @@ -330,3 +432,4 @@ MeshBindVertex { MeshInitVertexAttribs { param RsMesh mesh } + diff --git a/libs/rs/rsAllocation.cpp b/libs/rs/rsAllocation.cpp index a759004..743b2c4 100644 --- a/libs/rs/rsAllocation.cpp +++ b/libs/rs/rsAllocation.cpp @@ -833,7 +833,7 @@ RsAllocation rsaAllocationCreateTyped(RsContext con, RsType vtype, RsAllocation rsaAllocationCreateFromBitmap(RsContext con, RsType vtype, RsAllocationMipmapControl mips, - const void *data, uint32_t usages) { + const void *data, size_t data_length, uint32_t usages) { Context *rsc = static_cast<Context *>(con); Type *t = static_cast<Type *>(vtype); @@ -855,7 +855,7 @@ RsAllocation rsaAllocationCreateFromBitmap(RsContext con, RsType vtype, RsAllocation rsaAllocationCubeCreateFromBitmap(RsContext con, RsType vtype, RsAllocationMipmapControl mips, - const void *data, uint32_t usages) { + const void *data, size_t data_length, uint32_t usages) { Context *rsc = static_cast<Context *>(con); Type *t = static_cast<Type *>(vtype); diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp index 0ca892d..50f5f55 100644 --- a/libs/rs/rsContext.cpp +++ b/libs/rs/rsContext.cpp @@ -768,14 +768,20 @@ RsContext rsContextCreateGL(RsDevice vdev, uint32_t version, return rsc; } -RsMessageToClientType rsContextPeekMessage(RsContext vrsc, size_t *receiveLen, uint32_t *subID, bool wait) { +RsMessageToClientType rsContextPeekMessage(RsContext vrsc, + size_t * receiveLen, size_t receiveLen_length, + uint32_t * subID, size_t subID_length, bool wait) { Context * rsc = static_cast<Context *>(vrsc); return rsc->peekMessageToClient(receiveLen, subID, wait); } -RsMessageToClientType rsContextGetMessage(RsContext vrsc, void *data, size_t *receiveLen, uint32_t *subID, size_t bufferLen, bool wait) { +RsMessageToClientType rsContextGetMessage(RsContext vrsc, void * data, size_t data_length, + size_t * receiveLen, size_t receiveLen_length, + uint32_t * subID, size_t subID_length, bool wait) { Context * rsc = static_cast<Context *>(vrsc); - return rsc->getMessageToClient(data, receiveLen, subID, bufferLen, wait); + rsAssert(subID_length == sizeof(uint32_t)); + rsAssert(receiveLen_length == sizeof(size_t)); + return rsc->getMessageToClient(data, receiveLen, subID, data_length, wait); } void rsContextInitToClient(RsContext vrsc) { diff --git a/libs/rs/rsg_generator.c b/libs/rs/rsg_generator.c index 4ac5b7f..14b380a 100644 --- a/libs/rs/rsg_generator.c +++ b/libs/rs/rsg_generator.c @@ -4,7 +4,7 @@ void printFileHeader(FILE *f) { fprintf(f, "/*\n"); - fprintf(f, " * Copyright (C) 2010 The Android Open Source Project\n"); + fprintf(f, " * Copyright (C) 2011 The Android Open Source Project\n"); fprintf(f, " *\n"); fprintf(f, " * Licensed under the Apache License, Version 2.0 (the \"License\");\n"); fprintf(f, " * you may not use this file except in compliance with the License.\n"); @@ -96,12 +96,14 @@ void printStructures(FILE *f) { void printFuncDecl(FILE *f, const ApiEntry *api, const char *prefix, int addContext) { printVarType(f, &api->ret); fprintf(f, " %s%s (", prefix, api->name); - if (addContext) { - fprintf(f, "Context *"); - } else { - fprintf(f, "RsContext rsc"); + if (!api->nocontext) { + if (addContext) { + fprintf(f, "Context *"); + } else { + fprintf(f, "RsContext rsc"); + } } - printArgList(f, api, 1); + printArgList(f, api, !api->nocontext); fprintf(f, ")"); } @@ -117,6 +119,10 @@ void printFuncDecls(FILE *f, const char *prefix, int addContext) { void printPlaybackFuncs(FILE *f, const char *prefix) { int ct; for (ct=0; ct < apiCount; ct++) { + if (apis[ct].direct) { + continue; + } + fprintf(f, "void %s%s (Context *, const void *);\n", prefix, apis[ct].name); } } @@ -140,6 +146,10 @@ void printApiCpp(FILE *f) { int needFlush = 0; const ApiEntry * api = &apis[ct]; + if (api->direct) { + continue; + } + printFuncDecl(f, api, "rs", 0); fprintf(f, "\n{\n"); if (api->handcodeApi) { @@ -198,31 +208,37 @@ void printPlaybackCpp(FILE *f) { for (ct=0; ct < apiCount; ct++) { const ApiEntry * api = &apis[ct]; + if (api->direct) { + continue; + } + fprintf(f, "void rsp_%s(Context *con, const void *vp)\n", api->name); fprintf(f, "{\n"); - if (api->handcodePlay) { - fprintf(f, " rsHCPLAY_%s(con, vp);\n", api->name); - } else { - //fprintf(f, " LOGE(\"play command %s\\n\");\n", api->name); - fprintf(f, " const RS_CMD_%s *cmd = static_cast<const RS_CMD_%s *>(vp);\n", api->name, api->name); - fprintf(f, " "); - if (api->ret.typeName[0]) { - fprintf(f, "con->mIO.mToCoreRet = (intptr_t)"); - } - fprintf(f, "rsi_%s(con", api->name); - for (ct2=0; ct2 < api->paramCount; ct2++) { - const VarType *vt = &api->params[ct2]; - fprintf(f, ",\n cmd->%s", vt->name); - } - fprintf(f, ");\n"); + + //fprintf(f, " LOGE(\"play command %s\\n\");\n", api->name); + fprintf(f, " const RS_CMD_%s *cmd = static_cast<const RS_CMD_%s *>(vp);\n", api->name, api->name); + fprintf(f, " "); + if (api->ret.typeName[0]) { + fprintf(f, "con->mIO.mToCoreRet = (intptr_t)"); } + fprintf(f, "rsi_%s(con", api->name); + for (ct2=0; ct2 < api->paramCount; ct2++) { + const VarType *vt = &api->params[ct2]; + fprintf(f, ",\n cmd->%s", vt->name); + } + fprintf(f, ");\n"); + fprintf(f, "};\n\n"); } fprintf(f, "RsPlaybackFunc gPlaybackFuncs[%i] = {\n", apiCount + 1); fprintf(f, " NULL,\n"); for (ct=0; ct < apiCount; ct++) { - fprintf(f, " %s%s,\n", "rsp_", apis[ct].name); + if (apis[ct].direct) { + fprintf(f, " NULL,\n"); + } else { + fprintf(f, " %s%s,\n", "rsp_", apis[ct].name); + } } fprintf(f, "};\n"); diff --git a/libs/rs/spec.h b/libs/rs/spec.h index 82650a7..ecc5cc7 100644 --- a/libs/rs/spec.h +++ b/libs/rs/spec.h @@ -25,7 +25,8 @@ typedef struct { char name[256]; int sync; int handcodeApi; - int handcodePlay; + int direct; + int nocontext; int paramCount; VarType ret; VarType params[16]; diff --git a/libs/rs/spec.l b/libs/rs/spec.l index c8af891..dcd4435 100644 --- a/libs/rs/spec.l +++ b/libs/rs/spec.l @@ -44,6 +44,7 @@ ID [a-zA-Z_][a-zA-Z0-9_]* <comment>"*"+"/" BEGIN(INITIAL); <*>" " //printf("found ' '\n"); +<*>"\t" //printf("found ' '\n"); <*>"\n" ++num_lines; //printf("found lf \n"); {ID} { @@ -64,8 +65,12 @@ ID [a-zA-Z_][a-zA-Z0-9_]* apis[apiCount].handcodeApi = 1; } -<api_entry2>"handcodePlay" { - apis[apiCount].handcodePlay = 1; +<api_entry2>"direct" { + apis[apiCount].direct = 1; + } + +<api_entry2>"nocontext" { + apis[apiCount].nocontext = 1; } <api_entry2>"ret" { diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp index 08db902..ef4d3d0 100644 --- a/media/libstagefright/SampleTable.cpp +++ b/media/libstagefright/SampleTable.cpp @@ -453,6 +453,10 @@ status_t SampleTable::findSampleAtTime( } if (left == mNumSampleSizes) { + if (flags == kFlagAfter) { + return ERROR_OUT_OF_RANGE; + } + --left; } diff --git a/media/libstagefright/omx/tests/OMXHarness.cpp b/media/libstagefright/omx/tests/OMXHarness.cpp index 4f28855..54c0d77 100644 --- a/media/libstagefright/omx/tests/OMXHarness.cpp +++ b/media/libstagefright/omx/tests/OMXHarness.cpp @@ -487,14 +487,12 @@ static const char *GetURLForMime(const char *mime) { { "audio/3gpp", "file:///sdcard/media_api/video/H263_500_AMRNB_12.3gp" }, { "audio/amr-wb", - "file:///sdcard/media_api/music_perf/AMRWB/" - "NIN_AMR-WB_15.85kbps_16kbps.amr" }, + "file:///sdcard/media_api/music/" + "AI_AMR-WB_12.65kbps(13kbps)_16khz_mono_NMC.awb" }, { "audio/mp4a-latm", - "file:///sdcard/media_api/music_perf/AAC/" - "WC_AAC_80kbps_32khz_Stereo_1pCBR_SSE.mp4" }, + "file:///sdcard/media_api/video/H264_AAC.3gp" }, { "audio/mpeg", - "file:///sdcard/media_api/music_perf/MP3/" - "WC_256kbps_44.1khz_mono_CBR_DPA.mp3" } + "file:///sdcard/media_api/music/MP3CBR.mp3" } }; for (size_t i = 0; i < sizeof(kMimeToURL) / sizeof(kMimeToURL[0]); ++i) { @@ -626,8 +624,10 @@ status_t Harness::testSeek( requestedSeekTimeUs, requestedSeekTimeUs / 1E6); } - MediaBuffer *buffer; - options.setSeekTo(requestedSeekTimeUs); + MediaBuffer *buffer = NULL; + options.setSeekTo( + requestedSeekTimeUs, MediaSource::ReadOptions::SEEK_NEXT_SYNC); + if (seekSource->read(&buffer, &options) != OK) { CHECK_EQ(buffer, NULL); actualSeekTimeUs = -1; diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java index 1ad8047..d96369b 100644 --- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -642,14 +642,16 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } /** - * Installs or removes the accessibility input filter when accessibility is enabled - * or disabled. + * Sets the input filter state. If the filter is in enabled it is registered + * in the window manager, otherwise the filter is removed from the latter. + * + * @param enabled Whether the input filter is enabled. */ - private void updateInputFilterLocked() { + private void setInputFilterEnabledLocked(boolean enabled) { WindowManagerService wm = (WindowManagerService)ServiceManager.getService( Context.WINDOW_SERVICE); if (wm != null) { - if (mIsEnabled) { + if (enabled) { if (mInputFilter == null) { mInputFilter = new AccessibilityInputFilter(mContext); } @@ -681,7 +683,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub if (enabledServices.size() > 0 && service.mFeedbackType == AccessibilityServiceInfo.FEEDBACK_SPOKEN) { updateClientsLocked(); - updateInputFilterLocked(); + setInputFilterEnabledLocked(true); } } @@ -697,7 +699,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub if (enabledServices.isEmpty() && service.mFeedbackType == AccessibilityServiceInfo.FEEDBACK_SPOKEN) { updateClientsLocked(); - updateInputFilterLocked(); + setInputFilterEnabledLocked(false); } } diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index c4027e0..b2f95cd 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -986,8 +986,16 @@ status_t Layer::BufferManager::initEglImage(EGLDisplay dpy, ssize_t index = mActiveBufferIndex; if (index >= 0) { if (!mFailover) { - Image& texture(mBufferData[index].texture); - err = mTextureManager.initEglImage(&texture, dpy, buffer); + { + // Without that lock, there is a chance of race condition + // where while composing a specific index, requestBuf + // with the same index can be executed and touch the same data + // that is being used in initEglImage. + // (e.g. dirty flag in texture) + Mutex::Autolock _l(mLock); + Image& texture(mBufferData[index].texture); + err = mTextureManager.initEglImage(&texture, dpy, buffer); + } // if EGLImage fails, we switch to regular texture mode, and we // free all resources associated with using EGLImages. if (err == NO_ERROR) { diff --git a/tests/DumpRenderTree/assets/run_page_cycler.py b/tests/DumpRenderTree/assets/run_page_cycler.py index 692f32e..f995086 100755 --- a/tests/DumpRenderTree/assets/run_page_cycler.py +++ b/tests/DumpRenderTree/assets/run_page_cycler.py @@ -33,10 +33,16 @@ def main(options, args): # Include all tests if none are specified. if not args: print "need a URL, e.g. file:///sdcard/webkit/page_cycler/moz/start.html\?auto=1\&iterations=10" + print " or remote:android-browser-test:80/page_cycler/" sys.exit(1) else: path = ' '.join(args); + if path[:7] == "remote:": + remote_path = path[7:] + else: + remote_path = None + adb_cmd = "adb "; if options.adb_options: adb_cmd += options.adb_options @@ -56,7 +62,20 @@ def main(options, args): run_load_test_cmd_postfix = " -w com.android.dumprendertree/.LayoutTestsAutoRunner" # Call LoadTestsAutoTest::runTest. - run_load_test_cmd = run_load_test_cmd_prefix + " -e class com.android.dumprendertree.LoadTestsAutoTest#runPageCyclerTest -e path \"" + path + "\" -e timeout " + timeout_ms + run_load_test_cmd = run_load_test_cmd_prefix + " -e class com.android.dumprendertree.LoadTestsAutoTest#runPageCyclerTest -e timeout " + timeout_ms + + if remote_path: + if options.suite: + run_load_test_cmd += " -e suite %s -e forward %s " % (options.suite, + remote_path) + else: + print "for network mode, need to specify --suite as well." + sys.exit(1) + if options.iteration: + run_load_test_cmd += " -e iteration %s" % options.iteration + else: + run_load_test_cmd += " -e path \"%s\" " % path + if options.drawtime: run_load_test_cmd += " -e drawtime true " @@ -130,5 +149,15 @@ if '__main__' == __name__: default=None, help="stores rendered page to a location on device.") + option_parser.add_option("-u", "--suite", + default=None, + help="(for network mode) specify the suite to" + " run by name") + + option_parser.add_option("-i", "--iteration", + default="5", + help="(for network mode) specify how many iterations" + " to run") + options, args = option_parser.parse_args(); main(options, args) diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoRunner.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoRunner.java index e058f32..3ba3488 100755 --- a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoRunner.java +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoRunner.java @@ -25,7 +25,7 @@ import junit.framework.TestSuite; /** * Instrumentation Test Runner for all DumpRenderTree tests. - * + * * Running all tests: * * adb shell am instrument \ @@ -57,7 +57,7 @@ public class LayoutTestsAutoRunner extends InstrumentationTestRunner { e.printStackTrace(); } } - + String delay_str = (String) icicle.get("delay"); if(delay_str != null) { try { @@ -66,30 +66,37 @@ public class LayoutTestsAutoRunner extends InstrumentationTestRunner { } } - String r = (String)icicle.get("rebaseline"); + String r = icicle.getString("rebaseline"); this.mRebaseline = (r != null && r.toLowerCase().equals("true")); - String logtime = (String) icicle.get("logtime"); + String logtime = icicle.getString("logtime"); this.mLogtime = (logtime != null && logtime.toLowerCase().equals("true")); - String drawTime = (String) icicle.get("drawtime"); + String drawTime = icicle.getString("drawtime"); this.mGetDrawTime = (drawTime != null && drawTime.toLowerCase().equals("true")); - mSaveImagePath = (String) icicle.get("saveimage"); + mSaveImagePath = icicle.getString("saveimage"); - mJsEngine = (String) icicle.get("jsengine"); + mJsEngine = icicle.getString("jsengine"); + + mPageCyclerSuite = icicle.getString("suite"); + mPageCyclerForwardHost = icicle.getString("forward"); + mPageCyclerIteration = icicle.getString("iteration", "5"); super.onCreate(icicle); } - - public String mTestPath; - public String mSaveImagePath; - public int mTimeoutInMillis; - public int mDelay; - public boolean mRebaseline; - public boolean mLogtime; - public boolean mGetDrawTime; - public String mJsEngine; + + String mPageCyclerSuite; + String mPageCyclerForwardHost; + String mPageCyclerIteration; + String mTestPath; + String mSaveImagePath; + int mTimeoutInMillis; + int mDelay; + boolean mRebaseline; + boolean mLogtime; + boolean mGetDrawTime; + String mJsEngine; } diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java index 050b779..7ac0665 100644 --- a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java @@ -401,15 +401,6 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh activity.setDefaultDumpDataType(DumpDataType.EXT_REPR); // Run tests. - int addr = -1; - try{ - addr = AdbUtils.resolve("android-browser-test.mtv.corp.google.com"); - } catch (IOException ioe) { - Log.w(LOGTAG, "error while resolving test host name", ioe); - } - if(addr == -1) { - Log.w(LOGTAG, "failed to resolve test host. http tests will fail."); - } for (int i = 0; i < mTestList.size(); i++) { String s = mTestList.elementAt(i); boolean ignoreResult = mTestListIgnoreResult.elementAt(i); diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LoadTestsAutoTest.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LoadTestsAutoTest.java index 622fb0e..ee5bb5d 100644 --- a/tests/DumpRenderTree/src/com/android/dumprendertree/LoadTestsAutoTest.java +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/LoadTestsAutoTest.java @@ -16,6 +16,9 @@ package com.android.dumprendertree; +import com.android.dumprendertree.forwarder.AdbUtils; +import com.android.dumprendertree.forwarder.ForwardServer; + import android.app.Instrumentation; import android.content.Context; import android.content.Intent; @@ -34,6 +37,8 @@ import java.io.OutputStream; import java.io.PrintStream; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import java.util.regex.Matcher; +import java.util.regex.Pattern; public class LoadTestsAutoTest extends ActivityInstrumentationTestCase2<TestShellActivity> { @@ -41,13 +46,15 @@ public class LoadTestsAutoTest extends ActivityInstrumentationTestCase2<TestShel private final static String LOAD_TEST_RESULT = Environment.getExternalStorageDirectory() + "/load_test_result.txt"; private final static int MAX_GC_WAIT_SEC = 10; + private final static int LOCAL_PORT = 17171; private boolean mFinished; static final String LOAD_TEST_RUNNER_FILES[] = { "run_page_cycler.py" }; + private ForwardServer mForwardServer; public LoadTestsAutoTest() { - super("com.android.dumprendertree", TestShellActivity.class); + super(TestShellActivity.class); } // This function writes the result of the layout test to @@ -59,14 +66,38 @@ public class LoadTestsAutoTest extends ActivityInstrumentationTestCase2<TestShel inst.sendStatus(0, bundle); } + private String setUpForwarding(String forwardInfo, String suite, String iteration) throws IOException { + // read forwarding information first + Pattern forwardPattern = Pattern.compile("(.*):(\\d+)/(.*)/"); + Matcher matcher = forwardPattern.matcher(forwardInfo); + if (!matcher.matches()) { + throw new RuntimeException("Invalid forward information"); + } + String host = matcher.group(1); + int port = Integer.parseInt(matcher.group(2)); + mForwardServer = new ForwardServer(LOCAL_PORT, AdbUtils.resolve(host), port); + mForwardServer.start(); + return String.format("http://127.0.0.1:%d/%s/%s/start.html?auto=1&iterations=%s", + LOCAL_PORT, matcher.group(3), suite, iteration); + } + // Invokes running of layout tests // and waits till it has finished running. - public void runPageCyclerTest() { + public void runPageCyclerTest() throws IOException { LayoutTestsAutoRunner runner = (LayoutTestsAutoRunner) getInstrumentation(); + if (runner.mPageCyclerSuite != null) { + // start forwarder to use page cycler suites hosted on external web server + if (runner.mPageCyclerForwardHost == null) { + throw new RuntimeException("no forwarder information provided"); + } + runner.mTestPath = setUpForwarding(runner.mPageCyclerForwardHost, + runner.mPageCyclerSuite, runner.mPageCyclerIteration); + Log.d(LOGTAG, "using path: " + runner.mTestPath); + } + if (runner.mTestPath == null) { - Log.e(LOGTAG, "No test specified"); - return; + throw new RuntimeException("No test specified"); } TestShellActivity activity = (TestShellActivity) getActivity(); @@ -79,6 +110,10 @@ public class LoadTestsAutoTest extends ActivityInstrumentationTestCase2<TestShel runner.mGetDrawTime, runner.mSaveImagePath); activity.clearCache(); + if (mForwardServer != null) { + mForwardServer.stop(); + mForwardServer = null; + } try { Thread.sleep(5000); } catch (InterruptedException e) { @@ -92,7 +127,9 @@ public class LoadTestsAutoTest extends ActivityInstrumentationTestCase2<TestShel private void freeMem() { Log.v(LOGTAG, "freeMem: calling gc..."); final CountDownLatch latch = new CountDownLatch(1); + @SuppressWarnings("unused") Object dummy = new Object() { + // this object instance is used to track gc @Override protected void finalize() throws Throwable { latch.countDown(); diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/Forwarder.java b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/Forwarder.java index a1f3cdf..a971e7b 100644 --- a/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/Forwarder.java +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/Forwarder.java @@ -36,6 +36,7 @@ public class Forwarder { private Socket from, to; private static final String LOGTAG = "Forwarder"; + private static final int BUFFER_SIZE = 16384; public Forwarder (Socket from, Socket to, ForwardServer server) { this.server = server; @@ -90,7 +91,7 @@ public class Forwarder { int length; InputStream is = in.getInputStream(); OutputStream os = out.getOutputStream(); - byte[] buffer = new byte[4096]; + byte[] buffer = new byte[BUFFER_SIZE]; while ((length = is.read(buffer)) > 0) { os.write(buffer, 0, length); } diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml index c763b1d..31b2ddd 100644 --- a/tests/HwAccelerationTest/AndroidManifest.xml +++ b/tests/HwAccelerationTest/AndroidManifest.xml @@ -406,6 +406,15 @@ </activity> <activity + android:name="PointsActivity" + android:label="_Points"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + + <activity android:name="Transform3dActivity" android:label="_3d"> <intent-filter> diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/Lines2Activity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/Lines2Activity.java index ccf0631..55fab3f 100644 --- a/tests/HwAccelerationTest/src/com/android/test/hwui/Lines2Activity.java +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/Lines2Activity.java @@ -42,8 +42,9 @@ public class Lines2Activity extends Activity { swView.setLayerType(View.LAYER_TYPE_SOFTWARE, null); frame.addView(swView); final LinesView hwBothView = new LinesView(this, 850, Color.GREEN); - // BUG: some lines not drawn or drawn with alpha when enabling hw layers -// hwBothView.setLayerType(View.LAYER_TYPE_HARDWARE, null); + // Don't actually need to render to a hw layer, but it's a good sanity-check that + // we're rendering to/from layers correctly + hwBothView.setLayerType(View.LAYER_TYPE_HARDWARE, null); frame.addView(hwBothView); final LinesView swBothView = new LinesView(this, 854, Color.RED); swBothView.setLayerType(View.LAYER_TYPE_SOFTWARE, null); diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/PointsActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/PointsActivity.java new file mode 100644 index 0000000..b3fb7a1 --- /dev/null +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/PointsActivity.java @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.test.hwui; + +import android.animation.ObjectAnimator; +import android.app.Activity; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.drawable.ColorDrawable; +import android.os.Bundle; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.LinearLayout; +import android.widget.ProgressBar; +import android.widget.SeekBar; + +@SuppressWarnings({"UnusedDeclaration"}) +public class PointsActivity extends Activity { + + float mSeekValue = .5f; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + getWindow().setBackgroundDrawable(new ColorDrawable(0xff000000)); + SeekBar slider = new SeekBar(this); + LinearLayout container = new LinearLayout(this); + container.setOrientation(LinearLayout.VERTICAL); + setContentView(container); + + container.addView(slider); + slider.setMax(100); + slider.setProgress(50); + FrameLayout frame = new FrameLayout(this); + final RenderingView gpuView = new RenderingView(this, Color.GREEN); + frame.addView(gpuView); + final RenderingView swView = new RenderingView(this, Color.RED); + swView.setLayerType(View.LAYER_TYPE_SOFTWARE, null); + frame.addView(swView); + container.addView(frame); + + slider.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + mSeekValue = (float)progress / 100.0f; + float gpuAlpha = Math.min(2.0f * mSeekValue, 1f); + gpuView.setAlpha(gpuAlpha); + float swAlpha = Math.min((1 - mSeekValue) * 2.0f, 1f); + System.out.println("(gpuAlpha, swAlpha = " + gpuAlpha + ", " + swAlpha); + swView.setAlpha(swAlpha); + } + + @Override + public void onStartTrackingTouch(SeekBar seekBar) { + } + + @Override + public void onStopTrackingTouch(SeekBar seekBar) { + } + }); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + } + + public static class RenderingView extends View { + + private int mColor; + + public RenderingView(Context c, int color) { + super(c); + mColor = color; + } + + private void drawPoints(Canvas canvas, Paint p, float xOffset, float yOffset) { + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + Paint p = new Paint(); + p.setColor(mColor); + + float yOffset = 0; + for (int i = 0; i < 2; ++i) { + float xOffset = 0; + + p.setStrokeWidth(0f); + p.setStrokeCap(Paint.Cap.SQUARE); + canvas.drawPoint(100 + xOffset, 100 + yOffset, p); + xOffset += 5; + + p.setStrokeWidth(1f); + canvas.drawPoint(100 + xOffset, 100 + yOffset, p); + xOffset += 15; + + p.setStrokeWidth(20); + canvas.drawPoint(100 + xOffset, 100 + yOffset, p); + xOffset += 30; + + p.setStrokeCap(Paint.Cap.ROUND); + canvas.drawPoint(100 + xOffset, 100 + yOffset, p); + + p.setAntiAlias(true); + yOffset += 30; + } + + } + } +} diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java index 7462701..e776463 100644 --- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java +++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java @@ -88,9 +88,8 @@ public class ImageProcessingActivity extends Activity } // This is a hack to work around an invalidation bug - mBitmapOut = Bitmap.createBitmap(mBitmapOut); + mBitmapOut.setPixel(0, 0, 0); mOutPixelsAllocation.copyTo(mBitmapOut); - mDisplayView.setImageBitmap(mBitmapOut); mDisplayView.invalidate(); } }; |