summaryrefslogtreecommitdiffstats
path: root/core/java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/inputmethodservice/InputMethodService.java1
-rw-r--r--core/java/android/text/format/DateFormat.java40
-rw-r--r--core/java/android/text/format/DateUtils.java82
-rw-r--r--core/java/android/view/Surface.java105
-rw-r--r--core/java/android/view/SurfaceControl.java11
-rw-r--r--core/java/android/view/View.java8
-rw-r--r--core/java/android/widget/AbsListView.java4
-rw-r--r--core/java/android/widget/DigitalClock.java15
-rw-r--r--core/java/android/widget/Editor.java2
-rw-r--r--core/java/android/widget/ListView.java50
-rw-r--r--core/java/android/widget/TextClock.java111
-rw-r--r--core/java/android/widget/TextView.java111
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;
}