summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.txt4
-rw-r--r--cmds/svc/src/com/android/commands/svc/PowerCommand.java30
-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/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/TextClock.java111
-rw-r--r--core/java/android/widget/TextView.java111
-rw-r--r--core/res/res/values/attrs.xml4
-rw-r--r--core/tests/coretests/src/android/webkit/WebkitTest.java2
-rw-r--r--docs/html/design/building-blocks/buttons.jd1
-rw-r--r--docs/html/design/building-blocks/dialogs.jd1
-rw-r--r--docs/html/design/building-blocks/grid-lists.jd1
-rw-r--r--docs/html/design/building-blocks/lists.jd1
-rw-r--r--docs/html/design/building-blocks/pickers.jd1
-rw-r--r--docs/html/design/building-blocks/progress.jd1
-rw-r--r--docs/html/design/building-blocks/scrolling.jd1
-rw-r--r--docs/html/design/building-blocks/seek-bars.jd1
-rw-r--r--docs/html/design/building-blocks/spinners.jd1
-rw-r--r--docs/html/design/building-blocks/switches.jd1
-rw-r--r--docs/html/design/building-blocks/tabs.jd1
-rw-r--r--docs/html/design/building-blocks/text-fields.jd1
-rw-r--r--docs/html/design/patterns/accessibility.jd1
-rw-r--r--docs/html/design/patterns/actionbar.jd1
-rw-r--r--docs/html/design/patterns/app-structure.jd1
-rw-r--r--docs/html/design/patterns/confirming-acknowledging.jd1
-rw-r--r--docs/html/design/patterns/gestures.jd1
-rw-r--r--docs/html/design/patterns/multi-pane-layouts.jd1
-rw-r--r--docs/html/design/patterns/navigation.jd1
-rw-r--r--docs/html/design/patterns/notifications.jd1
-rw-r--r--docs/html/design/patterns/selection.jd1
-rw-r--r--docs/html/design/patterns/settings.jd1
-rw-r--r--docs/html/design/patterns/swipe-views.jd1
-rw-r--r--docs/html/design/patterns/widgets.jd1
-rw-r--r--docs/html/guide/components/activities.jd1
-rw-r--r--docs/html/guide/topics/graphics/hardware-accel.jd7
-rw-r--r--docs/html/guide/topics/manifest/data-element.jd3
-rw-r--r--docs/html/guide/topics/ui/actionbar.jd1
-rw-r--r--docs/html/training/animation/index.jd1
-rw-r--r--docs/html/training/basics/data-storage/databases.jd2
-rw-r--r--docs/html/training/basics/data-storage/files.jd2
-rw-r--r--docs/html/training/basics/data-storage/index.jd1
-rw-r--r--docs/html/training/basics/data-storage/shared-preferences.jd2
-rw-r--r--docs/html/training/basics/fragments/communicating.jd4
-rw-r--r--docs/html/training/basics/fragments/creating.jd6
-rw-r--r--docs/html/training/basics/fragments/fragment-ui.jd6
-rw-r--r--docs/html/training/basics/fragments/index.jd3
-rw-r--r--docs/html/training/basics/fragments/support-lib.jd5
-rw-r--r--docs/html/training/basics/intents/index.jd3
-rw-r--r--docs/html/training/basics/network-ops/index.jd1
-rw-r--r--docs/html/training/basics/supporting-devices/index.jd3
-rw-r--r--docs/html/training/camera/index.jd1
-rw-r--r--docs/html/training/cloudsync/index.jd3
-rw-r--r--docs/html/training/connect-devices-wirelessly/index.jd3
-rw-r--r--docs/html/training/displaying-bitmaps/index.jd3
-rw-r--r--docs/html/training/efficient-downloads/index.jd3
-rw-r--r--docs/html/training/graphics/opengl/index.jd3
-rw-r--r--docs/html/training/managing-audio/index.jd3
-rw-r--r--docs/html/training/sharing/index.jd3
-rw-r--r--libs/hwui/Android.mk1
-rw-r--r--libs/hwui/Caches.cpp20
-rw-r--r--libs/hwui/Caches.h6
-rw-r--r--libs/hwui/Debug.h2
-rw-r--r--libs/hwui/DeferredDisplayList.cpp2
-rw-r--r--libs/hwui/DisplayList.cpp6
-rw-r--r--libs/hwui/DisplayListRenderer.cpp1
-rw-r--r--libs/hwui/FontRenderer.cpp29
-rw-r--r--libs/hwui/FontRenderer.h30
-rw-r--r--libs/hwui/OpenGLRenderer.cpp20
-rw-r--r--libs/hwui/PathCache.cpp443
-rw-r--r--libs/hwui/PathCache.h249
-rw-r--r--libs/hwui/Properties.h6
-rw-r--r--libs/hwui/ShapeCache.cpp168
-rw-r--r--libs/hwui/ShapeCache.h816
-rw-r--r--libs/hwui/SkiaShader.cpp10
-rw-r--r--libs/hwui/font/FontUtil.h2
-rw-r--r--services/java/com/android/server/BackupManagerService.java2
-rw-r--r--services/java/com/android/server/pm/PackageManagerService.java12
-rw-r--r--services/java/com/android/server/wm/WindowManagerService.java6
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/MoreShadersActivity.java13
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/ShapesActivity.java31
84 files changed, 1037 insertions, 1359 deletions
diff --git a/api/current.txt b/api/current.txt
index f2fcbd6b7b67..e89dc2207873 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -29863,8 +29863,8 @@ package android.widget {
method public void setFormat12Hour(java.lang.CharSequence);
method public void setFormat24Hour(java.lang.CharSequence);
method public void setTimeZone(java.lang.String);
- field public static final java.lang.CharSequence DEFAULT_FORMAT_12_HOUR;
- field public static final java.lang.CharSequence DEFAULT_FORMAT_24_HOUR;
+ field public static final deprecated java.lang.CharSequence DEFAULT_FORMAT_12_HOUR;
+ field public static final deprecated java.lang.CharSequence DEFAULT_FORMAT_24_HOUR;
}
public class TextSwitcher extends android.widget.ViewSwitcher {
diff --git a/cmds/svc/src/com/android/commands/svc/PowerCommand.java b/cmds/svc/src/com/android/commands/svc/PowerCommand.java
index 58105fae96cc..da8586c14256 100644
--- a/cmds/svc/src/com/android/commands/svc/PowerCommand.java
+++ b/cmds/svc/src/com/android/commands/svc/PowerCommand.java
@@ -36,12 +36,18 @@ public class PowerCommand extends Svc.Command {
return shortHelp() + "\n"
+ "\n"
+ "usage: svc power stayon [true|false|usb|ac|wireless]\n"
- + " Set the 'keep awake while plugged in' setting.\n";
+ + " Set the 'keep awake while plugged in' setting.\n"
+ + " svc power reboot [reason]\n"
+ + " Perform a runtime shutdown and reboot device with specified reason.\n"
+ + " svc power shutdown\n"
+ + " Perform a runtime shutdown and power off the device.\n";
}
public void run(String[] args) {
fail: {
if (args.length >= 2) {
+ IPowerManager pm = IPowerManager.Stub.asInterface(
+ ServiceManager.getService(Context.POWER_SERVICE));
if ("stayon".equals(args[1]) && args.length == 3) {
int val;
if ("true".equals(args[2])) {
@@ -60,8 +66,6 @@ public class PowerCommand extends Svc.Command {
} else {
break fail;
}
- IPowerManager pm
- = IPowerManager.Stub.asInterface(ServiceManager.getService(Context.POWER_SERVICE));
try {
if (val != 0) {
// if the request is not to set it to false, wake up the screen so that
@@ -74,6 +78,26 @@ public class PowerCommand extends Svc.Command {
System.err.println("Faild to set setting: " + e);
}
return;
+ } else if ("reboot".equals(args[1])) {
+ String mode = null;
+ if (args.length == 3) {
+ mode = args[2];
+ }
+ try {
+ // no confirm, wait till device is rebooted
+ pm.reboot(false, mode, true);
+ } catch (RemoteException e) {
+ System.err.println("Failed to reboot.");
+ }
+ return;
+ } else if ("shutdown".equals(args[1])) {
+ try {
+ // no confirm, wait till device is off
+ pm.shutdown(false, true);
+ } catch (RemoteException e) {
+ System.err.println("Failed to shutdown.");
+ }
+ return;
}
}
}
diff --git a/core/java/android/text/format/DateFormat.java b/core/java/android/text/format/DateFormat.java
index be4663d87385..f813df3d6739 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 6c8a7379eb63..7e9d81191837 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/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index df07dcd1e016..e869d09adaa7 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 2fa9484b6f4a..34f5a2bed932 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 d659110b1266..3fa09408f58e 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 c6b6dd68f182..b6c1e5b9532f 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 dc305a55c644..0aeef63020c7 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/TextClock.java b/core/java/android/widget/TextClock.java
index 5bf21c0d82f7..a564c96ee220 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 b084ac437f77..1ab9943f26e1 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;
}
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 4a1d12d4d748..badd3d7d6cdd 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3081,12 +3081,12 @@
<!-- Specifies the formatting pattern used to show the time and/or date
in 12-hour mode. Please refer to {@link android.text.format.DateFormat}
for a complete description of accepted formatting patterns.
- The default pattern is "h:mm aa". -->
+ The default pattern is a locale-appropriate equivalent of "h:mm a". -->
<attr name="format12Hour" format="string"/>
<!-- Specifies the formatting pattern used to show the time and/or date
in 24-hour mode. Please refer to {@link android.text.format.DateFormat}
for a complete description of accepted formatting patterns.
- The default pattern is "k:mm". -->
+ The default pattern is a locale-appropriate equivalent of "H:mm". -->
<attr name="format24Hour" format="string"/>
<!-- Specifies the time zone to use. When this attribute is specified, the
TextClock will ignore the time zone of the system. To use the user's
diff --git a/core/tests/coretests/src/android/webkit/WebkitTest.java b/core/tests/coretests/src/android/webkit/WebkitTest.java
index 17b4088f0996..4685e3cf08d7 100644
--- a/core/tests/coretests/src/android/webkit/WebkitTest.java
+++ b/core/tests/coretests/src/android/webkit/WebkitTest.java
@@ -52,7 +52,7 @@ public class WebkitTest extends AndroidTestCase {
date.setTime(time);
c.setTime(date);
index = dateSorter.getIndex(time);
- Log.i(LOGTAG, "time: " + DateFormat.format("yyyy/MM/dd kk:mm:ss", c).toString() +
+ Log.i(LOGTAG, "time: " + DateFormat.format("yyyy/MM/dd HH:mm:ss", c).toString() +
" " + index + " " + dateSorter.getLabel(index));
}
}
diff --git a/docs/html/design/building-blocks/buttons.jd b/docs/html/design/building-blocks/buttons.jd
index 82e2477c86be..9e82ed4c243a 100644
--- a/docs/html/design/building-blocks/buttons.jd
+++ b/docs/html/design/building-blocks/buttons.jd
@@ -1,4 +1,5 @@
page.title=Buttons
+page.tags="button"
@jd:body
<p>A button consists of text and/or an image that clearly communicates what action will occur when the
diff --git a/docs/html/design/building-blocks/dialogs.jd b/docs/html/design/building-blocks/dialogs.jd
index a2ece2ea5cce..2f6ca2709182 100644
--- a/docs/html/design/building-blocks/dialogs.jd
+++ b/docs/html/design/building-blocks/dialogs.jd
@@ -1,4 +1,5 @@
page.title=Dialogs
+page.tags="dialog","alert","popup","toast"
@jd:body
<p>Dialogs prompt the user for decisions or additional information required by the app to continue a
diff --git a/docs/html/design/building-blocks/grid-lists.jd b/docs/html/design/building-blocks/grid-lists.jd
index 775ebcc8752c..69a43b17ab9a 100644
--- a/docs/html/design/building-blocks/grid-lists.jd
+++ b/docs/html/design/building-blocks/grid-lists.jd
@@ -1,4 +1,5 @@
page.title=Grid Lists
+page.tags="gridview","layout"
@jd:body
<img src="{@docRoot}design/media/gridview_overview.png">
diff --git a/docs/html/design/building-blocks/lists.jd b/docs/html/design/building-blocks/lists.jd
index aaa86b85ec10..16927a61ceb0 100644
--- a/docs/html/design/building-blocks/lists.jd
+++ b/docs/html/design/building-blocks/lists.jd
@@ -1,4 +1,5 @@
page.title=Lists
+page.tags="listview","layout"
@jd:body
<p>Lists present multiple line items in a vertical arrangement. They can be used for data selection as
diff --git a/docs/html/design/building-blocks/pickers.jd b/docs/html/design/building-blocks/pickers.jd
index b328df90548b..47363d075e62 100644
--- a/docs/html/design/building-blocks/pickers.jd
+++ b/docs/html/design/building-blocks/pickers.jd
@@ -1,4 +1,5 @@
page.title=Pickers
+page.tags="datepicker","timepicker"
@jd:body
<p>Pickers provide a simple way to select a single value from a set. In addition to touching the
diff --git a/docs/html/design/building-blocks/progress.jd b/docs/html/design/building-blocks/progress.jd
index 7342387a28f4..96cc1afca555 100644
--- a/docs/html/design/building-blocks/progress.jd
+++ b/docs/html/design/building-blocks/progress.jd
@@ -1,4 +1,5 @@
page.title=Progress &amp; Activity
+page.tags="progressbar"
@jd:body
<p>Progress bars and activity indicators signal to users that something is happening that will take a moment.</p>
diff --git a/docs/html/design/building-blocks/scrolling.jd b/docs/html/design/building-blocks/scrolling.jd
index 7695157a15cf..66999f9fc7cc 100644
--- a/docs/html/design/building-blocks/scrolling.jd
+++ b/docs/html/design/building-blocks/scrolling.jd
@@ -1,4 +1,5 @@
page.title=Scrolling
+page.tags="scrollview","listview"
@jd:body
<p>Scrolling allows the user to navigate to content in the overflow using a swipe gesture. The
diff --git a/docs/html/design/building-blocks/seek-bars.jd b/docs/html/design/building-blocks/seek-bars.jd
index 3407ddd07050..9d38e36e2d90 100644
--- a/docs/html/design/building-blocks/seek-bars.jd
+++ b/docs/html/design/building-blocks/seek-bars.jd
@@ -1,4 +1,5 @@
page.title=Seek Bars and Sliders
+page.tags="seekbar","progressbar"
@jd:body
<p>Interactive sliders make it possible to select a value from a continuous or discrete range of values
diff --git a/docs/html/design/building-blocks/spinners.jd b/docs/html/design/building-blocks/spinners.jd
index 279565f88fa4..8c80b9178de6 100644
--- a/docs/html/design/building-blocks/spinners.jd
+++ b/docs/html/design/building-blocks/spinners.jd
@@ -1,4 +1,5 @@
page.title=Spinners
+page.tags="spinner","drop down"
@jd:body
<p>Spinners provide a quick way to select one value from a set. In the default state, a spinner shows
diff --git a/docs/html/design/building-blocks/switches.jd b/docs/html/design/building-blocks/switches.jd
index d9cfd07fd379..6386bdf5e64b 100644
--- a/docs/html/design/building-blocks/switches.jd
+++ b/docs/html/design/building-blocks/switches.jd
@@ -1,4 +1,5 @@
page.title=Switches
+page.tags="switch","checkbox","radiobutton"
@jd:body
<p>Switches allow the user to select options. There are three kinds of switches: checkboxes, radio
diff --git a/docs/html/design/building-blocks/tabs.jd b/docs/html/design/building-blocks/tabs.jd
index 0a0f9077981b..1fe2c6203fdf 100644
--- a/docs/html/design/building-blocks/tabs.jd
+++ b/docs/html/design/building-blocks/tabs.jd
@@ -1,4 +1,5 @@
page.title=Tabs
+page.tags="tabs","action bar","navigation"
@jd:body
<img src="{@docRoot}design/media/tabs_overview.png">
diff --git a/docs/html/design/building-blocks/text-fields.jd b/docs/html/design/building-blocks/text-fields.jd
index 563f2475ae4e..c1bed783bc5d 100644
--- a/docs/html/design/building-blocks/text-fields.jd
+++ b/docs/html/design/building-blocks/text-fields.jd
@@ -1,4 +1,5 @@
page.title=Text Fields
+page.tags="text","edittext","input",
@jd:body
<p>Text fields allow the user to type text into your app. They can be either single line or multi-line.
diff --git a/docs/html/design/patterns/accessibility.jd b/docs/html/design/patterns/accessibility.jd
index 2c3333f4d6ac..edf38432a8aa 100644
--- a/docs/html/design/patterns/accessibility.jd
+++ b/docs/html/design/patterns/accessibility.jd
@@ -1,4 +1,5 @@
page.title=Accessibility
+page.tags="accessibility","navigation"
@jd:body
<p>One of Android's missions is to organize the world's information and make it universally accessible and useful. Accessibility is the measure of how successfully a product can be used by people with varying abilities. Our mission applies to all users-including people with disabilities such as visual impairment, color deficiency, hearing loss, and limited dexterity.</p>
diff --git a/docs/html/design/patterns/actionbar.jd b/docs/html/design/patterns/actionbar.jd
index 265ccde1bc6d..da9c3c3e3fc0 100644
--- a/docs/html/design/patterns/actionbar.jd
+++ b/docs/html/design/patterns/actionbar.jd
@@ -1,4 +1,5 @@
page.title=Action Bar
+page.tags="actionbar","navigation"
@jd:body
<img src="{@docRoot}design/media/action_bar_pattern_overview.png">
diff --git a/docs/html/design/patterns/app-structure.jd b/docs/html/design/patterns/app-structure.jd
index 04af57bea2dd..e1bb81992e0a 100644
--- a/docs/html/design/patterns/app-structure.jd
+++ b/docs/html/design/patterns/app-structure.jd
@@ -1,4 +1,5 @@
page.title=Application Structure
+page.tags="navigation","layout"
@jd:body
<p>Apps come in many varieties that address very different needs. For example:</p>
diff --git a/docs/html/design/patterns/confirming-acknowledging.jd b/docs/html/design/patterns/confirming-acknowledging.jd
index ce0631bad500..f2e88eca7f41 100644
--- a/docs/html/design/patterns/confirming-acknowledging.jd
+++ b/docs/html/design/patterns/confirming-acknowledging.jd
@@ -1,4 +1,5 @@
page.title=Confirming &amp; Acknowledging
+page.tags="dialog","toast"
@jd:body
<p>In some situations, when a user invokes an action in your app, it's a good idea to <em>confirm</em> or <em>acknowledge</em> that action through text.</p>
diff --git a/docs/html/design/patterns/gestures.jd b/docs/html/design/patterns/gestures.jd
index e579cee1aed5..3ef133d20b37 100644
--- a/docs/html/design/patterns/gestures.jd
+++ b/docs/html/design/patterns/gestures.jd
@@ -1,4 +1,5 @@
page.title=Gestures
+page.tags="gesture","input"
@jd:body
<p>Gestures allow users to interact with your app by manipulating the screen objects you provide. The
diff --git a/docs/html/design/patterns/multi-pane-layouts.jd b/docs/html/design/patterns/multi-pane-layouts.jd
index e607676152e0..cbf29cb0f557 100644
--- a/docs/html/design/patterns/multi-pane-layouts.jd
+++ b/docs/html/design/patterns/multi-pane-layouts.jd
@@ -1,4 +1,5 @@
page.title=Multi-pane Layouts
+page.tags="tablet","navigation","layout","fragment"
@jd:body
<p>When writing an app for Android, keep in mind that Android devices come in many different screen
diff --git a/docs/html/design/patterns/navigation.jd b/docs/html/design/patterns/navigation.jd
index 656e6e5338fa..36debbef949c 100644
--- a/docs/html/design/patterns/navigation.jd
+++ b/docs/html/design/patterns/navigation.jd
@@ -1,4 +1,5 @@
page.title=Navigation with Back and Up
+page.tags="navigation","activity"
@jd:body
<p>Consistent navigation is an essential component of the overall user experience. Few things frustrate
diff --git a/docs/html/design/patterns/notifications.jd b/docs/html/design/patterns/notifications.jd
index 0665774a563a..3ae827e70450 100644
--- a/docs/html/design/patterns/notifications.jd
+++ b/docs/html/design/patterns/notifications.jd
@@ -1,4 +1,5 @@
page.title=Notifications
+page.tags="notification"
@jd:body
<p>The notification system allows your app to keep the user informed about events, such as new chat messages or a calendar event. Think of notifications as a news channel that alerts the user to important events as they happen or a log that chronicles events while the user is not paying attention.</p>
diff --git a/docs/html/design/patterns/selection.jd b/docs/html/design/patterns/selection.jd
index e9d22e641f82..682ce5689f04 100644
--- a/docs/html/design/patterns/selection.jd
+++ b/docs/html/design/patterns/selection.jd
@@ -1,4 +1,5 @@
page.title=Selection
+page.tags="actionmode","navigation"
@jd:body
<p>Android 3.0 changed the <em>long press</em> gesture&mdash;that is, a touch that's held in the same position for a moment&mdash;to be the global gesture to select data.. This affects the way you should
diff --git a/docs/html/design/patterns/settings.jd b/docs/html/design/patterns/settings.jd
index fef7585ac7de..f86cd39367f1 100644
--- a/docs/html/design/patterns/settings.jd
+++ b/docs/html/design/patterns/settings.jd
@@ -1,4 +1,5 @@
page.title=Settings
+page.tags="settings","preferences"
@jd:body
<p>Settings is a place in your app where users indicate their preferences for how your app should
diff --git a/docs/html/design/patterns/swipe-views.jd b/docs/html/design/patterns/swipe-views.jd
index daddd31e4730..b86d990007e8 100644
--- a/docs/html/design/patterns/swipe-views.jd
+++ b/docs/html/design/patterns/swipe-views.jd
@@ -1,4 +1,5 @@
page.title=Swipe Views
+page.tags="viewpager","navigation"
@jd:body
<p>Efficient navigation is one of the cornerstones of a well-designed app. While apps are generally
diff --git a/docs/html/design/patterns/widgets.jd b/docs/html/design/patterns/widgets.jd
index 54726b1b530b..a5979ce9ad80 100644
--- a/docs/html/design/patterns/widgets.jd
+++ b/docs/html/design/patterns/widgets.jd
@@ -1,4 +1,5 @@
page.title=Widgets
+page.tags="appwidget"
@jd:body
<p>Widgets are an essential aspect of home screen customization. You can imagine them as "at-a-glance" views of an app's most important data and functionality that is accessible right from the user's home screen. Users can move widgets across their home screen panels, and, if supported, resize them to tailor the amount of information within a widget to their preference.</p>
diff --git a/docs/html/guide/components/activities.jd b/docs/html/guide/components/activities.jd
index 289780421a61..1cbaa79194e5 100644
--- a/docs/html/guide/components/activities.jd
+++ b/docs/html/guide/components/activities.jd
@@ -1,4 +1,5 @@
page.title=Activities
+page.tags="activity","intent"
@jd:body
<div id="qv-wrapper">
diff --git a/docs/html/guide/topics/graphics/hardware-accel.jd b/docs/html/guide/topics/graphics/hardware-accel.jd
index 01dd79aebddc..9859c2840136 100644
--- a/docs/html/guide/topics/graphics/hardware-accel.jd
+++ b/docs/html/guide/topics/graphics/hardware-accel.jd
@@ -512,6 +512,13 @@ changed.</li>
<td class="s7">&#10007;</td>
<td class="s11">&#10007;</td>
</tr>
+ <tr>
+ <td class="s10">Local matrix on ComposeShader</td>
+ <td class="s7">&#10007;</td>
+ <td class="s11">&#10007;</td>
+ <td class="s7">&#10007;</td>
+ <td class="s11">&#10003;</td>
+ </tr>
</tbody>
</table>
diff --git a/docs/html/guide/topics/manifest/data-element.jd b/docs/html/guide/topics/manifest/data-element.jd
index 8fd91deae6a2..766d2d7b4d6c 100644
--- a/docs/html/guide/topics/manifest/data-element.jd
+++ b/docs/html/guide/topics/manifest/data-element.jd
@@ -85,6 +85,9 @@ host names using lowercase letters.</p>
The subtype can be the asterisk wildcard ({@code *}) to indicate that any
subtype matches.
+<p>It's common for an intent filter to declare a {@code &lt;data>} that includes
+only the {@code android:mimeType} attribute.</p>
+
<p class="note">Note: MIME type matching in the Android framework is
case-sensitive, unlike formal RFC MIME types. As a result, you should always
specify MIME types using lowercase letters.</p>
diff --git a/docs/html/guide/topics/ui/actionbar.jd b/docs/html/guide/topics/ui/actionbar.jd
index 3115c8f1f9d8..678a512e0f88 100644
--- a/docs/html/guide/topics/ui/actionbar.jd
+++ b/docs/html/guide/topics/ui/actionbar.jd
@@ -1,4 +1,5 @@
page.title=Action Bar
+page.tags="action bar","menu"
parent.title=User Interface
parent.link=index.html
@jd:body
diff --git a/docs/html/training/animation/index.jd b/docs/html/training/animation/index.jd
index 9cc7e6c405c0..b2815fcce95a 100644
--- a/docs/html/training/animation/index.jd
+++ b/docs/html/training/animation/index.jd
@@ -1,4 +1,5 @@
page.title=Adding Animations
+page.tags="animation","views","layout","user interface"
trainingnavtop=true
startpage=true
diff --git a/docs/html/training/basics/data-storage/databases.jd b/docs/html/training/basics/data-storage/databases.jd
index 8b1198383991..9976bb16291f 100644
--- a/docs/html/training/basics/data-storage/databases.jd
+++ b/docs/html/training/basics/data-storage/databases.jd
@@ -1,6 +1,4 @@
page.title=Saving Data in SQL Databases
-parent.title=Data Storage
-parent.link=index.html
trainingnavtop=true
previous.title=Saving Data in Files
diff --git a/docs/html/training/basics/data-storage/files.jd b/docs/html/training/basics/data-storage/files.jd
index dd081a6db8e8..52bea4c09b8b 100644
--- a/docs/html/training/basics/data-storage/files.jd
+++ b/docs/html/training/basics/data-storage/files.jd
@@ -1,6 +1,4 @@
page.title=Saving Files
-parent.title=Data Storage
-parent.link=index.html
trainingnavtop=true
diff --git a/docs/html/training/basics/data-storage/index.jd b/docs/html/training/basics/data-storage/index.jd
index 433493658ec5..4ccad75a2714 100644
--- a/docs/html/training/basics/data-storage/index.jd
+++ b/docs/html/training/basics/data-storage/index.jd
@@ -1,4 +1,5 @@
page.title=Saving Data
+page.tags="data storage","files","sql","database","preferences"
trainingnavtop=true
startpage=true
diff --git a/docs/html/training/basics/data-storage/shared-preferences.jd b/docs/html/training/basics/data-storage/shared-preferences.jd
index 099da6749819..a6717c46aa43 100644
--- a/docs/html/training/basics/data-storage/shared-preferences.jd
+++ b/docs/html/training/basics/data-storage/shared-preferences.jd
@@ -1,6 +1,4 @@
page.title=Saving Key-Value Sets
-parent.title=Data Storage
-parent.link=index.html
trainingnavtop=true
diff --git a/docs/html/training/basics/fragments/communicating.jd b/docs/html/training/basics/fragments/communicating.jd
index eb9b3689fc8b..b30045d2103e 100644
--- a/docs/html/training/basics/fragments/communicating.jd
+++ b/docs/html/training/basics/fragments/communicating.jd
@@ -1,10 +1,6 @@
page.title=Communicating with Other Fragments
-parent.title=Building a Dynamic UI with Fragments
-parent.link=index.html
trainingnavtop=true
-previous.title=Building a Flexible UI
-previous.link=fragment-ui.html
@jd:body
diff --git a/docs/html/training/basics/fragments/creating.jd b/docs/html/training/basics/fragments/creating.jd
index 0646230beb26..b5df4e1f7b56 100644
--- a/docs/html/training/basics/fragments/creating.jd
+++ b/docs/html/training/basics/fragments/creating.jd
@@ -1,12 +1,6 @@
page.title=Creating a Fragment
-parent.title=Building a Dynamic UI with Fragments
-parent.link=index.html
trainingnavtop=true
-previous.title=Using the Android Support Library
-previous.link=support-lib.html
-next.title=Building a Flexible UI
-next.link=fragment-ui.html
@jd:body
diff --git a/docs/html/training/basics/fragments/fragment-ui.jd b/docs/html/training/basics/fragments/fragment-ui.jd
index 4ec4de56366d..d648938f2c6c 100644
--- a/docs/html/training/basics/fragments/fragment-ui.jd
+++ b/docs/html/training/basics/fragments/fragment-ui.jd
@@ -1,12 +1,6 @@
page.title=Building a Flexible UI
-parent.title=Building a Dynamic UI with Fragments
-parent.link=index.html
trainingnavtop=true
-previous.title=Create a Fragment
-previous.link=creating.html
-next.title=Communicating with Other Fragments
-next.link=communicating.html
@jd:body
diff --git a/docs/html/training/basics/fragments/index.jd b/docs/html/training/basics/fragments/index.jd
index bc93f43df923..1b82f2cd5dd0 100644
--- a/docs/html/training/basics/fragments/index.jd
+++ b/docs/html/training/basics/fragments/index.jd
@@ -1,9 +1,8 @@
page.title=Building a Dynamic UI with Fragments
+page.tags="fragments", "user interface", "support library"
trainingnavtop=true
startpage=true
-next.title=Using the Android Support Library
-next.link=support-lib.html
@jd:body
diff --git a/docs/html/training/basics/fragments/support-lib.jd b/docs/html/training/basics/fragments/support-lib.jd
index cc867d3de112..b097de15b5f8 100644
--- a/docs/html/training/basics/fragments/support-lib.jd
+++ b/docs/html/training/basics/fragments/support-lib.jd
@@ -1,10 +1,7 @@
page.title=Using the Support Library
-parent.title=Building a Dynamic UI with Fragments
-parent.link=index.html
+page.tags="support library"
trainingnavtop=true
-next.title=Creating a Fragment
-next.link=creating.html
@jd:body
diff --git a/docs/html/training/basics/intents/index.jd b/docs/html/training/basics/intents/index.jd
index d94ff0154a84..8876a331914f 100644
--- a/docs/html/training/basics/intents/index.jd
+++ b/docs/html/training/basics/intents/index.jd
@@ -1,9 +1,8 @@
page.title=Interacting with Other Apps
+page.tags="intents","activity"
trainingnavtop=true
startpage=true
-next.title=Sending the User to Another App
-next.link=sending.html
@jd:body
diff --git a/docs/html/training/basics/network-ops/index.jd b/docs/html/training/basics/network-ops/index.jd
index b213c035d423..cb3a3907d0c6 100644
--- a/docs/html/training/basics/network-ops/index.jd
+++ b/docs/html/training/basics/network-ops/index.jd
@@ -1,4 +1,5 @@
page.title=Performing Network Operations
+page.tags="network","wireless"
trainingnavtop=true
startpage=true
diff --git a/docs/html/training/basics/supporting-devices/index.jd b/docs/html/training/basics/supporting-devices/index.jd
index 49ea81d27d72..1e3eb425639d 100644
--- a/docs/html/training/basics/supporting-devices/index.jd
+++ b/docs/html/training/basics/supporting-devices/index.jd
@@ -1,9 +1,8 @@
page.title=Supporting Different Devices
+page.tags="resources","screens","versions","localization"
trainingnavtop=true
startpage=true
-next.title=Supporting Multiple Languages
-next.link=languages.html
@jd:body
diff --git a/docs/html/training/camera/index.jd b/docs/html/training/camera/index.jd
index 282bed8d8b08..fa754a0aec3a 100644
--- a/docs/html/training/camera/index.jd
+++ b/docs/html/training/camera/index.jd
@@ -1,4 +1,5 @@
page.title=Capturing Photos
+page.tags="camera","video"
trainingnavtop=true
startpage=true
diff --git a/docs/html/training/cloudsync/index.jd b/docs/html/training/cloudsync/index.jd
index 91885e85ab56..55b275b89983 100644
--- a/docs/html/training/cloudsync/index.jd
+++ b/docs/html/training/cloudsync/index.jd
@@ -1,9 +1,8 @@
page.title=Syncing to the Cloud
+page.tags="cloud","sync","backup"
trainingnavtop=true
startpage=true
-next.title=Making the Most of Google Cloud Messaging
-next.link=gcm.html
@jd:body
diff --git a/docs/html/training/connect-devices-wirelessly/index.jd b/docs/html/training/connect-devices-wirelessly/index.jd
index 37cf633a4538..f27b9c39d963 100644
--- a/docs/html/training/connect-devices-wirelessly/index.jd
+++ b/docs/html/training/connect-devices-wirelessly/index.jd
@@ -1,9 +1,8 @@
page.title=Connecting Devices Wirelessly
+page.tags="wifi","network","wireless"
trainingnavtop=true
startpage=true
-next.title=Using Network Service Discovery
-next.link=nsd.html
@jd:body
diff --git a/docs/html/training/displaying-bitmaps/index.jd b/docs/html/training/displaying-bitmaps/index.jd
index a82829158026..857edeefb9bf 100644
--- a/docs/html/training/displaying-bitmaps/index.jd
+++ b/docs/html/training/displaying-bitmaps/index.jd
@@ -1,9 +1,8 @@
page.title=Displaying Bitmaps Efficiently
+page.tags="bitmaps","images","graphics"
trainingnavtop=true
startpage=true
-next.title=Loading Large Bitmaps Efficiently
-next.link=load-bitmap.html
@jd:body
diff --git a/docs/html/training/efficient-downloads/index.jd b/docs/html/training/efficient-downloads/index.jd
index a29be916863a..2ab93aed06dc 100644
--- a/docs/html/training/efficient-downloads/index.jd
+++ b/docs/html/training/efficient-downloads/index.jd
@@ -1,9 +1,8 @@
page.title=Transferring Data Without Draining the Battery
+page.tags="battery","network","wireless"
trainingnavtop=true
startpage=true
-next.title=Optimizing Downloads for Efficient Network Access
-next.link=efficient-network-access.html
@jd:body
diff --git a/docs/html/training/graphics/opengl/index.jd b/docs/html/training/graphics/opengl/index.jd
index 23a734acb473..cf33d80127e4 100644
--- a/docs/html/training/graphics/opengl/index.jd
+++ b/docs/html/training/graphics/opengl/index.jd
@@ -1,7 +1,6 @@
page.title=Displaying Graphics with OpenGL ES
+page=tags="open gl","graphics"
trainingnavtop=true
-next.title=Building an OpenGL ES Environment
-next.link=environment.html
@jd:body
diff --git a/docs/html/training/managing-audio/index.jd b/docs/html/training/managing-audio/index.jd
index 0f7bbfdd0d8e..3e3bcf02d100 100644
--- a/docs/html/training/managing-audio/index.jd
+++ b/docs/html/training/managing-audio/index.jd
@@ -1,9 +1,8 @@
page.title=Managing Audio Playback
+page.tags="audio","media"
trainingnavtop=true
startpage=true
-next.title=Controlling Your App's Volume and Playback
-next.link=volume-playback.html
@jd:body
diff --git a/docs/html/training/sharing/index.jd b/docs/html/training/sharing/index.jd
index c2e8dbc83223..2aa22b6a0490 100644
--- a/docs/html/training/sharing/index.jd
+++ b/docs/html/training/sharing/index.jd
@@ -1,9 +1,8 @@
page.title=Sharing Content
+page.tags="intents","share"
trainingnavtop=true
startpage=true
-next.title=Sending Content to Other Apps
-next.link=send.html
@jd:body
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 161811070e75..06e658d0ef8d 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -34,7 +34,6 @@ ifeq ($(USE_OPENGL_RENDERER),true)
ProgramCache.cpp \
RenderBufferCache.cpp \
ResourceCache.cpp \
- ShapeCache.cpp \
SkiaColorFilter.cpp \
SkiaShader.cpp \
Snapshot.cpp \
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index 4642a4f6eb36..dc3a4e2dc8cb 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -224,16 +224,6 @@ void Caches::dumpMemoryUsage(String8 &log) {
gradientCache.getSize(), gradientCache.getMaxSize());
log.appendFormat(" PathCache %8d / %8d\n",
pathCache.getSize(), pathCache.getMaxSize());
- log.appendFormat(" CircleShapeCache %8d / %8d\n",
- circleShapeCache.getSize(), circleShapeCache.getMaxSize());
- log.appendFormat(" OvalShapeCache %8d / %8d\n",
- ovalShapeCache.getSize(), ovalShapeCache.getMaxSize());
- log.appendFormat(" RoundRectShapeCache %8d / %8d\n",
- roundRectShapeCache.getSize(), roundRectShapeCache.getMaxSize());
- log.appendFormat(" RectShapeCache %8d / %8d\n",
- rectShapeCache.getSize(), rectShapeCache.getMaxSize());
- log.appendFormat(" ArcShapeCache %8d / %8d\n",
- arcShapeCache.getSize(), arcShapeCache.getMaxSize());
log.appendFormat(" TextDropShadowCache %8d / %8d\n", dropShadowCache.getSize(),
dropShadowCache.getMaxSize());
for (uint32_t i = 0; i < fontRenderer->getFontRendererCount(); i++) {
@@ -253,11 +243,6 @@ void Caches::dumpMemoryUsage(String8 &log) {
total += gradientCache.getSize();
total += pathCache.getSize();
total += dropShadowCache.getSize();
- total += roundRectShapeCache.getSize();
- total += circleShapeCache.getSize();
- total += ovalShapeCache.getSize();
- total += rectShapeCache.getSize();
- total += arcShapeCache.getSize();
for (uint32_t i = 0; i < fontRenderer->getFontRendererCount(); i++) {
total += fontRenderer->getFontRendererSize(i);
}
@@ -325,11 +310,6 @@ void Caches::flush(FlushMode mode) {
fontRenderer->flush();
textureCache.flush();
pathCache.clear();
- roundRectShapeCache.clear();
- circleShapeCache.clear();
- ovalShapeCache.clear();
- rectShapeCache.clear();
- arcShapeCache.clear();
// fall through
case kFlushMode_Layers:
layerCache.clear();
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index dc32a7ec63fa..63836c1c7dea 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -36,7 +36,6 @@
#include "GradientCache.h"
#include "PatchCache.h"
#include "ProgramCache.h"
-#include "ShapeCache.h"
#include "PathCache.h"
#include "TextDropShadowCache.h"
#include "FboCache.h"
@@ -269,11 +268,6 @@ public:
GradientCache gradientCache;
ProgramCache programCache;
PathCache pathCache;
- RoundRectShapeCache roundRectShapeCache;
- CircleShapeCache circleShapeCache;
- OvalShapeCache ovalShapeCache;
- RectShapeCache rectShapeCache;
- ArcShapeCache arcShapeCache;
PatchCache patchCache;
TextDropShadowCache dropShadowCache;
FboCache fboCache;
diff --git a/libs/hwui/Debug.h b/libs/hwui/Debug.h
index 773fe82f31a5..46beb94fecd2 100644
--- a/libs/hwui/Debug.h
+++ b/libs/hwui/Debug.h
@@ -64,7 +64,7 @@
#define DEBUG_PATCHES_EMPTY_VERTICES 0
// Turn on to display debug info about shapes
-#define DEBUG_SHAPES 0
+#define DEBUG_PATHS 0
// Turn on to display debug info about textures
#define DEBUG_TEXTURES 0
diff --git a/libs/hwui/DeferredDisplayList.cpp b/libs/hwui/DeferredDisplayList.cpp
index 84555450ecf5..5c5bf45354b0 100644
--- a/libs/hwui/DeferredDisplayList.cpp
+++ b/libs/hwui/DeferredDisplayList.cpp
@@ -17,6 +17,8 @@
#define LOG_TAG "OpenGLRenderer"
#define ATRACE_TAG ATRACE_TAG_VIEW
+#include <SkCanvas.h>
+
#include <utils/Trace.h>
#include "Debug.h"
diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp
index 4743f58dddb7..4944fe8714ca 100644
--- a/libs/hwui/DisplayList.cpp
+++ b/libs/hwui/DisplayList.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include <SkCanvas.h>
+
#include "Debug.h"
#include "DisplayList.h"
#include "DisplayListOp.h"
@@ -121,9 +123,7 @@ void DisplayList::clearResources() {
}
for (size_t i = 0; i < mPaths.size(); i++) {
- SkPath* path = mPaths.itemAt(i);
- caches.pathCache.remove(path);
- delete path;
+ delete mPaths.itemAt(i);
}
for (size_t i = 0; i < mMatrices.size(); i++) {
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 11a655e5c135..8b5b54c578bf 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -17,6 +17,7 @@
#define LOG_TAG "OpenGLRenderer"
#include <SkCamera.h>
+#include <SkCanvas.h>
#include <private/hwui/DrawGlInfo.h>
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index f0dcb30db549..0c70e272d0a5 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -378,9 +378,9 @@ void FontRenderer::checkInit() {
void FontRenderer::updateDrawParams() {
if (mCurrentQuadIndex != mLastQuadIndex) {
- mDrawOffsets.add((uint16_t*)(mLastQuadIndex * sizeof(uint16_t) * 6));
- mDrawCounts.add(mCurrentQuadIndex - mLastQuadIndex);
- mDrawCacheTextures.add(mCurrentCacheTexture);
+ uint16_t* offset = (uint16_t*)(mLastQuadIndex * sizeof(uint16_t) * 6);
+ uint32_t count = mCurrentQuadIndex - mLastQuadIndex;
+ mDrawBatch.add(TextBatch(offset, count, mCurrentCacheTexture));
mLastQuadIndex = mCurrentQuadIndex;
}
}
@@ -438,26 +438,27 @@ void FontRenderer::issueDrawCommand() {
caches.bindTexCoordsVertexPointer(force, buffer + offset);
}
- for (uint32_t i = 0; i < mDrawOffsets.size(); i++) {
- uint16_t* offset = mDrawOffsets[i];
- uint32_t count = mDrawCounts[i];
- CacheTexture* texture = mDrawCacheTextures[i];
+ caches.activeTexture(0);
+ GLuint lastId = 0;
- caches.activeTexture(0);
- glBindTexture(GL_TEXTURE_2D, texture->getTextureId());
+ for (uint32_t i = 0; i < mDrawBatch.size(); i++) {
+ const TextBatch& batch = mDrawBatch[i];
- texture->setLinearFiltering(mLinearFiltering, false);
+ GLuint id = batch.texture->getTextureId();
+ if (id != lastId) {
+ glBindTexture(GL_TEXTURE_2D, id);
+ batch.texture->setLinearFiltering(mLinearFiltering, false);
+ lastId = id;
+ }
- glDrawElements(GL_TRIANGLES, count * 6, GL_UNSIGNED_SHORT, offset);
+ glDrawElements(GL_TRIANGLES, batch.count * 6, GL_UNSIGNED_SHORT, batch.offset);
}
mDrawn = true;
mCurrentQuadIndex = 0;
mLastQuadIndex = 0;
- mDrawOffsets.clear();
- mDrawCounts.clear();
- mDrawCacheTextures.clear();
+ mDrawBatch.clear();
}
void FontRenderer::appendMeshQuadNoClip(float x1, float y1, float u1, float v1,
diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h
index d0c44ef5b982..442f4e2714a2 100644
--- a/libs/hwui/FontRenderer.h
+++ b/libs/hwui/FontRenderer.h
@@ -28,6 +28,7 @@
#include "font/CacheTexture.h"
#include "font/CachedGlyphInfo.h"
#include "font/Font.h"
+#include "utils/SortedList.h"
#include "Matrix.h"
#include "Properties.h"
@@ -180,9 +181,32 @@ private:
bool mLinearFiltering;
- Vector<uint16_t*> mDrawOffsets;
- Vector<uint32_t> mDrawCounts;
- Vector<CacheTexture*> mDrawCacheTextures;
+ struct TextBatch {
+ TextBatch(): offset(NULL), count(0), texture(NULL) {
+ }
+
+ TextBatch(uint16_t* offset, uint32_t count, CacheTexture* texture):
+ offset(offset), count(count), texture(texture) {
+ }
+
+ static int compare(const TextBatch& lhs, const TextBatch& rhs) {
+ return lhs.texture->getTextureId() - rhs.texture->getTextureId();
+ }
+
+ friend inline int strictly_order_type(const TextBatch& lhs, const TextBatch& rhs) {
+ return compare(lhs, rhs) < 0;
+ }
+
+ friend inline int compare_type(const TextBatch& lhs, const TextBatch& rhs) {
+ return compare(lhs, rhs);
+ }
+
+ uint16_t* offset;
+ uint32_t count;
+ CacheTexture* texture;
+ };
+
+ SortedList<TextBatch> mDrawBatch;
// RS constructs
sp<RSC::RS> mRs;
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index e576f76f8660..e31f6f6fe669 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -1805,7 +1805,7 @@ status_t OpenGLRenderer::drawDisplayList(DisplayList* displayList, Rect& dirty,
// All the usual checks and setup operations (quickReject, setupDraw, etc.)
// will be performed by the display list itself
if (displayList && displayList->isRenderable()) {
- if (CC_UNLIKELY(mCaches.drawDeferDisabled)) {
+ if (true || CC_UNLIKELY(mCaches.drawDeferDisabled)) { // NOTE: temporary workaround
ReplayStateStruct replayStruct(*this, dirty, replayFlags);
displayList->replay(replayStruct, 0);
return replayStruct.mDrawGlStatus;
@@ -2257,9 +2257,11 @@ status_t OpenGLRenderer::drawConvexPath(const SkPath& path, SkPaint* paint) {
// TODO: try clipping large paths to viewport
PathTessellator::tessellatePath(path, paint, mSnapshot->transform, vertexBuffer);
- SkRect bounds = path.getBounds();
- PathTessellator::expandBoundsForStroke(bounds, paint, false);
- dirtyLayer(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, currentTransform());
+ if (hasLayer()) {
+ SkRect bounds = path.getBounds();
+ PathTessellator::expandBoundsForStroke(bounds, paint, false);
+ dirtyLayer(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, currentTransform());
+ }
return drawVertexBuffer(vertexBuffer, paint);
}
@@ -2389,7 +2391,7 @@ status_t OpenGLRenderer::drawRoundRect(float left, float top, float right, float
if (p->getPathEffect() != 0) {
mCaches.activeTexture(0);
- const PathTexture* texture = mCaches.roundRectShapeCache.getRoundRect(
+ const PathTexture* texture = mCaches.pathCache.getRoundRect(
right - left, bottom - top, rx, ry, p);
return drawShape(left, top, texture, p);
}
@@ -2413,7 +2415,7 @@ status_t OpenGLRenderer::drawCircle(float x, float y, float radius, SkPaint* p)
}
if (p->getPathEffect() != 0) {
mCaches.activeTexture(0);
- const PathTexture* texture = mCaches.circleShapeCache.getCircle(radius, p);
+ const PathTexture* texture = mCaches.pathCache.getCircle(radius, p);
return drawShape(x - radius, y - radius, texture, p);
}
@@ -2434,7 +2436,7 @@ status_t OpenGLRenderer::drawOval(float left, float top, float right, float bott
if (p->getPathEffect() != 0) {
mCaches.activeTexture(0);
- const PathTexture* texture = mCaches.ovalShapeCache.getOval(right - left, bottom - top, p);
+ const PathTexture* texture = mCaches.pathCache.getOval(right - left, bottom - top, p);
return drawShape(left, top, texture, p);
}
@@ -2460,7 +2462,7 @@ status_t OpenGLRenderer::drawArc(float left, float top, float right, float botto
// TODO: support fills (accounting for concavity if useCenter && sweepAngle > 180)
if (p->getStyle() != SkPaint::kStroke_Style || p->getPathEffect() != 0 || useCenter) {
mCaches.activeTexture(0);
- const PathTexture* texture = mCaches.arcShapeCache.getArc(right - left, bottom - top,
+ const PathTexture* texture = mCaches.pathCache.getArc(right - left, bottom - top,
startAngle, sweepAngle, useCenter, p);
return drawShape(left, top, texture, p);
}
@@ -2495,7 +2497,7 @@ status_t OpenGLRenderer::drawRect(float left, float top, float right, float bott
p->getStrokeMiter() != SkPaintDefaults_MiterLimit) {
mCaches.activeTexture(0);
const PathTexture* texture =
- mCaches.rectShapeCache.getRect(right - left, bottom - top, p);
+ mCaches.pathCache.getRect(right - left, bottom - top, p);
return drawShape(left, top, texture, p);
}
diff --git a/libs/hwui/PathCache.cpp b/libs/hwui/PathCache.cpp
index fb687cd16ff5..490c22a00553 100644
--- a/libs/hwui/PathCache.cpp
+++ b/libs/hwui/PathCache.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2013 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.
@@ -15,19 +15,301 @@
*/
#define LOG_TAG "OpenGLRenderer"
+#define ATRACE_TAG ATRACE_TAG_VIEW
-#include <utils/Mutex.h>
+#include <SkBitmap.h>
+#include <SkCanvas.h>
+#include <SkPaint.h>
+#include <SkPath.h>
+#include <SkRect.h>
-#include <sys/sysinfo.h>
+#include <utils/JenkinsHash.h>
+#include <utils/Trace.h>
#include "Caches.h"
#include "PathCache.h"
-#include "Properties.h"
+
+#include "thread/Signal.h"
+#include "thread/Task.h"
+#include "thread/TaskProcessor.h"
namespace android {
namespace uirenderer {
///////////////////////////////////////////////////////////////////////////////
+// Cache entries
+///////////////////////////////////////////////////////////////////////////////
+
+PathDescription::PathDescription():
+ type(kShapeNone),
+ join(SkPaint::kDefault_Join),
+ cap(SkPaint::kDefault_Cap),
+ style(SkPaint::kFill_Style),
+ miter(4.0f),
+ strokeWidth(1.0f),
+ pathEffect(NULL) {
+ memset(&shape, 0, sizeof(Shape));
+}
+
+PathDescription::PathDescription(ShapeType type, SkPaint* paint):
+ type(type),
+ join(paint->getStrokeJoin()),
+ cap(paint->getStrokeCap()),
+ style(paint->getStyle()),
+ miter(paint->getStrokeMiter()),
+ strokeWidth(paint->getStrokeWidth()),
+ pathEffect(paint->getPathEffect()) {
+ memset(&shape, 0, sizeof(Shape));
+}
+
+hash_t PathDescription::hash() const {
+ uint32_t hash = JenkinsHashMix(0, type);
+ hash = JenkinsHashMix(hash, join);
+ hash = JenkinsHashMix(hash, cap);
+ hash = JenkinsHashMix(hash, style);
+ hash = JenkinsHashMix(hash, android::hash_type(miter));
+ hash = JenkinsHashMix(hash, android::hash_type(strokeWidth));
+ hash = JenkinsHashMix(hash, android::hash_type(pathEffect));
+ hash = JenkinsHashMixBytes(hash, (uint8_t*) &shape, sizeof(Shape));
+ return JenkinsHashWhiten(hash);
+}
+
+int PathDescription::compare(const PathDescription& rhs) const {
+ return memcmp(this, &rhs, sizeof(PathDescription));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Utilities
+///////////////////////////////////////////////////////////////////////////////
+
+bool PathCache::canDrawAsConvexPath(SkPath* path, SkPaint* paint) {
+ // NOTE: This should only be used after PathTessellator handles joins properly
+ return paint->getPathEffect() == NULL && path->getConvexity() == SkPath::kConvex_Convexity;
+}
+
+void PathCache::computePathBounds(const SkPath* path, const SkPaint* paint,
+ float& left, float& top, float& offset, uint32_t& width, uint32_t& height) {
+ const SkRect& bounds = path->getBounds();
+ PathCache::computeBounds(bounds, paint, left, top, offset, width, height);
+}
+
+void PathCache::computeBounds(const SkRect& bounds, const SkPaint* paint,
+ float& left, float& top, float& offset, uint32_t& width, uint32_t& height) {
+ const float pathWidth = fmax(bounds.width(), 1.0f);
+ const float pathHeight = fmax(bounds.height(), 1.0f);
+
+ left = bounds.fLeft;
+ top = bounds.fTop;
+
+ offset = (int) floorf(fmax(paint->getStrokeWidth(), 1.0f) * 1.5f + 0.5f);
+
+ width = uint32_t(pathWidth + offset * 2.0 + 0.5);
+ height = uint32_t(pathHeight + offset * 2.0 + 0.5);
+}
+
+static void initBitmap(SkBitmap& bitmap, uint32_t width, uint32_t height) {
+ bitmap.setConfig(SkBitmap::kA8_Config, width, height);
+ bitmap.allocPixels();
+ bitmap.eraseColor(0);
+}
+
+static void initPaint(SkPaint& paint) {
+ // Make sure the paint is opaque, color, alpha, filter, etc.
+ // will be applied later when compositing the alpha8 texture
+ paint.setColor(0xff000000);
+ paint.setAlpha(255);
+ paint.setColorFilter(NULL);
+ paint.setMaskFilter(NULL);
+ paint.setShader(NULL);
+ SkXfermode* mode = SkXfermode::Create(SkXfermode::kSrc_Mode);
+ SkSafeUnref(paint.setXfermode(mode));
+}
+
+static void drawPath(const SkPath *path, const SkPaint* paint, SkBitmap& bitmap,
+ float left, float top, float offset, uint32_t width, uint32_t height) {
+ initBitmap(bitmap, width, height);
+
+ SkPaint pathPaint(*paint);
+ initPaint(pathPaint);
+
+ SkCanvas canvas(bitmap);
+ canvas.translate(-left + offset, -top + offset);
+ canvas.drawPath(*path, pathPaint);
+}
+
+static PathTexture* createTexture(float left, float top, float offset,
+ uint32_t width, uint32_t height, uint32_t id) {
+ PathTexture* texture = new PathTexture();
+ texture->left = left;
+ texture->top = top;
+ texture->offset = offset;
+ texture->width = width;
+ texture->height = height;
+ texture->generation = id;
+ return texture;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Cache constructor/destructor
+///////////////////////////////////////////////////////////////////////////////
+
+PathCache::PathCache():
+ mCache(LruCache<PathDescription, PathTexture*>::kUnlimitedCapacity),
+ mSize(0), mMaxSize(MB(DEFAULT_PATH_CACHE_SIZE)) {
+ char property[PROPERTY_VALUE_MAX];
+ if (property_get(PROPERTY_PATH_CACHE_SIZE, property, NULL) > 0) {
+ INIT_LOGD(" Setting %s cache size to %sMB", name, property);
+ setMaxSize(MB(atof(property)));
+ } else {
+ INIT_LOGD(" Using default %s cache size of %.2fMB", name, DEFAULT_PATH_CACHE_SIZE);
+ }
+ init();
+}
+
+PathCache::~PathCache() {
+ mCache.clear();
+}
+
+void PathCache::init() {
+ mCache.setOnEntryRemovedListener(this);
+
+ GLint maxTextureSize;
+ glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
+ mMaxTextureSize = maxTextureSize;
+
+ mDebugEnabled = readDebugLevel() & kDebugCaches;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Size management
+///////////////////////////////////////////////////////////////////////////////
+
+uint32_t PathCache::getSize() {
+ return mSize;
+}
+
+uint32_t PathCache::getMaxSize() {
+ return mMaxSize;
+}
+
+void PathCache::setMaxSize(uint32_t maxSize) {
+ mMaxSize = maxSize;
+ while (mSize > mMaxSize) {
+ mCache.removeOldest();
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Callbacks
+///////////////////////////////////////////////////////////////////////////////
+
+void PathCache::operator()(PathDescription& entry, PathTexture*& texture) {
+ removeTexture(texture);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Caching
+///////////////////////////////////////////////////////////////////////////////
+
+void PathCache::removeTexture(PathTexture* texture) {
+ if (texture) {
+ const uint32_t size = texture->width * texture->height;
+ mSize -= size;
+
+ PATH_LOGD("PathCache::delete name, size, mSize = %d, %d, %d",
+ texture->id, size, mSize);
+ if (mDebugEnabled) {
+ ALOGD("Shape deleted, size = %d", size);
+ }
+
+ if (texture->id) {
+ glDeleteTextures(1, &texture->id);
+ }
+ delete texture;
+ }
+}
+
+void PathCache::purgeCache(uint32_t width, uint32_t height) {
+ const uint32_t size = width * height;
+ // Don't even try to cache a bitmap that's bigger than the cache
+ if (size < mMaxSize) {
+ while (mSize + size > mMaxSize) {
+ mCache.removeOldest();
+ }
+ }
+}
+
+void PathCache::trim() {
+ while (mSize > mMaxSize) {
+ mCache.removeOldest();
+ }
+}
+
+PathTexture* PathCache::addTexture(const PathDescription& entry, const SkPath *path,
+ const SkPaint* paint) {
+ ATRACE_CALL();
+
+ float left, top, offset;
+ uint32_t width, height;
+ computePathBounds(path, paint, left, top, offset, width, height);
+
+ if (!checkTextureSize(width, height)) return NULL;
+
+ purgeCache(width, height);
+
+ SkBitmap bitmap;
+ drawPath(path, paint, bitmap, left, top, offset, width, height);
+
+ PathTexture* texture = createTexture(left, top, offset, width, height,
+ path->getGenerationID());
+ addTexture(entry, &bitmap, texture);
+
+ return texture;
+}
+
+void PathCache::addTexture(const PathDescription& entry, SkBitmap* bitmap, PathTexture* texture) {
+ generateTexture(*bitmap, texture);
+
+ uint32_t size = texture->width * texture->height;
+ if (size < mMaxSize) {
+ mSize += size;
+ PATH_LOGD("PathCache::get/create: name, size, mSize = %d, %d, %d",
+ texture->id, size, mSize);
+ if (mDebugEnabled) {
+ ALOGD("Shape created, size = %d", size);
+ }
+ mCache.put(entry, texture);
+ } else {
+ texture->cleanup = true;
+ }
+}
+
+void PathCache::clear() {
+ mCache.clear();
+}
+
+void PathCache::generateTexture(SkBitmap& bitmap, Texture* texture) {
+ SkAutoLockPixels alp(bitmap);
+ if (!bitmap.readyToDraw()) {
+ ALOGE("Cannot generate texture from bitmap");
+ return;
+ }
+
+ glGenTextures(1, &texture->id);
+
+ glBindTexture(GL_TEXTURE_2D, texture->id);
+ // Textures are Alpha8
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
+ texture->blend = true;
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, texture->width, texture->height, 0,
+ GL_ALPHA, GL_UNSIGNED_BYTE, bitmap.getPixels());
+
+ texture->setFilter(GL_LINEAR);
+ texture->setWrap(GL_CLAMP_TO_EDGE);
+}
+
+///////////////////////////////////////////////////////////////////////////////
// Path precaching
///////////////////////////////////////////////////////////////////////////////
@@ -52,7 +334,7 @@ void PathCache::PathProcessor::onProcess(const sp<Task<SkBitmap*> >& task) {
if (width <= mMaxTextureSize && height <= mMaxTextureSize) {
SkBitmap* bitmap = new SkBitmap();
- PathCache::drawPath(t->path, t->paint, *bitmap, left, top, offset, width, height);
+ drawPath(t->path, t->paint, *bitmap, left, top, offset, width, height);
t->setResult(bitmap);
} else {
texture->width = 0;
@@ -62,23 +344,17 @@ void PathCache::PathProcessor::onProcess(const sp<Task<SkBitmap*> >& task) {
}
///////////////////////////////////////////////////////////////////////////////
-// Path cache
+// Paths
///////////////////////////////////////////////////////////////////////////////
-PathCache::PathCache(): ShapeCache<PathCacheEntry>("path",
- PROPERTY_PATH_CACHE_SIZE, DEFAULT_PATH_CACHE_SIZE) {
-}
-
-PathCache::~PathCache() {
-}
-
void PathCache::remove(SkPath* path) {
- Vector<PathCacheEntry> pathsToRemove;
- LruCache<PathCacheEntry, PathTexture*>::Iterator i(mCache);
+ Vector<PathDescription> pathsToRemove;
+ LruCache<PathDescription, PathTexture*>::Iterator i(mCache);
while (i.next()) {
- const PathCacheEntry& key = i.key();
- if (key.path == path || key.path == path->getSourcePath()) {
+ const PathDescription& key = i.key();
+ if (key.type == kShapePath &&
+ (key.shape.path.mPath == path || key.shape.path.mPath == path->getSourcePath())) {
pathsToRemove.push(key);
}
}
@@ -121,7 +397,9 @@ static SkPath* getSourcePath(SkPath* path) {
PathTexture* PathCache::get(SkPath* path, SkPaint* paint) {
path = getSourcePath(path);
- PathCacheEntry entry(path, paint);
+ PathDescription entry(kShapePath, paint);
+ entry.shape.path.mPath = path;
+
PathTexture* texture = mCache.get(entry);
if (!texture) {
@@ -159,7 +437,9 @@ void PathCache::precache(SkPath* path, SkPaint* paint) {
path = getSourcePath(path);
- PathCacheEntry entry(path, paint);
+ PathDescription entry(kShapePath, paint);
+ entry.shape.path.mPath = path;
+
PathTexture* texture = mCache.get(entry);
bool generate = false;
@@ -193,5 +473,130 @@ void PathCache::precache(SkPath* path, SkPaint* paint) {
}
}
+///////////////////////////////////////////////////////////////////////////////
+// Rounded rects
+///////////////////////////////////////////////////////////////////////////////
+
+PathTexture* PathCache::getRoundRect(float width, float height,
+ float rx, float ry, SkPaint* paint) {
+ PathDescription entry(kShapeRoundRect, paint);
+ entry.shape.roundRect.mWidth = width;
+ entry.shape.roundRect.mHeight = height;
+ entry.shape.roundRect.mRx = rx;
+ entry.shape.roundRect.mRy = ry;
+
+ PathTexture* texture = get(entry);
+
+ if (!texture) {
+ SkPath path;
+ SkRect r;
+ r.set(0.0f, 0.0f, width, height);
+ path.addRoundRect(r, rx, ry, SkPath::kCW_Direction);
+
+ texture = addTexture(entry, &path, paint);
+ }
+
+ return texture;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Circles
+///////////////////////////////////////////////////////////////////////////////
+
+PathTexture* PathCache::getCircle(float radius, SkPaint* paint) {
+ PathDescription entry(kShapeCircle, paint);
+ entry.shape.circle.mRadius = radius;
+
+ PathTexture* texture = get(entry);
+
+ if (!texture) {
+ SkPath path;
+ path.addCircle(radius, radius, radius, SkPath::kCW_Direction);
+
+ texture = addTexture(entry, &path, paint);
+ }
+
+ return texture;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Ovals
+///////////////////////////////////////////////////////////////////////////////
+
+PathTexture* PathCache::getOval(float width, float height, SkPaint* paint) {
+ PathDescription entry(kShapeOval, paint);
+ entry.shape.oval.mWidth = width;
+ entry.shape.oval.mHeight = height;
+
+ PathTexture* texture = get(entry);
+
+ if (!texture) {
+ SkPath path;
+ SkRect r;
+ r.set(0.0f, 0.0f, width, height);
+ path.addOval(r, SkPath::kCW_Direction);
+
+ texture = addTexture(entry, &path, paint);
+ }
+
+ return texture;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Rects
+///////////////////////////////////////////////////////////////////////////////
+
+PathTexture* PathCache::getRect(float width, float height, SkPaint* paint) {
+ PathDescription entry(kShapeRect, paint);
+ entry.shape.rect.mWidth = width;
+ entry.shape.rect.mHeight = height;
+
+ PathTexture* texture = get(entry);
+
+ if (!texture) {
+ SkPath path;
+ SkRect r;
+ r.set(0.0f, 0.0f, width, height);
+ path.addRect(r, SkPath::kCW_Direction);
+
+ texture = addTexture(entry, &path, paint);
+ }
+
+ return texture;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Arcs
+///////////////////////////////////////////////////////////////////////////////
+
+PathTexture* PathCache::getArc(float width, float height,
+ float startAngle, float sweepAngle, bool useCenter, SkPaint* paint) {
+ PathDescription entry(kShapeArc, paint);
+ entry.shape.arc.mWidth = width;
+ entry.shape.arc.mHeight = height;
+ entry.shape.arc.mStartAngle = startAngle;
+ entry.shape.arc.mSweepAngle = sweepAngle;
+ entry.shape.arc.mUseCenter = useCenter;
+
+ PathTexture* texture = get(entry);
+
+ if (!texture) {
+ SkPath path;
+ SkRect r;
+ r.set(0.0f, 0.0f, width, height);
+ if (useCenter) {
+ path.moveTo(r.centerX(), r.centerY());
+ }
+ path.arcTo(r, startAngle, sweepAngle, !useCenter);
+ if (useCenter) {
+ path.close();
+ }
+
+ texture = addTexture(entry, &path, paint);
+ }
+
+ return texture;
+}
+
}; // namespace uirenderer
}; // namespace android
diff --git a/libs/hwui/PathCache.h b/libs/hwui/PathCache.h
index 27031a5e04a7..e6d92df0b06c 100644
--- a/libs/hwui/PathCache.h
+++ b/libs/hwui/PathCache.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2013 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.
@@ -17,17 +17,21 @@
#ifndef ANDROID_HWUI_PATH_CACHE_H
#define ANDROID_HWUI_PATH_CACHE_H
-#include <utils/Thread.h>
+#include <GLES2/gl2.h>
+
+#include <utils/LruCache.h>
+#include <utils/Mutex.h>
#include <utils/Vector.h>
#include "Debug.h"
-#include "ShapeCache.h"
-#include "thread/Signal.h"
-#include "thread/Task.h"
-#include "thread/TaskProcessor.h"
+#include "Properties.h"
+#include "Texture.h"
+class SkBitmap;
+class SkCanvas;
class SkPaint;
class SkPath;
+class SkRect;
namespace android {
namespace uirenderer {
@@ -35,56 +39,181 @@ namespace uirenderer {
class Caches;
///////////////////////////////////////////////////////////////////////////////
+// Defines
+///////////////////////////////////////////////////////////////////////////////
+
+// Debug
+#if DEBUG_PATHS
+ #define PATH_LOGD(...) ALOGD(__VA_ARGS__)
+#else
+ #define PATH_LOGD(...)
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
// Classes
///////////////////////////////////////////////////////////////////////////////
-struct PathCacheEntry: public ShapeCacheEntry {
- PathCacheEntry(SkPath* path, SkPaint* paint):
- ShapeCacheEntry(ShapeCacheEntry::kShapePath, paint) {
- this->path = path;
+/**
+ * Alpha texture used to represent a path.
+ */
+struct PathTexture: public Texture {
+ PathTexture(): Texture() {
+ }
+
+ ~PathTexture() {
+ clearTask();
+ }
+
+ /**
+ * Left coordinate of the path bounds.
+ */
+ float left;
+ /**
+ * Top coordinate of the path bounds.
+ */
+ float top;
+ /**
+ * Offset to draw the path at the correct origin.
+ */
+ float offset;
+
+ sp<Task<SkBitmap*> > task() const {
+ return mTask;
}
- PathCacheEntry(): ShapeCacheEntry() {
- path = NULL;
+ void setTask(const sp<Task<SkBitmap*> >& task) {
+ mTask = task;
}
- hash_t hash() const {
- uint32_t hash = ShapeCacheEntry::hash();
- hash = JenkinsHashMix(hash, android::hash_type(path));
- return JenkinsHashWhiten(hash);
+ void clearTask() {
+ if (mTask != NULL) {
+ mTask.clear();
+ }
}
- int compare(const ShapeCacheEntry& r) const {
- int deltaInt = ShapeCacheEntry::compare(r);
- if (deltaInt != 0) return deltaInt;
+private:
+ sp<Task<SkBitmap*> > mTask;
+}; // struct PathTexture
+
+enum ShapeType {
+ kShapeNone,
+ kShapeRect,
+ kShapeRoundRect,
+ kShapeCircle,
+ kShapeOval,
+ kShapeArc,
+ kShapePath
+};
+
+struct PathDescription {
+ ShapeType type;
+ SkPaint::Join join;
+ SkPaint::Cap cap;
+ SkPaint::Style style;
+ float miter;
+ float strokeWidth;
+ SkPathEffect* pathEffect;
+ union Shape {
+ struct Path {
+ SkPath* mPath;
+ } path;
+ struct RoundRect {
+ float mWidth;
+ float mHeight;
+ float mRx;
+ float mRy;
+ } roundRect;
+ struct Circle {
+ float mRadius;
+ } circle;
+ struct Oval {
+ float mWidth;
+ float mHeight;
+ } oval;
+ struct Rect {
+ float mWidth;
+ float mHeight;
+ } rect;
+ struct Arc {
+ float mWidth;
+ float mHeight;
+ float mStartAngle;
+ float mSweepAngle;
+ bool mUseCenter;
+ } arc;
+ } shape;
+
+ PathDescription();
+ PathDescription(ShapeType shapeType, SkPaint* paint);
+
+ hash_t hash() const;
- const PathCacheEntry& rhs = (const PathCacheEntry&) r;
- return path - rhs.path;
+ int compare(const PathDescription& rhs) const;
+
+ bool operator==(const PathDescription& other) const {
+ return compare(other) == 0;
+ }
+
+ bool operator!=(const PathDescription& other) const {
+ return compare(other) != 0;
}
- SkPath* path;
+ friend inline int strictly_order_type(
+ const PathDescription& lhs, const PathDescription& rhs) {
+ return lhs.compare(rhs) < 0;
+ }
-}; // PathCacheEntry
+ friend inline int compare_type(const PathDescription& lhs, const PathDescription& rhs) {
+ return lhs.compare(rhs);
+ }
-inline hash_t hash_type(const PathCacheEntry& entry) {
- return entry.hash();
-}
+ friend inline hash_t hash_type(const PathDescription& entry) {
+ return entry.hash();
+ }
+};
/**
- * A simple LRU path cache. The cache has a maximum size expressed in bytes.
+ * A simple LRU shape cache. The cache has a maximum size expressed in bytes.
* Any texture added to the cache causing the cache to grow beyond the maximum
* allowed size will also cause the oldest texture to be kicked out.
*/
-class PathCache: public ShapeCache<PathCacheEntry> {
+class PathCache: public OnEntryRemoved<PathDescription, PathTexture*> {
public:
PathCache();
~PathCache();
/**
- * Returns the texture associated with the specified path. If the texture
- * cannot be found in the cache, a new texture is generated.
+ * Used as a callback when an entry is removed from the cache.
+ * Do not invoke directly.
*/
+ void operator()(PathDescription& path, PathTexture*& texture);
+
+ /**
+ * Clears the cache. This causes all textures to be deleted.
+ */
+ void clear();
+
+ /**
+ * Sets the maximum size of the cache in bytes.
+ */
+ void setMaxSize(uint32_t maxSize);
+ /**
+ * Returns the maximum size of the cache in bytes.
+ */
+ uint32_t getMaxSize();
+ /**
+ * Returns the current size of the cache in bytes.
+ */
+ uint32_t getSize();
+
+ PathTexture* getRoundRect(float width, float height, float rx, float ry, SkPaint* paint);
+ PathTexture* getCircle(float radius, SkPaint* paint);
+ PathTexture* getOval(float width, float height, SkPaint* paint);
+ PathTexture* getRect(float width, float height, SkPaint* paint);
+ PathTexture* getArc(float width, float height, float startAngle, float sweepAngle,
+ bool useCenter, SkPaint* paint);
PathTexture* get(SkPath* path, SkPaint* paint);
+
/**
* Removes an entry.
*/
@@ -98,10 +227,63 @@ public:
* Process deferred removals.
*/
void clearGarbage();
+ /**
+ * Trims the contents of the cache, removing items until it's under its
+ * specified limit.
+ *
+ * Trimming is used for caches that support pre-caching from a worker
+ * thread. During pre-caching the maximum limit of the cache can be
+ * exceeded for the duration of the frame. It is therefore required to
+ * trim the cache at the end of the frame to keep the total amount of
+ * memory used under control.
+ */
+ void trim();
+ /**
+ * Precaches the specified path using background threads.
+ */
void precache(SkPath* path, SkPaint* paint);
+ static bool canDrawAsConvexPath(SkPath* path, SkPaint* paint);
+ static void computePathBounds(const SkPath* path, const SkPaint* paint,
+ float& left, float& top, float& offset, uint32_t& width, uint32_t& height);
+ static void computeBounds(const SkRect& bounds, const SkPaint* paint,
+ float& left, float& top, float& offset, uint32_t& width, uint32_t& height);
+
private:
+ PathTexture* addTexture(const PathDescription& entry,
+ const SkPath *path, const SkPaint* paint);
+ PathTexture* addTexture(const PathDescription& entry, SkBitmap* bitmap);
+ void addTexture(const PathDescription& entry, SkBitmap* bitmap, PathTexture* texture);
+
+ PathTexture* get(const PathDescription& entry) {
+ return mCache.get(entry);
+ }
+
+ /**
+ * Ensures there is enough space in the cache for a texture of the specified
+ * dimensions.
+ */
+ void purgeCache(uint32_t width, uint32_t height);
+
+ void removeTexture(PathTexture* texture);
+
+ bool checkTextureSize(uint32_t width, uint32_t height) {
+ if (width > mMaxTextureSize || height > mMaxTextureSize) {
+ ALOGW("Shape too large to be rendered into a texture (%dx%d, max=%dx%d)",
+ width, height, mMaxTextureSize, mMaxTextureSize);
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Generates the texture from a bitmap into the specified texture structure.
+ */
+ void generateTexture(SkBitmap& bitmap, Texture* texture);
+
+ void init();
+
class PathTask: public Task<SkBitmap*> {
public:
PathTask(SkPath* path, SkPaint* paint, PathTexture* texture):
@@ -128,6 +310,13 @@ private:
uint32_t mMaxTextureSize;
};
+ LruCache<PathDescription, PathTexture*> mCache;
+ uint32_t mSize;
+ uint32_t mMaxSize;
+ GLuint mMaxTextureSize;
+
+ bool mDebugEnabled;
+
sp<PathProcessor> mProcessor;
Vector<SkPath*> mGarbage;
mutable Mutex mLock;
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index b8559bc8eabb..e4b4f3c4fb8d 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -115,12 +115,11 @@ enum DebugLevel {
#define PROPERTY_RENDER_BUFFER_CACHE_SIZE "ro.hwui.r_buffer_cache_size"
#define PROPERTY_GRADIENT_CACHE_SIZE "ro.hwui.gradient_cache_size"
#define PROPERTY_PATH_CACHE_SIZE "ro.hwui.path_cache_size"
-#define PROPERTY_SHAPE_CACHE_SIZE "ro.hwui.shape_cache_size"
#define PROPERTY_DROP_SHADOW_CACHE_SIZE "ro.hwui.drop_shadow_cache_size"
#define PROPERTY_FBO_CACHE_SIZE "ro.hwui.fbo_cache_size"
// These properties are defined in percentage (range 0..1)
-#define PROPERTY_TEXTURE_CACHE_FLUSH_RATE "ro.hwui.texture_cache_flush_rate"
+#define PROPERTY_TEXTURE_CACHE_FLUSH_RATE "ro.hwui.texture_cache_flushrate"
// These properties are defined in pixels
#define PROPERTY_TEXT_SMALL_CACHE_WIDTH "ro.hwui.text_small_cache_width"
@@ -159,8 +158,7 @@ enum DebugLevel {
#define DEFAULT_TEXTURE_CACHE_SIZE 24.0f
#define DEFAULT_LAYER_CACHE_SIZE 16.0f
#define DEFAULT_RENDER_BUFFER_CACHE_SIZE 2.0f
-#define DEFAULT_PATH_CACHE_SIZE 4.0f
-#define DEFAULT_SHAPE_CACHE_SIZE 1.0f
+#define DEFAULT_PATH_CACHE_SIZE 10.0f
#define DEFAULT_PATCH_CACHE_SIZE 512
#define DEFAULT_GRADIENT_CACHE_SIZE 0.5f
#define DEFAULT_DROP_SHADOW_CACHE_SIZE 2.0f
diff --git a/libs/hwui/ShapeCache.cpp b/libs/hwui/ShapeCache.cpp
deleted file mode 100644
index 5a23235f7241..000000000000
--- a/libs/hwui/ShapeCache.cpp
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * 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.
- */
-
-#define LOG_TAG "OpenGLRenderer"
-
-#include "ShapeCache.h"
-
-namespace android {
-namespace uirenderer {
-
-///////////////////////////////////////////////////////////////////////////////
-// Rounded rects
-///////////////////////////////////////////////////////////////////////////////
-
-RoundRectShapeCache::RoundRectShapeCache(): ShapeCache<RoundRectShapeCacheEntry>(
- "round rect", PROPERTY_SHAPE_CACHE_SIZE, DEFAULT_SHAPE_CACHE_SIZE) {
-}
-
-PathTexture* RoundRectShapeCache::getRoundRect(float width, float height,
- float rx, float ry, SkPaint* paint) {
- RoundRectShapeCacheEntry entry(width, height, rx, ry, paint);
- PathTexture* texture = get(entry);
-
- if (!texture) {
- SkPath path;
- SkRect r;
- r.set(0.0f, 0.0f, width, height);
- path.addRoundRect(r, rx, ry, SkPath::kCW_Direction);
-
- texture = addTexture(entry, &path, paint);
- }
-
- return texture;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Circles
-///////////////////////////////////////////////////////////////////////////////
-
-CircleShapeCache::CircleShapeCache(): ShapeCache<CircleShapeCacheEntry>(
- "circle", PROPERTY_SHAPE_CACHE_SIZE, DEFAULT_SHAPE_CACHE_SIZE) {
-}
-
-PathTexture* CircleShapeCache::getCircle(float radius, SkPaint* paint) {
- CircleShapeCacheEntry entry(radius, paint);
- PathTexture* texture = get(entry);
-
- if (!texture) {
- SkPath path;
- path.addCircle(radius, radius, radius, SkPath::kCW_Direction);
-
- texture = addTexture(entry, &path, paint);
- }
-
- return texture;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Ovals
-///////////////////////////////////////////////////////////////////////////////
-
-OvalShapeCache::OvalShapeCache(): ShapeCache<OvalShapeCacheEntry>(
- "oval", PROPERTY_SHAPE_CACHE_SIZE, DEFAULT_SHAPE_CACHE_SIZE) {
-}
-
-PathTexture* OvalShapeCache::getOval(float width, float height, SkPaint* paint) {
- OvalShapeCacheEntry entry(width, height, paint);
- PathTexture* texture = get(entry);
-
- if (!texture) {
- SkPath path;
- SkRect r;
- r.set(0.0f, 0.0f, width, height);
- path.addOval(r, SkPath::kCW_Direction);
-
- texture = addTexture(entry, &path, paint);
- }
-
- return texture;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Rects
-///////////////////////////////////////////////////////////////////////////////
-
-RectShapeCache::RectShapeCache(): ShapeCache<RectShapeCacheEntry>(
- "rect", PROPERTY_SHAPE_CACHE_SIZE, DEFAULT_SHAPE_CACHE_SIZE) {
-}
-
-PathTexture* RectShapeCache::getRect(float width, float height, SkPaint* paint) {
- RectShapeCacheEntry entry(width, height, paint);
- PathTexture* texture = get(entry);
-
- if (!texture) {
- SkRect bounds;
- bounds.set(0.0f, 0.0f, width, height);
-
- float left, top, offset;
- uint32_t rectWidth, rectHeight;
- computeBounds(bounds, paint, left, top, offset, rectWidth, rectHeight);
-
- if (!checkTextureSize(rectWidth, rectHeight)) return NULL;
-
- purgeCache(rectWidth, rectHeight);
-
- SkBitmap bitmap;
- initBitmap(bitmap, rectWidth, rectHeight);
-
- SkPaint pathPaint(*paint);
- initPaint(pathPaint);
-
- SkCanvas canvas(bitmap);
- canvas.translate(-left + offset, -top + offset);
- canvas.drawRect(bounds, pathPaint);
-
- texture = createTexture(0, 0, offset, rectWidth, rectHeight, 0);
- addTexture(entry, &bitmap, texture);
- }
-
- return texture;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Arcs
-///////////////////////////////////////////////////////////////////////////////
-
-ArcShapeCache::ArcShapeCache(): ShapeCache<ArcShapeCacheEntry>(
- "arc", PROPERTY_SHAPE_CACHE_SIZE, DEFAULT_SHAPE_CACHE_SIZE) {
-}
-
-PathTexture* ArcShapeCache::getArc(float width, float height,
- float startAngle, float sweepAngle, bool useCenter, SkPaint* paint) {
- ArcShapeCacheEntry entry(width, height, startAngle, sweepAngle, useCenter, paint);
- PathTexture* texture = get(entry);
-
- if (!texture) {
- SkPath path;
- SkRect r;
- r.set(0.0f, 0.0f, width, height);
- if (useCenter) {
- path.moveTo(r.centerX(), r.centerY());
- }
- path.arcTo(r, startAngle, sweepAngle, !useCenter);
- if (useCenter) {
- path.close();
- }
-
- texture = addTexture(entry, &path, paint);
- }
-
- return texture;
-}
-
-}; // namespace uirenderer
-}; // namespace android
diff --git a/libs/hwui/ShapeCache.h b/libs/hwui/ShapeCache.h
deleted file mode 100644
index 92314b029520..000000000000
--- a/libs/hwui/ShapeCache.h
+++ /dev/null
@@ -1,816 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef ANDROID_HWUI_SHAPE_CACHE_H
-#define ANDROID_HWUI_SHAPE_CACHE_H
-
-#define ATRACE_TAG ATRACE_TAG_VIEW
-
-#include <GLES2/gl2.h>
-
-#include <SkBitmap.h>
-#include <SkCanvas.h>
-#include <SkPaint.h>
-#include <SkPath.h>
-#include <SkRect.h>
-
-#include <utils/JenkinsHash.h>
-#include <utils/LruCache.h>
-#include <utils/Trace.h>
-
-#include "Debug.h"
-#include "Properties.h"
-#include "Texture.h"
-#include "thread/Task.h"
-
-namespace android {
-namespace uirenderer {
-
-///////////////////////////////////////////////////////////////////////////////
-// Defines
-///////////////////////////////////////////////////////////////////////////////
-
-// Debug
-#if DEBUG_SHAPES
- #define SHAPE_LOGD(...) ALOGD(__VA_ARGS__)
-#else
- #define SHAPE_LOGD(...)
-#endif
-
-///////////////////////////////////////////////////////////////////////////////
-// Classes
-///////////////////////////////////////////////////////////////////////////////
-
-/**
- * Alpha texture used to represent a path.
- */
-struct PathTexture: public Texture {
- PathTexture(): Texture() {
- }
-
- ~PathTexture() {
- clearTask();
- }
-
- /**
- * Left coordinate of the path bounds.
- */
- float left;
- /**
- * Top coordinate of the path bounds.
- */
- float top;
- /**
- * Offset to draw the path at the correct origin.
- */
- float offset;
-
- sp<Task<SkBitmap*> > task() const {
- return mTask;
- }
-
- void setTask(const sp<Task<SkBitmap*> >& task) {
- mTask = task;
- }
-
- void clearTask() {
- if (mTask != NULL) {
- mTask.clear();
- }
- }
-
-private:
- sp<Task<SkBitmap*> > mTask;
-}; // struct PathTexture
-
-/**
- * Describe a shape in the shape cache.
- */
-struct ShapeCacheEntry {
- enum ShapeType {
- kShapeNone,
- kShapeRect,
- kShapeRoundRect,
- kShapeCircle,
- kShapeOval,
- kShapeArc,
- kShapePath
- };
-
- ShapeCacheEntry() {
- shapeType = kShapeNone;
- join = SkPaint::kDefault_Join;
- cap = SkPaint::kDefault_Cap;
- style = SkPaint::kFill_Style;
- miter = 4.0f;
- strokeWidth = 1.0f;
- pathEffect = NULL;
- }
-
- ShapeCacheEntry(ShapeType type, SkPaint* paint) {
- shapeType = type;
- join = paint->getStrokeJoin();
- cap = paint->getStrokeCap();
- miter = paint->getStrokeMiter();
- strokeWidth = paint->getStrokeWidth();
- style = paint->getStyle();
- pathEffect = paint->getPathEffect();
- }
-
- virtual ~ShapeCacheEntry() {
- }
-
- virtual hash_t hash() const {
- uint32_t hash = JenkinsHashMix(0, shapeType);
- hash = JenkinsHashMix(hash, join);
- hash = JenkinsHashMix(hash, cap);
- hash = JenkinsHashMix(hash, style);
- hash = JenkinsHashMix(hash, android::hash_type(miter));
- hash = JenkinsHashMix(hash, android::hash_type(strokeWidth));
- hash = JenkinsHashMix(hash, android::hash_type(pathEffect));
- return JenkinsHashWhiten(hash);
- }
-
- virtual int compare(const ShapeCacheEntry& rhs) const {
- int deltaInt = shapeType - rhs.shapeType;
- if (deltaInt != 0) return deltaInt;
-
- deltaInt = join - rhs.join;
- if (deltaInt != 0) return deltaInt;
-
- deltaInt = cap - rhs.cap;
- if (deltaInt != 0) return deltaInt;
-
- deltaInt = style - rhs.style;
- if (deltaInt != 0) return deltaInt;
-
- if (miter < rhs.miter) return -1;
- if (miter > rhs.miter) return +1;
-
- if (strokeWidth < rhs.strokeWidth) return -1;
- if (strokeWidth > rhs.strokeWidth) return +1;
-
- if (pathEffect < rhs.pathEffect) return -1;
- if (pathEffect > rhs.pathEffect) return +1;
-
- return 0;
- }
-
- bool operator==(const ShapeCacheEntry& other) const {
- return compare(other) == 0;
- }
-
- bool operator!=(const ShapeCacheEntry& other) const {
- return compare(other) != 0;
- }
-
- ShapeType shapeType;
- SkPaint::Join join;
- SkPaint::Cap cap;
- SkPaint::Style style;
- float miter;
- float strokeWidth;
- SkPathEffect* pathEffect;
-}; // struct ShapeCacheEntry
-
-// Cache support
-
-inline int strictly_order_type(const ShapeCacheEntry& lhs, const ShapeCacheEntry& rhs) {
- return lhs.compare(rhs) < 0;
-}
-
-inline int compare_type(const ShapeCacheEntry& lhs, const ShapeCacheEntry& rhs) {
- return lhs.compare(rhs);
-}
-
-inline hash_t hash_type(const ShapeCacheEntry& entry) {
- return entry.hash();
-}
-
-struct RoundRectShapeCacheEntry: public ShapeCacheEntry {
- RoundRectShapeCacheEntry(float width, float height, float rx, float ry, SkPaint* paint):
- ShapeCacheEntry(ShapeCacheEntry::kShapeRoundRect, paint) {
- mWidth = width;
- mHeight = height;
- mRx = rx;
- mRy = ry;
- }
-
- RoundRectShapeCacheEntry(): ShapeCacheEntry() {
- mWidth = 0;
- mHeight = 0;
- mRx = 0;
- mRy = 0;
- }
-
- hash_t hash() const {
- uint32_t hash = ShapeCacheEntry::hash();
- hash = JenkinsHashMix(hash, android::hash_type(mWidth));
- hash = JenkinsHashMix(hash, android::hash_type(mHeight));
- hash = JenkinsHashMix(hash, android::hash_type(mRx));
- hash = JenkinsHashMix(hash, android::hash_type(mRy));
- return JenkinsHashWhiten(hash);
- }
-
- int compare(const ShapeCacheEntry& r) const {
- int deltaInt = ShapeCacheEntry::compare(r);
- if (deltaInt != 0) return deltaInt;
-
- const RoundRectShapeCacheEntry& rhs = (const RoundRectShapeCacheEntry&) r;
-
- if (mWidth < rhs.mWidth) return -1;
- if (mWidth > rhs.mWidth) return +1;
-
- if (mHeight < rhs.mHeight) return -1;
- if (mHeight > rhs.mHeight) return +1;
-
- if (mRx < rhs.mRx) return -1;
- if (mRx > rhs.mRx) return +1;
-
- if (mRy < rhs.mRy) return -1;
- if (mRy > rhs.mRy) return +1;
-
- return 0;
- }
-
-private:
- float mWidth;
- float mHeight;
- float mRx;
- float mRy;
-}; // RoundRectShapeCacheEntry
-
-inline hash_t hash_type(const RoundRectShapeCacheEntry& entry) {
- return entry.hash();
-}
-
-struct CircleShapeCacheEntry: public ShapeCacheEntry {
- CircleShapeCacheEntry(float radius, SkPaint* paint):
- ShapeCacheEntry(ShapeCacheEntry::kShapeCircle, paint) {
- mRadius = radius;
- }
-
- CircleShapeCacheEntry(): ShapeCacheEntry() {
- mRadius = 0;
- }
-
- hash_t hash() const {
- uint32_t hash = ShapeCacheEntry::hash();
- hash = JenkinsHashMix(hash, android::hash_type(mRadius));
- return JenkinsHashWhiten(hash);
- }
-
- int compare(const ShapeCacheEntry& r) const {
- int deltaInt = ShapeCacheEntry::compare(r);
- if (deltaInt != 0) return deltaInt;
-
- const CircleShapeCacheEntry& rhs = (const CircleShapeCacheEntry&) r;
-
- if (mRadius < rhs.mRadius) return -1;
- if (mRadius > rhs.mRadius) return +1;
-
- return 0;
- }
-
-private:
- float mRadius;
-}; // CircleShapeCacheEntry
-
-inline hash_t hash_type(const CircleShapeCacheEntry& entry) {
- return entry.hash();
-}
-
-struct OvalShapeCacheEntry: public ShapeCacheEntry {
- OvalShapeCacheEntry(float width, float height, SkPaint* paint):
- ShapeCacheEntry(ShapeCacheEntry::kShapeOval, paint) {
- mWidth = width;
- mHeight = height;
- }
-
- OvalShapeCacheEntry(): ShapeCacheEntry() {
- mWidth = mHeight = 0;
- }
-
- hash_t hash() const {
- uint32_t hash = ShapeCacheEntry::hash();
- hash = JenkinsHashMix(hash, android::hash_type(mWidth));
- hash = JenkinsHashMix(hash, android::hash_type(mHeight));
- return JenkinsHashWhiten(hash);
- }
-
- int compare(const ShapeCacheEntry& r) const {
- int deltaInt = ShapeCacheEntry::compare(r);
- if (deltaInt != 0) return deltaInt;
-
- const OvalShapeCacheEntry& rhs = (const OvalShapeCacheEntry&) r;
-
- if (mWidth < rhs.mWidth) return -1;
- if (mWidth > rhs.mWidth) return +1;
-
- if (mHeight < rhs.mHeight) return -1;
- if (mHeight > rhs.mHeight) return +1;
-
- return 0;
- }
-
-private:
- float mWidth;
- float mHeight;
-}; // OvalShapeCacheEntry
-
-inline hash_t hash_type(const OvalShapeCacheEntry& entry) {
- return entry.hash();
-}
-
-struct RectShapeCacheEntry: public ShapeCacheEntry {
- RectShapeCacheEntry(float width, float height, SkPaint* paint):
- ShapeCacheEntry(ShapeCacheEntry::kShapeRect, paint) {
- mWidth = width;
- mHeight = height;
- }
-
- RectShapeCacheEntry(): ShapeCacheEntry() {
- mWidth = mHeight = 0;
- }
-
- hash_t hash() const {
- uint32_t hash = ShapeCacheEntry::hash();
- hash = JenkinsHashMix(hash, android::hash_type(mWidth));
- hash = JenkinsHashMix(hash, android::hash_type(mHeight));
- return JenkinsHashWhiten(hash);
- }
-
- int compare(const ShapeCacheEntry& r) const {
- int deltaInt = ShapeCacheEntry::compare(r);
- if (deltaInt != 0) return deltaInt;
-
- const RectShapeCacheEntry& rhs = (const RectShapeCacheEntry&) r;
-
- if (mWidth < rhs.mWidth) return -1;
- if (mWidth > rhs.mWidth) return +1;
-
- if (mHeight < rhs.mHeight) return -1;
- if (mHeight > rhs.mHeight) return +1;
-
- return 0;
- }
-
-private:
- float mWidth;
- float mHeight;
-}; // RectShapeCacheEntry
-
-inline hash_t hash_type(const RectShapeCacheEntry& entry) {
- return entry.hash();
-}
-
-struct ArcShapeCacheEntry: public ShapeCacheEntry {
- ArcShapeCacheEntry(float width, float height, float startAngle, float sweepAngle,
- bool useCenter, SkPaint* paint):
- ShapeCacheEntry(ShapeCacheEntry::kShapeArc, paint) {
- mWidth = width;
- mHeight = height;
- mStartAngle = startAngle;
- mSweepAngle = sweepAngle;
- mUseCenter = useCenter ? 1 : 0;
- }
-
- ArcShapeCacheEntry(): ShapeCacheEntry() {
- mWidth = 0;
- mHeight = 0;
- mStartAngle = 0;
- mSweepAngle = 0;
- mUseCenter = 0;
- }
-
- hash_t hash() const {
- uint32_t hash = ShapeCacheEntry::hash();
- hash = JenkinsHashMix(hash, android::hash_type(mWidth));
- hash = JenkinsHashMix(hash, android::hash_type(mHeight));
- hash = JenkinsHashMix(hash, android::hash_type(mStartAngle));
- hash = JenkinsHashMix(hash, android::hash_type(mSweepAngle));
- hash = JenkinsHashMix(hash, mUseCenter);
- return JenkinsHashWhiten(hash);
- }
-
- int compare(const ShapeCacheEntry& r) const {
- int deltaInt = ShapeCacheEntry::compare(r);
- if (deltaInt != 0) return deltaInt;
-
- const ArcShapeCacheEntry& rhs = (const ArcShapeCacheEntry&) r;
-
- if (mWidth < rhs.mWidth) return -1;
- if (mWidth > rhs.mWidth) return +1;
-
- if (mHeight < rhs.mHeight) return -1;
- if (mHeight > rhs.mHeight) return +1;
-
- if (mStartAngle < rhs.mStartAngle) return -1;
- if (mStartAngle > rhs.mStartAngle) return +1;
-
- if (mSweepAngle < rhs.mSweepAngle) return -1;
- if (mSweepAngle > rhs.mSweepAngle) return +1;
-
- return mUseCenter - rhs.mUseCenter;
- }
-
-private:
- float mWidth;
- float mHeight;
- float mStartAngle;
- float mSweepAngle;
- uint32_t mUseCenter;
-}; // ArcShapeCacheEntry
-
-inline hash_t hash_type(const ArcShapeCacheEntry& entry) {
- return entry.hash();
-}
-
-/**
- * A simple LRU shape cache. The cache has a maximum size expressed in bytes.
- * Any texture added to the cache causing the cache to grow beyond the maximum
- * allowed size will also cause the oldest texture to be kicked out.
- */
-template<typename Entry>
-class ShapeCache: public OnEntryRemoved<Entry, PathTexture*> {
-public:
- ShapeCache(const char* name, const char* propertyName, float defaultSize);
- ~ShapeCache();
-
- /**
- * Used as a callback when an entry is removed from the cache.
- * Do not invoke directly.
- */
- void operator()(Entry& path, PathTexture*& texture);
-
- /**
- * Clears the cache. This causes all textures to be deleted.
- */
- void clear();
-
- /**
- * Sets the maximum size of the cache in bytes.
- */
- void setMaxSize(uint32_t maxSize);
- /**
- * Returns the maximum size of the cache in bytes.
- */
- uint32_t getMaxSize();
- /**
- * Returns the current size of the cache in bytes.
- */
- uint32_t getSize();
-
- /**
- * Trims the contents of the cache, removing items until it's under its
- * specified limit.
- *
- * Trimming is used for caches that support pre-caching from a worker
- * thread. During pre-caching the maximum limit of the cache can be
- * exceeded for the duration of the frame. It is therefore required to
- * trim the cache at the end of the frame to keep the total amount of
- * memory used under control.
- *
- * Only the PathCache currently supports pre-caching.
- */
- void trim();
-
- static void computePathBounds(const SkPath* path, const SkPaint* paint,
- float& left, float& top, float& offset, uint32_t& width, uint32_t& height) {
- const SkRect& bounds = path->getBounds();
- computeBounds(bounds, paint, left, top, offset, width, height);
- }
-
- static void computeBounds(const SkRect& bounds, const SkPaint* paint,
- float& left, float& top, float& offset, uint32_t& width, uint32_t& height) {
- const float pathWidth = fmax(bounds.width(), 1.0f);
- const float pathHeight = fmax(bounds.height(), 1.0f);
-
- left = bounds.fLeft;
- top = bounds.fTop;
-
- offset = (int) floorf(fmax(paint->getStrokeWidth(), 1.0f) * 1.5f + 0.5f);
-
- width = uint32_t(pathWidth + offset * 2.0 + 0.5);
- height = uint32_t(pathHeight + offset * 2.0 + 0.5);
- }
-
- static void drawPath(const SkPath *path, const SkPaint* paint, SkBitmap& bitmap,
- float left, float top, float offset, uint32_t width, uint32_t height) {
- initBitmap(bitmap, width, height);
-
- SkPaint pathPaint(*paint);
- initPaint(pathPaint);
-
- SkCanvas canvas(bitmap);
- canvas.translate(-left + offset, -top + offset);
- canvas.drawPath(*path, pathPaint);
- }
-
-protected:
- PathTexture* addTexture(const Entry& entry, const SkPath *path, const SkPaint* paint);
- PathTexture* addTexture(const Entry& entry, SkBitmap* bitmap);
- void addTexture(const Entry& entry, SkBitmap* bitmap, PathTexture* texture);
-
- /**
- * Ensures there is enough space in the cache for a texture of the specified
- * dimensions.
- */
- void purgeCache(uint32_t width, uint32_t height);
-
- PathTexture* get(Entry entry) {
- return mCache.get(entry);
- }
-
- void removeTexture(PathTexture* texture);
-
- bool checkTextureSize(uint32_t width, uint32_t height) {
- if (width > mMaxTextureSize || height > mMaxTextureSize) {
- ALOGW("Shape %s too large to be rendered into a texture (%dx%d, max=%dx%d)",
- mName, width, height, mMaxTextureSize, mMaxTextureSize);
- return false;
- }
- return true;
- }
-
- static PathTexture* createTexture(float left, float top, float offset,
- uint32_t width, uint32_t height, uint32_t id) {
- PathTexture* texture = new PathTexture();
- texture->left = left;
- texture->top = top;
- texture->offset = offset;
- texture->width = width;
- texture->height = height;
- texture->generation = id;
- return texture;
- }
-
- static void initBitmap(SkBitmap& bitmap, uint32_t width, uint32_t height) {
- bitmap.setConfig(SkBitmap::kA8_Config, width, height);
- bitmap.allocPixels();
- bitmap.eraseColor(0);
- }
-
- static void initPaint(SkPaint& paint) {
- // Make sure the paint is opaque, color, alpha, filter, etc.
- // will be applied later when compositing the alpha8 texture
- paint.setColor(0xff000000);
- paint.setAlpha(255);
- paint.setColorFilter(NULL);
- paint.setMaskFilter(NULL);
- paint.setShader(NULL);
- SkXfermode* mode = SkXfermode::Create(SkXfermode::kSrc_Mode);
- SkSafeUnref(paint.setXfermode(mode));
- }
-
- LruCache<Entry, PathTexture*> mCache;
- uint32_t mSize;
- uint32_t mMaxSize;
- GLuint mMaxTextureSize;
-
- char* mName;
- bool mDebugEnabled;
-
-private:
- /**
- * Generates the texture from a bitmap into the specified texture structure.
- */
- void generateTexture(SkBitmap& bitmap, Texture* texture);
-
- void init();
-}; // class ShapeCache
-
-class RoundRectShapeCache: public ShapeCache<RoundRectShapeCacheEntry> {
-public:
- RoundRectShapeCache();
-
- PathTexture* getRoundRect(float width, float height, float rx, float ry, SkPaint* paint);
-}; // class RoundRectShapeCache
-
-class CircleShapeCache: public ShapeCache<CircleShapeCacheEntry> {
-public:
- CircleShapeCache();
-
- PathTexture* getCircle(float radius, SkPaint* paint);
-}; // class CircleShapeCache
-
-class OvalShapeCache: public ShapeCache<OvalShapeCacheEntry> {
-public:
- OvalShapeCache();
-
- PathTexture* getOval(float width, float height, SkPaint* paint);
-}; // class OvalShapeCache
-
-class RectShapeCache: public ShapeCache<RectShapeCacheEntry> {
-public:
- RectShapeCache();
-
- PathTexture* getRect(float width, float height, SkPaint* paint);
-}; // class RectShapeCache
-
-class ArcShapeCache: public ShapeCache<ArcShapeCacheEntry> {
-public:
- ArcShapeCache();
-
- PathTexture* getArc(float width, float height, float startAngle, float sweepAngle,
- bool useCenter, SkPaint* paint);
-}; // class ArcShapeCache
-
-///////////////////////////////////////////////////////////////////////////////
-// Constructors/destructor
-///////////////////////////////////////////////////////////////////////////////
-
-template<class Entry>
-ShapeCache<Entry>::ShapeCache(const char* name, const char* propertyName, float defaultSize):
- mCache(LruCache<ShapeCacheEntry, PathTexture*>::kUnlimitedCapacity),
- mSize(0), mMaxSize(MB(defaultSize)) {
- char property[PROPERTY_VALUE_MAX];
- if (property_get(propertyName, property, NULL) > 0) {
- INIT_LOGD(" Setting %s cache size to %sMB", name, property);
- setMaxSize(MB(atof(property)));
- } else {
- INIT_LOGD(" Using default %s cache size of %.2fMB", name, defaultSize);
- }
-
- size_t len = strlen(name);
- mName = new char[len + 1];
- strcpy(mName, name);
- mName[len] = '\0';
-
- init();
-}
-
-template<class Entry>
-ShapeCache<Entry>::~ShapeCache() {
- mCache.clear();
- delete[] mName;
-}
-
-template<class Entry>
-void ShapeCache<Entry>::init() {
- mCache.setOnEntryRemovedListener(this);
-
- GLint maxTextureSize;
- glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
- mMaxTextureSize = maxTextureSize;
-
- mDebugEnabled = readDebugLevel() & kDebugCaches;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Size management
-///////////////////////////////////////////////////////////////////////////////
-
-template<class Entry>
-uint32_t ShapeCache<Entry>::getSize() {
- return mSize;
-}
-
-template<class Entry>
-uint32_t ShapeCache<Entry>::getMaxSize() {
- return mMaxSize;
-}
-
-template<class Entry>
-void ShapeCache<Entry>::setMaxSize(uint32_t maxSize) {
- mMaxSize = maxSize;
- while (mSize > mMaxSize) {
- mCache.removeOldest();
- }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Callbacks
-///////////////////////////////////////////////////////////////////////////////
-
-template<class Entry>
-void ShapeCache<Entry>::operator()(Entry& path, PathTexture*& texture) {
- removeTexture(texture);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Caching
-///////////////////////////////////////////////////////////////////////////////
-
-template<class Entry>
-void ShapeCache<Entry>::removeTexture(PathTexture* texture) {
- if (texture) {
- const uint32_t size = texture->width * texture->height;
- mSize -= size;
-
- SHAPE_LOGD("ShapeCache::callback: delete %s: name, size, mSize = %d, %d, %d",
- mName, texture->id, size, mSize);
- if (mDebugEnabled) {
- ALOGD("Shape %s deleted, size = %d", mName, size);
- }
-
- if (texture->id) {
- glDeleteTextures(1, &texture->id);
- }
- delete texture;
- }
-}
-
-template<class Entry>
-void ShapeCache<Entry>::purgeCache(uint32_t width, uint32_t height) {
- const uint32_t size = width * height;
- // Don't even try to cache a bitmap that's bigger than the cache
- if (size < mMaxSize) {
- while (mSize + size > mMaxSize) {
- mCache.removeOldest();
- }
- }
-}
-
-template<class Entry>
-void ShapeCache<Entry>::trim() {
- while (mSize > mMaxSize) {
- mCache.removeOldest();
- }
-}
-
-template<class Entry>
-PathTexture* ShapeCache<Entry>::addTexture(const Entry& entry, const SkPath *path,
- const SkPaint* paint) {
- ATRACE_CALL();
-
- float left, top, offset;
- uint32_t width, height;
- computePathBounds(path, paint, left, top, offset, width, height);
-
- if (!checkTextureSize(width, height)) return NULL;
-
- purgeCache(width, height);
-
- SkBitmap bitmap;
- drawPath(path, paint, bitmap, left, top, offset, width, height);
-
- PathTexture* texture = createTexture(left, top, offset, width, height,
- path->getGenerationID());
- addTexture(entry, &bitmap, texture);
-
- return texture;
-}
-
-template<class Entry>
-void ShapeCache<Entry>::addTexture(const Entry& entry, SkBitmap* bitmap, PathTexture* texture) {
- generateTexture(*bitmap, texture);
-
- uint32_t size = texture->width * texture->height;
- if (size < mMaxSize) {
- mSize += size;
- SHAPE_LOGD("ShapeCache::get: create %s: name, size, mSize = %d, %d, %d",
- mName, texture->id, size, mSize);
- if (mDebugEnabled) {
- ALOGD("Shape %s created, size = %d", mName, size);
- }
- mCache.put(entry, texture);
- } else {
- texture->cleanup = true;
- }
-}
-
-template<class Entry>
-void ShapeCache<Entry>::clear() {
- mCache.clear();
-}
-
-template<class Entry>
-void ShapeCache<Entry>::generateTexture(SkBitmap& bitmap, Texture* texture) {
- SkAutoLockPixels alp(bitmap);
- if (!bitmap.readyToDraw()) {
- ALOGE("Cannot generate texture from bitmap");
- return;
- }
-
- glGenTextures(1, &texture->id);
-
- glBindTexture(GL_TEXTURE_2D, texture->id);
- // Textures are Alpha8
- glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
-
- texture->blend = true;
- glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, texture->width, texture->height, 0,
- GL_ALPHA, GL_UNSIGNED_BYTE, bitmap.getPixels());
-
- texture->setFilter(GL_LINEAR);
- texture->setWrap(GL_CLAMP_TO_EDGE);
-}
-
-}; // namespace uirenderer
-}; // namespace android
-
-#endif // ANDROID_HWUI_SHAPE_CACHE_H
diff --git a/libs/hwui/SkiaShader.cpp b/libs/hwui/SkiaShader.cpp
index 9013fd5f9fed..c38eedbcf654 100644
--- a/libs/hwui/SkiaShader.cpp
+++ b/libs/hwui/SkiaShader.cpp
@@ -411,8 +411,14 @@ void SkiaComposeShader::describe(ProgramDescription& description, const Extensio
void SkiaComposeShader::setupProgram(Program* program, const mat4& modelView,
const Snapshot& snapshot, GLuint* textureUnit) {
- mFirst->setupProgram(program, modelView, snapshot, textureUnit);
- mSecond->setupProgram(program, modelView, snapshot, textureUnit);
+ // Apply this compose shader's local transform and pass it down to
+ // the child shaders. They will in turn apply their local transform
+ // to this matrix.
+ mat4 transform;
+ computeScreenSpaceMatrix(transform, modelView);
+
+ mFirst->setupProgram(program, transform, snapshot, textureUnit);
+ mSecond->setupProgram(program, transform, snapshot, textureUnit);
}
}; // namespace uirenderer
diff --git a/libs/hwui/font/FontUtil.h b/libs/hwui/font/FontUtil.h
index 4f9c46be35a9..f758666c1fc8 100644
--- a/libs/hwui/font/FontUtil.h
+++ b/libs/hwui/font/FontUtil.h
@@ -26,7 +26,7 @@
///////////////////////////////////////////////////////////////////////////////
#define DEFAULT_TEXT_SMALL_CACHE_WIDTH 1024
-#define DEFAULT_TEXT_SMALL_CACHE_HEIGHT 256
+#define DEFAULT_TEXT_SMALL_CACHE_HEIGHT 512
#define DEFAULT_TEXT_LARGE_CACHE_WIDTH 2048
#define DEFAULT_TEXT_LARGE_CACHE_HEIGHT 512
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index 328b503e759d..a45c0ff6f91e 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -3931,7 +3931,7 @@ class BackupManagerService extends IBackupManager.Stub {
b.append(String.format(" %9d ", info.size));
Date stamp = new Date(info.mtime);
- b.append(new SimpleDateFormat("MMM dd kk:mm:ss ").format(stamp));
+ b.append(new SimpleDateFormat("MMM dd HH:mm:ss ").format(stamp));
b.append(info.packageName);
b.append(" :: ");
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 2d12a774bdaf..09d1426b29eb 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -5077,7 +5077,7 @@ public class PackageManagerService extends IPackageManager.Stub {
final int N = pkg.requestedPermissions.size();
for (int i=0; i<N; i++) {
final String name = pkg.requestedPermissions.get(i);
- //final boolean required = pkg.requestedPermssionsRequired.get(i);
+ final boolean required = pkg.requestedPermissionsRequired.get(i);
final BasePermission bp = mSettings.mPermissions.get(name);
if (DEBUG_INSTALL) {
if (gp != ps) {
@@ -5091,7 +5091,9 @@ public class PackageManagerService extends IPackageManager.Stub {
final int level = bp.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE;
if (level == PermissionInfo.PROTECTION_NORMAL
|| level == PermissionInfo.PROTECTION_DANGEROUS) {
- allowed = true;
+ // If the permission is required, or it's optional and was previously
+ // granted to the application, then allow it. Otherwise deny.
+ allowed = (required || origPermissions.contains(perm));
} else if (bp.packageSetting == null) {
// This permission is invalid; skip it.
allowed = false;
@@ -5141,11 +5143,7 @@ public class PackageManagerService extends IPackageManager.Stub {
& PermissionInfo.PROTECTION_FLAG_DEVELOPMENT) != 0) {
// For development permissions, a development permission
// is granted only if it was already granted.
- if (origPermissions.contains(perm)) {
- allowed = true;
- } else {
- allowed = false;
- }
+ allowed = origPermissions.contains(perm);
}
if (allowed) {
allowedSig = true;
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index cfefadd53432..56f4de5ed152 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -1481,7 +1481,11 @@ public class WindowManagerService extends IWindowManager.Stub
pos++;
}
if (pos >= N) {
- // All is good!
+ // Z order is good.
+ // The IM target window may be changed, so update the mTargetAppToken.
+ if (imWin != null) {
+ imWin.mTargetAppToken = mInputMethodTarget.mAppToken;
+ }
return false;
}
}
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/MoreShadersActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/MoreShadersActivity.java
index 02cb4b6a33ac..1847f43b7ea0 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/MoreShadersActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/MoreShadersActivity.java
@@ -57,6 +57,7 @@ public class MoreShadersActivity extends Activity {
private Paint mLargePaint;
private BitmapShader mScaled2Shader;
private ColorFilter mColorFilter;
+ private final Matrix mMtx1;
ShadersView(Context c) {
super(c);
@@ -70,7 +71,7 @@ public class MoreShadersActivity extends Activity {
mScaledShader = new BitmapShader(texture, Shader.TileMode.MIRROR,
Shader.TileMode.MIRROR);
Matrix m2 = new Matrix();
- m2.setScale(0.5f, 0.5f);
+ m2.setScale(0.1f, 0.1f);
mScaledShader.setLocalMatrix(m2);
mScaled2Shader = new BitmapShader(texture, Shader.TileMode.MIRROR,
@@ -81,12 +82,20 @@ public class MoreShadersActivity extends Activity {
mHorGradient = new LinearGradient(0.0f, 0.0f, mDrawWidth, 0.0f,
Color.RED, 0x7f00ff00, Shader.TileMode.CLAMP);
-
+ Matrix m4 = new Matrix();
+ m4.setScale(0.5f, 0.5f);
+ mHorGradient.setLocalMatrix(m4);
+
mVertGradient = new LinearGradient(0.0f, 0.0f, 0.0f, mDrawHeight / 2.0f,
Color.YELLOW, Color.MAGENTA, Shader.TileMode.MIRROR);
mComposeShader = new ComposeShader(mScaledShader, mHorGradient,
PorterDuff.Mode.SRC_OVER);
+ mMtx1 = new Matrix();
+ mMtx1.setTranslate(mTexWidth / 2.0f, mTexHeight / 2.0f);
+ mMtx1.postRotate(45, 0, 0);
+ mComposeShader.setLocalMatrix(mMtx1);
+
mCompose2Shader = new ComposeShader(mHorGradient, mScaledShader,
PorterDuff.Mode.SRC_OUT);
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ShapesActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ShapesActivity.java
index 97e55269b128..61dca784ce5e 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/ShapesActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ShapesActivity.java
@@ -20,6 +20,7 @@ import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
+import android.graphics.Path;
import android.graphics.RectF;
import android.os.Bundle;
import android.view.View;
@@ -34,12 +35,13 @@ public class ShapesActivity extends Activity {
}
static class ShapesView extends View {
- private Paint mNormalPaint;
- private Paint mStrokePaint;
- private Paint mFillPaint;
- private RectF mRect;
- private RectF mOval;
- private RectF mArc;
+ private final Paint mNormalPaint;
+ private final Paint mStrokePaint;
+ private final Paint mFillPaint;
+ private final RectF mRect;
+ private final RectF mOval;
+ private final RectF mArc;
+ private final Path mTriangle;
ShapesView(Context c) {
super(c);
@@ -65,6 +67,12 @@ public class ShapesActivity extends Activity {
mOval = new RectF(0.0f, 0.0f, 80.0f, 45.0f);
mArc = new RectF(0.0f, 0.0f, 100.0f, 120.0f);
+
+ mTriangle = new Path();
+ mTriangle.moveTo(0.0f, 90.0f);
+ mTriangle.lineTo(45.0f, 0.0f);
+ mTriangle.lineTo(90.0f, 90.0f);
+ mTriangle.close();
}
@Override
@@ -136,6 +144,17 @@ public class ShapesActivity extends Activity {
canvas.translate(0.0f, 110.0f);
canvas.drawArc(mArc, 30.0f, 100.0f, false, mFillPaint);
canvas.restore();
+
+ canvas.save();
+ canvas.translate(50.0f, 400.0f);
+ canvas.drawPath(mTriangle, mNormalPaint);
+
+ canvas.translate(110.0f, 0.0f);
+ canvas.drawPath(mTriangle, mStrokePaint);
+
+ canvas.translate(110.0f, 0.0f);
+ canvas.drawPath(mTriangle, mFillPaint);
+ canvas.restore();
}
}
}