diff options
24 files changed, 471 insertions, 145 deletions
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java index 42eda02..8e2d360 100644 --- a/core/java/android/app/SearchDialog.java +++ b/core/java/android/app/SearchDialog.java @@ -168,6 +168,7 @@ public class SearchDialog extends Dialog { SearchBar searchBar = (SearchBar) findViewById(com.android.internal.R.id.search_bar); searchBar.setSearchDialog(this); mSearchView = (SearchView) findViewById(com.android.internal.R.id.search_view); + mSearchView.setIconified(false); mSearchView.setOnCloseListener(mOnCloseListener); mSearchView.setOnQueryTextListener(mOnQueryChangeListener); mSearchView.setOnSuggestionListener(mOnSuggestionSelectionListener); @@ -633,31 +634,6 @@ public class SearchDialog extends Dialog { } /** - * Overrides the handling of the back key to move back to the previous - * sources or dismiss the search dialog, instead of dismissing the input - * method. - */ - @Override - public boolean dispatchKeyEventPreIme(KeyEvent event) { - if (DBG) - Log.d(LOG_TAG, "onKeyPreIme(" + event + ")"); - if (mSearchDialog != null && event.getKeyCode() == KeyEvent.KEYCODE_BACK) { - KeyEvent.DispatcherState state = getKeyDispatcherState(); - if (state != null) { - if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) { - state.startTracking(event, this); - return true; - } else if (event.getAction() == KeyEvent.ACTION_UP && !event.isCanceled() - && state.isTracking(event)) { - mSearchDialog.onBackPressed(); - return true; - } - } - } - return super.dispatchKeyEventPreIme(event); - } - - /** * Don't allow action modes in a SearchBar, it looks silly. */ @Override diff --git a/core/java/android/content/SearchRecentSuggestionsProvider.java b/core/java/android/content/SearchRecentSuggestionsProvider.java index 3d89e92..e1a8d21 100644 --- a/core/java/android/content/SearchRecentSuggestionsProvider.java +++ b/core/java/android/content/SearchRecentSuggestionsProvider.java @@ -186,6 +186,9 @@ public class SearchRecentSuggestionsProvider extends ContentProvider { mSuggestionProjection = new String [] { "0 AS " + SearchManager.SUGGEST_COLUMN_FORMAT, + "'android.resource://system/" + + com.android.internal.R.drawable.ic_menu_recent_history + "' AS " + + SearchManager.SUGGEST_COLUMN_ICON_1, "display1 AS " + SearchManager.SUGGEST_COLUMN_TEXT_1, "display2 AS " + SearchManager.SUGGEST_COLUMN_TEXT_2, "query AS " + SearchManager.SUGGEST_COLUMN_QUERY, @@ -196,6 +199,9 @@ public class SearchRecentSuggestionsProvider extends ContentProvider { mSuggestionProjection = new String [] { "0 AS " + SearchManager.SUGGEST_COLUMN_FORMAT, + "'android.resource://system/" + + com.android.internal.R.drawable.ic_menu_recent_history + "' AS " + + SearchManager.SUGGEST_COLUMN_ICON_1, "display1 AS " + SearchManager.SUGGEST_COLUMN_TEXT_1, "query AS " + SearchManager.SUGGEST_COLUMN_QUERY, "_id" diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java index f3bda43..b2d1a1e 100644 --- a/core/java/android/widget/SearchView.java +++ b/core/java/android/widget/SearchView.java @@ -18,8 +18,6 @@ package android.widget; import static android.widget.SuggestionsAdapter.getColumnString; -import com.android.internal.R; - import android.app.PendingIntent; import android.app.SearchManager; import android.app.SearchableInfo; @@ -39,10 +37,14 @@ import android.net.Uri; import android.os.Bundle; import android.speech.RecognizerIntent; import android.text.Editable; +import android.text.Spannable; +import android.text.SpannableStringBuilder; import android.text.TextUtils; import android.text.TextWatcher; +import android.text.style.ImageSpan; import android.util.AttributeSet; import android.util.Log; +import android.util.TypedValue; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; @@ -51,6 +53,8 @@ import android.widget.AdapterView.OnItemClickListener; import android.widget.AdapterView.OnItemSelectedListener; import android.widget.TextView.OnEditorActionListener; +import com.android.internal.R; + import java.util.WeakHashMap; /** @@ -87,6 +91,8 @@ public class SearchView extends LinearLayout { private View mSearchEditFrame; private View mVoiceButton; private SearchAutoComplete mQueryTextView; + private View mDropDownAnchor; + private ImageView mSearchHintIcon; private boolean mSubmitButtonEnabled; private CharSequence mQueryHint; private boolean mQueryRefinement; @@ -195,6 +201,7 @@ public class SearchView extends LinearLayout { mSubmitButton = findViewById(R.id.search_go_btn); mCloseButton = (ImageView) findViewById(R.id.search_close_btn); mVoiceButton = findViewById(R.id.search_voice_btn); + mSearchHintIcon = (ImageView) findViewById(R.id.search_mag_icon); mSearchButton.setOnClickListener(mOnClickListener); mCloseButton.setOnClickListener(mOnClickListener); @@ -244,7 +251,20 @@ public class SearchView extends LinearLayout { mVoiceAppSearchIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); mVoiceAppSearchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + mDropDownAnchor = findViewById(mQueryTextView.getDropDownAnchor()); + if (mDropDownAnchor != null) { + mDropDownAnchor.addOnLayoutChangeListener(new OnLayoutChangeListener() { + @Override + public void onLayoutChange(View v, int left, int top, int right, int bottom, + int oldLeft, int oldTop, int oldRight, int oldBottom) { + adjustDropDownSizeAndPosition(); + } + + }); + } + updateViewsVisibility(mIconifiedByDefault); + updateQueryHint(); } /** @@ -263,7 +283,7 @@ public class SearchView extends LinearLayout { } // Cache the voice search capability mVoiceButtonEnabled = hasVoiceSearch(); - updateViewsVisibility(mIconifiedByDefault); + updateViewsVisibility(isIconified()); } /** @@ -300,7 +320,6 @@ public class SearchView extends LinearLayout { mQueryTextView.clearFocus(); setImeVisibility(false); mClearingFocus = false; - updateViewsVisibility(mIconifiedByDefault); } /** @@ -555,6 +574,7 @@ public class SearchView extends LinearLayout { mSearchButton.setVisibility(visCollapsed); updateSubmitButton(hasText); mSearchEditFrame.setVisibility(collapsed ? GONE : VISIBLE); + mSearchHintIcon.setVisibility(mIconifiedByDefault ? GONE : VISIBLE); updateCloseButton(); updateVoiceButton(!hasText); updateSubmitArea(); @@ -822,9 +842,29 @@ public class SearchView extends LinearLayout { return result; } + private int getSearchIconId() { + TypedValue outValue = new TypedValue(); + getContext().getTheme().resolveAttribute(com.android.internal.R.attr.searchViewSearchIcon, + outValue, true); + return outValue.resourceId; + } + + private CharSequence getDecoratedHint(CharSequence hintText) { + // If the field is always expanded, then don't add the search icon to the hint + if (!mIconifiedByDefault) return hintText; + + SpannableStringBuilder ssb = new SpannableStringBuilder(" "); // for the icon + ssb.append(hintText); + Drawable searchIcon = getContext().getResources().getDrawable(getSearchIconId()); + int textSize = (int) (mQueryTextView.getTextSize() * 1.25); + searchIcon.setBounds(0, 0, textSize, textSize); + ssb.setSpan(new ImageSpan(searchIcon), 1, 2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + return ssb; + } + private void updateQueryHint() { if (mQueryHint != null) { - mQueryTextView.setHint(mQueryHint); + mQueryTextView.setHint(getDecoratedHint(mQueryHint)); } else if (mSearchable != null) { CharSequence hint = null; int hintId = mSearchable.getHintId(); @@ -832,8 +872,10 @@ public class SearchView extends LinearLayout { hint = getContext().getString(hintId); } if (hint != null) { - mQueryTextView.setHint(hint); + mQueryTextView.setHint(getDecoratedHint(hint)); } + } else { + mQueryTextView.setHint(getDecoratedHint("")); } } @@ -922,9 +964,13 @@ public class SearchView extends LinearLayout { CharSequence text = mQueryTextView.getText(); if (TextUtils.isEmpty(text)) { if (mIconifiedByDefault) { - // query field already empty, hide the keyboard and remove focus - clearFocus(); - setImeVisibility(false); + // If the app doesn't override the close behavior + if (mOnCloseListener == null || !mOnCloseListener.onClose()) { + // hide the keyboard and remove focus + clearFocus(); + // collapse the search field + updateViewsVisibility(true); + } } } else { mQueryTextView.setText(""); @@ -932,10 +978,6 @@ public class SearchView extends LinearLayout { setImeVisibility(true); } - if (mIconifiedByDefault && (mOnCloseListener == null || !mOnCloseListener.onClose())) { - updateViewsVisibility(mIconifiedByDefault); - setImeVisibility(false); - } } private void onSearchClicked() { @@ -975,6 +1017,28 @@ public class SearchView extends LinearLayout { updateFocusedState(mQueryTextView.hasFocus()); } + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + } + + private void adjustDropDownSizeAndPosition() { + if (mDropDownAnchor.getWidth() > 1) { + Resources res = getContext().getResources(); + int anchorPadding = mSearchPlate.getPaddingLeft(); + Rect dropDownPadding = new Rect(); + int iconOffset = mIconifiedByDefault + ? res.getDimensionPixelSize(R.dimen.dropdownitem_icon_width) + + res.getDimensionPixelSize(R.dimen.dropdownitem_text_padding_left) + : 0; + mQueryTextView.getDropDownBackground().getPadding(dropDownPadding); + mQueryTextView.setDropDownHorizontalOffset(-(dropDownPadding.left + iconOffset) + + anchorPadding); + mQueryTextView.setDropDownWidth(mDropDownAnchor.getWidth() + dropDownPadding.left + + dropDownPadding.right + iconOffset - (anchorPadding)); + } + } + private boolean onItemClicked(int position, int actionKey, String actionMsg) { if (mOnSuggestionListener == null || !mOnSuggestionListener.onSuggestionClick(position)) { @@ -1393,5 +1457,32 @@ public class SearchView extends LinearLayout { public boolean enoughToFilter() { return mThreshold <= 0 || super.enoughToFilter(); } + + @Override + public boolean onKeyPreIme(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK) { + // special case for the back key, we do not even try to send it + // to the drop down list but instead, consume it immediately + if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) { + KeyEvent.DispatcherState state = getKeyDispatcherState(); + if (state != null) { + state.startTracking(event, this); + } + return true; + } else if (event.getAction() == KeyEvent.ACTION_UP) { + KeyEvent.DispatcherState state = getKeyDispatcherState(); + if (state != null) { + state.handleUpEvent(event); + } + if (event.isTracking() && !event.isCanceled()) { + mSearchView.clearFocus(); + mSearchView.setImeVisibility(false); + return true; + } + } + } + return super.onKeyPreIme(keyCode, event); + } + } } diff --git a/core/java/android/widget/SuggestionsAdapter.java b/core/java/android/widget/SuggestionsAdapter.java index 2cfc016..9e32c9a 100644 --- a/core/java/android/widget/SuggestionsAdapter.java +++ b/core/java/android/widget/SuggestionsAdapter.java @@ -16,8 +16,6 @@ package android.widget; -import com.android.internal.R; - import android.app.SearchDialog; import android.app.SearchManager; import android.app.SearchableInfo; @@ -47,6 +45,8 @@ import android.view.View; import android.view.ViewGroup; import android.view.View.OnClickListener; +import com.android.internal.R; + import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; @@ -88,8 +88,8 @@ class SuggestionsAdapter extends ResourceCursorAdapter implements OnClickListene private int mIconName2Col = INVALID_INDEX; private int mFlagsCol = INVALID_INDEX; - private final Runnable mStartSpinnerRunnable; - private final Runnable mStopSpinnerRunnable; + // private final Runnable mStartSpinnerRunnable; + // private final Runnable mStopSpinnerRunnable; /** * The amount of time we delay in the filter when the user presses the delete key. @@ -113,17 +113,18 @@ class SuggestionsAdapter extends ResourceCursorAdapter implements OnClickListene mOutsideDrawablesCache = outsideDrawablesCache; - mStartSpinnerRunnable = new Runnable() { - public void run() { - // mSearchView.setWorking(true); // TODO: - } - }; - mStopSpinnerRunnable = new Runnable() { - public void run() { - // mSearchView.setWorking(false); // TODO: - } - }; + // mStartSpinnerRunnable = new Runnable() { + // public void run() { + // // mSearchView.setWorking(true); // TODO: + // } + // }; + // + // mStopSpinnerRunnable = new Runnable() { + // public void run() { + // // mSearchView.setWorking(false); // TODO: + // } + // }; // delay 500ms when deleting getFilter().setDelayer(new Filter.Delayer() { @@ -341,10 +342,10 @@ class SuggestionsAdapter extends ResourceCursorAdapter implements OnClickListene } if (views.mIcon1 != null) { - setViewDrawable(views.mIcon1, getIcon1(cursor)); + setViewDrawable(views.mIcon1, getIcon1(cursor), View.INVISIBLE); } if (views.mIcon2 != null) { - setViewDrawable(views.mIcon2, getIcon2(cursor)); + setViewDrawable(views.mIcon2, getIcon2(cursor), View.GONE); } if (mQueryRefinement == REFINE_ALL || (mQueryRefinement == REFINE_BY_ENTRY @@ -414,13 +415,13 @@ class SuggestionsAdapter extends ResourceCursorAdapter implements OnClickListene * Sets the drawable in an image view, makes sure the view is only visible if there * is a drawable. */ - private void setViewDrawable(ImageView v, Drawable drawable) { + private void setViewDrawable(ImageView v, Drawable drawable, int nullVisibility) { // Set the icon even if the drawable is null, since we need to clear any // previous icon. v.setImageDrawable(drawable); if (drawable == null) { - v.setVisibility(View.GONE); + v.setVisibility(nullVisibility); } else { v.setVisibility(View.VISIBLE); diff --git a/core/jni/Android.mk b/core/jni/Android.mk index 06dc083..514e59d 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -139,6 +139,7 @@ LOCAL_SRC_FILES:= \ android_bluetooth_common.cpp \ android_bluetooth_BluetoothAudioGateway.cpp \ android_bluetooth_BluetoothSocket.cpp \ + android_bluetooth_c.c \ android_server_BluetoothService.cpp \ android_server_BluetoothEventLoop.cpp \ android_server_BluetoothA2dpService.cpp \ diff --git a/core/jni/android/graphics/TextLayoutCache.cpp b/core/jni/android/graphics/TextLayoutCache.cpp index 6a13876..30fe298 100644 --- a/core/jni/android/graphics/TextLayoutCache.cpp +++ b/core/jni/android/graphics/TextLayoutCache.cpp @@ -323,9 +323,7 @@ size_t TextLayoutCacheValue::getSize() { void TextLayoutCacheValue::setupShaperItem(HB_ShaperItem* shaperItem, HB_FontRec* font, FontData* fontData, SkPaint* paint, const UChar* chars, size_t start, size_t count, - size_t contextCount, int dirFlags) { - bool isRTL = dirFlags & 0x1; - + size_t contextCount, bool isRTL) { font->klass = &harfbuzzSkiaClass; font->userData = 0; // The values which harfbuzzSkiaClass returns are already scaled to @@ -374,10 +372,10 @@ void TextLayoutCacheValue::setupShaperItem(HB_ShaperItem* shaperItem, HB_FontRec void TextLayoutCacheValue::shapeWithHarfbuzz(HB_ShaperItem* shaperItem, HB_FontRec* font, FontData* fontData, SkPaint* paint, const UChar* chars, size_t start, size_t count, - size_t contextCount, int dirFlags) { + size_t contextCount, bool isRTL) { // Setup Harfbuzz Shaper setupShaperItem(shaperItem, font, fontData, paint, chars, start, count, - contextCount, dirFlags); + contextCount, isRTL); // Shape resetGlyphArrays(shaperItem); @@ -430,7 +428,7 @@ void TextLayoutCacheValue::computeValuesWithHarfbuzz(SkPaint* paint, const UChar LOGD("computeValuesWithHarfbuzz -- forcing run with LTR=%d RTL=%d", forceLTR, forceRTL); #endif - computeRunValuesWithHarfbuzz(paint, chars, start, count, contextCount, dirFlags, + computeRunValuesWithHarfbuzz(paint, chars, start, count, contextCount, forceRTL, outAdvances, outTotalAdvance, outGlyphs, outGlyphsCount); if (forceRTL && *outGlyphsCount > 1) { @@ -451,10 +449,15 @@ void TextLayoutCacheValue::computeValuesWithHarfbuzz(SkPaint* paint, const UChar LOGD("computeValuesWithHarfbuzz -- dirFlags=%d run-count=%d paraDir=%d", dirFlags, rc, paraDir); #endif if (rc == 1 || !U_SUCCESS(status)) { + bool isRTL = (paraDir == 1); +#if DEBUG_GLYPHS + LOGD("computeValuesWithHarfbuzz -- processing SINGLE run " + "-- run-start=%d run-len=%d isRTL=%d", start, count, isRTL); +#endif computeRunValuesWithHarfbuzz(paint, chars, start, count, contextCount, - dirFlags, outAdvances, outTotalAdvance, outGlyphs, outGlyphsCount); + isRTL, outAdvances, outTotalAdvance, outGlyphs, outGlyphsCount); - if (dirFlags == 1 && *outGlyphsCount > 1) { + if (isRTL && *outGlyphsCount > 1) { reverseGlyphArray(*outGlyphs, *outGlyphsCount); } } else { @@ -485,14 +488,14 @@ void TextLayoutCacheValue::computeValuesWithHarfbuzz(SkPaint* paint, const UChar lengthRun = endRun - startRun; - int newFlags = (runDir == UBIDI_RTL) ? kDirection_RTL : kDirection_LTR; + bool isRTL = (runDir == UBIDI_RTL); jfloat runTotalAdvance = 0; #if DEBUG_GLYPHS - LOGD("computeValuesWithHarfbuzz -- run-start=%d run-len=%d newFlags=%d", - startRun, lengthRun, newFlags); + LOGD("computeValuesWithHarfbuzz -- run-start=%d run-len=%d isRTL=%d", + startRun, lengthRun, isRTL); #endif computeRunValuesWithHarfbuzz(paint, chars, startRun, - lengthRun, contextCount, newFlags, + lengthRun, contextCount, isRTL, outAdvances, &runTotalAdvance, &runGlyphs, &runGlyphsCount); @@ -506,7 +509,7 @@ void TextLayoutCacheValue::computeValuesWithHarfbuzz(SkPaint* paint, const UChar LOGD(" -- glyphs[%d]=%d", j, runGlyphs[j]); } #endif - glyphRuns.push(GlyphRun(runGlyphs, runGlyphsCount, newFlags)); + glyphRuns.push(GlyphRun(runGlyphs, runGlyphsCount, isRTL)); } *outGlyphs = new jchar[*outGlyphsCount]; @@ -528,13 +531,15 @@ void TextLayoutCacheValue::computeValuesWithHarfbuzz(SkPaint* paint, const UChar ubidi_close(bidi); } else { // Cannot run BiDi, just consider one Run + bool isRTL = (bidiReq = 1) || (bidiReq = UBIDI_DEFAULT_RTL); #if DEBUG_GLYPHS - LOGD("computeValuesWithHarfbuzz -- cannot run BiDi, considering only one Run"); + LOGD("computeValuesWithHarfbuzz -- cannot run BiDi, considering a SINGLE Run " + "-- run-start=%d run-len=%d isRTL=%d", start, count, isRTL); #endif - computeRunValuesWithHarfbuzz(paint, chars, start, count, contextCount, dirFlags, + computeRunValuesWithHarfbuzz(paint, chars, start, count, contextCount, isRTL, outAdvances, outTotalAdvance, outGlyphs, outGlyphsCount); - if (dirFlags == 1 && *outGlyphsCount > 1) { + if (isRTL && *outGlyphsCount > 1) { reverseGlyphArray(*outGlyphs, *outGlyphsCount); } } @@ -545,17 +550,15 @@ void TextLayoutCacheValue::computeValuesWithHarfbuzz(SkPaint* paint, const UChar } void TextLayoutCacheValue::computeRunValuesWithHarfbuzz(SkPaint* paint, const UChar* chars, - size_t start, size_t count, size_t contextCount, int dirFlags, + size_t start, size_t count, size_t contextCount, bool isRTL, jfloat* outAdvances, jfloat* outTotalAdvance, jchar** outGlyphs, size_t* outGlyphsCount) { - bool isRTL = dirFlags & 0x1; - HB_ShaperItem shaperItem; HB_FontRec font; FontData fontData; shapeWithHarfbuzz(&shaperItem, &font, &fontData, paint, chars, start, count, - contextCount, dirFlags); + contextCount, isRTL); #if DEBUG_GLYPHS LOGD("HARFBUZZ -- num_glypth=%d - kerning_applied=%d", shaperItem.num_glyphs, diff --git a/core/jni/android/graphics/TextLayoutCache.h b/core/jni/android/graphics/TextLayoutCache.h index 690caac..10dee87 100644 --- a/core/jni/android/graphics/TextLayoutCache.h +++ b/core/jni/android/graphics/TextLayoutCache.h @@ -128,11 +128,11 @@ public: static void setupShaperItem(HB_ShaperItem* shaperItem, HB_FontRec* font, FontData* fontData, SkPaint* paint, const UChar* chars, size_t start, size_t count, size_t contextCount, - int dirFlags); + bool isRTL); static void shapeWithHarfbuzz(HB_ShaperItem* shaperItem, HB_FontRec* font, FontData* fontData, SkPaint* paint, const UChar* chars, size_t start, size_t count, size_t contextCount, - int dirFlags); + bool isRTL); static void computeValuesWithHarfbuzz(SkPaint* paint, const UChar* chars, size_t start, size_t count, size_t contextCount, int dirFlags, @@ -179,7 +179,7 @@ private: static void resetGlyphArrays(HB_ShaperItem* shaperItem); static void computeRunValuesWithHarfbuzz(SkPaint* paint, const UChar* chars, size_t start, - size_t count, size_t contextCount, int dirFlags, + size_t count, size_t contextCount, bool isRTL, jfloat* outAdvances, jfloat* outTotalAdvance, jchar** outGlyphs, size_t* outGlyphsCount); }; // TextLayoutCacheValue diff --git a/core/jni/android_bluetooth_BluetoothAudioGateway.cpp b/core/jni/android_bluetooth_BluetoothAudioGateway.cpp index cb742a3..29c9c2d 100755 --- a/core/jni/android_bluetooth_BluetoothAudioGateway.cpp +++ b/core/jni/android_bluetooth_BluetoothAudioGateway.cpp @@ -17,6 +17,7 @@ #define LOG_TAG "BluetoothAudioGateway.cpp" #include "android_bluetooth_common.h" +#include "android_bluetooth_c.h" #include "android_runtime/AndroidRuntime.h" #include "JNIHelp.h" #include "jni.h" @@ -491,7 +492,8 @@ static int setup_listening_socket(int dev, int channel) { } laddr.rc_family = AF_BLUETOOTH; - memcpy(&laddr.rc_bdaddr, BDADDR_ANY, sizeof(bdaddr_t)); + bdaddr_t any = android_bluetooth_bdaddr_any(); + memcpy(&laddr.rc_bdaddr, &any, sizeof(bdaddr_t)); laddr.rc_channel = channel; if (bind(sk, (struct sockaddr *)&laddr, sizeof(laddr)) < 0) { diff --git a/core/jni/android_bluetooth_BluetoothSocket.cpp b/core/jni/android_bluetooth_BluetoothSocket.cpp index d09c4e9..4c84324 100644 --- a/core/jni/android_bluetooth_BluetoothSocket.cpp +++ b/core/jni/android_bluetooth_BluetoothSocket.cpp @@ -17,6 +17,7 @@ #define LOG_TAG "BluetoothSocket.cpp" #include "android_bluetooth_common.h" +#include "android_bluetooth_c.h" #include "android_runtime/AndroidRuntime.h" #include "JNIHelp.h" #include "utils/Log.h" @@ -245,7 +246,7 @@ static int bindListenNative(JNIEnv *env, jobject obj) { jint type; socklen_t addr_sz; struct sockaddr *addr; - bdaddr_t bdaddr = *BDADDR_ANY; + bdaddr_t bdaddr = android_bluetooth_bdaddr_any(); struct asocket *s = get_socketData(env, obj); if (!s) diff --git a/core/jni/android_bluetooth_c.c b/core/jni/android_bluetooth_c.c new file mode 100755 index 0000000..b4c6727 --- /dev/null +++ b/core/jni/android_bluetooth_c.c @@ -0,0 +1,31 @@ +/* +** Copyright 2011, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#ifdef HAVE_BLUETOOTH + +#include "android_bluetooth_c.h" + +/* + * A C helper for creating a bdaddr_t object with the value BDADDR_ANY. + * We have to do this in C because the macro BDADDR_ANY in bluetooth.h + * is not valid C++ code. + */ +bdaddr_t android_bluetooth_bdaddr_any(void) +{ + bdaddr_t any = *BDADDR_ANY; + return any; +} +#endif diff --git a/core/jni/android_bluetooth_c.h b/core/jni/android_bluetooth_c.h new file mode 100644 index 0000000..e890244 --- /dev/null +++ b/core/jni/android_bluetooth_c.h @@ -0,0 +1,39 @@ +/* +** 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. +*/ + +#ifndef ANDROID_BLUETOOTH_C_H +#define ANDROID_BLUETOOTH_C_H +#ifdef HAVE_BLUETOOTH + +#include <bluetooth/bluetooth.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * A C helper for creating a bdaddr_t object with the value BDADDR_ANY. + * We have to do this in C because the macro BDADDR_ANY in bluetooth.h + * is not valid C++ code. + */ +bdaddr_t android_bluetooth_bdaddr_any(void); + +#ifdef __cplusplus +} +#endif + +#endif /*HAVE_BLUETOOTH*/ +#endif /*ANDROID_BLUETOOTH_C_H*/ diff --git a/core/res/res/layout/search_bar.xml b/core/res/res/layout/search_bar.xml index 790ac6b..f6b5b53 100644 --- a/core/res/res/layout/search_bar.xml +++ b/core/res/res/layout/search_bar.xml @@ -66,7 +66,6 @@ android:layout_height="wrap_content" android:layout_weight="1" android:maxWidth="600dip" - android:iconifiedByDefault="false" android:layout_gravity="center_vertical" /> diff --git a/core/res/res/layout/search_dropdown_item_icons_2line.xml b/core/res/res/layout/search_dropdown_item_icons_2line.xml index 53906f9..acef2cc 100644 --- a/core/res/res/layout/search_dropdown_item_icons_2line.xml +++ b/core/res/res/layout/search_dropdown_item_icons_2line.xml @@ -19,21 +19,21 @@ --> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:paddingLeft="4dip" - android:paddingRight="2dip" + android:paddingLeft="@dimen/dropdownitem_text_padding_left" + android:paddingRight="4dip" android:layout_width="match_parent" android:layout_height="?android:attr/searchResultListItemHeight" > <!-- Icons come first in the layout, since their placement doesn't depend on the placement of the text views. --> <ImageView android:id="@android:id/icon1" - android:layout_width="48dip" + android:layout_width="@dimen/dropdownitem_icon_width" android:layout_height="48dip" android:scaleType="centerInside" android:layout_alignParentLeft="true" android:layout_alignParentTop="true" android:layout_alignParentBottom="true" - android:visibility="gone" /> + android:visibility="invisible" /> <ImageView android:id="@+id/edit_query" android:layout_width="48dip" diff --git a/core/res/res/layout/search_view.xml b/core/res/res/layout/search_view.xml index fee27eb..6b70d8d 100644 --- a/core/res/res/layout/search_view.xml +++ b/core/res/res/layout/search_view.xml @@ -22,6 +22,8 @@ android:id="@+id/search_bar" android:layout_width="match_parent" android:layout_height="match_parent" + android:paddingLeft="8dip" + android:paddingRight="8dip" android:orientation="horizontal" > @@ -30,7 +32,7 @@ android:id="@+id/search_badge" android:layout_width="wrap_content" android:layout_height="match_parent" - android:layout_gravity="center_vertical" + android:gravity="center_vertical" android:layout_marginBottom="2dip" android:drawablePadding="0dip" android:textAppearance="?android:attr/textAppearanceMedium" @@ -54,12 +56,21 @@ android:layout_height="wrap_content" android:layout_weight="1" android:layout_gravity="center_vertical" - android:layout_marginLeft="8dip" - android:layout_marginRight="8dip" android:layout_marginTop="4dip" android:layout_marginBottom="4dip" android:orientation="horizontal"> + <ImageView + android:id="@+id/search_mag_icon" + android:layout_width="@dimen/dropdownitem_icon_width" + android:layout_height="wrap_content" + android:scaleType="centerInside" + android:layout_marginLeft="@dimen/dropdownitem_text_padding_left" + android:layout_gravity="center_vertical" + android:src="?android:attr/searchViewSearchIcon" + android:visibility="gone" + /> + <!-- Inner layout contains the app icon, button(s) and EditText --> <LinearLayout android:id="@+id/search_plate" @@ -70,14 +81,6 @@ android:orientation="horizontal" android:background="?android:attr/searchViewTextField"> - <ImageView - android:id="@+id/search_app_icon" - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:layout_gravity="center_vertical" - android:src="?android:attr/searchViewSearchIcon" - /> - <view class="android.widget.SearchView$SearchAutoComplete" android:id="@+id/search_src_text" android:layout_height="36dip" @@ -85,8 +88,8 @@ android:layout_weight="1" android:minWidth="@dimen/search_view_text_min_width" android:layout_gravity="bottom" - android:paddingLeft="8dip" - android:paddingRight="6dip" + android:paddingLeft="@dimen/dropdownitem_text_padding_left" + android:paddingRight="@dimen/dropdownitem_text_padding_right" android:singleLine="true" android:ellipsize="end" android:background="@null" @@ -100,7 +103,7 @@ <ImageView android:id="@+id/search_close_btn" - android:layout_width="wrap_content" + android:layout_width="@dimen/dropdownitem_icon_width" android:layout_height="match_parent" android:paddingLeft="8dip" android:paddingRight="8dip" @@ -131,7 +134,7 @@ android:visibility="gone" android:focusable="true" /> - + <ImageView android:id="@+id/search_voice_btn" android:layout_width="wrap_content" diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index 73f636f..2ba4e66 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -141,4 +141,13 @@ <!-- The default gap between components in a layout. --> <dimen name="default_gap">16dip</dimen> + <!-- Text padding for dropdown items --> + <dimen name="dropdownitem_text_padding_left">6dip</dimen> + + <!-- Text padding for dropdown items --> + <dimen name="dropdownitem_text_padding_right">6dip</dimen> + + <!-- Width of the icon in a dropdown list --> + <dimen name="dropdownitem_icon_width">48dip</dimen> + </resources> diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml index 5b5e7c3..d647467 100644 --- a/core/res/res/values/styles.xml +++ b/core/res/res/values/styles.xml @@ -563,8 +563,8 @@ <style name="Widget.DropDownItem"> <item name="android:textAppearance">@style/TextAppearance.Widget.DropDownItem</item> - <item name="android:paddingLeft">6dip</item> - <item name="android:paddingRight">6dip</item> + <item name="android:paddingLeft">@dimen/dropdownitem_text_padding_left</item> + <item name="android:paddingRight">@dimen/dropdownitem_text_padding_right</item> <item name="android:gravity">center_vertical</item> </style> diff --git a/media/libstagefright/codecs/aacenc/src/bit_cnt.c b/media/libstagefright/codecs/aacenc/src/bit_cnt.c index dd0b9b4..8853efc 100644 --- a/media/libstagefright/codecs/aacenc/src/bit_cnt.c +++ b/media/libstagefright/codecs/aacenc/src/bit_cnt.c @@ -496,7 +496,7 @@ Word16 codeValues(Word16 *values, Word16 width, Word16 codeBook, HANDLE_BIT_BUF { Word32 i, t0, t1, t2, t3, t00, t01; - Word16 codeWord, codeLength; + UWord16 codeWord, codeLength; Word16 sign, signLength; diff --git a/tests/BiDiTests/res/layout/canvas2.xml b/tests/BiDiTests/res/layout/canvas2.xml new file mode 100644 index 0000000..b3e038f --- /dev/null +++ b/tests/BiDiTests/res/layout/canvas2.xml @@ -0,0 +1,66 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2011 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/canvas2" + android:layout_width="fill_parent" + android:layout_height="fill_parent"> + + <LinearLayout + xmlns:local="http://schemas.android.com/apk/res/com.android.bidi" + android:orientation="vertical" + android:layout_width="fill_parent" + android:layout_height="fill_parent"> + + <TextView + android:text="@string/ltr" + android:textSize="40dip" + android:gravity="center" + android:layout_width="fill_parent" + android:layout_height="wrap_content" /> + + <com.android.bidi.BiDiTestViewDrawText + local:text="@string/ltr" + android:layout_width="fill_parent" + android:layout_height="64dp" /> + + <TextView + android:text="@string/rtl" + android:textSize="40dip" + android:gravity="center" + android:layout_width="fill_parent" + android:layout_height="wrap_content"/> + + <com.android.bidi.BiDiTestViewDrawText + local:text="@string/rtl" + android:layout_width="fill_parent" + android:layout_height="64dp" /> + + <TextView + android:text="@string/composing" + android:textSize="40dip" + android:gravity="center" + android:layout_width="fill_parent" + android:layout_height="wrap_content"/> + + <com.android.bidi.BiDiTestViewDrawText + local:text="@string/composing" + android:layout_width="fill_parent" + android:layout_height="64dp" /> + + </LinearLayout> + +</FrameLayout>
\ No newline at end of file diff --git a/tests/BiDiTests/res/values/attrs.xml b/tests/BiDiTests/res/values/attrs.xml new file mode 100644 index 0000000..7f8a1d8 --- /dev/null +++ b/tests/BiDiTests/res/values/attrs.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <declare-styleable name="DrawTextTestView"> + <attr name="size" format="dimension" /> + <attr name="color" format="color" /> + <attr name="text" format="string" /> + </declare-styleable> +</resources>
\ No newline at end of file diff --git a/tests/BiDiTests/res/values/strings.xml b/tests/BiDiTests/res/values/strings.xml index bc99e79..1f6be7f 100644 --- a/tests/BiDiTests/res/values/strings.xml +++ b/tests/BiDiTests/res/values/strings.xml @@ -42,5 +42,8 @@ <string name="textview_hebrew_text">םמab?!</string> <string name="textview_latin_text">abםמ?!</string> <string name="textview_multiline_text">םמ?!\nab?!\n?!</string> + <string name="ltr">Left to right text"</string> + <string name="rtl">"والحق أن تترك ونص"</string> + <string name="composing">"\u0644\u0627"</string> </resources> diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java index 7002c41..6b38cc1 100644 --- a/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java +++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java @@ -102,6 +102,7 @@ public class BiDiTestActivity extends Activity { addItem(result, "Basic", BiDiTestBasic.class, R.id.basic); addItem(result, "Canvas", BiDiTestCanvas.class, R.id.canvas); + addItem(result, "Canvas2", BiDiTestCanvas2.class, R.id.canvas2); addItem(result, "Linear LTR", BiDiTestLinearLayoutLtr.class, R.id.linear_layout_ltr); addItem(result, "Linear RTL", BiDiTestLinearLayoutRtl.class, R.id.linear_layout_rtl); diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestCanvas2.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestCanvas2.java new file mode 100644 index 0000000..b801f0e --- /dev/null +++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestCanvas2.java @@ -0,0 +1,36 @@ +/* + * 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.bidi; + +import android.app.Fragment; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.SeekBar; + +import static com.android.bidi.BiDiTestConstants.FONT_MAX_SIZE; +import static com.android.bidi.BiDiTestConstants.FONT_MIN_SIZE; + +public class BiDiTestCanvas2 extends Fragment { + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + return inflater.inflate(R.layout.canvas2, container, false); + } +} diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java index 27e1887..0126dea 100644 --- a/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java +++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java @@ -21,7 +21,7 @@ import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; -import android.graphics.Typeface; +import android.text.TextPaint; import android.util.AttributeSet; import android.util.Log; import android.view.View; @@ -37,7 +37,6 @@ public class BiDiTestView extends View { private static final float DEFAULT_ITALIC_SKEW_X = -0.25f; - private Paint paint = new Paint(); private Rect rect = new Rect(); private String NORMAL_TEXT; @@ -51,8 +50,7 @@ public class BiDiTestView extends View { private String CHINESE_TEXT; private String MIXED_TEXT_1; private String HEBREW_TEXT; - - private Typeface typeface; + private String RTL_TEXT; private int currentTextSize; @@ -83,9 +81,7 @@ public class BiDiTestView extends View { CHINESE_TEXT = context.getString(R.string.chinese_text); MIXED_TEXT_1 = context.getString(R.string.mixed_text_1); HEBREW_TEXT = context.getString(R.string.hebrew_text); - - typeface = paint.getTypeface(); - paint.setAntiAlias(true); + RTL_TEXT = context.getString(R.string.rtl); } public void setCurrentTextSize(int size) { @@ -95,54 +91,56 @@ public class BiDiTestView extends View { @Override public void onDraw(Canvas canvas) { - drawInsideRect(canvas, Color.BLACK); + drawInsideRect(canvas, new Paint(), Color.BLACK); int deltaX = 0; deltaX = testString(canvas, NORMAL_TEXT, ORIGIN, ORIGIN, - paint, typeface, false, false, Paint.DIRECTION_LTR, currentTextSize); + false, false, Paint.DIRECTION_LTR, currentTextSize); deltaX += testString(canvas, ITALIC_TEXT, ORIGIN + deltaX, ORIGIN, - paint, typeface, true, false, Paint.DIRECTION_LTR, currentTextSize); + true, false, Paint.DIRECTION_LTR, currentTextSize); deltaX += testString(canvas, BOLD_TEXT, ORIGIN + deltaX, ORIGIN, - paint, typeface, false, true, Paint.DIRECTION_LTR, currentTextSize); + false, true, Paint.DIRECTION_LTR, currentTextSize); deltaX += testString(canvas, BOLD_ITALIC_TEXT, ORIGIN + deltaX, ORIGIN, - paint, typeface, true, true, Paint.DIRECTION_LTR, currentTextSize); + true, true, Paint.DIRECTION_LTR, currentTextSize); // Test with a long string deltaX = testString(canvas, NORMAL_LONG_TEXT, ORIGIN, ORIGIN + 2 * currentTextSize, - paint, typeface, false, false, Paint.DIRECTION_LTR, currentTextSize); + false, false, Paint.DIRECTION_LTR, currentTextSize); // Test with a long string deltaX = testString(canvas, NORMAL_LONG_TEXT_2, ORIGIN, ORIGIN + 4 * currentTextSize, - paint, typeface, false, false, Paint.DIRECTION_LTR, currentTextSize); + false, false, Paint.DIRECTION_LTR, currentTextSize); // Test with a long string deltaX = testString(canvas, NORMAL_LONG_TEXT_3, ORIGIN, ORIGIN + 6 * currentTextSize, - paint, typeface, false, false, Paint.DIRECTION_LTR, currentTextSize); + false, false, Paint.DIRECTION_LTR, currentTextSize); // Test Arabic ligature deltaX = testString(canvas, ARABIC_TEXT, ORIGIN, ORIGIN + 8 * currentTextSize, - paint, typeface, false, false, Paint.DIRECTION_RTL, currentTextSize); + false, false, Paint.DIRECTION_RTL, currentTextSize); // Test Chinese deltaX = testString(canvas, CHINESE_TEXT, ORIGIN, ORIGIN + 10 * currentTextSize, - paint, typeface, false, false, Paint.DIRECTION_LTR, currentTextSize); + false, false, Paint.DIRECTION_LTR, currentTextSize); // Test Mixed (English and Arabic) deltaX = testString(canvas, MIXED_TEXT_1, ORIGIN, ORIGIN + 12 * currentTextSize, - paint, typeface, false, false, Paint.DIRECTION_LTR, currentTextSize); + false, false, Paint.DIRECTION_LTR, currentTextSize); // Test Hebrew - deltaX = testString(canvas, HEBREW_TEXT, ORIGIN, ORIGIN + 14 * currentTextSize, - paint, typeface, false, false, Paint.DIRECTION_RTL, currentTextSize); + deltaX = testString(canvas, RTL_TEXT, ORIGIN, ORIGIN + 14 * currentTextSize, + false, false, Paint.DIRECTION_RTL, currentTextSize); } - private int testString(Canvas canvas, String text, int x, int y, Paint paint, Typeface typeface, + private int testString(Canvas canvas, String text, int x, int y, boolean isItalic, boolean isBold, int dir, int textSize) { - paint.setTypeface(typeface); + + TextPaint paint = new TextPaint(); + paint.setAntiAlias(true); // Set paint properties boolean oldFakeBold = paint.isFakeBoldText(); @@ -153,9 +151,9 @@ public class BiDiTestView extends View { paint.setTextSkewX(DEFAULT_ITALIC_SKEW_X); } - Log.v(TAG, "START -- drawTextWithCanvasDrawText"); - drawTextWithCanvasDrawText(text, canvas, x, y, textSize, Color.WHITE, dir); - Log.v(TAG, "END -- drawTextWithCanvasDrawText"); + paint.setTextSize(textSize); + paint.setColor(Color.WHITE); + canvas.drawText(text, x, y, paint); int length = text.length(); float[] advances = new float[length]; @@ -167,13 +165,6 @@ public class BiDiTestView extends View { logAdvances(text, textWidthHB, textWidthICU, advances); drawMetricsAroundText(canvas, x, y, textWidthHB, textWidthICU, textSize, Color.RED, Color.GREEN); - paint.setColor(Color.WHITE); - - Log.v(TAG, "START -- drawText"); - setPaintDir(paint, dir); - canvas.drawText(text, x, y + currentTextSize, this.paint); - Log.v(TAG, "END -- drawText"); - // Restore old paint properties paint.setFakeBoldText(oldFakeBold); paint.setTextSkewX(oldTextSkewX); @@ -186,7 +177,7 @@ public class BiDiTestView extends View { paint.setBidiFlags(dir); } - private void drawInsideRect(Canvas canvas, int color) { + private void drawInsideRect(Canvas canvas, Paint paint, int color) { paint.setColor(color); int width = getWidth(); int height = getHeight(); @@ -194,16 +185,9 @@ public class BiDiTestView extends View { canvas.drawRect(rect, paint); } - private void drawTextWithCanvasDrawText(String text, Canvas canvas, - float x, float y, float textSize, int color, int dir) { - setPaintDir(paint, dir); - paint.setColor(color); - paint.setTextSize(textSize); - canvas.drawText(text, x, y, paint); - } - private void drawMetricsAroundText(Canvas canvas, int x, int y, float textWidthHB, float textWidthICU, int textSize, int color, int colorICU) { + Paint paint = new Paint(); paint.setColor(color); canvas.drawLine(x, y - textSize, x, y + 8, paint); canvas.drawLine(x, y + 8, x + textWidthHB, y + 8, paint); diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestViewDrawText.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestViewDrawText.java new file mode 100644 index 0000000..dfdb807 --- /dev/null +++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestViewDrawText.java @@ -0,0 +1,66 @@ +/* + * 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.bidi; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint.Align; +import android.text.TextPaint; +import android.util.AttributeSet; +import android.view.View; + +public class BiDiTestViewDrawText extends View { + private float mSize; + private int mColor; + private String mText; + + public BiDiTestViewDrawText(Context context) { + this(context, null); + } + + public BiDiTestViewDrawText(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public BiDiTestViewDrawText(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + + final TypedArray a = context.obtainStyledAttributes(attrs, + R.styleable.DrawTextTestView, defStyle, 0); + mSize = a.getDimension(R.styleable.DrawTextTestView_size, 40.0f); + mColor = a.getColor(R.styleable.DrawTextTestView_color, Color.YELLOW); + final CharSequence text = a.getText(R.styleable.DrawTextTestView_text); + mText = (text != null) ? text.toString() : "(empty)"; + a.recycle(); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + final int width = getWidth(); + final int height = getHeight(); + + final TextPaint paint = new TextPaint(); + paint.setTextSize(mSize); + paint.setColor(mColor); + paint.setTextAlign(Align.CENTER); + + canvas.drawText(mText, width / 2, height * 2 / 3, paint); + } +}
\ No newline at end of file |