diff options
Diffstat (limited to 'core/java')
| -rw-r--r-- | core/java/android/inputmethodservice/InputMethodService.java | 1 | ||||
| -rw-r--r-- | core/java/android/text/format/DateFormat.java | 40 | ||||
| -rw-r--r-- | core/java/android/text/format/DateUtils.java | 82 | ||||
| -rw-r--r-- | core/java/android/view/Surface.java | 105 | ||||
| -rw-r--r-- | core/java/android/view/SurfaceControl.java | 11 | ||||
| -rw-r--r-- | core/java/android/view/View.java | 8 | ||||
| -rw-r--r-- | core/java/android/widget/AbsListView.java | 4 | ||||
| -rw-r--r-- | core/java/android/widget/DigitalClock.java | 15 | ||||
| -rw-r--r-- | core/java/android/widget/Editor.java | 2 | ||||
| -rw-r--r-- | core/java/android/widget/ListView.java | 50 | ||||
| -rw-r--r-- | core/java/android/widget/TextClock.java | 111 | ||||
| -rw-r--r-- | core/java/android/widget/TextView.java | 111 |
12 files changed, 282 insertions, 258 deletions
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index 5a9cde1..2b15afd 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -427,6 +427,7 @@ public class InputMethodService extends AbstractInputMethodService { } catch (BadTokenException e) { if (DEBUG) Log.v(TAG, "BadTokenException: IME is done."); mWindowVisible = false; + mWindowAdded = false; } } // If user uses hard keyboard, IME button should always be shown. diff --git a/core/java/android/text/format/DateFormat.java b/core/java/android/text/format/DateFormat.java index be4663d..f813df3 100644 --- a/core/java/android/text/format/DateFormat.java +++ b/core/java/android/text/format/DateFormat.java @@ -43,11 +43,17 @@ import libcore.icu.LocaleData; * for both formatting and parsing dates. For the canonical documentation * of format strings, see {@link java.text.SimpleDateFormat}. * - * <p>The format methods in this class implement a subset of Unicode + * <p>The {@code format} methods in this class implement a subset of Unicode * <a href="http://www.unicode.org/reports/tr35/#Date_Format_Patterns">UTS #35</a> patterns. - * The subset supported by this class includes the following format characters: - * {@code acdEHhLKkLMmsyz}. See {@link java.text.SimpleDateFormat} for more documentation - * about patterns, or if you need a more compete implementation. + * The subset currently supported by this class includes the following format characters: + * {@code acdEHhLKkLMmsyz}. Up to API level 17, only {@code adEhkMmszy} were supported. + * Note that this class incorrectly implements {@code k} as if it were {@code H} for backwards + * compatibility. + * + * <p>See {@link java.text.SimpleDateFormat} for more documentation + * about patterns, or if you need a more complete or correct implementation. + * Note that the non-{@code format} methods in this class are implemented by + * {@code SimpleDateFormat}. */ public class DateFormat { /** @deprecated Use a literal {@code '} instead. */ @@ -74,7 +80,11 @@ public class DateFormat { @Deprecated public static final char HOUR = 'h'; - /** @deprecated Use a literal {@code 'k'} instead. */ + /** + * @deprecated Use a literal {@code 'H'} (for compatibility with {@link SimpleDateFormat} + * and Unicode) or {@code 'k'} (for compatibility with Android releases up to and including + * Jelly Bean MR-1) instead. Note that the two are incompatible. + */ @Deprecated public static final char HOUR_OF_DAY = 'k'; @@ -160,9 +170,18 @@ public class DateFormat { * @return the {@link java.text.DateFormat} object that properly formats the time. */ public static java.text.DateFormat getTimeFormat(Context context) { + return new java.text.SimpleDateFormat(getTimeFormatString(context)); + } + + /** + * Returns a String pattern that can be used to format the time according + * to the current locale and the user's 12-/24-hour clock preference. + * @param context the application context + * @hide + */ + public static String getTimeFormatString(Context context) { LocaleData d = LocaleData.get(context.getResources().getConfiguration().locale); - boolean is24 = is24HourFormat(context); - return new java.text.SimpleDateFormat(is24 ? d.timeFormat24 : d.timeFormat12); + return is24HourFormat(context) ? d.timeFormat24 : d.timeFormat12; } /** @@ -451,10 +470,13 @@ public class DateFormat { } break; case 'H': // hour in day (0-23) - case 'k': // hour in day (1-24) + case 'k': // hour in day (1-24) [but see note below] { int hour = inDate.get(Calendar.HOUR_OF_DAY); - if (c == 'k' && hour == 0) { + // Historically on Android 'k' was interpreted as 'H', which wasn't + // implemented, so pretty much all callers that want to format 24-hour + // times are abusing 'k'. http://b/8359981. + if (false && c == 'k' && hour == 0) { hour = 24; } replacement = zeroPad(hour, count); diff --git a/core/java/android/text/format/DateUtils.java b/core/java/android/text/format/DateUtils.java index 6c8a737..7e9d811 100644 --- a/core/java/android/text/format/DateUtils.java +++ b/core/java/android/text/format/DateUtils.java @@ -288,36 +288,6 @@ public class DateUtils } /** - * Return a localized string for the month of the year, for - * contexts where the month is not formatted together with - * a day of the month. - * - * @param month One of {@link Calendar#JANUARY Calendar.JANUARY}, - * {@link Calendar#FEBRUARY Calendar.FEBRUARY}, etc. - * @param abbrev One of {@link #LENGTH_LONG}, {@link #LENGTH_MEDIUM}, - * or {@link #LENGTH_SHORTEST}. - * Undefined lengths will return {@link #LENGTH_MEDIUM} - * but may return something different in the future. - * @return Localized month of the year. - * @hide Pending API council approval - * @deprecated use {@link java.text.SimpleDateFormat} instead. - */ - @Deprecated - public static String getStandaloneMonthString(int month, int abbrev) { - LocaleData d = LocaleData.get(Locale.getDefault()); - String[] names; - switch (abbrev) { - case LENGTH_LONG: names = d.longStandAloneMonthNames; break; - case LENGTH_MEDIUM: names = d.shortMonthNames; break; - case LENGTH_SHORT: names = d.shortMonthNames; break; - case LENGTH_SHORTER: names = d.shortMonthNames; break; - case LENGTH_SHORTEST: names = d.tinyStandAloneMonthNames; break; - default: names = d.shortMonthNames; break; - } - return names[month]; - } - - /** * Returns a string describing the elapsed time since startTime. * @param startTime some time in the past. * @return a String object containing the elapsed time. @@ -551,18 +521,6 @@ public class DateUtils } /** - * Format a time so it appears like it would in the status bar clock. - * @deprecated use {@link #DateFormat.getTimeFormat(Context)} instead. - * @hide - */ - public static final CharSequence timeString(long millis) { - synchronized (sLock) { - initFormatStringsLocked(); - return sStatusTimeFormat.format(millis); - } - } - - /** * Return given duration in a human-friendly format. For example, "4 * minutes" or "1 second". Returns only largest meaningful unit of time, * from seconds up to hours. @@ -676,18 +634,6 @@ public class DateUtils } /** - * @hide - * @deprecated use {@link android.text.format.Time} - */ - public static Calendar newCalendar(boolean zulu) - { - if (zulu) - return Calendar.getInstance(TimeZone.getTimeZone("GMT")); - - return Calendar.getInstance(); - } - - /** * @return true if the supplied when is today else false */ public static boolean isToday(long when) { @@ -705,23 +651,6 @@ public class DateUtils } /** - * @hide - * @deprecated use {@link android.text.format.Time} - * Return true if this date string is local time - */ - public static boolean isUTC(String s) - { - if (s.length() == 16 && s.charAt(15) == 'Z') { - return true; - } - if (s.length() == 9 && s.charAt(8) == 'Z') { - // XXX not sure if this case possible/valid - return true; - } - return false; - } - - /** * Return a string containing the date and time in RFC2445 format. * Ensures that the time is written in UTC. The Calendar class doesn't * really help out with this, so this is slower than it ought to be. @@ -815,17 +744,6 @@ public class DateUtils } /** - * @hide - * @deprecated use {@link android.text.format.Time} - */ - public static void assign(Calendar lval, Calendar rval) - { - // there should be a faster way. - lval.clear(); - lval.setTimeInMillis(rval.getTimeInMillis()); - } - - /** * Formats a date or a time range according to the local conventions. * <p> * Note that this is a convenience method. Using it involves creating an diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java index 0492d29..edfef56 100644 --- a/core/java/android/view/Surface.java +++ b/core/java/android/view/Surface.java @@ -72,6 +72,9 @@ public class Surface implements Parcelable { // mNativeSurface. int mNativeObject; // package scope only for SurfaceControl access + // protects the native state + private final Object mNativeObjectLock = new Object(); + private int mGenerationId; // incremented each time mNativeSurface changes @SuppressWarnings("UnusedDeclaration") private final Canvas mCanvas = new CompatibleCanvas(); @@ -157,12 +160,14 @@ public class Surface implements Parcelable { * This will make the surface invalid. */ public void release() { - if (mNativeObject != 0) { - nativeRelease(mNativeObject); - mNativeObject = 0; - mGenerationId++; + synchronized (mNativeObjectLock) { + if (mNativeObject != 0) { + nativeRelease(mNativeObject); + mNativeObject = 0; + mGenerationId++; + } + mCloseGuard.close(); } - mCloseGuard.close(); } /** @@ -182,8 +187,10 @@ public class Surface implements Parcelable { * Otherwise returns false. */ public boolean isValid() { - if (mNativeObject == 0) return false; - return nativeIsValid(mNativeObject); + synchronized (mNativeObjectLock) { + if (mNativeObject == 0) return false; + return nativeIsValid(mNativeObject); + } } /** @@ -204,8 +211,10 @@ public class Surface implements Parcelable { * @hide */ public boolean isConsumerRunningBehind() { - checkNotReleased(); - return nativeIsConsumerRunningBehind(mNativeObject); + synchronized (mNativeObjectLock) { + checkNotReleasedLocked(); + return nativeIsConsumerRunningBehind(mNativeObject); + } } /** @@ -225,8 +234,10 @@ public class Surface implements Parcelable { */ public Canvas lockCanvas(Rect inOutDirty) throws OutOfResourcesException, IllegalArgumentException { - checkNotReleased(); - return nativeLockCanvas(mNativeObject, inOutDirty); + synchronized (mNativeObjectLock) { + checkNotReleasedLocked(); + return nativeLockCanvas(mNativeObject, inOutDirty); + } } /** @@ -236,8 +247,10 @@ public class Surface implements Parcelable { * @param canvas The canvas previously obtained from {@link #lockCanvas}. */ public void unlockCanvasAndPost(Canvas canvas) { - checkNotReleased(); - nativeUnlockCanvasAndPost(mNativeObject, canvas); + synchronized (mNativeObjectLock) { + checkNotReleasedLocked(); + nativeUnlockCanvasAndPost(mNativeObject, canvas); + } } /** @@ -278,38 +291,40 @@ public class Surface implements Parcelable { throw new NullPointerException( "SurfaceControl native object is null. Are you using a released SurfaceControl?"); } - mNativeObject = nativeCopyFrom(mNativeObject, other.mNativeObject); - if (mNativeObject == 0) { - // nativeCopyFrom released our reference - mCloseGuard.close(); + synchronized (mNativeObjectLock) { + mNativeObject = nativeCopyFrom(mNativeObject, other.mNativeObject); + if (mNativeObject == 0) { + // nativeCopyFrom released our reference + mCloseGuard.close(); + } + mGenerationId++; } - mGenerationId++; } /** - * Transfer the native state from 'other' to this surface, releasing it - * from 'other'. This is for use in the client side for drawing into a - * surface; not guaranteed to work on the window manager side. - * This is for use by the client to move the underlying surface from - * one Surface object to another, in particular in SurfaceFlinger. - * @hide. + * This is intended to be used by {@link SurfaceView.updateWindow} only. + * @param other access is not thread safe + * @hide + * @deprecated */ + @Deprecated public void transferFrom(Surface other) { if (other == null) { throw new IllegalArgumentException("other must not be null"); } if (other != this) { - if (mNativeObject != 0) { - // release our reference to our native object - nativeRelease(mNativeObject); + synchronized (mNativeObjectLock) { + if (mNativeObject != 0) { + // release our reference to our native object + nativeRelease(mNativeObject); + } + // transfer the reference from other to us + if (other.mNativeObject != 0 && mNativeObject == 0) { + mCloseGuard.open("release"); + } + mNativeObject = other.mNativeObject; + mGenerationId++; } - // transfer the reference from other to us - if (other.mNativeObject != 0 && mNativeObject == 0) { - mCloseGuard.open("release"); - } - mNativeObject = other.mNativeObject; - mGenerationId++; - other.mNativeObject = 0; other.mGenerationId++; other.mCloseGuard.close(); @@ -325,13 +340,15 @@ public class Surface implements Parcelable { if (source == null) { throw new IllegalArgumentException("source must not be null"); } - mName = source.readString(); - int nativeObject = nativeReadFromParcel(mNativeObject, source); - if (nativeObject !=0 && mNativeObject == 0) { - mCloseGuard.open("release"); + synchronized (mNativeObjectLock) { + mName = source.readString(); + int nativeObject = nativeReadFromParcel(mNativeObject, source); + if (nativeObject !=0 && mNativeObject == 0) { + mCloseGuard.open("release"); + } + mNativeObject = nativeObject; + mGenerationId++; } - mNativeObject = nativeObject; - mGenerationId++; } @Override @@ -339,8 +356,10 @@ public class Surface implements Parcelable { if (dest == null) { throw new IllegalArgumentException("dest must not be null"); } - dest.writeString(mName); - nativeWriteToParcel(mNativeObject, dest); + synchronized (mNativeObjectLock) { + dest.writeString(mName); + nativeWriteToParcel(mNativeObject, dest); + } if ((flags & Parcelable.PARCELABLE_WRITE_RETURN_VALUE) != 0) { release(); } @@ -433,7 +452,7 @@ public class Surface implements Parcelable { } } - private void checkNotReleased() { + private void checkNotReleasedLocked() { if (mNativeObject == 0) throw new NullPointerException( "mNativeObject is null. Have you called release() already?"); } diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index df07dcd..e869d09 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -574,7 +574,8 @@ public class SurfaceControl { * @param maxLayer The highest (top-most Z order) surface layer to * include in the screenshot. * @return Returns a Bitmap containing the screen contents, or null - * if an error occurs. + * if an error occurs. Make sure to call Bitmap.recycle() as soon as + * possible, once its content is not needed anymore. */ public static Bitmap screenshot(int width, int height, int minLayer, int maxLayer) { // TODO: should take the display as a parameter @@ -586,6 +587,14 @@ public class SurfaceControl { /** * Like {@link SurfaceControl#screenshot(int, int, int, int)} but includes all * Surfaces in the screenshot. + * + * @param width The desired width of the returned bitmap; the raw + * screen will be scaled down to this size. + * @param height The desired height of the returned bitmap; the raw + * screen will be scaled down to this size. + * @return Returns a Bitmap containing the screen contents, or null + * if an error occurs. Make sure to call Bitmap.recycle() as soon as + * possible, once its content is not needed anymore. */ public static Bitmap screenshot(int width, int height) { // TODO: should take the display as a parameter diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 2fa9484..34f5a2b 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -16990,6 +16990,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * * @attr ref android.R.styleable#View_textDirection */ + @ViewDebug.ExportedProperty(category = "text", mapping = { + @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"), + @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"), + @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"), + @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"), + @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"), + @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE") + }) public int getTextDirection() { return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED_MASK) >> PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; } diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index d659110..3fa0940 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -6366,7 +6366,9 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te mTransientStateViewsById = new LongSparseArray<View>(); } mTransientStateViewsById.put(lp.itemId, scrap); - } else { + } else if (!mDataChanged) { + // avoid putting views on transient state list during a data change; + // the layout positions may be out of sync with the adapter positions if (mTransientStateViews == null) { mTransientStateViews = new SparseArray<View>(); } diff --git a/core/java/android/widget/DigitalClock.java b/core/java/android/widget/DigitalClock.java index c6b6dd6..b6c1e5b 100644 --- a/core/java/android/widget/DigitalClock.java +++ b/core/java/android/widget/DigitalClock.java @@ -39,8 +39,6 @@ public class DigitalClock extends TextView { // proportional fonts don't shake rendering Calendar mCalendar; - private final static String m12 = "h:mm:ss aa"; - private final static String m24 = "k:mm:ss"; @SuppressWarnings("FieldCanBeLocal") // We must keep a reference to this observer private FormatChangeObserver mFormatChangeObserver; @@ -102,19 +100,8 @@ public class DigitalClock extends TextView { mTickerStopped = true; } - /** - * Pulls 12/24 mode from system settings - */ - private boolean get24HourMode() { - return android.text.format.DateFormat.is24HourFormat(getContext()); - } - private void setFormat() { - if (get24HourMode()) { - mFormat = m24; - } else { - mFormat = m12; - } + mFormat = DateFormat.getTimeFormatString(getContext()); } private class FormatChangeObserver extends ContentObserver { diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index dc305a5..0aeef63 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -316,7 +316,7 @@ public class Editor { private void setErrorIcon(Drawable icon) { Drawables dr = mTextView.mDrawables; if (dr == null) { - mTextView.mDrawables = dr = new Drawables(); + mTextView.mDrawables = dr = new Drawables(mTextView.getContext()); } dr.setErrorDrawable(icon, mTextView); diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java index 69e3177..7c40a64 100644 --- a/core/java/android/widget/ListView.java +++ b/core/java/android/widget/ListView.java @@ -1550,6 +1550,32 @@ public class ListView extends AbsListView { setSelectedPositionInt(mNextSelectedPosition); + // Remember which child, if any, had accessibility focus. This must + // occur before recycling any views, since that will clear + // accessibility focus. + final ViewRootImpl viewRootImpl = getViewRootImpl(); + if (viewRootImpl != null) { + final View accessFocusedView = viewRootImpl.getAccessibilityFocusedHost(); + if (accessFocusedView != null) { + final View accessFocusedChild = findAccessibilityFocusedChild( + accessFocusedView); + if (accessFocusedChild != null) { + if (!dataChanged || isDirectChildHeaderOrFooter(accessFocusedChild)) { + // If the views won't be changing, try to maintain + // focus on the current view host and (if + // applicable) its virtual view. + accessibilityFocusLayoutRestoreView = accessFocusedView; + accessibilityFocusLayoutRestoreNode = viewRootImpl + .getAccessibilityFocusedVirtualView(); + } else { + // Otherwise, try to maintain focus at the same + // position. + accessibilityFocusPosition = getPositionForView(accessFocusedChild); + } + } + } + } + // Pull all children into the RecycleBin. // These views will be reused if possible final int firstPosition = mFirstPosition; @@ -1590,30 +1616,6 @@ public class ListView extends AbsListView { requestFocus(); } - // Remember which child, if any, had accessibility focus. - final ViewRootImpl viewRootImpl = getViewRootImpl(); - if (viewRootImpl != null) { - final View accessFocusedView = viewRootImpl.getAccessibilityFocusedHost(); - if (accessFocusedView != null) { - final View accessFocusedChild = findAccessibilityFocusedChild( - accessFocusedView); - if (accessFocusedChild != null) { - if (!dataChanged || isDirectChildHeaderOrFooter(accessFocusedChild)) { - // If the views won't be changing, try to maintain - // focus on the current view host and (if - // applicable) its virtual view. - accessibilityFocusLayoutRestoreView = accessFocusedView; - accessibilityFocusLayoutRestoreNode = viewRootImpl - .getAccessibilityFocusedVirtualView(); - } else { - // Otherwise, try to maintain focus at the same - // position. - accessibilityFocusPosition = getPositionForView(accessFocusedChild); - } - } - } - } - // Clear out old views detachAllViewsFromParent(); recycleBin.removeSkippedScrap(); diff --git a/core/java/android/widget/TextClock.java b/core/java/android/widget/TextClock.java index 5bf21c0..a564c96 100644 --- a/core/java/android/widget/TextClock.java +++ b/core/java/android/widget/TextClock.java @@ -36,21 +36,24 @@ import com.android.internal.R; import java.util.Calendar; import java.util.TimeZone; +import libcore.icu.LocaleData; + import static android.view.ViewDebug.ExportedProperty; import static android.widget.RemoteViews.*; /** * <p><code>TextClock</code> can display the current date and/or time as * a formatted string.</p> - * + * * <p>This view honors the 24-hour format system setting. As such, it is * possible and recommended to provide two different formatting patterns: * one to display the date/time in 24-hour mode and one to display the - * date/time in 12-hour mode.</p> - * + * date/time in 12-hour mode. Most callers will want to use the defaults, + * though, which will be appropriate for the user's locale.</p> + * * <p>It is possible to determine whether the system is currently in * 24-hour mode by calling {@link #is24HourModeEnabled()}.</p> - * + * * <p>The rules used by this widget to decide how to format the date and * time are the following:</p> * <ul> @@ -58,22 +61,24 @@ import static android.widget.RemoteViews.*; * <ul> * <li>Use the value returned by {@link #getFormat24Hour()} when non-null</li> * <li>Otherwise, use the value returned by {@link #getFormat12Hour()} when non-null</li> - * <li>Otherwise, use {@link #DEFAULT_FORMAT_24_HOUR}</li> + * <li>Otherwise, use a default value appropriate for the user's locale, such as {@code h:mm a}</li> * </ul> * </li> * <li>In 12-hour mode: * <ul> * <li>Use the value returned by {@link #getFormat12Hour()} when non-null</li> * <li>Otherwise, use the value returned by {@link #getFormat24Hour()} when non-null</li> - * <li>Otherwise, use {@link #DEFAULT_FORMAT_12_HOUR}</li> + * <li>Otherwise, use a default value appropriate for the user's locale, such as {@code HH:mm}</li> * </ul> * </li> * </ul> - * + * * <p>The {@link CharSequence} instances used as formatting patterns when calling either * {@link #setFormat24Hour(CharSequence)} or {@link #setFormat12Hour(CharSequence)} can - * contain styling information. To do so, use a {@link android.text.Spanned} object.</p> - * + * contain styling information. To do so, use a {@link android.text.Spanned} object. + * Note that if you customize these strings, it is your responsibility to supply strings + * appropriate for formatting dates and/or times in the user's locale.</p> + * * @attr ref android.R.styleable#TextClock_format12Hour * @attr ref android.R.styleable#TextClock_format24Hour * @attr ref android.R.styleable#TextClock_timeZone @@ -81,32 +86,34 @@ import static android.widget.RemoteViews.*; @RemoteView public class TextClock extends TextView { /** - * The default formatting pattern in 12-hour mode. This pattenr is used + * The default formatting pattern in 12-hour mode. This pattern is used * if {@link #setFormat12Hour(CharSequence)} is called with a null pattern * or if no pattern was specified when creating an instance of this class. - * + * * This default pattern shows only the time, hours and minutes, and an am/pm * indicator. * * @see #setFormat12Hour(CharSequence) * @see #getFormat12Hour() + * @deprecated Let the system use locale-appropriate defaults instead. */ - public static final CharSequence DEFAULT_FORMAT_12_HOUR = "h:mm aa"; + public static final CharSequence DEFAULT_FORMAT_12_HOUR = "h:mm a"; /** - * The default formatting pattern in 24-hour mode. This pattenr is used + * The default formatting pattern in 24-hour mode. This pattern is used * if {@link #setFormat24Hour(CharSequence)} is called with a null pattern * or if no pattern was specified when creating an instance of this class. * * This default pattern shows only the time, hours and minutes. - * - * @see #setFormat24Hour(CharSequence) - * @see #getFormat24Hour() + * + * @see #setFormat24Hour(CharSequence) + * @see #getFormat24Hour() + * @deprecated Let the system use locale-appropriate defaults instead. */ - public static final CharSequence DEFAULT_FORMAT_24_HOUR = "k:mm"; + public static final CharSequence DEFAULT_FORMAT_24_HOUR = "H:mm"; - private CharSequence mFormat12 = DEFAULT_FORMAT_12_HOUR; - private CharSequence mFormat24 = DEFAULT_FORMAT_24_HOUR; + private CharSequence mFormat12; + private CharSequence mFormat24; @ExportedProperty private CharSequence mFormat; @@ -158,7 +165,7 @@ public class TextClock extends TextView { * Creates a new clock using the default patterns * {@link #DEFAULT_FORMAT_24_HOUR} and {@link #DEFAULT_FORMAT_12_HOUR} * respectively for the 24-hour and 12-hour modes. - * + * * @param context The Context the view is running in, through which it can * access the current theme, resources, etc. */ @@ -171,7 +178,7 @@ public class TextClock extends TextView { /** * Creates a new clock inflated from XML. This object's properties are * intialized from the attributes specified in XML. - * + * * This constructor uses a default style of 0, so the only attribute values * applied are those in the Context's Theme and the given AttributeSet. * @@ -201,14 +208,8 @@ public class TextClock extends TextView { TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TextClock, defStyle, 0); try { - CharSequence format; - - format = a.getText(R.styleable.TextClock_format12Hour); - mFormat12 = format == null ? DEFAULT_FORMAT_12_HOUR : format; - - format = a.getText(R.styleable.TextClock_format24Hour); - mFormat24 = format == null ? DEFAULT_FORMAT_24_HOUR : format; - + mFormat12 = a.getText(R.styleable.TextClock_format12Hour); + mFormat24 = a.getText(R.styleable.TextClock_format24Hour); mTimeZone = a.getString(R.styleable.TextClock_timeZone); } finally { a.recycle(); @@ -218,6 +219,16 @@ public class TextClock extends TextView { } private void init() { + if (mFormat12 == null || mFormat24 == null) { + LocaleData ld = LocaleData.get(getContext().getResources().getConfiguration().locale); + if (mFormat12 == null) { + mFormat12 = ld.timeFormat12; + } + if (mFormat24 == null) { + mFormat24 = ld.timeFormat24; + } + } + createTime(mTimeZone); // Wait until onAttachedToWindow() to handle the ticker chooseFormat(false); @@ -235,11 +246,11 @@ public class TextClock extends TextView { * Returns the formatting pattern used to display the date and/or time * in 12-hour mode. The formatting pattern syntax is described in * {@link DateFormat}. - * + * * @return A {@link CharSequence} or null. - * - * @see #setFormat12Hour(CharSequence) - * @see #is24HourModeEnabled() + * + * @see #setFormat12Hour(CharSequence) + * @see #is24HourModeEnabled() */ @ExportedProperty public CharSequence getFormat12Hour() { @@ -257,12 +268,12 @@ public class TextClock extends TextView { * {@link #DEFAULT_FORMAT_12_HOUR} will be used instead. * * @param format A date/time formatting pattern as described in {@link DateFormat} - * + * * @see #getFormat12Hour() * @see #is24HourModeEnabled() * @see #DEFAULT_FORMAT_12_HOUR * @see DateFormat - * + * * @attr ref android.R.styleable#TextClock_format12Hour */ @RemotableViewMethod @@ -292,7 +303,7 @@ public class TextClock extends TextView { * Specifies the formatting pattern used to display the date and/or time * in 24-hour mode. The formatting pattern syntax is described in * {@link DateFormat}. - * + * * If this pattern is set to null, {@link #getFormat12Hour()} will be used * even in 24-hour mode. If both 24-hour and 12-hour formatting patterns * are set to null, {@link #DEFAULT_FORMAT_24_HOUR} and @@ -301,7 +312,7 @@ public class TextClock extends TextView { * @param format A date/time formatting pattern as described in {@link DateFormat} * * @see #getFormat24Hour() - * @see #is24HourModeEnabled() + * @see #is24HourModeEnabled() * @see #DEFAULT_FORMAT_24_HOUR * @see DateFormat * @@ -317,22 +328,22 @@ public class TextClock extends TextView { /** * Indicates whether the system is currently using the 24-hour mode. - * + * * When the system is in 24-hour mode, this view will use the pattern * returned by {@link #getFormat24Hour()}. In 12-hour mode, the pattern * returned by {@link #getFormat12Hour()} is used instead. - * + * * If either one of the formats is null, the other format is used. If * both formats are null, the default values {@link #DEFAULT_FORMAT_12_HOUR} * and {@link #DEFAULT_FORMAT_24_HOUR} are used instead. - * + * * @return true if time should be displayed in 24-hour format, false if it * should be displayed in 12-hour format. - * + * * @see #setFormat12Hour(CharSequence) - * @see #getFormat12Hour() + * @see #getFormat12Hour() * @see #setFormat24Hour(CharSequence) - * @see #getFormat24Hour() + * @see #getFormat24Hour() */ public boolean is24HourModeEnabled() { return DateFormat.is24HourFormat(getContext()); @@ -340,13 +351,13 @@ public class TextClock extends TextView { /** * Indicates which time zone is currently used by this view. - * + * * @return The ID of the current time zone or null if the default time zone, * as set by the user, must be used * * @see TimeZone * @see java.util.TimeZone#getAvailableIDs() - * @see #setTimeZone(String) + * @see #setTimeZone(String) */ public String getTimeZone() { return mTimeZone; @@ -378,7 +389,7 @@ public class TextClock extends TextView { /** * Selects either one of {@link #getFormat12Hour()} or {@link #getFormat24Hour()} * depending on whether the user has selected 24-hour format. - * + * * Calling this method does not schedule or unschedule the time ticker. */ private void chooseFormat() { @@ -398,17 +409,19 @@ public class TextClock extends TextView { /** * Selects either one of {@link #getFormat12Hour()} or {@link #getFormat24Hour()} * depending on whether the user has selected 24-hour format. - * + * * @param handleTicker true if calling this method should schedule/unschedule the * time ticker, false otherwise */ private void chooseFormat(boolean handleTicker) { final boolean format24Requested = is24HourModeEnabled(); + LocaleData ld = LocaleData.get(getContext().getResources().getConfiguration().locale); + if (format24Requested) { - mFormat = abc(mFormat24, mFormat12, DEFAULT_FORMAT_24_HOUR); + mFormat = abc(mFormat24, mFormat12, ld.timeFormat24); } else { - mFormat = abc(mFormat12, mFormat24, DEFAULT_FORMAT_12_HOUR); + mFormat = abc(mFormat12, mFormat24, ld.timeFormat12); } boolean hadSeconds = mHasSeconds; diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index b084ac4..1ab9943 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -136,6 +136,8 @@ import java.util.ArrayList; import java.util.Locale; import java.util.concurrent.locks.ReentrantLock; +import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1; + /** * Displays text to the user and optionally allows them to edit it. A TextView * is a complete text editor, however the basic class is configured to not @@ -294,6 +296,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener Drawable mDrawableTop, mDrawableBottom, mDrawableLeft, mDrawableRight, mDrawableStart, mDrawableEnd, mDrawableError, mDrawableTemp; + Drawable mDrawableLeftInitial, mDrawableRightInitial; + boolean mIsRtlCompatibilityMode; + boolean mOverride; + int mDrawableSizeTop, mDrawableSizeBottom, mDrawableSizeLeft, mDrawableSizeRight, mDrawableSizeStart, mDrawableSizeEnd, mDrawableSizeError, mDrawableSizeTemp; @@ -304,38 +310,64 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener int mDrawableSaved = DRAWABLE_NONE; - public void resolveWithLayoutDirection(int layoutDirection) { - switch(layoutDirection) { - case LAYOUT_DIRECTION_RTL: - if (mDrawableStart != null) { - mDrawableRight = mDrawableStart; - - mDrawableSizeRight = mDrawableSizeStart; - mDrawableHeightRight = mDrawableHeightStart; - } - if (mDrawableEnd != null) { - mDrawableLeft = mDrawableEnd; + public Drawables(Context context) { + final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion; + mIsRtlCompatibilityMode = (targetSdkVersion < JELLY_BEAN_MR1 || + !context.getApplicationInfo().hasRtlSupport()); + mOverride = false; + } - mDrawableSizeLeft = mDrawableSizeEnd; - mDrawableHeightLeft = mDrawableHeightEnd; - } - break; + public void resolveWithLayoutDirection(int layoutDirection) { + // First reset "left" and "right" drawables to their initial values + mDrawableLeft = mDrawableLeftInitial; + mDrawableRight = mDrawableRightInitial; + + if (mIsRtlCompatibilityMode) { + // Use "start" drawable as "left" drawable if the "left" drawable was not defined + if (mDrawableStart != null && mDrawableLeft == null) { + mDrawableLeft = mDrawableStart; + mDrawableSizeLeft = mDrawableSizeStart; + mDrawableHeightLeft = mDrawableHeightStart; + } + // Use "end" drawable as "right" drawable if the "right" drawable was not defined + if (mDrawableEnd != null && mDrawableRight == null) { + mDrawableRight = mDrawableEnd; + mDrawableSizeRight = mDrawableSizeEnd; + mDrawableHeightRight = mDrawableHeightEnd; + } + } else { + // JB-MR1+ normal case: "start" / "end" drawables are overriding "left" / "right" + // drawable if and only if they have been defined + switch(layoutDirection) { + case LAYOUT_DIRECTION_RTL: + if (mOverride) { + mDrawableRight = mDrawableStart; + mDrawableSizeRight = mDrawableSizeStart; + mDrawableHeightRight = mDrawableHeightStart; + } - case LAYOUT_DIRECTION_LTR: - default: - if (mDrawableStart != null) { - mDrawableLeft = mDrawableStart; + if (mOverride) { + mDrawableLeft = mDrawableEnd; + mDrawableSizeLeft = mDrawableSizeEnd; + mDrawableHeightLeft = mDrawableHeightEnd; + } + break; - mDrawableSizeLeft = mDrawableSizeStart; - mDrawableHeightLeft = mDrawableHeightStart; - } - if (mDrawableEnd != null) { - mDrawableRight = mDrawableEnd; + case LAYOUT_DIRECTION_LTR: + default: + if (mOverride) { + mDrawableLeft = mDrawableStart; + mDrawableSizeLeft = mDrawableSizeStart; + mDrawableHeightLeft = mDrawableHeightStart; + } - mDrawableSizeRight = mDrawableSizeEnd; - mDrawableHeightRight = mDrawableHeightEnd; - } - break; + if (mOverride) { + mDrawableRight = mDrawableEnd; + mDrawableSizeRight = mDrawableSizeEnd; + mDrawableHeightRight = mDrawableHeightEnd; + } + break; + } } applyErrorDrawableIfNeeded(layoutDirection); updateDrawablesLayoutDirection(layoutDirection); @@ -1154,6 +1186,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener bufferType = BufferType.SPANNABLE; } + // This call will save the initial left/right drawables setCompoundDrawablesWithIntrinsicBounds( drawableLeft, drawableTop, drawableRight, drawableBottom); setRelativeDrawablesIfNeeded(drawableStart, drawableEnd); @@ -1302,8 +1335,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (hasRelativeDrawables) { Drawables dr = mDrawables; if (dr == null) { - mDrawables = dr = new Drawables(); + mDrawables = dr = new Drawables(getContext()); } + mDrawables.mOverride = true; final Rect compoundRect = dr.mCompoundRect; int[] state = getDrawableState(); if (start != null) { @@ -1876,9 +1910,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } else { if (dr == null) { - mDrawables = dr = new Drawables(); + mDrawables = dr = new Drawables(getContext()); } + mDrawables.mOverride = false; + if (dr.mDrawableLeft != left && dr.mDrawableLeft != null) { dr.mDrawableLeft.setCallback(null); } @@ -1945,6 +1981,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } + // Save initial left/right drawables + if (dr != null) { + dr.mDrawableLeftInitial = left; + dr.mDrawableRightInitial = right; + } + invalidate(); requestLayout(); } @@ -2045,9 +2087,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } else { if (dr == null) { - mDrawables = dr = new Drawables(); + mDrawables = dr = new Drawables(getContext()); } + mDrawables.mOverride = true; + if (dr.mDrawableStart != start && dr.mDrawableStart != null) { dr.mDrawableStart.setCallback(null); } @@ -2114,6 +2158,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } + resetResolvedDrawables(); resolveDrawables(); invalidate(); requestLayout(); @@ -2138,7 +2183,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener @android.view.RemotableViewMethod public void setCompoundDrawablesRelativeWithIntrinsicBounds(int start, int top, int end, int bottom) { - resetResolvedDrawables(); final Resources resources = getContext().getResources(); setCompoundDrawablesRelativeWithIntrinsicBounds( start != 0 ? resources.getDrawable(start) : null, @@ -2161,7 +2205,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener public void setCompoundDrawablesRelativeWithIntrinsicBounds(Drawable start, Drawable top, Drawable end, Drawable bottom) { - resetResolvedDrawables(); if (start != null) { start.setBounds(0, 0, start.getIntrinsicWidth(), start.getIntrinsicHeight()); } @@ -2230,7 +2273,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } else { if (dr == null) { - mDrawables = dr = new Drawables(); + mDrawables = dr = new Drawables(getContext()); } dr.mDrawablePadding = pad; } |
