Merge "New media button API." into jb-mr2-dev
diff --git a/core/java/android/appwidget/AppWidgetHost.java b/core/java/android/appwidget/AppWidgetHost.java
index f7933d3..c62bf32 100644
--- a/core/java/android/appwidget/AppWidgetHost.java
+++ b/core/java/android/appwidget/AppWidgetHost.java
@@ -338,8 +338,8 @@
*/
public final AppWidgetHostView createView(Context context, int appWidgetId,
AppWidgetProviderInfo appWidget) {
- final int userId = context.getUserId();
- AppWidgetHostView view = onCreateView(context, appWidgetId, appWidget);
+ final int userId = mContext.getUserId();
+ AppWidgetHostView view = onCreateView(mContext, appWidgetId, appWidget);
view.setUserId(userId);
view.setOnClickHandler(mOnClickHandler);
view.setAppWidget(appWidgetId, appWidget);
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index e522754..eedc372 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -121,7 +121,7 @@
public Collection<String> getAllInterfaceNames() {
Collection interfaceNames = new ArrayList<String>(mStackedLinks.size() + 1);
- interfaceNames.add(new String(mIfaceName));
+ if (mIfaceName != null) interfaceNames.add(new String(mIfaceName));
for (LinkProperties stacked: mStackedLinks.values()) {
interfaceNames.addAll(stacked.getAllInterfaceNames());
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 19283be..f9ad8c0 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -4411,6 +4411,14 @@
public static final String DATA_ROAMING = "data_roaming";
/**
+ * The value passed to a Mobile DataConnection via bringUp which defines the
+ * number of retries to preform when setting up the initial connection. The default
+ * value defined in DataConnectionTrackerBase#DEFAULT_MDC_INITIAL_RETRY is currently 1.
+ * @hide
+ */
+ public static final String MDC_INITIAL_MAX_RETRY = "mdc_initial_max_retry";
+
+ /**
* Whether user has enabled development settings.
*/
public static final String DEVELOPMENT_SETTINGS_ENABLED = "development_settings_enabled";
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index c369ebe..2ec9a7d 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -399,12 +399,13 @@
///////////////////////////////////////////////////////////////////////////
void drawHardwareLayer(HardwareLayer layer, float x, float y, Paint paint) {
+ layer.setLayerPaint(paint);
+
final GLES20Layer glLayer = (GLES20Layer) layer;
- final int nativePaint = paint == null ? 0 : paint.mNativePaint;
- nDrawLayer(mRenderer, glLayer.getLayer(), x, y, nativePaint);
+ nDrawLayer(mRenderer, glLayer.getLayer(), x, y);
}
- private static native void nDrawLayer(int renderer, int layer, float x, float y, int paint);
+ private static native void nDrawLayer(int renderer, int layer, float x, float y);
void interrupt() {
nInterrupt(mRenderer);
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 925a5e76..3ce4c13 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -107,6 +107,7 @@
private static final boolean DEBUG_IMF = false || LOCAL_LOGV;
private static final boolean DEBUG_CONFIGURATION = false || LOCAL_LOGV;
private static final boolean DEBUG_FPS = false;
+ private static final boolean DEBUG_INPUT_PROCESSING = false || LOCAL_LOGV;
private static final boolean USE_RENDER_THREAD = false;
@@ -231,24 +232,38 @@
int mClientWindowLayoutFlags;
boolean mLastOverscanRequested;
- /** @hide */
+ /** Event was not handled and is finished.
+ * @hide */
public static final int EVENT_NOT_HANDLED = 0;
- /** @hide */
+ /** Event was handled and is finished.
+ * @hide */
public static final int EVENT_HANDLED = 1;
- /** @hide */
- public static final int EVENT_IN_PROGRESS = 2;
+ /** Event is waiting on the IME.
+ * @hide */
+ public static final int EVENT_PENDING_IME = 2;
+ /** Event requires post-IME dispatch.
+ * @hide */
+ public static final int EVENT_POST_IME = 3;
// Pool of queued input events.
private static final int MAX_QUEUED_INPUT_EVENT_POOL_SIZE = 10;
private QueuedInputEvent mQueuedInputEventPool;
private int mQueuedInputEventPoolSize;
- // Input event queue.
- QueuedInputEvent mFirstPendingInputEvent;
+ /* Input event queue.
+ * Pending input events are input events waiting to be handled by the application. Current
+ * input events are input events which are being handled but are waiting on some action by the
+ * IME, even if they themselves may not need to be handled by the IME.
+ */
+ QueuedInputEvent mPendingInputEventHead;
+ QueuedInputEvent mPendingInputEventTail;
int mPendingInputEventCount;
- QueuedInputEvent mCurrentInputEvent;
+ QueuedInputEvent mCurrentInputEventHead;
+ QueuedInputEvent mCurrentInputEventTail;
+ int mCurrentInputEventCount;
boolean mProcessInputEventsScheduled;
String mPendingInputEventQueueLengthCounterName = "pq";
+ String mCurrentInputEventQueueLengthCounterName = "cq";
boolean mWindowAttributesChanged = false;
int mWindowAttributesChangesFlag = 0;
@@ -646,6 +661,7 @@
}
mPendingInputEventQueueLengthCounterName = "pq:" + attrs.getTitle();
+ mCurrentInputEventQueueLengthCounterName = "cq:" + attrs.getTitle();
}
}
}
@@ -3441,17 +3457,13 @@
if (DEBUG_IMF)
Log.v(TAG, "Sending trackball event to IME: seq="
+ seq + " event=" + event);
- int result = imm.dispatchTrackballEvent(mView.getContext(), seq, event,
+ return imm.dispatchTrackballEvent(mView.getContext(), seq, event,
mInputMethodCallback);
- if (result != EVENT_NOT_HANDLED) {
- return result;
- }
}
}
}
- // Not dispatching to IME, continue with post IME actions.
- return deliverTrackballEventPostIme(q);
+ return EVENT_POST_IME;
}
private int deliverTrackballEventPostIme(QueuedInputEvent q) {
@@ -3599,17 +3611,13 @@
if (DEBUG_IMF)
Log.v(TAG, "Sending generic motion event to IME: seq="
+ seq + " event=" + event);
- int result = imm.dispatchGenericMotionEvent(mView.getContext(), seq, event,
+ return imm.dispatchGenericMotionEvent(mView.getContext(), seq, event,
mInputMethodCallback);
- if (result != EVENT_NOT_HANDLED) {
- return result;
- }
}
}
}
- // Not dispatching to IME, continue with post IME actions.
- return deliverGenericMotionEventPostIme(q);
+ return EVENT_POST_IME;
}
private int deliverGenericMotionEventPostIme(QueuedInputEvent q) {
@@ -3814,17 +3822,13 @@
final int seq = event.getSequenceNumber();
if (DEBUG_IMF) Log.v(TAG, "Sending key event to IME: seq="
+ seq + " event=" + event);
- int result = imm.dispatchKeyEvent(mView.getContext(), seq, event,
+ return imm.dispatchKeyEvent(mView.getContext(), seq, event,
mInputMethodCallback);
- if (result != EVENT_NOT_HANDLED) {
- return result;
- }
}
}
}
- // Not dispatching to IME, continue with post IME actions.
- return deliverKeyEventPostIme(q);
+ return EVENT_POST_IME;
}
private int deliverKeyEventPostIme(QueuedInputEvent q) {
@@ -4425,14 +4429,13 @@
// in response to touch events and we want to ensure that the injected keys
// are processed in the order they were received and we cannot trust that
// the time stamp of injected events are monotonic.
- QueuedInputEvent last = mFirstPendingInputEvent;
+ QueuedInputEvent last = mPendingInputEventTail;
if (last == null) {
- mFirstPendingInputEvent = q;
+ mPendingInputEventHead = q;
+ mPendingInputEventTail = q;
} else {
- while (last.mNext != null) {
- last = last.mNext;
- }
last.mNext = q;
+ mPendingInputEventTail = q;
}
mPendingInputEventCount += 1;
Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
@@ -4455,19 +4458,44 @@
}
void doProcessInputEvents() {
- while (mCurrentInputEvent == null && mFirstPendingInputEvent != null) {
- QueuedInputEvent q = mFirstPendingInputEvent;
- mFirstPendingInputEvent = q.mNext;
+ // Handle all of the available pending input events. Currently this will immediately
+ // process all of the events it can until it encounters one that must go through the IME.
+ // After that it will continue adding events to the current input queue but will wait for a
+ // response from the IME, regardless of whether that particular event needs it or not, in
+ // order to guarantee ordering consistency. This could be slightly improved by only
+ // queueing events whose source has previously encountered something that needs to be
+ // handled by the IME, and otherwise handling them immediately since we only need to
+ // guarantee ordering within a given source.
+ while (mPendingInputEventHead != null) {
+ QueuedInputEvent q = mPendingInputEventHead;
+ mPendingInputEventHead = q.mNext;
+ if (mPendingInputEventHead == null) {
+ mPendingInputEventTail = null;
+ }
q.mNext = null;
- mCurrentInputEvent = q;
mPendingInputEventCount -= 1;
Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
mPendingInputEventCount);
- final int result = deliverInputEvent(q);
- if (result != EVENT_IN_PROGRESS) {
- finishCurrentInputEvent(result == EVENT_HANDLED);
+ int result = deliverInputEvent(q);
+
+ if (result == EVENT_HANDLED || result == EVENT_NOT_HANDLED) {
+ finishInputEvent(q, result == EVENT_HANDLED);
+ } else if (result == EVENT_PENDING_IME) {
+ enqueueCurrentInputEvent(q);
+ } else {
+ q.mFlags |= QueuedInputEvent.FLAG_DELIVER_POST_IME;
+ // If the IME decided not to handle this event, and we have no events already being
+ // handled by the IME, go ahead and handle this one and then continue to the next
+ // input event. Otherwise, queue it up and handle it after whatever in front of it
+ // in the queue has been handled.
+ if (mCurrentInputEventHead == null) {
+ result = deliverInputEventPostIme(q);
+ finishInputEvent(q, result == EVENT_HANDLED);
+ } else {
+ enqueueCurrentInputEvent(q);
+ }
}
}
@@ -4479,9 +4507,36 @@
}
}
+ private void enqueueCurrentInputEvent(QueuedInputEvent q) {
+ if (mCurrentInputEventHead == null) {
+ mCurrentInputEventHead = q;
+ mCurrentInputEventTail = q;
+ } else {
+ mCurrentInputEventTail.mNext = q;
+ mCurrentInputEventTail = q;
+ }
+ mCurrentInputEventCount += 1;
+ Trace.traceCounter(Trace.TRACE_TAG_INPUT, mCurrentInputEventQueueLengthCounterName,
+ mCurrentInputEventCount);
+ }
+
+ private QueuedInputEvent dequeueCurrentInputEvent() {
+ QueuedInputEvent q = mCurrentInputEventHead;
+ mCurrentInputEventHead = q.mNext;
+ if (mCurrentInputEventHead == null) {
+ mCurrentInputEventTail = null;
+ }
+ q.mNext = null;
+ mCurrentInputEventCount -= 1;
+ Trace.traceCounter(Trace.TRACE_TAG_INPUT, mCurrentInputEventQueueLengthCounterName,
+ mCurrentInputEventCount);
+ return q;
+ }
+
void handleImeFinishedEvent(int seq, boolean handled) {
- final QueuedInputEvent q = mCurrentInputEvent;
+ QueuedInputEvent q = mCurrentInputEventHead;
if (q != null && q.mEvent.getSequenceNumber() == seq) {
+ dequeueCurrentInputEvent();
if (DEBUG_IMF) {
Log.v(TAG, "IME finished event: seq=" + seq
+ " handled=" + handled + " event=" + q);
@@ -4500,22 +4555,26 @@
}
}
}
- finishCurrentInputEvent(handled);
- // Immediately start processing the next input event.
- doProcessInputEvents();
+ finishInputEvent(q, handled);
+
+ // Flush all of the input events that are no longer waiting on the IME
+ while (mCurrentInputEventHead != null && (mCurrentInputEventHead.mFlags &
+ QueuedInputEvent.FLAG_DELIVER_POST_IME) != 0) {
+ q = dequeueCurrentInputEvent();
+ final int result = deliverInputEventPostIme(q);
+ finishInputEvent(q, result == EVENT_HANDLED);
+ }
} else {
if (DEBUG_IMF) {
Log.v(TAG, "IME finished event: seq=" + seq
+ " handled=" + handled + ", event not found!");
}
}
+
}
- private void finishCurrentInputEvent(boolean handled) {
- final QueuedInputEvent q = mCurrentInputEvent;
- mCurrentInputEvent = null;
-
+ private void finishInputEvent(QueuedInputEvent q, boolean handled) {
if (q.mReceiver != null) {
q.mReceiver.finishInputEvent(q.mEvent, handled);
} else {
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index dba2354..e602eb7 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -1577,13 +1577,13 @@
final long startTime = SystemClock.uptimeMillis();
enqueuePendingEventLocked(startTime, seq, mCurId, callback);
mCurMethod.dispatchKeyEvent(seq, key, mInputMethodCallback);
- return ViewRootImpl.EVENT_IN_PROGRESS;
+ return ViewRootImpl.EVENT_PENDING_IME;
} catch (RemoteException e) {
Log.w(TAG, "IME died: " + mCurId + " dropping: " + key, e);
}
}
}
- return ViewRootImpl.EVENT_NOT_HANDLED;
+ return ViewRootImpl.EVENT_POST_IME;
}
/**
@@ -1600,13 +1600,13 @@
final long startTime = SystemClock.uptimeMillis();
enqueuePendingEventLocked(startTime, seq, mCurId, callback);
mCurMethod.dispatchTrackballEvent(seq, motion, mInputMethodCallback);
- return ViewRootImpl.EVENT_IN_PROGRESS;
+ return ViewRootImpl.EVENT_PENDING_IME;
} catch (RemoteException e) {
Log.w(TAG, "IME died: " + mCurId + " dropping trackball: " + motion, e);
}
}
}
- return ViewRootImpl.EVENT_NOT_HANDLED;
+ return ViewRootImpl.EVENT_POST_IME;
}
/**
@@ -1623,13 +1623,13 @@
final long startTime = SystemClock.uptimeMillis();
enqueuePendingEventLocked(startTime, seq, mCurId, callback);
mCurMethod.dispatchGenericMotionEvent(seq, motion, mInputMethodCallback);
- return ViewRootImpl.EVENT_IN_PROGRESS;
+ return ViewRootImpl.EVENT_PENDING_IME;
} catch (RemoteException e) {
Log.w(TAG, "IME died: " + mCurId + " dropping generic motion: " + motion, e);
}
}
}
- return ViewRootImpl.EVENT_NOT_HANDLED;
+ return ViewRootImpl.EVENT_POST_IME;
}
void finishedEvent(int seq, boolean handled) {
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index d44df0c..9137d3c 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -79,6 +79,10 @@
* @return true if they're equal, false otherwise
*/
public static boolean equals(byte[] array1, byte[] array2, int length) {
+ if (length < 0) {
+ throw new IllegalArgumentException();
+ }
+
if (array1 == array2) {
return true;
}
diff --git a/core/java/com/android/internal/util/XmlUtils.java b/core/java/com/android/internal/util/XmlUtils.java
index 93f6cf6..fa35308 100644
--- a/core/java/com/android/internal/util/XmlUtils.java
+++ b/core/java/com/android/internal/util/XmlUtils.java
@@ -16,6 +16,7 @@
package com.android.internal.util;
+import android.util.Xml;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -24,6 +25,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.net.ProtocolException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
@@ -32,11 +34,8 @@
import java.util.Map;
import java.util.Set;
-import android.util.Xml;
-
/** {@hide} */
-public class XmlUtils
-{
+public class XmlUtils {
public static void skipCurrentTag(XmlPullParser parser)
throws XmlPullParserException, IOException {
@@ -900,4 +899,42 @@
}
}
}
+
+ public static int readIntAttribute(XmlPullParser in, String name) throws IOException {
+ final String value = in.getAttributeValue(null, name);
+ try {
+ return Integer.parseInt(value);
+ } catch (NumberFormatException e) {
+ throw new ProtocolException("problem parsing " + name + "=" + value + " as int");
+ }
+ }
+
+ public static void writeIntAttribute(XmlSerializer out, String name, int value)
+ throws IOException {
+ out.attribute(null, name, Integer.toString(value));
+ }
+
+ public static long readLongAttribute(XmlPullParser in, String name) throws IOException {
+ final String value = in.getAttributeValue(null, name);
+ try {
+ return Long.parseLong(value);
+ } catch (NumberFormatException e) {
+ throw new ProtocolException("problem parsing " + name + "=" + value + " as long");
+ }
+ }
+
+ public static void writeLongAttribute(XmlSerializer out, String name, long value)
+ throws IOException {
+ out.attribute(null, name, Long.toString(value));
+ }
+
+ public static boolean readBooleanAttribute(XmlPullParser in, String name) {
+ final String value = in.getAttributeValue(null, name);
+ return Boolean.parseBoolean(value);
+ }
+
+ public static void writeBooleanAttribute(XmlSerializer out, String name, boolean value)
+ throws IOException {
+ out.attribute(null, name, Boolean.toString(value));
+ }
}
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 3a23aa1..b87fe27 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -868,8 +868,7 @@
}
static void android_view_GLES20Canvas_drawLayer(JNIEnv* env, jobject clazz,
- OpenGLRenderer* renderer, Layer* layer, jfloat x, jfloat y, SkPaint* paint) {
- // TODO: don't pass the paint from java
+ OpenGLRenderer* renderer, Layer* layer, jfloat x, jfloat y) {
renderer->drawLayer(layer, x, y);
}
@@ -1051,7 +1050,7 @@
{ "nClearLayerTexture", "(I)V", (void*) android_view_GLES20Canvas_clearLayerTexture },
{ "nDestroyLayer", "(I)V", (void*) android_view_GLES20Canvas_destroyLayer },
{ "nDestroyLayerDeferred", "(I)V", (void*) android_view_GLES20Canvas_destroyLayerDeferred },
- { "nDrawLayer", "(IIFFI)V", (void*) android_view_GLES20Canvas_drawLayer },
+ { "nDrawLayer", "(IIFF)V", (void*) android_view_GLES20Canvas_drawLayer },
{ "nCopyLayer", "(II)Z", (void*) android_view_GLES20Canvas_copyLayer },
{ "nClearLayerUpdates", "(I)V", (void*) android_view_GLES20Canvas_clearLayerUpdates },
{ "nPushLayerUpdate", "(II)V", (void*) android_view_GLES20Canvas_pushLayerUpdate },
diff --git a/libs/hwui/DeferredDisplayList.cpp b/libs/hwui/DeferredDisplayList.cpp
index 7907224..020c1e9 100644
--- a/libs/hwui/DeferredDisplayList.cpp
+++ b/libs/hwui/DeferredDisplayList.cpp
@@ -368,13 +368,18 @@
status_t status = DrawGlInfo::kStatusDone;
if (isEmpty()) return status; // nothing to flush
+ renderer.restoreToCount(1);
DEFER_LOGD("--flushing");
renderer.eventMark("Flush");
+ // save and restore (with draw modifiers) so that reordering doesn't affect final state
DrawModifiers restoreDrawModifiers = renderer.getDrawModifiers();
- renderer.restoreToCount(1);
+ renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
+
status |= replayBatchList(mBatches, renderer, dirty);
+
+ renderer.restoreToCount(1);
renderer.setDrawModifiers(restoreDrawModifiers);
DEFER_LOGD("--flush complete, returning %x", status);
diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java
index 3ae652a..a82f421 100644
--- a/services/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -63,13 +63,13 @@
import static android.text.format.DateUtils.DAY_IN_MILLIS;
import static com.android.internal.util.ArrayUtils.appendInt;
import static com.android.internal.util.Preconditions.checkNotNull;
+import static com.android.internal.util.XmlUtils.readBooleanAttribute;
+import static com.android.internal.util.XmlUtils.readIntAttribute;
+import static com.android.internal.util.XmlUtils.readLongAttribute;
+import static com.android.internal.util.XmlUtils.writeBooleanAttribute;
+import static com.android.internal.util.XmlUtils.writeIntAttribute;
+import static com.android.internal.util.XmlUtils.writeLongAttribute;
import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT;
-import static com.android.server.net.NetworkPolicyManagerService.XmlUtils.readBooleanAttribute;
-import static com.android.server.net.NetworkPolicyManagerService.XmlUtils.readIntAttribute;
-import static com.android.server.net.NetworkPolicyManagerService.XmlUtils.readLongAttribute;
-import static com.android.server.net.NetworkPolicyManagerService.XmlUtils.writeBooleanAttribute;
-import static com.android.server.net.NetworkPolicyManagerService.XmlUtils.writeIntAttribute;
-import static com.android.server.net.NetworkPolicyManagerService.XmlUtils.writeLongAttribute;
import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_UPDATED;
import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
import static org.xmlpull.v1.XmlPullParser.START_TAG;
@@ -149,7 +149,6 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
-import java.net.ProtocolException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@@ -2088,44 +2087,4 @@
}
fout.print("]");
}
-
- public static class XmlUtils {
- public static int readIntAttribute(XmlPullParser in, String name) throws IOException {
- final String value = in.getAttributeValue(null, name);
- try {
- return Integer.parseInt(value);
- } catch (NumberFormatException e) {
- throw new ProtocolException("problem parsing " + name + "=" + value + " as int");
- }
- }
-
- public static void writeIntAttribute(XmlSerializer out, String name, int value)
- throws IOException {
- out.attribute(null, name, Integer.toString(value));
- }
-
- public static long readLongAttribute(XmlPullParser in, String name) throws IOException {
- final String value = in.getAttributeValue(null, name);
- try {
- return Long.parseLong(value);
- } catch (NumberFormatException e) {
- throw new ProtocolException("problem parsing " + name + "=" + value + " as long");
- }
- }
-
- public static void writeLongAttribute(XmlSerializer out, String name, long value)
- throws IOException {
- out.attribute(null, name, Long.toString(value));
- }
-
- public static boolean readBooleanAttribute(XmlPullParser in, String name) {
- final String value = in.getAttributeValue(null, name);
- return Boolean.parseBoolean(value);
- }
-
- public static void writeBooleanAttribute(XmlSerializer out, String name, boolean value)
- throws IOException {
- out.attribute(null, name, Boolean.toString(value));
- }
- }
}
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 56f4de5..b46fb2f 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -76,6 +76,7 @@
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Canvas;
+import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.PixelFormat;
import android.graphics.Point;
@@ -282,6 +283,8 @@
private static final String SYSTEM_SECURE = "ro.secure";
private static final String SYSTEM_DEBUGGABLE = "ro.debuggable";
+ private static final int MAX_SCREENSHOT_RETRIES = 3;
+
final private KeyguardDisableHandler mKeyguardDisableHandler;
private final boolean mHeadless;
@@ -5277,134 +5280,191 @@
throw new SecurityException("Requires READ_FRAME_BUFFER permission");
}
- Bitmap rawss;
+ Bitmap rawss = null;
int maxLayer = 0;
final Rect frame = new Rect();
- float scale;
+ float scale = 0;
int dw, dh;
- int rot;
+ int rot = Surface.ROTATION_0;
- synchronized(mWindowMap) {
- long ident = Binder.clearCallingIdentity();
+ boolean screenshotReady;
+ int minLayer;
+ if (appToken == null) {
+ screenshotReady = true;
+ minLayer = 0;
+ } else {
+ screenshotReady = false;
+ minLayer = Integer.MAX_VALUE;
+ }
- final DisplayContent displayContent = getDisplayContentLocked(displayId);
- if (displayContent == null) {
- return null;
+ int retryCount = 0;
+ WindowState appWin = null;
+
+ do {
+ if (retryCount++ > 0) {
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ }
}
- final DisplayInfo displayInfo = displayContent.getDisplayInfo();
- dw = displayInfo.logicalWidth;
- dh = displayInfo.logicalHeight;
-
- int aboveAppLayer = mPolicy.windowTypeToLayerLw(TYPE_APPLICATION)
- * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
- aboveAppLayer += TYPE_LAYER_MULTIPLIER;
-
- boolean isImeTarget = mInputMethodTarget != null
- && mInputMethodTarget.mAppToken != null
- && mInputMethodTarget.mAppToken.appToken != null
- && mInputMethodTarget.mAppToken.appToken.asBinder() == appToken;
-
- // Figure out the part of the screen that is actually the app.
- boolean including = false;
- final WindowList windows = displayContent.getWindowList();
- for (int i = windows.size() - 1; i >= 0; i--) {
- WindowState ws = windows.get(i);
- if (!ws.mHasSurface) {
- continue;
+ synchronized(mWindowMap) {
+ final DisplayContent displayContent = getDisplayContentLocked(displayId);
+ if (displayContent == null) {
+ return null;
}
- if (ws.mLayer >= aboveAppLayer) {
- continue;
- }
- // When we will skip windows: when we are not including
- // ones behind a window we didn't skip, and we are actually
- // taking a screenshot of a specific app.
- if (!including && appToken != null) {
- // Also, we can possibly skip this window if it is not
- // an IME target or the application for the screenshot
- // is not the current IME target.
- if (!ws.mIsImWindow || !isImeTarget) {
- // And finally, this window is of no interest if it
- // is not associated with the screenshot app.
- if (ws.mAppToken == null || ws.mAppToken.token != appToken) {
- continue;
+ final DisplayInfo displayInfo = displayContent.getDisplayInfo();
+ dw = displayInfo.logicalWidth;
+ dh = displayInfo.logicalHeight;
+
+ int aboveAppLayer = mPolicy.windowTypeToLayerLw(TYPE_APPLICATION)
+ * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
+ aboveAppLayer += TYPE_LAYER_MULTIPLIER;
+
+ boolean isImeTarget = mInputMethodTarget != null
+ && mInputMethodTarget.mAppToken != null
+ && mInputMethodTarget.mAppToken.appToken != null
+ && mInputMethodTarget.mAppToken.appToken.asBinder() == appToken;
+
+ // Figure out the part of the screen that is actually the app.
+ boolean including = false;
+ appWin = null;
+ final WindowList windows = displayContent.getWindowList();
+ for (int i = windows.size() - 1; i >= 0; i--) {
+ WindowState ws = windows.get(i);
+ if (!ws.mHasSurface) {
+ continue;
+ }
+ if (ws.mLayer >= aboveAppLayer) {
+ continue;
+ }
+ // When we will skip windows: when we are not including
+ // ones behind a window we didn't skip, and we are actually
+ // taking a screenshot of a specific app.
+ if (!including && appToken != null) {
+ // Also, we can possibly skip this window if it is not
+ // an IME target or the application for the screenshot
+ // is not the current IME target.
+ if (!ws.mIsImWindow || !isImeTarget) {
+ // And finally, this window is of no interest if it
+ // is not associated with the screenshot app.
+ if (ws.mAppToken == null || ws.mAppToken.token != appToken) {
+ continue;
+ }
+ appWin = ws;
+ }
+ }
+
+ // We keep on including windows until we go past a full-screen
+ // window.
+ boolean fullscreen = ws.isFullscreen(dw, dh);
+ including = !ws.mIsImWindow && !fullscreen;
+
+ final WindowStateAnimator winAnim = ws.mWinAnimator;
+ if (maxLayer < winAnim.mSurfaceLayer) {
+ maxLayer = winAnim.mSurfaceLayer;
+ }
+
+ // Don't include wallpaper in bounds calculation
+ if (!ws.mIsWallpaper) {
+ final Rect wf = ws.mFrame;
+ final Rect cr = ws.mContentInsets;
+ int left = wf.left + cr.left;
+ int top = wf.top + cr.top;
+ int right = wf.right - cr.right;
+ int bottom = wf.bottom - cr.bottom;
+ frame.union(left, top, right, bottom);
+ }
+
+ if (ws.mAppToken != null && ws.mAppToken.token == appToken) {
+ if (minLayer > ws.mWinAnimator.mSurfaceLayer) {
+ minLayer = ws.mWinAnimator.mSurfaceLayer;
+ }
+ if (ws.isDisplayedLw()) {
+ screenshotReady = true;
+ }
+ if (fullscreen) {
+ // No point in continuing down through windows.
+ break;
}
}
}
- // We keep on including windows until we go past a full-screen
- // window.
- including = !ws.mIsImWindow && !ws.isFullscreen(dw, dh);
-
- if (maxLayer < ws.mWinAnimator.mSurfaceLayer) {
- maxLayer = ws.mWinAnimator.mSurfaceLayer;
+ if (appToken != null && appWin == null) {
+ // Can't find a window to snapshot.
+ if (DEBUG_SCREENSHOT) Slog.i(TAG,
+ "Screenshot: Couldn't find a surface matching " + appToken);
+ return null;
+ }
+ if (!screenshotReady) {
+ // Delay and hope that window gets drawn.
+ if (DEBUG_SCREENSHOT) Slog.i(TAG, "Screenshot: No image ready for " + appToken
+ + ", " + appWin + " drawState=" + appWin.mWinAnimator.mDrawState);
+ continue;
}
- // Don't include wallpaper in bounds calculation
- if (!ws.mIsWallpaper) {
- final Rect wf = ws.mFrame;
- final Rect cr = ws.mContentInsets;
- int left = wf.left + cr.left;
- int top = wf.top + cr.top;
- int right = wf.right - cr.right;
- int bottom = wf.bottom - cr.bottom;
- frame.union(left, top, right, bottom);
+ // Constrain frame to the screen size.
+ frame.intersect(0, 0, dw, dh);
+
+ if (frame.isEmpty() || maxLayer == 0) {
+ if (DEBUG_SCREENSHOT) Slog.i(TAG, "Screenshot of " + appToken
+ + ": returning null frame=" + frame.toShortString() + " maxLayer="
+ + maxLayer);
+ return null;
}
- }
- Binder.restoreCallingIdentity(ident);
- // Constrain frame to the screen size.
- frame.intersect(0, 0, dw, dh);
+ // The screenshot API does not apply the current screen rotation.
+ rot = getDefaultDisplayContentLocked().getDisplay().getRotation();
+ int fw = frame.width();
+ int fh = frame.height();
- if (frame.isEmpty() || maxLayer == 0) {
- return null;
- }
-
- // The screenshot API does not apply the current screen rotation.
- rot = getDefaultDisplayContentLocked().getDisplay().getRotation();
- int fw = frame.width();
- int fh = frame.height();
-
- // Constrain thumbnail to smaller of screen width or height. Assumes aspect
- // of thumbnail is the same as the screen (in landscape) or square.
- float targetWidthScale = width / (float) fw;
- float targetHeightScale = height / (float) fh;
- if (dw <= dh) {
- scale = targetWidthScale;
- // If aspect of thumbnail is the same as the screen (in landscape),
- // select the slightly larger value so we fill the entire bitmap
- if (targetHeightScale > scale && (int) (targetHeightScale * fw) == width) {
- scale = targetHeightScale;
- }
- } else {
- scale = targetHeightScale;
- // If aspect of thumbnail is the same as the screen (in landscape),
- // select the slightly larger value so we fill the entire bitmap
- if (targetWidthScale > scale && (int) (targetWidthScale * fh) == height) {
+ // Constrain thumbnail to smaller of screen width or height. Assumes aspect
+ // of thumbnail is the same as the screen (in landscape) or square.
+ float targetWidthScale = width / (float) fw;
+ float targetHeightScale = height / (float) fh;
+ if (dw <= dh) {
scale = targetWidthScale;
+ // If aspect of thumbnail is the same as the screen (in landscape),
+ // select the slightly larger value so we fill the entire bitmap
+ if (targetHeightScale > scale && (int) (targetHeightScale * fw) == width) {
+ scale = targetHeightScale;
+ }
+ } else {
+ scale = targetHeightScale;
+ // If aspect of thumbnail is the same as the screen (in landscape),
+ // select the slightly larger value so we fill the entire bitmap
+ if (targetWidthScale > scale && (int) (targetWidthScale * fh) == height) {
+ scale = targetWidthScale;
+ }
}
- }
- // The screen shot will contain the entire screen.
- dw = (int)(dw*scale);
- dh = (int)(dh*scale);
- if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) {
- int tmp = dw;
- dw = dh;
- dh = tmp;
- rot = (rot == Surface.ROTATION_90) ? Surface.ROTATION_270 : Surface.ROTATION_90;
- }
- if (DEBUG_SCREENSHOT) {
- Slog.i(TAG, "Screenshot: " + dw + "x" + dh + " from 0 to " + maxLayer);
- for (int i = 0; i < windows.size(); i++) {
- WindowState win = windows.get(i);
- Slog.i(TAG, win + ": " + win.mLayer
- + " animLayer=" + win.mWinAnimator.mAnimLayer
- + " surfaceLayer=" + win.mWinAnimator.mSurfaceLayer);
+ // The screen shot will contain the entire screen.
+ dw = (int)(dw*scale);
+ dh = (int)(dh*scale);
+ if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) {
+ int tmp = dw;
+ dw = dh;
+ dh = tmp;
+ rot = (rot == Surface.ROTATION_90) ? Surface.ROTATION_270 : Surface.ROTATION_90;
}
+ if (DEBUG_SCREENSHOT) {
+ Slog.i(TAG, "Screenshot: " + dw + "x" + dh + " from " + minLayer + " to "
+ + maxLayer + " appToken=" + appToken);
+ for (int i = 0; i < windows.size(); i++) {
+ WindowState win = windows.get(i);
+ Slog.i(TAG, win + ": " + win.mLayer
+ + " animLayer=" + win.mWinAnimator.mAnimLayer
+ + " surfaceLayer=" + win.mWinAnimator.mSurfaceLayer);
+ }
+ }
+ rawss = SurfaceControl.screenshot(dw, dh, minLayer, maxLayer);
}
- rawss = SurfaceControl.screenshot(dw, dh, 0, maxLayer);
+ } while (!screenshotReady && retryCount <= MAX_SCREENSHOT_RETRIES);
+ if (DEBUG_SCREENSHOT && retryCount > MAX_SCREENSHOT_RETRIES) {
+ Slog.i(TAG, "Screenshot max retries " + retryCount + " of " + appToken + " appWin="
+ + (appWin == null ? "null" : (appWin + " drawState="
+ + appWin.mWinAnimator.mDrawState)));
}
if (rawss == null) {
@@ -5421,6 +5481,23 @@
canvas.drawBitmap(rawss, matrix, null);
canvas.setBitmap(null);
+ if (DEBUG_SCREENSHOT) {
+ // TEST IF IT's ALL BLACK
+ int[] buffer = new int[bm.getWidth() * bm.getHeight()];
+ bm.getPixels(buffer, 0, bm.getWidth(), 0, 0, bm.getWidth(), bm.getHeight());
+ boolean allBlack = true;
+ for (int i = 0; i < buffer.length; i++) {
+ if (buffer[i] != Color.BLACK) {
+ allBlack = false;
+ break;
+ }
+ }
+ if (allBlack) {
+ Slog.i(TAG, "Screenshot " + appWin + " was all black! mSurfaceLayer=" +
+ (appWin != null ? appWin.mWinAnimator.mSurfaceLayer : "null"));
+ }
+ }
+
rawss.recycle();
return bm;
}
@@ -7408,6 +7485,7 @@
performLayoutAndPlaceSurfacesLocked();
}
+ @Override
public void setOverscan(int displayId, int left, int top, int right, int bottom) {
if (mContext.checkCallingOrSelfPermission(
android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
diff --git a/telephony/java/com/android/internal/telephony/DctConstants.java b/telephony/java/com/android/internal/telephony/DctConstants.java
index 80c985f..cacafd4 100644
--- a/telephony/java/com/android/internal/telephony/DctConstants.java
+++ b/telephony/java/com/android/internal/telephony/DctConstants.java
@@ -30,10 +30,11 @@
* DISCONNECTING: Connection.disconnect() has been called, but PDP
* context is not yet deactivated
* FAILED: data connection fail for all apns settings
+ * RETRYING: data connection failed but we're going to retry.
*
* getDataConnectionState() maps State to DataState
* FAILED or IDLE : DISCONNECTED
- * CONNECTING or SCANNING: CONNECTING
+ * RETRYING or CONNECTING or SCANNING: CONNECTING
* CONNECTED : CONNECTED or DISCONNECTING
*/
public enum State {
@@ -42,7 +43,8 @@
SCANNING,
CONNECTED,
DISCONNECTING,
- FAILED
+ FAILED,
+ RETRYING
}
public enum Activity {
@@ -89,6 +91,8 @@
public static final int CMD_SET_DEPENDENCY_MET = BASE + 31;
public static final int CMD_SET_POLICY_DATA_ENABLE = BASE + 32;
public static final int EVENT_ICC_CHANGED = BASE + 33;
+ public static final int EVENT_DISCONNECT_DC_RETRYING = BASE + 34;
+ public static final int EVENT_DATA_SETUP_COMPLETE_ERROR = BASE + 35;
/***** Constants *****/
diff --git a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
index dffb617..62f6aff 100644
--- a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
+++ b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
@@ -15,6 +15,8 @@
*/
package com.android.tests.applaunch;
+import android.accounts.Account;
+import android.accounts.AccountManager;
import android.app.ActivityManager;
import android.app.ActivityManager.ProcessErrorStateInfo;
import android.app.ActivityManagerNative;
@@ -33,9 +35,11 @@
import android.util.Log;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.Set;
/**
* This test is intended to measure the time it takes for the apps to start.
@@ -52,6 +56,9 @@
private static final String TAG = AppLaunch.class.getSimpleName();
private static final String KEY_APPS = "apps";
private static final String KEY_LAUNCH_ITERATIONS = "launch_iterations";
+ // optional parameter: comma separated list of required account types before proceeding
+ // with the app launch
+ private static final String KEY_REQUIRED_ACCOUNTS = "required_accounts";
private static final int INITIAL_LAUNCH_IDLE_TIMEOUT = 7500; //7.5s to allow app to idle
private static final int POST_LAUNCH_IDLE_TIMEOUT = 750; //750ms idle for non initial launches
private static final int BETWEEN_LAUNCH_SLEEP_TIMEOUT = 2000; //2s between launching apps
@@ -63,6 +70,7 @@
private IActivityManager mAm;
private int mLaunchIterations = 10;
private Bundle mResult = new Bundle();
+ private Set<String> mRequiredAccounts;
public void testMeasureStartUpTime() throws RemoteException, NameNotFoundException {
InstrumentationTestRunner instrumentation =
@@ -72,6 +80,7 @@
createMappings();
parseArgs(args);
+ checkAccountSignIn();
// do initial app launch, without force stopping
for (String app : mNameToResultKey.keySet()) {
@@ -140,6 +149,13 @@
mNameToResultKey.put(parts[0], parts[1]);
mNameToLaunchTime.put(parts[0], 0L);
}
+ String requiredAccounts = args.getString(KEY_REQUIRED_ACCOUNTS);
+ if (requiredAccounts != null) {
+ mRequiredAccounts = new HashSet<String>();
+ for (String accountType : requiredAccounts.split(",")) {
+ mRequiredAccounts.add(accountType);
+ }
+ }
}
private void createMappings() {
@@ -204,6 +220,37 @@
return result.thisTime;
}
+ private void checkAccountSignIn() {
+ // ensure that the device has the required account types before starting test
+ // e.g. device must have a valid Google account sign in to measure a meaningful launch time
+ // for Gmail
+ if (mRequiredAccounts == null || mRequiredAccounts.isEmpty()) {
+ return;
+ }
+ final AccountManager am =
+ (AccountManager) getInstrumentation().getTargetContext().getSystemService(
+ Context.ACCOUNT_SERVICE);
+ Account[] accounts = am.getAccounts();
+ // use set here in case device has multiple accounts of the same type
+ Set<String> foundAccounts = new HashSet<String>();
+ for (Account account : accounts) {
+ if (mRequiredAccounts.contains(account.type)) {
+ foundAccounts.add(account.type);
+ }
+ }
+ // check if account type matches, if not, fail test with message on what account types
+ // are missing
+ if (mRequiredAccounts.size() != foundAccounts.size()) {
+ mRequiredAccounts.removeAll(foundAccounts);
+ StringBuilder sb = new StringBuilder("Device missing these accounts:");
+ for (String account : mRequiredAccounts) {
+ sb.append(' ');
+ sb.append(account);
+ }
+ fail(sb.toString());
+ }
+ }
+
private void closeApp(String appName, boolean forceStopApp) {
Intent homeIntent = new Intent(Intent.ACTION_MAIN);
homeIntent.addCategory(Intent.CATEGORY_HOME);