Merge "Query users excluding any being removed" into jb-mr1-dev
diff --git a/api/current.txt b/api/current.txt
index b81a87b..2381732 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -27471,7 +27471,7 @@
method public void clearFormData();
method public void clearHttpAuthUsernamePassword();
method public void clearUsernamePassword();
- method public static synchronized android.webkit.WebViewDatabase getInstance(android.content.Context);
+ method public static android.webkit.WebViewDatabase getInstance(android.content.Context);
method public boolean hasFormData();
method public boolean hasHttpAuthUsernamePassword();
method public boolean hasUsernamePassword();
@@ -28958,6 +28958,7 @@
method public int describeContents();
method public int getLayoutId();
method public java.lang.String getPackage();
+ method public void mergeRemoteViews(android.widget.RemoteViews);
method public boolean onLoadClass(java.lang.Class);
method public void reapply(android.content.Context, android.view.View);
method public void removeAllViews(int);
diff --git a/core/java/android/app/Presentation.java b/core/java/android/app/Presentation.java
index eb5a652..b5e5244 100644
--- a/core/java/android/app/Presentation.java
+++ b/core/java/android/app/Presentation.java
@@ -32,24 +32,26 @@
/**
* Base class for presentations.
- *
+ * <p>
* A presentation is a special kind of dialog whose purpose is to present
* content on a secondary display. A {@link Presentation} is associated with
* the target {@link Display} at creation time and configures its context and
* resource configuration according to the display's metrics.
- *
+ * </p><p>
* Notably, the {@link Context} of a presentation is different from the context
* of its containing {@link Activity}. It is important to inflate the layout
* of a presentation and load other resources using the presentation's own context
* to ensure that assets of the correct size and density for the target display
* are loaded.
- *
+ * </p><p>
* A presentation is automatically canceled (see {@link Dialog#cancel()}) when
* the display to which it is attached is removed. An activity should take
* care of pausing and resuming whatever content is playing within the presentation
- * whenever the activity itself is paused or resume.
+ * whenever the activity itself is paused or resumed.
+ * </p>
*
- * @see {@link DisplayManager} for information on how to enumerate displays.
+ * @see DisplayManager for information on how to enumerate displays and receive
+ * notifications when displays are added or removed.
*/
public class Presentation extends Dialog {
private static final String TAG = "Presentation";
diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java
index 6fb6dc4..888955c 100644
--- a/core/java/android/appwidget/AppWidgetManager.java
+++ b/core/java/android/appwidget/AppWidgetManager.java
@@ -436,10 +436,9 @@
*
* This update differs from {@link #updateAppWidget(int[], RemoteViews)} in that the
* RemoteViews object which is passed is understood to be an incomplete representation of the
- * widget, and hence is not cached by the AppWidgetService. Note that because these updates are
- * not cached, any state that they modify that is not restored by restoreInstanceState will not
- * persist in the case that the widgets are restored using the cached version in
- * AppWidgetService.
+ * widget, and hence does not replace the cached representation of the widget. As of API
+ * level 17, the new properties set within the views objects will be appended to the cached
+ * representation of the widget, and hence will persist.
*
* Use with {@link RemoteViews#showNext(int)}, {@link RemoteViews#showPrevious(int)},
* {@link RemoteViews#setScrollPosition(int, int)} and similar commands.
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 87221e0..13de538 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -2773,14 +2773,14 @@
* {@hide}
*/
@ViewDebug.ExportedProperty(category = "padding")
- protected int mPaddingLeft;
+ protected int mPaddingLeft = UNDEFINED_PADDING;
/**
* The right padding in pixels, that is the distance in pixels between the
* right edge of this view and the right edge of its content.
* {@hide}
*/
@ViewDebug.ExportedProperty(category = "padding")
- protected int mPaddingRight;
+ protected int mPaddingRight = UNDEFINED_PADDING;
/**
* The top padding in pixels, that is the distance in pixels between the
* top edge of this view and the top edge of its content.
@@ -3620,9 +3620,10 @@
// (stored at this point in mPadding*)
mUserPaddingLeftInitial = leftPadding >= 0 ? leftPadding : mPaddingLeft;
mUserPaddingRightInitial = rightPadding >= 0 ? rightPadding : mPaddingRight;
- internalSetPadding(mUserPaddingLeftInitial,
+ internalSetPadding(
+ mUserPaddingLeftInitial != UNDEFINED_PADDING ? mUserPaddingLeftInitial : 0,
topPadding >= 0 ? topPadding : mPaddingTop,
- mUserPaddingRightInitial,
+ mUserPaddingRightInitial != UNDEFINED_PADDING ? mUserPaddingRightInitial : 0,
bottomPadding >= 0 ? bottomPadding : mPaddingBottom);
if (viewFlagMasks != 0) {
@@ -11597,8 +11598,8 @@
mUserPaddingStart != UNDEFINED_PADDING) {
mUserPaddingLeft = mUserPaddingStart;
}
- if (mUserPaddingRightInitial == UNDEFINED_PADDING
- && mUserPaddingEnd != UNDEFINED_PADDING) {
+ if (mUserPaddingRightInitial == UNDEFINED_PADDING &&
+ mUserPaddingEnd != UNDEFINED_PADDING) {
mUserPaddingRight = mUserPaddingEnd;
}
diff --git a/core/java/android/view/VolumePanel.java b/core/java/android/view/VolumePanel.java
index d6f63a7..8315bd7 100644
--- a/core/java/android/view/VolumePanel.java
+++ b/core/java/android/view/VolumePanel.java
@@ -214,6 +214,7 @@
private Vibrator mVibrator;
private static AlertDialog sConfirmSafeVolumeDialog;
+ private static Object sConfirmSafeVolumeLock = new Object();
private static class WarningDialogReceiver extends BroadcastReceiver
implements DialogInterface.OnDismissListener {
@@ -230,10 +231,16 @@
@Override
public void onReceive(Context context, Intent intent) {
mDialog.cancel();
+ synchronized (sConfirmSafeVolumeLock) {
+ sConfirmSafeVolumeDialog = null;
+ }
}
public void onDismiss(DialogInterface unused) {
mContext.unregisterReceiver(this);
+ synchronized (sConfirmSafeVolumeLock) {
+ sConfirmSafeVolumeDialog = null;
+ }
}
}
@@ -556,6 +563,7 @@
}
public void postDisplaySafeVolumeWarning() {
+ if (hasMessages(MSG_DISPLAY_SAFE_VOLUME_WARNING)) return;
obtainMessage(MSG_DISPLAY_SAFE_VOLUME_WARNING, 0, 0).sendToTarget();
}
@@ -828,28 +836,29 @@
}
protected void onDisplaySafeVolumeWarning() {
- if (sConfirmSafeVolumeDialog != null) {
- sConfirmSafeVolumeDialog.dismiss();
+ synchronized (sConfirmSafeVolumeLock) {
+ if (sConfirmSafeVolumeDialog != null) {
+ return;
+ }
+ sConfirmSafeVolumeDialog = new AlertDialog.Builder(mContext)
+ .setMessage(com.android.internal.R.string.safe_media_volume_warning)
+ .setPositiveButton(com.android.internal.R.string.yes,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ mAudioService.disableSafeMediaVolume();
+ }
+ })
+ .setNegativeButton(com.android.internal.R.string.no, null)
+ .setIconAttribute(android.R.attr.alertDialogIcon)
+ .create();
+ final WarningDialogReceiver warning = new WarningDialogReceiver(mContext,
+ sConfirmSafeVolumeDialog);
+
+ sConfirmSafeVolumeDialog.setOnDismissListener(warning);
+ sConfirmSafeVolumeDialog.getWindow().setType(
+ WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
+ sConfirmSafeVolumeDialog.show();
}
- sConfirmSafeVolumeDialog = new AlertDialog.Builder(mContext)
- .setMessage(com.android.internal.R.string.safe_media_volume_warning)
- .setPositiveButton(com.android.internal.R.string.yes,
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- mAudioService.disableSafeMediaVolume();
- }
- })
- .setNegativeButton(com.android.internal.R.string.no, null)
- .setIconAttribute(android.R.attr.alertDialogIcon)
- .create();
-
- final WarningDialogReceiver warning = new WarningDialogReceiver(mContext,
- sConfirmSafeVolumeDialog);
-
- sConfirmSafeVolumeDialog.setOnDismissListener(warning);
- sConfirmSafeVolumeDialog.getWindow().setType(
- WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
- sConfirmSafeVolumeDialog.show();
}
/**
diff --git a/core/java/android/webkit/WebViewDatabase.java b/core/java/android/webkit/WebViewDatabase.java
index 62ec0d5..5597259 100644
--- a/core/java/android/webkit/WebViewDatabase.java
+++ b/core/java/android/webkit/WebViewDatabase.java
@@ -40,7 +40,7 @@
protected WebViewDatabase() {
}
- public static synchronized WebViewDatabase getInstance(Context context) {
+ public static WebViewDatabase getInstance(Context context) {
return WebViewFactory.getProvider().getWebViewDatabase(context);
}
diff --git a/core/java/android/webkit/WebViewDatabaseClassic.java b/core/java/android/webkit/WebViewDatabaseClassic.java
index c804b90..be01028 100644
--- a/core/java/android/webkit/WebViewDatabaseClassic.java
+++ b/core/java/android/webkit/WebViewDatabaseClassic.java
@@ -52,6 +52,7 @@
// implemented for b/5265606.
private static WebViewDatabaseClassic sInstance = null;
+ private static final Object sInstanceLock = new Object();
private static SQLiteDatabase sDatabase = null;
@@ -99,7 +100,7 @@
// Initially true until the background thread completes.
private boolean mInitialized = false;
- WebViewDatabaseClassic(final Context context) {
+ private WebViewDatabaseClassic(final Context context) {
JniUtil.setContext(context);
new Thread() {
@Override
@@ -111,11 +112,13 @@
// Singleton only, use getInstance()
}
- public static synchronized WebViewDatabaseClassic getInstance(Context context) {
- if (sInstance == null) {
- sInstance = new WebViewDatabaseClassic(context);
+ public static WebViewDatabaseClassic getInstance(Context context) {
+ synchronized (sInstanceLock) {
+ if (sInstance == null) {
+ sInstance = new WebViewDatabaseClassic(context);
+ }
+ return sInstance;
}
- return sInstance;
}
private synchronized void init(Context context) {
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index 2fc9b39..b833a01 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -41,36 +41,39 @@
// Cache the factory both for efficiency, and ensure any one process gets all webviews from the
// same provider.
private static WebViewFactoryProvider sProviderInstance;
+ private static final Object sProviderLock = new Object();
- static synchronized WebViewFactoryProvider getProvider() {
- // For now the main purpose of this function (and the factory abstraction) is to keep
- // us honest and minimize usage of WebViewClassic internals when binding the proxy.
- if (sProviderInstance != null) return sProviderInstance;
+ static WebViewFactoryProvider getProvider() {
+ synchronized (sProviderLock) {
+ // For now the main purpose of this function (and the factory abstraction) is to keep
+ // us honest and minimize usage of WebViewClassic internals when binding the proxy.
+ if (sProviderInstance != null) return sProviderInstance;
- // For debug builds, we allow a system property to specify that we should use the
- // Chromium powered WebView. This enables us to switch between implementations
- // at runtime. For user (release) builds, don't allow this.
- if (Build.IS_DEBUGGABLE && SystemProperties.getBoolean("webview.use_chromium", false)) {
- StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
- try {
- sProviderInstance = loadChromiumProvider();
- if (DEBUG) Log.v(LOGTAG, "Loaded Chromium provider: " + sProviderInstance);
- } finally {
- StrictMode.setThreadPolicy(oldPolicy);
+ // For debug builds, we allow a system property to specify that we should use the
+ // Chromium powered WebView. This enables us to switch between implementations
+ // at runtime. For user (release) builds, don't allow this.
+ if (Build.IS_DEBUGGABLE && SystemProperties.getBoolean("webview.use_chromium", false)) {
+ StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
+ try {
+ sProviderInstance = loadChromiumProvider();
+ if (DEBUG) Log.v(LOGTAG, "Loaded Chromium provider: " + sProviderInstance);
+ } finally {
+ StrictMode.setThreadPolicy(oldPolicy);
+ }
}
- }
- if (sProviderInstance == null) {
- if (DEBUG) Log.v(LOGTAG, "Falling back to default provider: "
- + DEFAULT_WEBVIEW_FACTORY);
- sProviderInstance = getFactoryByName(DEFAULT_WEBVIEW_FACTORY,
- WebViewFactory.class.getClassLoader());
if (sProviderInstance == null) {
- if (DEBUG) Log.v(LOGTAG, "Falling back to explicit linkage");
- sProviderInstance = new WebViewClassic.Factory();
+ if (DEBUG) Log.v(LOGTAG, "Falling back to default provider: "
+ + DEFAULT_WEBVIEW_FACTORY);
+ sProviderInstance = getFactoryByName(DEFAULT_WEBVIEW_FACTORY,
+ WebViewFactory.class.getClassLoader());
+ if (sProviderInstance == null) {
+ if (DEBUG) Log.v(LOGTAG, "Falling back to explicit linkage");
+ sProviderInstance = new WebViewClassic.Factory();
+ }
}
+ return sProviderInstance;
}
- return sProviderInstance;
}
// TODO: This allows us to have the legacy and Chromium WebView coexist for development
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index c65a67b..87ef23f 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -52,6 +52,7 @@
import java.lang.annotation.Target;
import java.lang.reflect.Method;
import java.util.ArrayList;
+import java.util.HashMap;
/**
@@ -187,6 +188,10 @@
public abstract void apply(View root, ViewGroup rootParent,
OnClickHandler handler) throws ActionException;
+ public static final int MERGE_REPLACE = 0;
+ public static final int MERGE_APPEND = 1;
+ public static final int MERGE_IGNORE = 2;
+
public int describeContents() {
return 0;
}
@@ -203,6 +208,60 @@
public void setBitmapCache(BitmapCache bitmapCache) {
// Do nothing
}
+
+ public int mergeBehavior() {
+ return MERGE_REPLACE;
+ }
+
+ public abstract String getActionName();
+
+ public String getUniqueKey() {
+ return (getActionName() + viewId);
+ }
+
+ int viewId;
+ }
+
+ public void mergeRemoteViews(RemoteViews newRv) {
+ // We first copy the new RemoteViews, as the process of merging modifies the way the actions
+ // reference the bitmap cache. We don't want to modify the object as it may need to
+ // be merged and applied multiple times.
+ Parcel p = Parcel.obtain();
+ newRv.writeToParcel(p, 0);
+ RemoteViews copy = new RemoteViews(p);
+
+ HashMap<String, Action> map = new HashMap<String, Action>();
+ if (mActions == null) {
+ mActions = new ArrayList<Action>();
+ }
+
+ int count = mActions.size();
+ for (int i = 0; i < count; i++) {
+ Action a = mActions.get(i);
+ map.put(a.getUniqueKey(), a);
+ }
+
+ ArrayList<Action> newActions = copy.mActions;
+ if (newActions == null) return;
+ count = newActions.size();
+ for (int i = 0; i < count; i++) {
+ Action a = newActions.get(i);
+ String key = newActions.get(i).getUniqueKey();
+ int mergeBehavior = map.get(key).mergeBehavior();
+ if (map.containsKey(key) && mergeBehavior == Action.MERGE_REPLACE) {
+ mActions.remove(map.get(key));
+ map.remove(key);
+ }
+
+ // If the merge behavior is ignore, we don't bother keeping the extra action
+ if (mergeBehavior == Action.MERGE_REPLACE || mergeBehavior == Action.MERGE_APPEND) {
+ mActions.add(a);
+ }
+ }
+
+ // Because pruning can remove the need for bitmaps, we reconstruct the bitmap cache
+ mBitmapCache = new BitmapCache();
+ setBitmapCache(mBitmapCache);
}
private class SetEmptyView extends Action {
@@ -239,6 +298,10 @@
adapterView.setEmptyView(emptyView);
}
+
+ public String getActionName() {
+ return "SetEmptyView";
+ }
}
private class SetOnClickFillInIntent extends Action {
@@ -316,7 +379,10 @@
}
}
- int viewId;
+ public String getActionName() {
+ return "SetOnClickFillInIntent";
+ }
+
Intent fillInIntent;
public final static int TAG = 9;
@@ -399,7 +465,10 @@
}
}
- int viewId;
+ public String getActionName() {
+ return "SetPendingIntentTemplate";
+ }
+
PendingIntent pendingIntentTemplate;
public final static int TAG = 8;
@@ -453,7 +522,10 @@
}
}
- int viewId;
+ public String getActionName() {
+ return "SetRemoteViewsAdapterIntent";
+ }
+
Intent intent;
public final static int TAG = 10;
@@ -539,7 +611,10 @@
}
}
- int viewId;
+ public String getActionName() {
+ return "SetOnClickPendingIntent";
+ }
+
PendingIntent pendingIntent;
public final static int TAG = 1;
@@ -625,7 +700,10 @@
}
}
- int viewId;
+ public String getActionName() {
+ return "SetDrawableParameters";
+ }
+
boolean targetBackground;
int alpha;
int colorFilter;
@@ -636,7 +714,6 @@
}
private class ReflectionActionWithoutParams extends Action {
- int viewId;
String methodName;
public final static int TAG = 5;
@@ -688,6 +765,19 @@
throw new ActionException(ex);
}
}
+
+ public int mergeBehavior() {
+ // we don't need to build up showNext or showPrevious calls
+ if (methodName.equals("showNext") || methodName.equals("showPrevious")) {
+ return MERGE_IGNORE;
+ } else {
+ return MERGE_REPLACE;
+ }
+ }
+
+ public String getActionName() {
+ return "ReflectionActionWithoutParams";
+ }
}
private static class BitmapCache {
@@ -755,7 +845,6 @@
private class BitmapReflectionAction extends Action {
int bitmapId;
- int viewId;
Bitmap bitmap;
String methodName;
@@ -794,6 +883,10 @@
bitmapId = bitmapCache.getBitmapId(bitmap);
}
+ public String getActionName() {
+ return "BitmapReflectionAction";
+ }
+
public final static int TAG = 12;
}
@@ -814,11 +907,12 @@
static final int STRING = 9;
static final int CHAR_SEQUENCE = 10;
static final int URI = 11;
+ // BITMAP actions are never stored in the list of actions. They are only used locally
+ // to implement BitmapReflectionAction, which eliminates duplicates using BitmapCache.
static final int BITMAP = 12;
static final int BUNDLE = 13;
static final int INTENT = 14;
- int viewId;
String methodName;
int type;
Object value;
@@ -1041,20 +1135,20 @@
}
}
- @Override
- public void updateMemoryUsageEstimate(MemoryUsageCounter counter) {
- // We currently only calculate Bitmap memory usage
- switch (this.type) {
- case BITMAP:
- if (this.value != null) {
- final Bitmap b = (Bitmap) this.value;
- counter.addBitmapMemory(b);
- }
- break;
- default:
- break;
+ public int mergeBehavior() {
+ // smoothScrollBy is cumulative, everything else overwites.
+ if (methodName.equals("smoothScrollBy")) {
+ return MERGE_APPEND;
+ } else {
+ return MERGE_REPLACE;
}
}
+
+ public String getActionName() {
+ // Each type of reflection action corresponds to a setter, so each should be seen as
+ // unique from the standpoint of merging.
+ return "ReflectionAction" + this.methodName + this.type;
+ }
}
private void configureRemoteViewsAsChild(RemoteViews rv) {
@@ -1131,7 +1225,14 @@
}
}
- int viewId;
+ public String getActionName() {
+ return "ViewGroupAction" + this.nestedViews == null ? "Remove" : "Add";
+ }
+
+ public int mergeBehavior() {
+ return MERGE_APPEND;
+ }
+
RemoteViews nestedViews;
public final static int TAG = 4;
@@ -1182,7 +1283,10 @@
}
}
- int viewId;
+ public String getActionName() {
+ return "TextViewDrawableAction";
+ }
+
boolean isRelative = false;
int d1, d2, d3, d4;
@@ -1220,7 +1324,10 @@
target.setTextSize(units, size);
}
- int viewId;
+ public String getActionName() {
+ return "TextViewSizeAction";
+ }
+
int units;
float size;
@@ -1264,7 +1371,10 @@
target.setPadding(left, top, right, bottom);
}
- int viewId;
+ public String getActionName() {
+ return "ViewPaddingAction";
+ }
+
int left, top, right, bottom;
public final static int TAG = 14;
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 5f6042d..3ca085b 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -223,13 +223,6 @@
LOCAL_SHARED_LIBRARIES += libhwui
endif
-ifeq ($(BOARD_HAVE_BLUETOOTH),true)
-LOCAL_C_INCLUDES += \
- external/dbus \
- system/bluetooth/bluez-clean-headers
-LOCAL_CFLAGS += -DHAVE_BLUETOOTH
-endif
-
LOCAL_SHARED_LIBRARIES += \
libdl
# we need to access the private Bionic header
diff --git a/core/res/res/layout/time_picker.xml b/core/res/res/layout/time_picker.xml
index 3958fc6..a78cd85 100644
--- a/core/res/res/layout/time_picker.xml
+++ b/core/res/res/layout/time_picker.xml
@@ -25,24 +25,31 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content">
- <!-- hour -->
- <NumberPicker
- android:id="@+id/hour"
- android:layout_width="70dip"
+ <LinearLayout android:orientation="horizontal"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:focusable="true"
- android:focusableInTouchMode="true"
- />
+ android:layoutDirection="ltr">
- <!-- minute -->
- <NumberPicker
- android:id="@+id/minute"
- android:layout_width="70dip"
- android:layout_height="wrap_content"
- android:layout_marginStart="5dip"
- android:focusable="true"
- android:focusableInTouchMode="true"
- />
+ <!-- hour -->
+ <NumberPicker
+ android:id="@+id/hour"
+ android:layout_width="70dip"
+ android:layout_height="wrap_content"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ />
+
+ <!-- minute -->
+ <NumberPicker
+ android:id="@+id/minute"
+ android:layout_width="70dip"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="5dip"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ />
+
+ </LinearLayout>
<!-- AM / PM -->
<Button
diff --git a/core/res/res/layout/time_picker_holo.xml b/core/res/res/layout/time_picker_holo.xml
index 765e71d..7d8900e 100644
--- a/core/res/res/layout/time_picker_holo.xml
+++ b/core/res/res/layout/time_picker_holo.xml
@@ -25,40 +25,47 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content">
- <!-- hour -->
- <NumberPicker
- android:id="@+id/hour"
+ <LinearLayout android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginTop="16dip"
- android:layout_marginBottom="16dip"
- android:layout_marginStart="16dip"
- android:layout_marginEnd="6dip"
- android:focusable="true"
- android:focusableInTouchMode="true"
- />
+ android:layoutDirection="ltr">
- <!-- divider -->
- <TextView
- android:id="@+id/divider"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:importantForAccessibility="no"
- />
+ <!-- hour -->
+ <NumberPicker
+ android:id="@+id/hour"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="16dip"
+ android:layout_marginBottom="16dip"
+ android:layout_marginStart="16dip"
+ android:layout_marginEnd="6dip"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ />
- <!-- minute -->
- <NumberPicker
- android:id="@+id/minute"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="16dip"
- android:layout_marginBottom="16dip"
- android:layout_marginStart="6dip"
- android:layout_marginEnd="8dip"
- android:focusable="true"
- android:focusableInTouchMode="true"
- />
+ <!-- divider -->
+ <TextView
+ android:id="@+id/divider"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:importantForAccessibility="no"
+ />
+
+ <!-- minute -->
+ <NumberPicker
+ android:id="@+id/minute"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="16dip"
+ android:layout_marginBottom="16dip"
+ android:layout_marginStart="6dip"
+ android:layout_marginEnd="8dip"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ />
+
+ </LinearLayout>
<!-- AM / PM -->
<NumberPicker
diff --git a/docs/html/images/systrace/display-rhythm.png b/docs/html/images/systrace/display-rhythm.png
new file mode 100644
index 0000000..a249161
--- /dev/null
+++ b/docs/html/images/systrace/display-rhythm.png
Binary files differ
diff --git a/docs/html/images/systrace/process-rhythm.png b/docs/html/images/systrace/process-rhythm.png
new file mode 100644
index 0000000..7498cc7
--- /dev/null
+++ b/docs/html/images/systrace/process-rhythm.png
Binary files differ
diff --git a/docs/html/images/systrace/report.png b/docs/html/images/systrace/report.png
new file mode 100644
index 0000000..a642960
--- /dev/null
+++ b/docs/html/images/systrace/report.png
Binary files differ
diff --git a/docs/html/tools/debugging/systrace.jd b/docs/html/tools/debugging/systrace.jd
new file mode 100644
index 0000000..287abe6
--- /dev/null
+++ b/docs/html/tools/debugging/systrace.jd
@@ -0,0 +1,239 @@
+page.title=Analyzing Display and Performance with Systrace
+parent.title=Debugging
+parent.link=index.html
+@jd:body
+
+<div id="qv-wrapper">
+ <div id="qv">
+ <h2>In this document</h2>
+ <ol>
+ <li><a href="#overview">Overview</a>
+ </li>
+ <li><a href="#generate">Generating Traces</a>
+ <ol>
+ <li><a href="#limit-trace">Limiting trace data</a></li>
+ <li><a href="#config-categories">Configuring trace data categories</a></li>
+ <li><a href="#running">Running a trace</a></li>
+ </ol>
+ </li>
+ <li><a href="#analysis">Analyzing Traces</a>
+ <ol>
+ <li><a href="#long-processes">Long running processes</a></li>
+ <li><a href="#display-interupts">Interruptions in display execution</a></li>
+ </ol>
+ </li>
+ </ol>
+ <h2>See also</h2>
+ <ol>
+ <li><a href="{@docRoot}tools/help/systrace.html">Systrace</a>
+ </li>
+ </ol>
+ </div>
+</div>
+
+<p>After building features, eliminating bugs and cleaning up your code, you should spend some
+ time looking at the performance of your application. The speed and smoothness with which your
+ application draws pixels and performs operations has an significant impact on your users'
+ experience.</p>
+
+<p>Android applications operate within a shared resource environment, and the performance of
+ your application can be impacted by how efficiently it interacts with those resources in
+ the larger system. Applications also operate in a multithreaded environment, competing with other
+ threaded processes for resources, which can cause performance problems that are hard to diagnose.
+</p>
+
+<p>The {@code systrace} tool allows you to collect and review code execution data for your
+ application and the Android system. You can use this data to diagnose execution problems and
+ improve the performance of your application.</p>
+
+
+<h2 id="overview">Overview</h2>
+
+<p>{@code systrace} helps you analyze how the execution of your application fits into the larger
+ Android environment, letting you see system and applications process execution on a common
+ timeline. The tool allows you to generate highly detailed, interactive reports from devices
+ running Android 4.1 and higher, such as the report in figure 1.</p>
+
+<img src="{@docRoot}images/systrace/report.png" alt="Systrace example report" id="figure1" />
+<p class="img-caption">
+ <strong>Figure 1.</strong> An example {@code systrace} report on 5 seconds of process execution
+ for a running application and related Android system processes.
+</p>
+
+
+<h2 id="generate">Generating Traces</h2>
+
+<p>In order to create a trace of your application, you must perform a few setup steps. First, you
+ must have a device running Android 4.1 or higher. Setup the device for
+ <a href="{@docRoot}tools/device.html#setting-up">debugging</a>, connect it to your development
+ system and install your application. Some types of trace information, specifically disk activity
+ and kernel work queues, require root access to the device, but most {@code systrace} log data
+ only requires that the device be enabled for developer debugging.</p>
+
+
+<h3 id="limit-trace">Limiting trace data</h3>
+
+<p>The {@code systrace} tool can generate a potentially huge amount of data from applications
+ and system sources. To limit the amount of data the tool collects and make the data more relevant
+ to your analysis, use the following options:</p>
+
+<ul>
+ <li>Limit the amount of time covered by the trace with the {@code -t, --time} option. The default
+ length of a trace is 5 seconds.</li>
+ <li>Limit the size of the data collected by the trace with the {@code -b, --buf-size} option.</li>
+ <li>Specify what types of processes are traced using the {@code --set-tags} option and the
+ {@code --disk}, {@code --cpu-freq}, {@code --cpu-idle}, {@code --cpu-load} options.</li>
+</ul>
+
+
+<h3 id="config-categories">Configuring trace data categories</h3>
+
+<p>To use {@code systrace} effectively, you must specify the types of processes you want to trace.
+ The tool can gather the following types of process information:</p>
+
+<ul>
+ <li>General system processes such as graphics, audio and input processes (selected using trace
+ <a href="{@docRoot}tools/help/systrace.html#tags">Tags</a>).</li>
+ <li>Low level system information such as CPU, kernel and disk activity (selected using
+ <a href="{@docRoot}tools/help/systrace.html#options">Options</a>).</li>
+</ul>
+
+<p>To set trace tags for {@code systrace} using the command-line:</p>
+
+<ol>
+ <li>Use the {@code --set-tags} option:
+<pre>
+$> python systrace.py --set-tags=gfx,view,wm
+</pre>
+ </li>
+ <li>Stop and restart the {@code adb} shell to enable tracing of these processes.
+<pre>
+$> adb shell stop
+$> adb shell start
+</pre></li>
+</ol>
+
+<p>To set trace tags for {@code systrace} using the device user interface:</p>
+
+<ol>
+ <li>On the device connected for tracing, navigate to: <strong>Settings >
+ Developer options > Monitoring > Enable traces</strong>.</li>
+ <li>Select the categories of processes to be traced and click <strong>OK</strong>.</li>
+</ol>
+
+<p class="note">
+ <strong>Note:</strong> The {@code adb} shell does not have to be stopped and restarted when
+ selecting trace tags using this method.
+</p>
+
+
+<h3 id="running">Running a trace</h3>
+
+<p>After you have configured the category tags for your trace, you can start collecting
+ information for analysis.</p>
+
+<p>To run a trace using the current trace tag settings:</p>
+
+<ol>
+ <li>Make sure the device is connected through a USB cable and is
+ <a href="{@docRoot}tools/device.html#setting-up">enabled for debugging</a>.</li>
+ <li>Run the trace with the low-level system trace options and limits you want, for example:
+<pre>
+$> python systrace.py --cpu-freq --cpu-load --time=10 -o mytracefile.html
+</pre>
+ </li>
+ <li>On the device, execute any user actions you want be included in the trace.</li>
+</ol>
+
+
+<h2 id="analysis">Analyzing Traces</h2>
+
+<p>After you have generated a trace using {@code systrace}, it lists the location of the output
+ file and you can open the report using a web browser.
+ How you use the trace data depends on the performance issues you are investigating. However,
+ this section provides some general instructions on how to analyze a trace.</p>
+
+<p>The reports generated by {@code systrace} are interactive, allowing you to zoom into and out of
+ the process execution details. Use the <em>W</em> key to zoom in, the <em>S</em>
+ key to zoom out, the <em>A</em> key to pan left and the <em>D</em> key to pan
+ right. Select a task in timeline using your mouse to get more information about the task.
+ For more information about the using the keyboard navigation shortcuts and navigation, see the
+ <a href="{@docRoot}tools/help/systrace.html#viewing-options">Systrace</a> reference
+ documentation.</p>
+
+<h3 id="long-processes">Long running processes</h3>
+
+<p>A well-behaved application executes many small operations quickly and with a regular rhythm,
+ with individual operations completing within few milliseconds, depending on the device
+ and the processes being performed, as shown in figure 2:</p>
+
+<img src="{@docRoot}images/systrace/process-rhythm.png" alt="Systrace exerpt of app processing"
+id="figure2" />
+<p class="img-caption">
+ <strong>Figure 2.</strong> Excerpt from a trace of a smoothly running application with a regular
+ execution rhythm.
+</p>
+
+<p>The trace excerpt in figure 2 shows a well-behaved application with
+ a regular process rhythm (1). The lower section of figure 2 shows a magnified section of
+ the trace indicated by the dotted outline, which reveals some irregularity in the process
+ execution. In particular, one of the wider task bars, indicated by (2), is taking slightly
+ longer (14 milliseconds) than other, similar tasks on this thread, which are averaging between
+ 9 and 12 milliseconds to complete. This particular task execution length is likely not noticeable
+ to a user, unless it impacts another process with specific timing, such as a screen update.</p>
+
+<p>Long running processes show up as thicker than usual execution bars in a trace. These thicker
+ bars can indicate a problem in your application performance. When they show up in your
+ trace, zoom in on the process using the
+ <a href="{@docRoot}tools/help/systrace.html#viewing-options">keyboard navigation</a> shortcuts to
+ identify the task causing the problem, and click on the task to get more information. You should
+ also look at other processes running at the same time, looking for a thread in one process that is
+ being blocked by another process.</p>
+
+
+<h3 id="display-interupts">Interruptions in display execution</h3>
+
+<p>The {@code systrace} tool is particularly useful in analyzing application display slowness,
+ or pauses in animations, because it shows you the execution of your application across multiple
+ system processes. With display execution, drawing screen frames with a regular rhythm is essential
+ for good performance. Having a regular rhythm for display ensures that animations and motion are
+ smooth on screen. If an application drops out of this rhythm, the display can become jerky or slow
+ from the users perspective.</p>
+
+<p>If you are analyzing an application for this type of problem, examine the
+ <strong>SurfaceFlinger</strong> process in the {@code systrace} report where your application is
+ also executing to look for places where it drops out of its regular rhythm.</p>
+
+<img src="{@docRoot}images/systrace/display-rhythm.png" alt="Systrace exerpt of display processing"
+id="figure3" />
+<p class="img-caption">
+ <strong>Figure 3.</strong> Excerpt from a trace of an application showing interruptions in
+ display processing.
+</p>
+
+<p>The trace excerpt in figure 3 shows an section of a trace that indicates an interruption in the
+ device display. The section of the <strong>SurfaceFlinger</strong> process in top excerpt,
+ indicated by (1), shows that display frames are being missed. These
+ dropped frames are potentially causing the display to stutter or halt. Zooming into this problem
+ area in the lower trace, shows that a memory operation (image buffer dequeuing and allocation) in
+ the <strong>surfaceflinger</strong> secondary thread is taking a long time (2). This delay
+ causes the application to miss the display update window, indicated by the dotted
+ line. As the developer of this application, you should investigate other threads in your
+ application that may also be trying to allocate memory at the same time or otherwise blocking
+ memory allocation with another request or task.</p>
+
+<p>Regular, rhythmic execution of the <strong>SurfaceFlinger</strong> process is essential to smooth
+ display of screen content, particularly for animations and motion. Interruptions in the regular
+ execution pattern of this thread is not always an indication of a display problem with your
+ application. Further testing is required to determine if this is actually a performance problem
+ from a user perspective. Being able to identify display execution patterns like the example above
+ can help you detect display problems and build a smooth-running, high-performance application.
+</p>
+
+<p class="note">
+ <strong>Note:</strong> When using {@code systrace} to analyze display problems, make sure
+ you activate the tracing tags for <strong>Graphics</strong> and <strong>Views</strong>.
+</p>
+
+<p>For more information on the command line options and keyboard controls for {@code systrace},
+see the <a href="{@docRoot}tools/help/systrace.html">Systrace</a> reference page.</p>
\ No newline at end of file
diff --git a/docs/html/tools/help/index.jd b/docs/html/tools/help/index.jd
index 447d39c..0f94395 100644
--- a/docs/html/tools/help/index.jd
+++ b/docs/html/tools/help/index.jd
@@ -55,6 +55,9 @@
<dt><a href="proguard.html">ProGuard</a></dt>
<dd>Shrinks, optimizes, and obfuscates your code by removing unused code and renaming
classes, fields, and methods with semantically obscure names.</dd>
+ <dt><a href="systrace.html">Systrace</a></dt>
+ <dd>Lets you analyze the execution of your application in the context of system processes,
+ to help diagnose display and performance issues.</dd>
<dt><a href="sqlite3.html">sqlite3</a></dt>
<dd>Lets you access the SQLite data files created and used by Android applications.</dd>
<dt><a href="traceview.html">traceview</a></dt>
diff --git a/docs/html/tools/help/systrace.jd b/docs/html/tools/help/systrace.jd
new file mode 100644
index 0000000..010cc78
--- /dev/null
+++ b/docs/html/tools/help/systrace.jd
@@ -0,0 +1,234 @@
+page.title=Systrace
+parent.title=Tools
+parent.link=index.html
+@jd:body
+
+
+<p>The {@code systrace} tool helps analyze the performance of your application by capturing and
+ displaying execution times of your applications processes and other Android system processes. The
+ tool combines data from the Android kernel such as the CPU scheduler, disk activity and
+ application threads to generate an HTML report that shows an overall picture of an Android
+ device’s system processes for a given period of time.</p>
+
+<p>The {@code systrace} tool is particularly useful in diagnosing display problems where an
+ application is slow to draw or stutters while displaying motion or animation. For more information
+ on how to use {@code systrace}, see <a href="{@docRoot}tools/debugging/systrace.html">Analyzing
+ Display and Performance with Systrace</a>.</p>
+
+
+<h2 id="usage">Usage</h2>
+
+<p>In order to run {@code systrace}, the {@code adb} tool and
+<a href="http://www.python.org/">Python</a> must be installed and included in your development
+computer's execution path. In order to generate a trace, you must connect a device running Android
+4.1 (API Level 16) or higher to your development system using a USB debugging connection.</p>
+
+<p>The syntax for running {@code systrace} is as follows.</p>
+
+<pre>
+$> python systrace.py [options]
+</pre>
+
+<p>Here is an example execution run that sets trace tags and generates a trace from a connected
+Android device.</p>
+
+<pre>
+$> cd <em>android-sdk</em>/tools/systrace
+$> python systrace.py --set-tags gfx,view,wm
+$> adb shell stop
+$> adb shell start
+$> python systrace.py --disk --time=10 -o mynewtrace.html
+</pre>
+
+
+
+<h2 id="options">Options</h2>
+
+<p>The table below lists the command line options for {@code systrace}.</p>
+
+<table>
+ <tr>
+ <th>Option</th>
+
+ <th>Description</th>
+ </tr>
+
+ <tr>
+ <td><code>-o <<em>FILE</em>></code></td>
+
+ <td>Write the HTML trace report to the specified file.</td>
+ </tr>
+
+ <tr>
+ <td><code>-t N, --time=N</code></td>
+
+ <td>Trace activity for N seconds. Default value is 5 seconds.</td>
+ </tr>
+
+ <tr>
+ <td><code>-b N, --buf-size=N</code></td>
+
+ <td>Use a trace buffer size of N kilobytes. This option lets you limit the total size of the
+ data collected during a trace.</td>
+ </tr>
+
+ <tr>
+ <td><code>-d, --disk</code></td>
+
+ <td>Trace disk input and output activity. This option requires root access on the device.</td>
+ </tr>
+
+ <tr>
+ <td><code>-f, --cpu-freq</code></td>
+
+ <td>Trace CPU frequency changes. Only changes to the CPU frequency are logged, so the initial
+ frequency of the CPU when tracing starts is not shown.</td>
+ </tr>
+
+ <tr>
+ <td><code>-i, --cpu-idle</code></td>
+
+ <td>Trace CPU idle events.</td>
+ </tr>
+
+ <tr>
+ <td><code>-l, --cpu-load</code></td>
+
+ <td>Trace CPU load. This value is a percentage determined by the interactive CPU frequency
+ governor.</td>
+ </tr>
+
+ <tr>
+ <td><nobr><code>-s, --no-cpu-sched</code></nobr></td>
+
+ <td>Prevent tracing of the CPU scheduler. This option allows for longer trace times by reducing
+ the rate of data flowing into the trace buffer.</td>
+ </tr>
+
+ <tr>
+ <td><code>-w, --workqueue</code></td>
+
+ <td>Trace kernel work queues. This option requires root access on the device.</td>
+ </tr>
+
+ <tr>
+ <td id="tags"><code>--set-tags=<<em>TAGS</em>></code></td>
+
+ <td>Set the enabled trace tags in a comma separated list. The available tags are:
+ <ul>
+ <li><code>gfx</code> - Graphics</li>
+ <li><code>input</code> - Input</li>
+ <li><code>view</code> - View</li>
+ <li><code>webview</code> - WebView</li>
+ <li><code>wm</code> - Window Manager</li>
+ <li><code>am</code> - Activity Manager</li>
+ <li><code>sync</code> - Sync Manager</li>
+ <li><code>audio</code> - Audio</li>
+ <li><code>video</code> - Video</li>
+ <li><code>camera</code> - Camera</li>
+ </ul>
+ <p class="note"><strong>Note:</strong> When setting trace tags from the command line, you
+ must stop and restart the framework ({@code $> adb shell stop; adb shell start}) for the
+ tag tracing changes to take effect.</p>
+ </td>
+ </tr>
+
+ <tr>
+ <td><code>--link-assets</code></td>
+
+ <td>Link to the original CSS or JS resources instead of embedding them in the HTML trace
+ report.</td>
+ </tr>
+
+ <tr>
+ <td><nobr><code>-h, --help</code></nobr></td>
+
+ <td>Show the help message.</td>
+ </tr>
+
+</table>
+
+<p>You can set the trace <a href="#tags">tags</a> for {@code systrace} with your device's user
+interface, by navigating to <strong>Settings > Developer options > Monitoring > Enable
+traces</strong>.</p>
+
+
+<h2 id="viewing-options">Trace Viewing Shortcuts</h2>
+
+<p>The table below lists the keyboard shortcuts that are available while viewing a {@code systrace}
+trace HTML report.</p>
+
+<table>
+ <tr>
+ <th>Key</th>
+
+ <th>Description</th>
+ </tr>
+
+ <tr>
+ <td><strong>w</strong></td>
+
+ <td>Zoom into the trace timeline.</td>
+ </tr>
+
+ <tr>
+ <td><strong>s</strong></td>
+
+ <td>Zoom out of the trace timeline.</td>
+ </tr>
+
+ <tr>
+ <td><strong>a</strong></td>
+
+ <td>Pan left on the trace timeline.</td>
+ </tr>
+
+ <tr>
+ <td><strong>d</strong></td>
+
+ <td>Pan right on the trace timeline.</td>
+ </tr>
+
+ <tr>
+ <td><strong>e</strong></td>
+
+ <td>Center the trace timeline on the current mouse location.</td>
+ </tr>
+
+ <tr>
+ <td><strong>g</strong></td>
+
+ <td>Show grid at the start of the currently selected task.</td>
+ </tr>
+
+ <tr>
+ <td><strong>Shift+g</strong></td>
+
+ <td>Show grid at the end of the currently selected task.</td>
+ </tr>
+
+ <tr>
+ <td><strong>Right Arrow</strong></td>
+
+ <td>Select the next event on the currently selected timeline.</td>
+ </tr>
+
+ <tr>
+ <td><strong>Left Arrow</strong></td>
+
+ <td>Select the previous event on the currently selected timeline.</td>
+ </tr>
+
+ <tr>
+ <td><strong>Double Click</strong></td>
+
+ <td>Zoom into the trace timeline.</td>
+ </tr>
+
+ <tr>
+ <td><strong>Shift+Double Click</strong></td>
+
+ <td>Zoom out of the trace timeline.</td>
+ </tr>
+
+</table>
diff --git a/docs/html/tools/tools_toc.cs b/docs/html/tools/tools_toc.cs
index f3936b8..5e2b9f7 100644
--- a/docs/html/tools/tools_toc.cs
+++ b/docs/html/tools/tools_toc.cs
@@ -114,6 +114,7 @@
<li><a href="<?cs var:toroot ?>tools/debugging/improving-w-lint.html"><span class="en">Improving Your Code with lint</span></a></li>
<li><a href="<?cs var:toroot ?>tools/debugging/debugging-ui.html"><span class="en">Optimizing your UI</span></a></li>
<li><a href="<?cs var:toroot ?>tools/debugging/debugging-tracing.html"><span class="en">Profiling with Traceview and dmtracedump</span></a></li>
+ <li><a href="<?cs var:toroot ?>tools/debugging/systrace.html"><span class="en">Analysing Display and Performance with Systrace</span></a></li>
<li><a href="<?cs var:toroot ?>tools/debugging/debugging-devtools.html"><span class="en">Using the Dev Tools App</span></a></li>
</ul>
</li>
@@ -159,6 +160,7 @@
</ul>
</li>
<li><a href="<?cs var:toroot ?>tools/help/proguard.html">ProGuard</a></li>
+ <li><a href="<?cs var:toroot ?>tools/help/systrace.html">Systrace</a></li>
<li><a href="<?cs var:toroot ?>tools/help/gltracer.html">Tracer for OpenGL ES</a></li>
<li><a href="<?cs var:toroot ?>tools/help/traceview.html">Traceview</a></li>
<li><a href="<?cs var:toroot ?>tools/help/zipalign.html">zipalign</a></li>
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index b149bb9..068eb9e 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -429,7 +429,7 @@
void Caches::startTiling(GLuint x, GLuint y, GLuint width, GLuint height, bool opaque) {
if (extensions.hasTiledRendering()) {
- glStartTilingQCOM(x, y, width, height, GL_COLOR_BUFFER_BIT0_QCOM);
+ glStartTilingQCOM(x, y, width, height, opaque ? GL_NONE : GL_COLOR_BUFFER_BIT0_QCOM);
}
}
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 9b9ca12..da0900a 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -175,7 +175,7 @@
mSaveCount = 1;
mSnapshot->setClip(left, top, right, bottom);
- mDirtyClip = mOpaqueFrame = opaque;
+ mDirtyClip = opaque;
// If we know that we are going to redraw the entire framebuffer,
// perform a discard to let the driver know we don't need to preserve
@@ -189,7 +189,7 @@
syncState();
mTilingSnapshot = mSnapshot;
- startTiling();
+ startTiling(mTilingSnapshot, true);
if (!opaque) {
mCaches.enableScissor();
@@ -213,16 +213,9 @@
}
}
-void OpenGLRenderer::startTiling() {
- startTiling(mTilingSnapshot);
-}
-
-void OpenGLRenderer::startTiling(const sp<Snapshot>& s) {
- bool opaque = mOpaqueFrame;
+void OpenGLRenderer::startTiling(const sp<Snapshot>& s, bool opaque) {
Rect* clip = mTilingSnapshot->clipRect;
-
if (s->flags & Snapshot::kFlagIsFboLayer) {
- opaque = !s->layer->isBlend();
clip = s->clipRect;
}
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 10ba86e..4bbdde1 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -351,8 +351,7 @@
* This method needs to be invoked every time getTargetFbo() is
* bound again.
*/
- void startTiling();
- void startTiling(const sp<Snapshot>& snapshot);
+ void startTiling(const sp<Snapshot>& snapshot, bool opaque = false);
/**
* Tells the GPU that we are done drawing the frame or that we
diff --git a/opengl/java/android/opengl/GLSurfaceView.java b/opengl/java/android/opengl/GLSurfaceView.java
index 8acbae3..54dcaaa 100644
--- a/opengl/java/android/opengl/GLSurfaceView.java
+++ b/opengl/java/android/opengl/GLSurfaceView.java
@@ -83,7 +83,7 @@
* </ul>
* <p>
* <h4>Specifying the android.view.Surface</h4>
- * By default GLSurfaceView will create a PixelFormat.RGB_565 format surface. If a translucent
+ * By default GLSurfaceView will create a PixelFormat.RGB_888 format surface. If a translucent
* surface is required, call getHolder().setFormat(PixelFormat.TRANSLUCENT).
* The exact format of a TRANSLUCENT surface is device dependent, but it will be
* a 32-bit-per-pixel surface with 8 bits per component.
@@ -94,7 +94,7 @@
* well as how many bits are allocated to each channel. Therefore, the first thing
* GLSurfaceView has to do when starting to render is choose what EGLConfig to use.
* <p>
- * By default GLSurfaceView chooses a EGLConfig that has an RGB_565 pixel format,
+ * By default GLSurfaceView chooses a EGLConfig that has an RGB_888 pixel format,
* with at least a 16-bit depth buffer and no stencil.
* <p>
* If you would prefer a different EGLConfig
@@ -414,7 +414,7 @@
* is called.
* <p>
* If no setEGLConfigChooser method is called, then by default the
- * view will choose an RGB_565 surface with a depth buffer depth of
+ * view will choose an RGB_888 surface with a depth buffer depth of
* at least 16 bits.
*
* @param needDepth
@@ -432,7 +432,7 @@
* is called.
* <p>
* If no setEGLConfigChooser method is called, then by default the
- * view will choose an RGB_565 surface with a depth buffer depth of
+ * view will choose an RGB_888 surface with a depth buffer depth of
* at least 16 bits.
*
*/
@@ -968,13 +968,13 @@
}
/**
- * This class will choose a RGB_565 surface with
+ * This class will choose a RGB_888 surface with
* or without a depth buffer.
*
*/
private class SimpleEGLConfigChooser extends ComponentSizeChooser {
public SimpleEGLConfigChooser(boolean withDepthBuffer) {
- super(5, 6, 5, 0, withDepthBuffer ? 16 : 0, 0);
+ super(8, 8, 8, 0, withDepthBuffer ? 16 : 0, 0);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsActivity.java
index 9c3756c..291f38c 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsActivity.java
@@ -94,6 +94,9 @@
@Override
public void onResume() {
mForeground = true;
+ if (mRecentsPanel != null) {
+ mRecentsPanel.refreshViews();
+ }
super.onResume();
}
@@ -186,4 +189,7 @@
}
}
+ boolean isForeground() {
+ return mForeground;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index 04e38a4..0caa671 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -24,7 +24,6 @@
import android.app.TaskStackBuilder;
import android.content.Context;
import android.content.Intent;
-import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
@@ -67,7 +66,6 @@
StatusBarPanel, Animator.AnimatorListener {
static final String TAG = "RecentsPanelView";
static final boolean DEBUG = TabletStatusBar.DEBUG || PhoneStatusBar.DEBUG || false;
- private Context mContext;
private PopupMenu mPopup;
private View mRecentsScrim;
private View mRecentsNoApps;
@@ -203,7 +201,6 @@
public RecentsPanelView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
- mContext = context;
updateValuesFromResources();
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RecentsPanelView,
@@ -374,7 +371,6 @@
protected void onFinishInflate() {
super.onFinishInflate();
- mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mRecentsContainer = (ViewGroup) findViewById(R.id.recents_container);
mStatusBarTouchProxy = (StatusBarTouchProxy) findViewById(R.id.status_bar_touch_proxy);
mListAdapter = new TaskDescriptionAdapter(mContext);
@@ -488,7 +484,7 @@
}
}
}
- }
+ }
showIfReady();
}
@@ -508,6 +504,12 @@
}
}
+ public void refreshViews() {
+ mListAdapter.notifyDataSetInvalidated();
+ updateUiElements();
+ showIfReady();
+ }
+
public void refreshRecentTasksList() {
refreshRecentTasksList(null, false);
}
@@ -530,12 +532,12 @@
} else {
mRecentTaskDescriptions.addAll(tasks);
}
- mListAdapter.notifyDataSetInvalidated();
- updateUiElements(getResources().getConfiguration());
- showIfReady();
+ if (((RecentsActivity)mContext).isForeground()) {
+ refreshViews();
+ }
}
- private void updateUiElements(Configuration config) {
+ private void updateUiElements() {
final int items = mRecentTaskDescriptions.size();
mRecentsContainer.setVisibility(items > 0 ? View.VISIBLE : View.GONE);
diff --git a/services/java/com/android/server/AppWidgetServiceImpl.java b/services/java/com/android/server/AppWidgetServiceImpl.java
index 499c15e..815ee24 100644
--- a/services/java/com/android/server/AppWidgetServiceImpl.java
+++ b/services/java/com/android/server/AppWidgetServiceImpl.java
@@ -980,9 +980,13 @@
// drop unbound appWidgetIds (shouldn't be possible under normal circumstances)
if (id != null && id.provider != null && !id.provider.zombie && !id.host.zombie) {
- // We do not want to save this RemoteViews
- if (!isPartialUpdate)
+ if (!isPartialUpdate) {
+ // For a full update we replace the RemoteViews completely.
id.views = views;
+ } else {
+ // For a partial update, we merge the new RemoteViews with the old.
+ id.views.mergeRemoteViews(views);
+ }
// is anyone listening?
if (id.host.callbacks != null) {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 6c5a4e2..fb1d530 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -302,16 +302,22 @@
Watchdog.getInstance().init(context, battery, power, alarm,
ActivityManagerService.self());
+ Slog.i(TAG, "Input Manager");
+ inputManager = new InputManagerService(context, wmHandler);
+
Slog.i(TAG, "Window Manager");
- wm = WindowManagerService.main(context, power, display,
+ wm = WindowManagerService.main(context, power, display, inputManager,
uiHandler, wmHandler,
factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL,
!firstBoot, onlyCore);
ServiceManager.addService(Context.WINDOW_SERVICE, wm);
- inputManager = wm.getInputManagerService();
ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
ActivityManagerService.self().setWindowManager(wm);
+
+ inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
+ inputManager.start();
+
display.setWindowManager(wm);
display.setInputManager(inputManager);
diff --git a/services/java/com/android/server/display/DisplayManagerService.java b/services/java/com/android/server/display/DisplayManagerService.java
index 02fc6b1..b109f2a 100644
--- a/services/java/com/android/server/display/DisplayManagerService.java
+++ b/services/java/com/android/server/display/DisplayManagerService.java
@@ -89,6 +89,11 @@
private static final String TAG = "DisplayManagerService";
private static final boolean DEBUG = false;
+ // When this system property is set to 0, WFD is forcibly disabled on boot.
+ // When this system property is set to 1, WFD is forcibly enabled on boot.
+ // Otherwise WFD is enabled according to the value of config_enableWifiDisplay.
+ private static final String FORCE_WIFI_DISPLAY_ENABLE = "persist.debug.wfd.enable";
+
private static final String SYSTEM_HEADLESS = "ro.config.headless";
private static final long WAIT_FOR_DEFAULT_DISPLAY_TIMEOUT = 10000;
@@ -499,7 +504,8 @@
private void registerWifiDisplayAdapterLocked() {
if (mContext.getResources().getBoolean(
- com.android.internal.R.bool.config_enableWifiDisplay)) {
+ com.android.internal.R.bool.config_enableWifiDisplay)
+ || SystemProperties.getInt(FORCE_WIFI_DISPLAY_ENABLE, -1) == 1) {
mWifiDisplayAdapter = new WifiDisplayAdapter(
mSyncRoot, mContext, mHandler, mDisplayAdapterListener,
mPersistentDataStore);
diff --git a/services/java/com/android/server/display/WifiDisplayController.java b/services/java/com/android/server/display/WifiDisplayController.java
index 84f4e83..58f0445 100644
--- a/services/java/com/android/server/display/WifiDisplayController.java
+++ b/services/java/com/android/server/display/WifiDisplayController.java
@@ -536,7 +536,7 @@
WifiP2pConfig config = new WifiP2pConfig();
config.deviceAddress = mConnectingDevice.deviceAddress;
// Helps with STA & P2P concurrency
- config.groupOwnerIntent = WifiP2pConfig.MAX_GROUP_OWNER_INTENT;
+ config.groupOwnerIntent = WifiP2pConfig.MIN_GROUP_OWNER_INTENT;
WifiDisplay display = createWifiDisplay(mConnectingDevice);
advertiseDisplay(display, null, 0, 0, 0);
diff --git a/services/java/com/android/server/input/InputManagerService.java b/services/java/com/android/server/input/InputManagerService.java
index 805818a..3709314 100644
--- a/services/java/com/android/server/input/InputManagerService.java
+++ b/services/java/com/android/server/input/InputManagerService.java
@@ -53,6 +53,7 @@
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
+import android.os.Looper;
import android.os.Message;
import android.os.MessageQueue;
import android.os.Process;
@@ -70,7 +71,6 @@
import android.view.InputEvent;
import android.view.KeyEvent;
import android.view.PointerIcon;
-import android.view.Surface;
import android.view.ViewConfiguration;
import android.view.WindowManagerPolicy;
import android.widget.Toast;
@@ -109,8 +109,9 @@
private final int mPtr;
private final Context mContext;
- private final Callbacks mCallbacks;
private final InputManagerHandler mHandler;
+
+ private WindowManagerCallbacks mWindowManagerCallbacks;
private boolean mSystemReady;
private NotificationManager mNotificationManager;
@@ -217,15 +218,18 @@
/** Switch code: Keypad slide. When set, keyboard is exposed. */
public static final int SW_KEYPAD_SLIDE = 0x0a;
- public InputManagerService(Context context, Callbacks callbacks) {
+ public InputManagerService(Context context, Handler handler) {
this.mContext = context;
- this.mCallbacks = callbacks;
- this.mHandler = new InputManagerHandler();
+ this.mHandler = new InputManagerHandler(handler.getLooper());
Slog.i(TAG, "Initializing input manager");
mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
}
+ public void setWindowManagerCallbacks(WindowManagerCallbacks callbacks) {
+ mWindowManagerCallbacks = callbacks;
+ }
+
public void start() {
Slog.i(TAG, "Starting input manager");
nativeStart(mPtr);
@@ -1204,7 +1208,7 @@
// Native callback.
private void notifyConfigurationChanged(long whenNanos) {
- mCallbacks.notifyConfigurationChanged();
+ mWindowManagerCallbacks.notifyConfigurationChanged();
}
// Native callback.
@@ -1224,20 +1228,20 @@
private void notifySwitch(long whenNanos, int switchCode, int switchValue) {
switch (switchCode) {
case SW_LID:
- mCallbacks.notifyLidSwitchChanged(whenNanos, switchValue == 0);
+ mWindowManagerCallbacks.notifyLidSwitchChanged(whenNanos, switchValue == 0);
break;
}
}
// Native callback.
private void notifyInputChannelBroken(InputWindowHandle inputWindowHandle) {
- mCallbacks.notifyInputChannelBroken(inputWindowHandle);
+ mWindowManagerCallbacks.notifyInputChannelBroken(inputWindowHandle);
}
// Native callback.
private long notifyANR(InputApplicationHandle inputApplicationHandle,
InputWindowHandle inputWindowHandle) {
- return mCallbacks.notifyANR(inputApplicationHandle, inputWindowHandle);
+ return mWindowManagerCallbacks.notifyANR(inputApplicationHandle, inputWindowHandle);
}
// Native callback.
@@ -1258,25 +1262,25 @@
// Native callback.
private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn) {
- return mCallbacks.interceptKeyBeforeQueueing(
+ return mWindowManagerCallbacks.interceptKeyBeforeQueueing(
event, policyFlags, isScreenOn);
}
// Native callback.
private int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags) {
- return mCallbacks.interceptMotionBeforeQueueingWhenScreenOff(policyFlags);
+ return mWindowManagerCallbacks.interceptMotionBeforeQueueingWhenScreenOff(policyFlags);
}
// Native callback.
private long interceptKeyBeforeDispatching(InputWindowHandle focus,
KeyEvent event, int policyFlags) {
- return mCallbacks.interceptKeyBeforeDispatching(focus, event, policyFlags);
+ return mWindowManagerCallbacks.interceptKeyBeforeDispatching(focus, event, policyFlags);
}
// Native callback.
private KeyEvent dispatchUnhandledKey(InputWindowHandle focus,
KeyEvent event, int policyFlags) {
- return mCallbacks.dispatchUnhandledKey(focus, event, policyFlags);
+ return mWindowManagerCallbacks.dispatchUnhandledKey(focus, event, policyFlags);
}
// Native callback.
@@ -1359,7 +1363,7 @@
// Native callback.
private int getPointerLayer() {
- return mCallbacks.getPointerLayer();
+ return mWindowManagerCallbacks.getPointerLayer();
}
// Native callback.
@@ -1414,7 +1418,7 @@
/**
* Callback interface implemented by the Window Manager.
*/
- public interface Callbacks {
+ public interface WindowManagerCallbacks {
public void notifyConfigurationChanged();
public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen);
@@ -1441,8 +1445,8 @@
* Private handler for the input manager.
*/
private final class InputManagerHandler extends Handler {
- public InputManagerHandler() {
- super(true /*async*/);
+ public InputManagerHandler(Looper looper) {
+ super(looper, null, true /*async*/);
}
@Override
diff --git a/services/java/com/android/server/wm/InputMonitor.java b/services/java/com/android/server/wm/InputMonitor.java
index aa18ee4..61310ca 100644
--- a/services/java/com/android/server/wm/InputMonitor.java
+++ b/services/java/com/android/server/wm/InputMonitor.java
@@ -33,7 +33,7 @@
import java.util.ArrayList;
import java.util.Arrays;
-final class InputMonitor implements InputManagerService.Callbacks {
+final class InputMonitor implements InputManagerService.WindowManagerCallbacks {
private final WindowManagerService mService;
// Current window with input focus for keys and other non-touch events. May be null.
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 73cc7ed..5a6e010 100755
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -74,6 +74,7 @@
import android.graphics.RectF;
import android.graphics.Region;
import android.hardware.display.DisplayManager;
+import android.hardware.input.InputManager;
import android.os.Binder;
import android.os.Bundle;
import android.os.Debug;
@@ -738,6 +739,7 @@
public static WindowManagerService main(final Context context,
final PowerManagerService pm, final DisplayManagerService dm,
+ final InputManagerService im,
final Handler uiHandler, final Handler wmHandler,
final boolean haveInputMethods, final boolean showBootMsgs,
final boolean onlyCore) {
@@ -745,7 +747,7 @@
wmHandler.runWithScissors(new Runnable() {
@Override
public void run() {
- holder[0] = new WindowManagerService(context, pm, dm,
+ holder[0] = new WindowManagerService(context, pm, dm, im,
uiHandler, haveInputMethods, showBootMsgs, onlyCore);
}
}, 0);
@@ -767,7 +769,8 @@
}
private WindowManagerService(Context context, PowerManagerService pm,
- DisplayManagerService displayManager, Handler uiHandler,
+ DisplayManagerService displayManager, InputManagerService inputManager,
+ Handler uiHandler,
boolean haveInputMethods, boolean showBootMsgs, boolean onlyCore) {
mContext = context;
mHaveInputMethods = haveInputMethods;
@@ -814,14 +817,12 @@
| PowerManager.ON_AFTER_RELEASE, TAG);
mHoldingScreenWakeLock.setReferenceCounted(false);
- mInputManager = new InputManagerService(context, mInputMonitor);
+ mInputManager = inputManager;
mFxSession = new SurfaceSession();
mAnimator = new WindowAnimator(this);
initPolicy(uiHandler);
- mInputManager.start();
-
// Add ourself to the Watchdog monitors.
Watchdog.getInstance().addMonitor(this);
@@ -833,8 +834,8 @@
}
}
- public InputManagerService getInputManagerService() {
- return mInputManager;
+ public InputMonitor getInputMonitor() {
+ return mInputMonitor;
}
@Override
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/MultiLayersActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/MultiLayersActivity.java
index 0127396..eb8a0a9 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/MultiLayersActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/MultiLayersActivity.java
@@ -45,10 +45,10 @@
row1.addView(new LayerView(this, 0xffff0000), new LinearLayout.LayoutParams(
0, LinearLayout.LayoutParams.MATCH_PARENT, 1.0f));
- row1.addView(new LayerView(this, 0xff00ff00), new LinearLayout.LayoutParams(
+ row1.addView(new LayerView(this, 0x0f00ff00), new LinearLayout.LayoutParams(
0, LinearLayout.LayoutParams.MATCH_PARENT, 1.0f));
- row2.addView(new LayerView(this, 0xff0000ff), new LinearLayout.LayoutParams(
+ row2.addView(new LayerView(this, 0x0f0000ff), new LinearLayout.LayoutParams(
0, LinearLayout.LayoutParams.MATCH_PARENT, 1.0f));
row2.addView(new LayerView(this, 0xffffff00), new LinearLayout.LayoutParams(
0, LinearLayout.LayoutParams.MATCH_PARENT, 1.0f));
diff --git a/tests/RenderScriptTests/ComputeBenchmark/src/com/example/android/rs/computebench/compute_benchmark.rs b/tests/RenderScriptTests/ComputeBenchmark/src/com/example/android/rs/computebench/compute_benchmark.rs
index 7b8ec04..2ee56ec 100644
--- a/tests/RenderScriptTests/ComputeBenchmark/src/com/example/android/rs/computebench/compute_benchmark.rs
+++ b/tests/RenderScriptTests/ComputeBenchmark/src/com/example/android/rs/computebench/compute_benchmark.rs
@@ -383,13 +383,12 @@
}
static void bench_approx_math() {
- BENCH_FN_FUNC_FN(approx_recip);
- BENCH_FN_FUNC_FN(approx_sqrt);
- BENCH_FN_FUNC_FN(approx_rsqrt);
- BENCH_FN_FUNC_FN(approx_length);
- BENCH_FN_FUNC_FN_FN(approx_distance);
- BENCH_FN_FUNC_FN(approx_normalize);
- BENCH_FN_FUNC_FN(approx_atan);
+ BENCH_FN_FUNC_FN(half_recip);
+ BENCH_FN_FUNC_FN(half_sqrt);
+ BENCH_FN_FUNC_FN(half_rsqrt);
+ BENCH_FN_FUNC_FN(fast_length);
+ BENCH_FN_FUNC_FN_FN(fast_distance);
+ BENCH_FN_FUNC_FN(fast_normalize);
}
void bench() {
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/fisheye_approx.rsh b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/fisheye_approx.rsh
index 008acbe..08b4126 100644
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/fisheye_approx.rsh
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/fisheye_approx.rsh
@@ -48,8 +48,8 @@
const float2 coord = mad(inCoord, inv_dimensions, neg_center);
const float2 scaledCoord = axis_scale * coord;
const float dist2 = scaledCoord.x*scaledCoord.x + scaledCoord.y*scaledCoord.y;
- const float inv_dist = approx_rsqrt(dist2);
- const float radian = M_PI_2 - approx_atan((alpha * approx_sqrt(radius2 - dist2)) * inv_dist);
+ const float inv_dist = half_rsqrt(dist2);
+ const float radian = M_PI_2 - atan((alpha * half_sqrt(radius2 - dist2)) * inv_dist);
const float scalar = radian * factor * inv_dist;
const float2 new_coord = mad(coord, scalar, center);
const float4 fout = rsSample(in_alloc, sampler, new_coord);
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/vignette_approx.rsh b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/vignette_approx.rsh
index 19d0117..7f7bdcf 100644
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/vignette_approx.rsh
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/vignette_approx.rsh
@@ -49,9 +49,9 @@
const float4 fin = convert_float4(*in);
const float2 inCoord = {(float)x, (float)y};
const float2 coord = mad(inCoord, inv_dimensions, neg_center);
- const float sloped_dist_ratio = approx_length(axis_scale * coord) * sloped_inv_max_dist;
- // TODO: add approx_exp once implemented
- const float lumen = opp_shade + shade * approx_recip(1.f + sloped_neg_range * exp(sloped_dist_ratio));
+ const float sloped_dist_ratio = fast_length(axis_scale * coord) * sloped_inv_max_dist;
+ // TODO: add half_exp once implemented
+ const float lumen = opp_shade + shade * half_recip(1.f + sloped_neg_range * exp(sloped_dist_ratio));
float4 fout;
fout.rgb = fin.rgb * lumen;
fout.w = fin.w;
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java b/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java
index f4440c8..b1501ed 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java
@@ -39,6 +39,8 @@
/** @hide */
public static final int MAX_GROUP_OWNER_INTENT = 15;
+ /** @hide */
+ public static final int MIN_GROUP_OWNER_INTENT = 0;
/**
* This is an integer value between 0 and 15 where 0 indicates the least