Merge "Expose unchecked copyFrom variants." into honeycomb
diff --git a/api/11.xml b/api/11.xml
index 945c614..31cfc85 100644
--- a/api/11.xml
+++ b/api/11.xml
@@ -160213,17 +160213,6 @@
visibility="public"
>
</field>
-<field name="ACTION_MTP_SESSION_END"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value=""android.provider.action.MTP_SESSION_END""
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
<field name="ACTION_VIDEO_CAPTURE"
type="java.lang.String"
transient="false"
diff --git a/api/current.xml b/api/current.xml
index 945c614..83bfedb 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -146705,6 +146705,17 @@
visibility="public"
>
</method>
+<method name="detectActivityLeaks"
+ return="android.os.StrictMode.VmPolicy.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="detectAll"
return="android.os.StrictMode.VmPolicy.Builder"
abstract="false"
@@ -160213,17 +160224,6 @@
visibility="public"
>
</field>
-<field name="ACTION_MTP_SESSION_END"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value=""android.provider.action.MTP_SESSION_END""
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
<field name="ACTION_VIDEO_CAPTURE"
type="java.lang.String"
transient="false"
diff --git a/build/phone-hdpi-512-dalvik-heap.mk b/build/phone-hdpi-512-dalvik-heap.mk
index afc45ee..a7f9d32 100644
--- a/build/phone-hdpi-512-dalvik-heap.mk
+++ b/build/phone-hdpi-512-dalvik-heap.mk
@@ -19,5 +19,4 @@
PRODUCT_PROPERTY_OVERRIDES += \
dalvik.vm.heapstartsize=5m \
- dalvik.vm.smallheapsize=32m \
dalvik.vm.heapsize=32m
diff --git a/build/phone-hdpi-dalvik-heap.mk b/build/phone-hdpi-dalvik-heap.mk
index ee30b92..ab33b96 100644
--- a/build/phone-hdpi-dalvik-heap.mk
+++ b/build/phone-hdpi-dalvik-heap.mk
@@ -18,5 +18,4 @@
PRODUCT_PROPERTY_OVERRIDES += \
dalvik.vm.heapstartsize=5m \
- dalvik.vm.smallheapsize=32m \
dalvik.vm.heapsize=32m
diff --git a/build/tablet-dalvik-heap.mk b/build/tablet-dalvik-heap.mk
index 9cb2f6b..37c3ec5 100644
--- a/build/tablet-dalvik-heap.mk
+++ b/build/tablet-dalvik-heap.mk
@@ -18,5 +18,5 @@
PRODUCT_PROPERTY_OVERRIDES += \
dalvik.vm.heapstartsize=5m \
- dalvik.vm.smallheapsize=48m \
- dalvik.vm.heapsize=48m
+ dalvik.vm.growthlimit=48m \
+ dalvik.vm.heapsize=256m
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 0a64070..ec6eaaa 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -4433,6 +4433,9 @@
mStopped = true;
}
mResumed = false;
+
+ // Check for Activity leaks, if enabled.
+ StrictMode.conditionallyCheckInstanceCounts();
}
final void performDestroy() {
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 0243b02..de84c56 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -34,6 +34,9 @@
* A class that represents how a persistent notification is to be presented to
* the user using the {@link android.app.NotificationManager}.
*
+ * <p>The {@link Notification.Builder Notification.Builder} has been added to make it
+ * easier to construct Notifications.</p>
+ *
* <p>For a guide to creating notifications, see the
* <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html">Creating Status
* Bar Notifications</a> document in the Dev Guide.</p>
@@ -119,15 +122,8 @@
/**
* An intent to launch instead of posting the notification to the status bar.
- * Only for use with extremely high-priority notifications demanding the user's
- * <strong>immediate</strong> attention, such as an incoming phone call or
- * alarm clock that the user has explicitly set to a particular time.
- * If this facility is used for something else, please give the user an option
- * to turn it off and use a normal notification, as this can be extremely
- * disruptive.
- *
- * <p>Use with {@link #FLAG_HIGH_PRIORITY} to ensure that this notification
- * will reach the user even when other notifications are suppressed.
+ *
+ * @see Notification.Builder#setFullScreenIntent
*/
public PendingIntent fullScreenIntent;
@@ -278,7 +274,7 @@
/**
* Bit to be bitwise-ored into the {@link #flags} field that should be
* set if the notification should be canceled when it is clicked by the
- * user.
+ * user. On tablets, the
*/
public static final int FLAG_AUTO_CANCEL = 0x00000010;
@@ -618,6 +614,10 @@
return sb.toString();
}
+ /**
+ * Builder class for {@link Notification} objects. Allows easier control over
+ * all the flags, as well as help constructing the typical notification layouts.
+ */
public static class Builder {
private Context mContext;
@@ -644,6 +644,16 @@
private int mDefaults;
private int mFlags;
+ /**
+ * Constructor.
+ *
+ * Automatically sets the when field to {@link System#currentTimeMillis()
+ * System.currentTimeMllis()} and the audio stream to the {@link #STREAM_DEFAULT}.
+ *
+ * @param context A {@link Context} that will be used to construct the
+ * RemoteViews. The Context will not be held past the lifetime of this
+ * Builder object.
+ */
public Builder(Context context) {
mContext = context;
@@ -652,96 +662,192 @@
mAudioStreamType = STREAM_DEFAULT;
}
+ /**
+ * Set the time that the event occurred. Notifications in the panel are
+ * sorted by this time.
+ */
public Builder setWhen(long when) {
mWhen = when;
return this;
}
+ /**
+ * Set the small icon to use in the notification layouts. Different classes of devices
+ * may return different sizes. See the UX guidelines for more information on how to
+ * design these icons.
+ *
+ * @param icon A resource ID in the application's package of the drawble to use.
+ */
public Builder setSmallIcon(int icon) {
mSmallIcon = icon;
return this;
}
+ /**
+ * A variant of {@link #setSmallIcon(int) setSmallIcon(int)} that takes an additional
+ * level parameter for when the icon is a {@link android.graphics.drawable.LevelListDrawable
+ * LevelListDrawable}.
+ *
+ * @param icon A resource ID in the application's package of the drawble to use.
+ * @param level The level to use for the icon.
+ *
+ * @see android.graphics.drawable.LevelListDrawable
+ */
public Builder setSmallIcon(int icon, int level) {
mSmallIcon = icon;
mSmallIconLevel = level;
return this;
}
+ /**
+ * Set the title (first row) of the notification, in a standard notification.
+ */
public Builder setContentTitle(CharSequence title) {
mContentTitle = title;
return this;
}
+ /**
+ * Set the text (second row) of the notification, in a standard notification.
+ */
public Builder setContentText(CharSequence text) {
mContentText = text;
return this;
}
+ /**
+ * Set the large number at the right-hand side of the notification. This is
+ * equivalent to setContentInfo, although it might show the number in a different
+ * font size for readability.
+ */
public Builder setNumber(int number) {
mNumber = number;
return this;
}
+ /**
+ * Set the large text at the right-hand side of the notification.
+ */
public Builder setContentInfo(CharSequence info) {
mContentInfo = info;
return this;
}
+ /**
+ * Supply a custom RemoteViews to use instead of the standard one.
+ */
public Builder setContent(RemoteViews views) {
mContentView = views;
return this;
}
+ /**
+ * Supply a {@link PendingIntent} to send when the notification is clicked.
+ * If you do not supply an intent, you can now add PendingIntents to individual
+ * views to be launched when clicked by calling {@link RemoteViews#setOnClickPendingIntent
+ * RemoteViews.setOnClickPendingIntent(int,PendingIntent)}.
+ */
public Builder setContentIntent(PendingIntent intent) {
mContentIntent = intent;
return this;
}
+ /**
+ * Supply a {@link PendingIntent} to send when the notification is cleared by the user
+ * directly from the notification panel. For example, this intent is sent when the user
+ * clicks the "Clear all" button, or the individual "X" buttons on notifications. This
+ * intent is not sent when the application calls {@link NotificationManager#cancel
+ * NotificationManager.cancel(int)}.
+ */
public Builder setDeleteIntent(PendingIntent intent) {
mDeleteIntent = intent;
return this;
}
+ /**
+ * An intent to launch instead of posting the notification to the status bar.
+ * Only for use with extremely high-priority notifications demanding the user's
+ * <strong>immediate</strong> attention, such as an incoming phone call or
+ * alarm clock that the user has explicitly set to a particular time.
+ * If this facility is used for something else, please give the user an option
+ * to turn it off and use a normal notification, as this can be extremely
+ * disruptive.
+ *
+ * @param intent The pending intent to launch.
+ * @param highPriority Passing true will cause this notification to be sent
+ * even if other notifications are suppressed.
+ */
public Builder setFullScreenIntent(PendingIntent intent, boolean highPriority) {
mFullScreenIntent = intent;
setFlag(FLAG_HIGH_PRIORITY, highPriority);
return this;
}
+ /**
+ * Set the text that is displayed in the status bar when the notification first
+ * arrives.
+ */
public Builder setTicker(CharSequence tickerText) {
mTickerText = tickerText;
return this;
}
+ /**
+ * Set the text that is displayed in the status bar when the notification first
+ * arrives, and also a RemoteViews object that may be displayed instead on some
+ * devices.
+ */
public Builder setTicker(CharSequence tickerText, RemoteViews views) {
mTickerText = tickerText;
mTickerView = views;
return this;
}
+ /**
+ * Set the large icon that is shown in the ticker and notification.
+ */
public Builder setLargeIcon(Bitmap icon) {
mLargeIcon = icon;
return this;
}
+ /**
+ * Set the sound to play. It will play on the default stream.
+ */
public Builder setSound(Uri sound) {
mSound = sound;
mAudioStreamType = STREAM_DEFAULT;
return this;
}
+ /**
+ * Set the sound to play. It will play on the stream you supply.
+ *
+ * @see #STREAM_DEFAULT
+ * @see AudioManager for the <code>STREAM_</code> constants.
+ */
public Builder setSound(Uri sound, int streamType) {
mSound = sound;
mAudioStreamType = streamType;
return this;
}
+ /**
+ * Set the vibration pattern to use.
+ *
+ * @see android.os.Vibrator for a discussion of the <code>pattern</code>
+ * parameter.
+ */
public Builder setVibrate(long[] pattern) {
mVibrate = pattern;
return this;
}
+ /**
+ * Set the argb value that you would like the LED on the device to blnk, as well as the
+ * rate. The rate is specified in terms of the number of milliseconds to be on
+ * and then the number of milliseconds to be off.
+ */
public Builder setLights(int argb, int onMs, int offMs) {
mLedArgb = argb;
mLedOnMs = onMs;
@@ -749,21 +855,51 @@
return this;
}
+ /**
+ * Set whether this is an ongoing notification.
+ *
+ * <p>Ongoing notifications differ from regular notifications in the following ways:
+ * <ul>
+ * <li>Ongoing notifications are sorted above the regular notifications in the
+ * notification panel.</li>
+ * <li>Ongoing notifications do not have an 'X' close button, and are not affected
+ * by the "Clear all" button.
+ * </ul>
+ */
public Builder setOngoing(boolean ongoing) {
setFlag(FLAG_ONGOING_EVENT, ongoing);
return this;
}
+ /**
+ * Set this flag if you would only like the sound, vibrate
+ * and ticker to be played if the notification is not already showing.
+ */
public Builder setOnlyAlertOnce(boolean onlyAlertOnce) {
setFlag(FLAG_ONLY_ALERT_ONCE, onlyAlertOnce);
return this;
}
+ /**
+ * Setting this flag will make it so the notification is automatically
+ * canceled when the user clicks it in the panel. The PendingIntent
+ * set with {@link #setDeleteIntent} will be broadcast when the notification
+ * is canceled.
+ */
public Builder setAutoCancel(boolean autoCancel) {
setFlag(FLAG_AUTO_CANCEL, autoCancel);
return this;
}
+ /**
+ * Set the default notification options that will be used.
+ * <p>
+ * The value should be one or more of the following fields combined with
+ * bitwise-or:
+ * {@link #DEFAULT_SOUND}, {@link #DEFAULT_VIBRATE}, {@link #DEFAULT_LIGHTS}.
+ * <p>
+ * For all default values, use {@link #DEFAULT_ALL}.
+ */
public Builder setDefaults(int defaults) {
mDefaults = defaults;
return this;
@@ -834,6 +970,10 @@
}
}
+ /**
+ * Combine all of the options that have been set and return a new {@link Notification}
+ * object.
+ */
public Notification getNotification() {
Notification n = new Notification();
n.when = mWhen;
diff --git a/core/java/android/bluetooth/BluetoothInputDevice.java b/core/java/android/bluetooth/BluetoothInputDevice.java
index bc8a836..a70de59 100644
--- a/core/java/android/bluetooth/BluetoothInputDevice.java
+++ b/core/java/android/bluetooth/BluetoothInputDevice.java
@@ -85,6 +85,19 @@
*/
public static final int PRIORITY_UNDEFINED = -1;
+ /**
+ * Return codes for the connect and disconnect Bluez / Dbus calls.
+ */
+ public static final int INPUT_DISCONNECT_FAILED_NOT_CONNECTED = 5000;
+
+ public static final int INPUT_CONNECT_FAILED_ALREADY_CONNECTED = 5001;
+
+ public static final int INPUT_CONNECT_FAILED_ATTEMPT_FAILED = 5002;
+
+ public static final int INPUT_OPERATION_GENERIC_FAILURE = 5003;
+
+ public static final int INPUT_OPERATION_SUCCESS = 5004;
+
private final IBluetooth mService;
private final Context mContext;
diff --git a/core/java/android/bluetooth/BluetoothPan.java b/core/java/android/bluetooth/BluetoothPan.java
index 7dee25e..1f07349 100644
--- a/core/java/android/bluetooth/BluetoothPan.java
+++ b/core/java/android/bluetooth/BluetoothPan.java
@@ -70,6 +70,19 @@
public static final int STATE_CONNECTED = 2;
public static final int STATE_DISCONNECTING = 3;
+ /**
+ * Return codes for the connect and disconnect Bluez / Dbus calls.
+ */
+ public static final int PAN_DISCONNECT_FAILED_NOT_CONNECTED = 1000;
+
+ public static final int PAN_CONNECT_FAILED_ALREADY_CONNECTED = 1001;
+
+ public static final int PAN_CONNECT_FAILED_ATTEMPT_FAILED = 1002;
+
+ public static final int PAN_OPERATION_GENERIC_FAILURE = 1003;
+
+ public static final int PAN_OPERATION_SUCCESS = 1004;
+
private final IBluetooth mService;
private final Context mContext;
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index 997ea53..ae92b09 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -30,6 +30,7 @@
import dalvik.system.BlockGuard;
import dalvik.system.CloseGuard;
+import dalvik.system.VMDebug;
import java.io.PrintWriter;
import java.io.StringWriter;
@@ -184,6 +185,15 @@
/**
* @hide
*/
+ private static final int DETECT_VM_INSTANCE_LEAKS = 0x1000; // for VmPolicy
+
+ private static final int ALL_VM_DETECT_BITS =
+ DETECT_VM_CURSOR_LEAKS | DETECT_VM_CLOSABLE_LEAKS |
+ DETECT_VM_ACTIVITY_LEAKS | DETECT_VM_INSTANCE_LEAKS;
+
+ /**
+ * @hide
+ */
public static final int PENALTY_LOG = 0x10; // normal android.util.Log
// Used for both process and thread policy:
@@ -573,11 +583,15 @@
} else if (mClassInstanceLimit == null) {
mClassInstanceLimit = new HashMap<Class, Integer>();
}
+ mMask |= DETECT_VM_INSTANCE_LEAKS;
mClassInstanceLimit.put(klass, instanceLimit);
return this;
}
- private Builder detectActivityLeaks() {
+ /**
+ * Detect leaks of {@link android.app.Activity} subclasses.
+ */
+ public Builder detectActivityLeaks() {
return enable(DETECT_VM_ACTIVITY_LEAKS);
}
@@ -585,8 +599,8 @@
* Detect everything that's potentially suspect.
*
* <p>In the Honeycomb release this includes leaks of
- * SQLite cursors and other closable objects but will
- * likely expand in future releases.
+ * SQLite cursors, Activities, and other closable objects
+ * but will likely expand in future releases.
*/
public Builder detectAll() {
return enable(DETECT_VM_ACTIVITY_LEAKS |
@@ -1347,6 +1361,41 @@
}
/**
+ * @hide
+ */
+ public static void conditionallyCheckInstanceCounts() {
+ VmPolicy policy = getVmPolicy();
+ if (policy.classInstanceLimit.size() == 0) {
+ return;
+ }
+ Runtime.getRuntime().gc();
+ // Note: classInstanceLimit is immutable, so this is lock-free
+ for (Class klass : policy.classInstanceLimit.keySet()) {
+ int limit = policy.classInstanceLimit.get(klass);
+ long instances = VMDebug.countInstancesOfClass(klass, false);
+ if (instances <= limit) {
+ continue;
+ }
+ Throwable tr = new InstanceCountViolation(klass, instances, limit);
+ onVmPolicyViolation(tr.getMessage(), tr);
+ }
+ }
+
+ private static long sLastInstanceCountCheckMillis = 0;
+ private static boolean sIsIdlerRegistered = false; // guarded by sProcessIdleHandler
+ private static final MessageQueue.IdleHandler sProcessIdleHandler =
+ new MessageQueue.IdleHandler() {
+ public boolean queueIdle() {
+ long now = SystemClock.uptimeMillis();
+ if (now - sLastInstanceCountCheckMillis > 30 * 1000) {
+ sLastInstanceCountCheckMillis = now;
+ conditionallyCheckInstanceCounts();
+ }
+ return true;
+ }
+ };
+
+ /**
* Sets the policy for what actions in the VM process (on any
* thread) should be detected, as well as the penalty if such
* actions occur.
@@ -1357,6 +1406,19 @@
sVmPolicy = policy;
sVmPolicyMask = policy.mask;
setCloseGuardEnabled(vmClosableObjectLeaksEnabled());
+
+ Looper looper = Looper.getMainLooper();
+ if (looper != null) {
+ MessageQueue mq = looper.mQueue;
+ synchronized (sProcessIdleHandler) {
+ if (policy.classInstanceLimit.size() == 0) {
+ mq.removeIdleHandler(sProcessIdleHandler);
+ } else if (!sIsIdlerRegistered) {
+ mq.addIdleHandler(sProcessIdleHandler);
+ sIsIdlerRegistered = true;
+ }
+ }
+ }
}
/**
@@ -1406,19 +1468,39 @@
onVmPolicyViolation(message, originStack);
}
+ // Map from VM violation fingerprint to uptime millis.
+ private static final HashMap<Integer, Long> sLastVmViolationTime = new HashMap<Integer, Long>();
+
/**
* @hide
*/
public static void onVmPolicyViolation(String message, Throwable originStack) {
- if ((sVmPolicyMask & PENALTY_LOG) != 0) {
+ final boolean penaltyDropbox = (sVmPolicyMask & PENALTY_DROPBOX) != 0;
+ final boolean penaltyDeath = (sVmPolicyMask & PENALTY_DEATH) != 0;
+ final boolean penaltyLog = (sVmPolicyMask & PENALTY_LOG) != 0;
+ final ViolationInfo info = new ViolationInfo(originStack, sVmPolicyMask);
+
+ final Integer fingerprint = info.hashCode();
+ final long now = SystemClock.uptimeMillis();
+ long lastViolationTime = 0;
+ long timeSinceLastViolationMillis = Long.MAX_VALUE;
+ synchronized (sLastVmViolationTime) {
+ if (sLastVmViolationTime.containsKey(fingerprint)) {
+ lastViolationTime = sLastVmViolationTime.get(fingerprint);
+ timeSinceLastViolationMillis = now - lastViolationTime;
+ }
+ if (timeSinceLastViolationMillis > MIN_LOG_INTERVAL_MS) {
+ sLastVmViolationTime.put(fingerprint, now);
+ }
+ }
+
+ Log.d(TAG, "Time since last vm violation: " + timeSinceLastViolationMillis);
+
+ if (penaltyLog && timeSinceLastViolationMillis > MIN_LOG_INTERVAL_MS) {
Log.e(TAG, message, originStack);
}
- boolean penaltyDropbox = (sVmPolicyMask & PENALTY_DROPBOX) != 0;
- boolean penaltyDeath = (sVmPolicyMask & PENALTY_DEATH) != 0;
-
- int violationMaskSubset = PENALTY_DROPBOX | DETECT_VM_CURSOR_LEAKS;
- ViolationInfo info = new ViolationInfo(originStack, sVmPolicyMask);
+ int violationMaskSubset = PENALTY_DROPBOX | (ALL_VM_DETECT_BITS & sVmPolicyMask);
if (penaltyDropbox && !penaltyDeath) {
// Common case for userdebug/eng builds. If no death and
@@ -1428,7 +1510,7 @@
return;
}
- if (penaltyDropbox) {
+ if (penaltyDropbox && lastViolationTime == 0) {
// The violationMask, passed to ActivityManager, is a
// subset of the original StrictMode policy bitmask, with
// only the bit violated and penalty bits to be executed
@@ -1786,6 +1868,12 @@
public String broadcastIntentAction;
/**
+ * If this is a instance count violation, the number of instances in memory,
+ * else -1.
+ */
+ public long numInstances = -1;
+
+ /**
* Create an uninitialized instance of ViolationInfo
*/
public ViolationInfo() {
@@ -1806,6 +1894,9 @@
broadcastIntentAction = broadcastIntent.getAction();
}
ThreadSpanState state = sThisThreadSpanState.get();
+ if (tr instanceof InstanceCountViolation) {
+ this.numInstances = ((InstanceCountViolation) tr).mInstances;
+ }
synchronized (state) {
int spanActiveCount = state.mActiveSize;
if (spanActiveCount > MAX_SPAN_TAGS) {
@@ -1867,6 +1958,7 @@
violationNumThisLoop = in.readInt();
numAnimationsRunning = in.readInt();
violationUptimeMillis = in.readLong();
+ numInstances = in.readLong();
broadcastIntentAction = in.readString();
tags = in.readStringArray();
}
@@ -1881,6 +1973,7 @@
dest.writeInt(violationNumThisLoop);
dest.writeInt(numAnimationsRunning);
dest.writeLong(violationUptimeMillis);
+ dest.writeLong(numInstances);
dest.writeString(broadcastIntentAction);
dest.writeStringArray(tags);
}
@@ -1895,6 +1988,9 @@
if (durationMillis != -1) {
pw.println(prefix + "durationMillis: " + durationMillis);
}
+ if (numInstances != -1) {
+ pw.println(prefix + "numInstances: " + numInstances);
+ }
if (violationNumThisLoop != 0) {
pw.println(prefix + "violationNumThisLoop: " + violationNumThisLoop);
}
@@ -1914,4 +2010,29 @@
}
}
+
+ // Dummy throwable, for now, since we don't know when or where the
+ // leaked instances came from. We might in the future, but for
+ // now we suppress the stack trace because it's useless and/or
+ // misleading.
+ private static class InstanceCountViolation extends Throwable {
+ final Class mClass;
+ final long mInstances;
+ final int mLimit;
+
+ private static final StackTraceElement[] FAKE_STACK = new StackTraceElement[1];
+ static {
+ FAKE_STACK[0] = new StackTraceElement("android.os.StrictMode", "setClassInstanceLimit",
+ "StrictMode.java", 1);
+ }
+
+ public InstanceCountViolation(Class klass, long instances, int limit) {
+ // Note: now including instances here, otherwise signatures would all be different.
+ super(klass.toString() + "; limit=" + limit);
+ setStackTrace(FAKE_STACK);
+ mClass = klass;
+ mInstances = instances;
+ mLimit = limit;
+ }
+ }
}
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 9f0ea32..82fe7de 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -57,6 +57,8 @@
* Broadcast Action: A broadcast to indicate the end of an MTP session with the host.
* This broadcast is only sent if MTP activity has modified the media database during the
* most recent MTP session.
+ *
+ * @hide
*/
public static final String ACTION_MTP_SESSION_END = "android.provider.action.MTP_SESSION_END";
diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java
index 539a696..cd3bc3e 100644
--- a/core/java/android/server/BluetoothEventLoop.java
+++ b/core/java/android/server/BluetoothEventLoop.java
@@ -748,9 +748,9 @@
}
}
- private void onInputDeviceConnectionResult(String path, boolean result) {
+ private void onInputDeviceConnectionResult(String path, int result) {
// Success case gets handled by Property Change signal
- if (!result) {
+ if (result != BluetoothInputDevice.INPUT_OPERATION_SUCCESS) {
String address = mBluetoothService.getAddressFromObjectPath(path);
if (address == null) return;
@@ -758,9 +758,18 @@
BluetoothDevice device = mAdapter.getRemoteDevice(address);
int state = mBluetoothService.getInputDeviceState(device);
if (state == BluetoothInputDevice.STATE_CONNECTING) {
- connected = false;
+ if (result == BluetoothInputDevice.INPUT_CONNECT_FAILED_ALREADY_CONNECTED) {
+ connected = true;
+ } else {
+ connected = false;
+ }
} else if (state == BluetoothInputDevice.STATE_DISCONNECTING) {
- connected = true;
+ if (result == BluetoothInputDevice.INPUT_DISCONNECT_FAILED_NOT_CONNECTED) {
+ connected = false;
+ } else {
+ // There is no better way to handle this, this shouldn't happen
+ connected = true;
+ }
} else {
Log.e(TAG, "Error onInputDeviceConnectionResult. State is:" + state);
}
@@ -768,10 +777,10 @@
}
}
- private void onPanDeviceConnectionResult(String path, boolean result) {
+ private void onPanDeviceConnectionResult(String path, int result) {
log ("onPanDeviceConnectionResult " + path + " " + result);
// Success case gets handled by Property Change signal
- if (!result) {
+ if (result != BluetoothPan.PAN_OPERATION_SUCCESS) {
String address = mBluetoothService.getAddressFromObjectPath(path);
if (address == null) return;
@@ -779,9 +788,18 @@
BluetoothDevice device = mAdapter.getRemoteDevice(address);
int state = mBluetoothService.getPanDeviceState(device);
if (state == BluetoothPan.STATE_CONNECTING) {
- connected = false;
+ if (result == BluetoothPan.PAN_CONNECT_FAILED_ALREADY_CONNECTED) {
+ connected = true;
+ } else {
+ connected = false;
+ }
} else if (state == BluetoothPan.STATE_DISCONNECTING) {
- connected = true;
+ if (result == BluetoothPan.PAN_DISCONNECT_FAILED_NOT_CONNECTED) {
+ connected = false;
+ } else {
+ // There is no better way to handle this, this shouldn't happen
+ connected = true;
+ }
} else {
Log.e(TAG, "Error onPanDeviceConnectionResult. State is: "
+ state + " result: "+ result);
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 99b686e..f480554 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -452,11 +452,14 @@
@Override
public int saveLayer(float left, float top, float right, float bottom, Paint paint,
int saveFlags) {
- boolean hasColorFilter = paint != null && setupColorFilter(paint);
- final int nativePaint = paint == null ? 0 : paint.mNativePaint;
- int count = nSaveLayer(mRenderer, left, top, right, bottom, nativePaint, saveFlags);
- if (hasColorFilter) nResetModifiers(mRenderer);
- return count;
+ if (left < right && top < bottom) {
+ boolean hasColorFilter = paint != null && setupColorFilter(paint);
+ final int nativePaint = paint == null ? 0 : paint.mNativePaint;
+ int count = nSaveLayer(mRenderer, left, top, right, bottom, nativePaint, saveFlags);
+ if (hasColorFilter) nResetModifiers(mRenderer);
+ return count;
+ }
+ return save(saveFlags);
}
private native int nSaveLayer(int renderer, float left, float top, float right, float bottom,
@@ -471,7 +474,10 @@
@Override
public int saveLayerAlpha(float left, float top, float right, float bottom, int alpha,
int saveFlags) {
- return nSaveLayerAlpha(mRenderer, left, top, right, bottom, alpha, saveFlags);
+ if (left < right && top < bottom) {
+ return nSaveLayerAlpha(mRenderer, left, top, right, bottom, alpha, saveFlags);
+ }
+ return save(saveFlags);
}
private native int nSaveLayerAlpha(int renderer, float left, float top, float right,
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 270ea76..2447f8c 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -58,7 +58,6 @@
import android.util.Pools;
import android.util.SparseArray;
import android.view.ContextMenu.ContextMenuInfo;
-import android.view.View.MeasureSpec;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityEventSource;
import android.view.accessibility.AccessibilityManager;
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index d1781cc..115431e 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -935,15 +935,17 @@
} break;
case DragEvent.ACTION_DRAG_ENDED: {
- // If a child was notified about an ongoing drag, it's told that it's over
- for (View child : mDragNotifiedChildren) {
- child.dispatchDragEvent(event);
- }
-
// Release the bookkeeping now that the drag lifecycle has ended
- mDragNotifiedChildren.clear();
- mCurrentDrag.recycle();
- mCurrentDrag = null;
+ if (mDragNotifiedChildren != null) {
+ for (View child : mDragNotifiedChildren) {
+ // If a child was notified about an ongoing drag, it's told that it's over
+ child.dispatchDragEvent(event);
+ }
+
+ mDragNotifiedChildren.clear();
+ mCurrentDrag.recycle();
+ mCurrentDrag = null;
+ }
// We consider drag-ended to have been handled if one of our children
// had offered to handle the drag.
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index 961b633..1f15628 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -2803,6 +2803,7 @@
// Report the drop result when we're done
if (what == DragEvent.ACTION_DROP) {
+ mDragDescription = null;
try {
Log.i(TAG, "Reporting drop result: " + result);
sWindowSession.reportDropResult(mWindow, result);
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index c54a3cf..8eb4269 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -817,7 +817,7 @@
public static final int SOFT_INPUT_IS_FORWARD_NAVIGATION = 0x100;
/**
- * Desired operating mode for any soft input area. May any combination
+ * Desired operating mode for any soft input area. May be any combination
* of:
*
* <ul>
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index c509dae..7b3ea74 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -408,10 +408,13 @@
PluginFullScreenHolder mFullScreenHolder;
/**
- * Position of the last touch event.
+ * Position of the last touch event in pixels.
+ * Use integer to prevent loss of dragging delta calculation accuracy;
+ * which was done in float and converted to integer, and resulted in gradual
+ * and compounding touch position and view dragging mismatch.
*/
- private float mLastTouchX;
- private float mLastTouchY;
+ private int mLastTouchX;
+ private int mLastTouchY;
/**
* Time of the last touch event.
@@ -2218,8 +2221,8 @@
if (type == HitTestResult.UNKNOWN_TYPE
|| type == HitTestResult.SRC_ANCHOR_TYPE) {
// Now check to see if it is an image.
- int contentX = viewToContentX((int) mLastTouchX + mScrollX);
- int contentY = viewToContentY((int) mLastTouchY + mScrollY);
+ int contentX = viewToContentX(mLastTouchX + mScrollX);
+ int contentY = viewToContentY(mLastTouchY + mScrollY);
String text = nativeImageURI(contentX, contentY);
if (text != null) {
result.setType(type == HitTestResult.UNKNOWN_TYPE ?
@@ -2256,8 +2259,8 @@
if (hrefMsg == null) {
return;
}
- int contentX = viewToContentX((int) mLastTouchX + mScrollX);
- int contentY = viewToContentY((int) mLastTouchY + mScrollY);
+ int contentX = viewToContentX(mLastTouchX + mScrollX);
+ int contentY = viewToContentY(mLastTouchY + mScrollY);
mWebViewCore.sendMessage(EventHub.REQUEST_CURSOR_HREF,
contentX, contentY, hrefMsg);
}
@@ -2271,8 +2274,8 @@
*/
public void requestImageRef(Message msg) {
if (0 == mNativeClass) return; // client isn't initialized
- int contentX = viewToContentX((int) mLastTouchX + mScrollX);
- int contentY = viewToContentY((int) mLastTouchY + mScrollY);
+ int contentX = viewToContentX(mLastTouchX + mScrollX);
+ int contentY = viewToContentY(mLastTouchY + mScrollY);
String ref = nativeImageURI(contentX, contentY);
Bundle data = msg.getData();
data.putString("url", ref);
@@ -3856,8 +3859,8 @@
* @hide pending API council approval
*/
public boolean selectText() {
- int x = viewToContentX((int) mLastTouchX + mScrollX);
- int y = viewToContentY((int) mLastTouchY + mScrollY);
+ int x = viewToContentX(mLastTouchX + mScrollX);
+ int y = viewToContentY(mLastTouchY + mScrollY);
return selectText(x, y);
}
@@ -4858,8 +4861,8 @@
mSelectX = contentToViewX(rect.left);
mSelectY = contentToViewY(rect.top);
} else if (mLastTouchY > getVisibleTitleHeight()) {
- mSelectX = mScrollX + (int) mLastTouchX;
- mSelectY = mScrollY + (int) mLastTouchY;
+ mSelectX = mScrollX + mLastTouchX;
+ mSelectY = mScrollY + mLastTouchY;
} else {
mSelectX = mScrollX + getViewWidth() / 2;
mSelectY = mScrollY + getViewHeightWithTitle() / 2;
@@ -5357,7 +5360,7 @@
return true;
}
- return handleTouchEventCommon(ev, ev.getX(), ev.getY());
+ return handleTouchEventCommon(ev, Math.round(ev.getX()), Math.round(ev.getY()));
}
/*
@@ -5365,7 +5368,7 @@
* (x, y) denotes current focus point, which is the touch point for single touch
* and the middle point for multi-touch.
*/
- private boolean handleTouchEventCommon(MotionEvent ev, float x, float y) {
+ private boolean handleTouchEventCommon(MotionEvent ev, int x, int y) {
int action = ev.getAction();
long eventTime = ev.getEventTime();
@@ -5377,12 +5380,10 @@
x = Math.min(x, getViewWidth() - 1);
y = Math.min(y, getViewHeightWithTitle() - 1);
- float fDeltaX = mLastTouchX - x;
- float fDeltaY = mLastTouchY - y;
- int deltaX = (int) fDeltaX;
- int deltaY = (int) fDeltaY;
- int contentX = viewToContentX((int) x + mScrollX);
- int contentY = viewToContentY((int) y + mScrollY);
+ int deltaX = mLastTouchX - x;
+ int deltaY = mLastTouchY - y;
+ int contentX = viewToContentX(x + mScrollX);
+ int contentY = viewToContentY(y + mScrollY);
switch (action) {
case MotionEvent.ACTION_DOWN: {
@@ -5607,8 +5608,6 @@
mTouchMode = TOUCH_DRAG_MODE;
mLastTouchX = x;
mLastTouchY = y;
- fDeltaX = 0.0f;
- fDeltaY = 0.0f;
deltaX = 0;
deltaY = 0;
@@ -5619,9 +5618,7 @@
// do pan
boolean done = false;
boolean keepScrollBarsVisible = false;
- if (Math.abs(fDeltaX) < 1.0f && Math.abs(fDeltaY) < 1.0f) {
- mLastTouchX = x;
- mLastTouchY = y;
+ if (deltaX == 0 && deltaY == 0) {
keepScrollBarsVisible = done = true;
} else {
if (mSnapScrollMode == SNAP_X || mSnapScrollMode == SNAP_Y) {
@@ -5670,12 +5667,6 @@
mLastTouchY = y;
}
mHeldMotionless = MOTIONLESS_FALSE;
- } else {
- // keep the scrollbar on the screen even there is no
- // scroll
- mLastTouchX = x;
- mLastTouchY = y;
- keepScrollBarsVisible = true;
}
mLastTouchTime = eventTime;
mUserScroll = true;
@@ -5937,8 +5928,8 @@
action = MotionEvent.ACTION_DOWN;
} else if (action == MotionEvent.ACTION_POINTER_UP) {
// set mLastTouchX/Y to the remaining point
- mLastTouchX = x;
- mLastTouchY = y;
+ mLastTouchX = Math.round(x);
+ mLastTouchY = Math.round(y);
} else if (action == MotionEvent.ACTION_MOVE) {
// negative x or y indicate it is on the edge, skip it.
if (x < 0 || y < 0) {
@@ -5946,7 +5937,7 @@
}
}
- return handleTouchEventCommon(ev, x, y);
+ return handleTouchEventCommon(ev, Math.round(x), Math.round(y));
}
private void cancelWebCoreTouchEvent(int x, int y, boolean removeEvents) {
@@ -5967,8 +5958,8 @@
private void startTouch(float x, float y, long eventTime) {
// Remember where the motion event started
- mLastTouchX = x;
- mLastTouchY = y;
+ mLastTouchX = Math.round(x);
+ mLastTouchY = Math.round(y);
mLastTouchTime = eventTime;
mVelocityTracker = VelocityTracker.obtain();
mSnapScrollMode = SNAP_NONE;
@@ -6598,8 +6589,8 @@
return;
}
// mLastTouchX and mLastTouchY are the point in the current viewport
- int contentX = viewToContentX((int) mLastTouchX + mScrollX);
- int contentY = viewToContentY((int) mLastTouchY + mScrollY);
+ int contentX = viewToContentX(mLastTouchX + mScrollX);
+ int contentY = viewToContentY(mLastTouchY + mScrollY);
Rect rect = new Rect(contentX - mNavSlop, contentY - mNavSlop,
contentX + mNavSlop, contentY + mNavSlop);
nativeSelectBestAt(rect);
@@ -6630,8 +6621,8 @@
if (!inEditingMode()) {
return;
}
- mLastTouchX = x + (float) (mWebTextView.getLeft() - mScrollX);
- mLastTouchY = y + (float) (mWebTextView.getTop() - mScrollY);
+ mLastTouchX = Math.round(x + mWebTextView.getLeft() - mScrollX);
+ mLastTouchY = Math.round(y + mWebTextView.getTop() - mScrollY);
mLastTouchTime = eventTime;
if (!mScroller.isFinished()) {
abortAnimation();
@@ -6690,8 +6681,8 @@
mTouchMode = TOUCH_DONE_MODE;
switchOutDrawHistory();
// mLastTouchX and mLastTouchY are the point in the current viewport
- int contentX = viewToContentX((int) mLastTouchX + mScrollX);
- int contentY = viewToContentY((int) mLastTouchY + mScrollY);
+ int contentX = viewToContentX(mLastTouchX + mScrollX);
+ int contentY = viewToContentY(mLastTouchY + mScrollY);
if (getSettings().supportTouchOnly()) {
removeTouchHighlight(false);
WebViewCore.TouchUpData touchUpData = new WebViewCore.TouchUpData();
@@ -7052,8 +7043,8 @@
|| (msg.arg1 == MotionEvent.ACTION_MOVE
&& mPreventDefault == PREVENT_DEFAULT_NO_FROM_TOUCH_DOWN)) {
cancelWebCoreTouchEvent(
- viewToContentX((int) mLastTouchX + mScrollX),
- viewToContentY((int) mLastTouchY + mScrollY),
+ viewToContentX(mLastTouchX + mScrollX),
+ viewToContentY(mLastTouchY + mScrollY),
true);
}
break;
@@ -7104,8 +7095,8 @@
ted.mIds = new int[1];
ted.mIds[0] = 0;
ted.mPoints = new Point[1];
- ted.mPoints[0] = new Point(viewToContentX((int) mLastTouchX + mScrollX),
- viewToContentY((int) mLastTouchY + mScrollY));
+ ted.mPoints[0] = new Point(viewToContentX(mLastTouchX + mScrollX),
+ viewToContentY(mLastTouchY + mScrollY));
// metaState for long press is tricky. Should it be the
// state when the press started or when the press was
// released? Or some intermediary key state? For
diff --git a/core/java/android/widget/ArrayAdapter.java b/core/java/android/widget/ArrayAdapter.java
index b4ece24..593cb59 100644
--- a/core/java/android/widget/ArrayAdapter.java
+++ b/core/java/android/widget/ArrayAdapter.java
@@ -25,9 +25,9 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
-import java.util.List;
-import java.util.Comparator;
import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
/**
* A concrete BaseAdapter that is backed by an array of arbitrary
@@ -86,6 +86,8 @@
private Context mContext;
+ // A copy of the original mObjects array, initialized from and then used instead as soon as
+ // the mFilter ArrayFilter is used. mObjects will then only contain the filtered values.
private ArrayList<T> mOriginalValues;
private ArrayFilter mFilter;
@@ -170,15 +172,14 @@
* @param object The object to add at the end of the array.
*/
public void add(T object) {
- if (mOriginalValues != null) {
- synchronized (mLock) {
+ synchronized (mLock) {
+ if (mOriginalValues != null) {
mOriginalValues.add(object);
- if (mNotifyOnChange) notifyDataSetChanged();
+ } else {
+ mObjects.add(object);
}
- } else {
- mObjects.add(object);
- if (mNotifyOnChange) notifyDataSetChanged();
}
+ if (mNotifyOnChange) notifyDataSetChanged();
}
/**
@@ -187,15 +188,14 @@
* @param collection The Collection to add at the end of the array.
*/
public void addAll(Collection<? extends T> collection) {
- if (mOriginalValues != null) {
- synchronized (mLock) {
+ synchronized (mLock) {
+ if (mOriginalValues != null) {
mOriginalValues.addAll(collection);
- if (mNotifyOnChange) notifyDataSetChanged();
+ } else {
+ mObjects.addAll(collection);
}
- } else {
- mObjects.addAll(collection);
- if (mNotifyOnChange) notifyDataSetChanged();
}
+ if (mNotifyOnChange) notifyDataSetChanged();
}
/**
@@ -204,19 +204,18 @@
* @param items The items to add at the end of the array.
*/
public void addAll(T ... items) {
- if (mOriginalValues != null) {
- synchronized (mLock) {
+ synchronized (mLock) {
+ if (mOriginalValues != null) {
for (T item : items) {
mOriginalValues.add(item);
}
- if (mNotifyOnChange) notifyDataSetChanged();
+ } else {
+ for (T item : items) {
+ mObjects.add(item);
+ }
}
- } else {
- for (T item : items) {
- mObjects.add(item);
- }
- if (mNotifyOnChange) notifyDataSetChanged();
}
+ if (mNotifyOnChange) notifyDataSetChanged();
}
/**
@@ -226,15 +225,14 @@
* @param index The index at which the object must be inserted.
*/
public void insert(T object, int index) {
- if (mOriginalValues != null) {
- synchronized (mLock) {
+ synchronized (mLock) {
+ if (mOriginalValues != null) {
mOriginalValues.add(index, object);
- if (mNotifyOnChange) notifyDataSetChanged();
+ } else {
+ mObjects.add(index, object);
}
- } else {
- mObjects.add(index, object);
- if (mNotifyOnChange) notifyDataSetChanged();
}
+ if (mNotifyOnChange) notifyDataSetChanged();
}
/**
@@ -243,12 +241,12 @@
* @param object The object to remove.
*/
public void remove(T object) {
- if (mOriginalValues != null) {
- synchronized (mLock) {
+ synchronized (mLock) {
+ if (mOriginalValues != null) {
mOriginalValues.remove(object);
+ } else {
+ mObjects.remove(object);
}
- } else {
- mObjects.remove(object);
}
if (mNotifyOnChange) notifyDataSetChanged();
}
@@ -257,12 +255,12 @@
* Remove all elements from the list.
*/
public void clear() {
- if (mOriginalValues != null) {
- synchronized (mLock) {
+ synchronized (mLock) {
+ if (mOriginalValues != null) {
mOriginalValues.clear();
+ } else {
+ mObjects.clear();
}
- } else {
- mObjects.clear();
}
if (mNotifyOnChange) notifyDataSetChanged();
}
@@ -274,7 +272,13 @@
* in this adapter.
*/
public void sort(Comparator<? super T> comparator) {
- Collections.sort(mObjects, comparator);
+ synchronized (mLock) {
+ if (mOriginalValues != null) {
+ Collections.sort(mOriginalValues, comparator);
+ } else {
+ Collections.sort(mObjects, comparator);
+ }
+ }
if (mNotifyOnChange) notifyDataSetChanged();
}
@@ -482,6 +486,7 @@
final String[] words = valueText.split(" ");
final int wordCount = words.length;
+ // Start at index 0, in case valueText starts with space(s)
for (int k = 0; k < wordCount; k++) {
if (words[k].startsWith(prefixString)) {
newValues.add(value);
diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java
index 4d8d21f..707b92d 100644
--- a/core/java/android/widget/AutoCompleteTextView.java
+++ b/core/java/android/widget/AutoCompleteTextView.java
@@ -16,6 +16,8 @@
package android.widget;
+import com.android.internal.R;
+
import android.content.Context;
import android.content.res.TypedArray;
import android.database.DataSetObserver;
@@ -36,8 +38,6 @@
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
-import com.android.internal.R;
-
/**
* <p>An editable text view that shows completion suggestions automatically
@@ -113,6 +113,7 @@
private Validator mValidator = null;
+ // Set to true when text is set directly and no filtering shall be performed
private boolean mBlockCompletion;
private PassThroughClickListener mPassThroughClickListener;
@@ -721,6 +722,10 @@
return;
}
+ updateList();
+ }
+
+ private void updateList() {
// the drop down is shown only when a minimum number of characters
// was typed in the text view
if (enoughToFilter()) {
@@ -840,7 +845,7 @@
mBlockCompletion = true;
replaceText(convertSelectionToString(selectedItem));
- mBlockCompletion = false;
+ mBlockCompletion = false;
if (mItemClickListener != null) {
final ListPopupWindow list = mPopup;
@@ -903,10 +908,10 @@
/** {@inheritDoc} */
public void onFilterComplete(int count) {
- updateDropDownForFilter(count);
+ updateDropDownForFilter(count, true);
}
- private void updateDropDownForFilter(int count) {
+ private void updateDropDownForFilter(int count, boolean forceShow) {
// Not attached to window, don't update drop-down
if (getWindowVisibility() == View.GONE) return;
@@ -919,7 +924,7 @@
final boolean dropDownAlwaysVisible = mPopup.isDropDownAlwaysVisible();
if ((count > 0 || dropDownAlwaysVisible) && enoughToFilter()) {
- if (hasFocus() && hasWindowFocus()) {
+ if (hasFocus() && hasWindowFocus() && (forceShow || isPopupShowing())) {
showDropDown();
}
} else if (!dropDownAlwaysVisible) {
@@ -1182,12 +1187,14 @@
// If the popup is not showing already, showing it will cause
// the list of data set observers attached to the adapter to
// change. We can't do it from here, because we are in the middle
- // of iterating throught he list of observers.
+ // of iterating through the list of observers.
post(new Runnable() {
public void run() {
final ListAdapter adapter = mAdapter;
if (adapter != null) {
- updateDropDownForFilter(adapter.getCount());
+ // This will re-layout, thus resetting mDataChanged, so that the
+ // listView click listener stays responsive
+ updateDropDownForFilter(adapter.getCount(), false);
}
}
});
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index f023e94..342b884 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -568,6 +568,7 @@
char jniOptsBuf[sizeof("-Xjniopts:")-1 + PROPERTY_VALUE_MAX];
char heapstartsizeOptsBuf[sizeof("-Xms")-1 + PROPERTY_VALUE_MAX];
char heapsizeOptsBuf[sizeof("-Xmx")-1 + PROPERTY_VALUE_MAX];
+ char heapgrowthlimitOptsBuf[sizeof("-XX:HeapGrowthLimit=")-1 + PROPERTY_VALUE_MAX];
char extraOptsBuf[PROPERTY_VALUE_MAX];
char* stackTraceFile = NULL;
bool checkJni = false;
@@ -659,6 +660,13 @@
opt.optionString = heapsizeOptsBuf;
mOptions.add(opt);
+ strcpy(heapgrowthlimitOptsBuf, "-XX:HeapGrowthLimit=");
+ property_get("dalvik.vm.heapgrowthlimit", heapgrowthlimitOptsBuf+20, "");
+ if (heapgrowthlimitOptsBuf[20] != '\0') {
+ opt.optionString = heapgrowthlimitOptsBuf;
+ mOptions.add(opt);
+ }
+
/*
* Enable or disable dexopt features, such as bytecode verification and
* calculation of register maps for precise GC.
diff --git a/core/jni/android/graphics/Region.cpp b/core/jni/android/graphics/Region.cpp
index c43b5ce..2445229 100644
--- a/core/jni/android/graphics/Region.cpp
+++ b/core/jni/android/graphics/Region.cpp
@@ -154,6 +154,16 @@
scale_rgn(rgn, *rgn, scale);
}
+static jstring Region_toString(JNIEnv* env, jobject clazz, SkRegion* region) {
+ char* str = region->toString();
+ if (str == NULL) {
+ return NULL;
+ }
+ jstring result = env->NewStringUTF(str);
+ free(str);
+ return result;
+}
+
////////////////////////////////////////////////////////////////////////////////////////////////////////////
static SkRegion* Region_createFromParcel(JNIEnv* env, jobject clazz, jobject parcel)
@@ -262,6 +272,7 @@
{ "quickReject", "(Landroid/graphics/Region;)Z", (void*)Region_quickRejectRgn },
{ "scale", "(FLandroid/graphics/Region;)V", (void*)Region_scale },
{ "translate", "(IILandroid/graphics/Region;)V", (void*)Region_translate },
+ { "nativeToString", "(I)Ljava/lang/String;", (void*)Region_toString },
// parceling methods
{ "nativeCreateFromParcel", "(Landroid/os/Parcel;)I", (void*)Region_createFromParcel },
{ "nativeWriteToParcel", "(ILandroid/os/Parcel;)Z", (void*)Region_writeToParcel },
diff --git a/core/jni/android_bluetooth_common.h b/core/jni/android_bluetooth_common.h
index 9222e1a..3364703 100644
--- a/core/jni/android_bluetooth_common.h
+++ b/core/jni/android_bluetooth_common.h
@@ -38,6 +38,7 @@
#ifdef HAVE_BLUETOOTH
#define BLUEZ_DBUS_BASE_PATH "/org/bluez"
#define BLUEZ_DBUS_BASE_IFC "org.bluez"
+#define BLUEZ_ERROR_IFC "org.bluez.Error"
// It would be nicer to retrieve this from bluez using GetDefaultAdapter,
// but this is only possible when the adapter is up (and hcid is running).
@@ -171,6 +172,30 @@
bool debug_no_encrypt();
+
+// Result codes from Bluez DBus calls
+#define BOND_RESULT_ERROR -1
+#define BOND_RESULT_SUCCESS 0
+#define BOND_RESULT_AUTH_FAILED 1
+#define BOND_RESULT_AUTH_REJECTED 2
+#define BOND_RESULT_AUTH_CANCELED 3
+#define BOND_RESULT_REMOTE_DEVICE_DOWN 4
+#define BOND_RESULT_DISCOVERY_IN_PROGRESS 5
+#define BOND_RESULT_AUTH_TIMEOUT 6
+#define BOND_RESULT_REPEATED_ATTEMPTS 7
+
+#define PAN_DISCONNECT_FAILED_NOT_CONNECTED 1000
+#define PAN_CONNECT_FAILED_ALREADY_CONNECTED 1001
+#define PAN_CONNECT_FAILED_ATTEMPT_FAILED 1002
+#define PAN_OPERATION_GENERIC_FAILURE 1003
+#define PAN_OPERATION_SUCCESS 1004
+
+#define INPUT_DISCONNECT_FAILED_NOT_CONNECTED 5000
+#define INPUT_CONNECT_FAILED_ALREADY_CONNECTED 5001
+#define INPUT_CONNECT_FAILED_ATTEMPT_FAILED 5002
+#define INPUT_OPERATION_GENERIC_FAILURE 5003
+#define INPUT_OPERATION_SUCCESS 5004
+
#endif
} /* namespace android */
diff --git a/core/jni/android_server_BluetoothEventLoop.cpp b/core/jni/android_server_BluetoothEventLoop.cpp
index b0ba695..fd12c2d7 100644
--- a/core/jni/android_server_BluetoothEventLoop.cpp
+++ b/core/jni/android_server_BluetoothEventLoop.cpp
@@ -134,11 +134,11 @@
method_onInputDevicePropertyChanged = env->GetMethodID(clazz, "onInputDevicePropertyChanged",
"(Ljava/lang/String;[Ljava/lang/String;)V");
method_onInputDeviceConnectionResult = env->GetMethodID(clazz, "onInputDeviceConnectionResult",
- "(Ljava/lang/String;Z)V");
+ "(Ljava/lang/String;I)V");
method_onPanDevicePropertyChanged = env->GetMethodID(clazz, "onPanDevicePropertyChanged",
"(Ljava/lang/String;[Ljava/lang/String;)V");
method_onPanDeviceConnectionResult = env->GetMethodID(clazz, "onPanDeviceConnectionResult",
- "(Ljava/lang/String;Z)V");
+ "(Ljava/lang/String;I)V");
method_onRequestOobData = env->GetMethodID(clazz, "onRequestOobData",
"(Ljava/lang/String;I)V");
@@ -1227,16 +1227,6 @@
#ifdef HAVE_BLUETOOTH
-//TODO: Unify result codes in a header
-#define BOND_RESULT_ERROR -1000
-#define BOND_RESULT_SUCCESS 0
-#define BOND_RESULT_AUTH_FAILED 1
-#define BOND_RESULT_AUTH_REJECTED 2
-#define BOND_RESULT_AUTH_CANCELED 3
-#define BOND_RESULT_REMOTE_DEVICE_DOWN 4
-#define BOND_RESULT_DISCOVERY_IN_PROGRESS 5
-#define BOND_RESULT_AUTH_TIMEOUT 6
-#define BOND_RESULT_REPEATED_ATTEMPTS 7
void onCreatePairedDeviceResult(DBusMessage *msg, void *user, void *n) {
LOGV(__FUNCTION__);
@@ -1406,11 +1396,25 @@
JNIEnv *env;
nat->vm->GetEnv((void**)&env, nat->envVer);
- bool result = JNI_TRUE;
+ jint result = INPUT_OPERATION_SUCCESS;
if (dbus_set_error_from_message(&err, msg)) {
+ if (!strcmp(err.name, BLUEZ_ERROR_IFC ".ConnectionAttemptFailed")) {
+ result = INPUT_CONNECT_FAILED_ATTEMPT_FAILED;
+ } else if (!strcmp(err.name, BLUEZ_ERROR_IFC ".AlreadyConnected")) {
+ result = INPUT_CONNECT_FAILED_ALREADY_CONNECTED;
+ } else if (!strcmp(err.name, BLUEZ_ERROR_IFC ".Failed")) {
+ // TODO():This is flaky, need to change Bluez to add new error codes
+ if (!strcmp(err.message, "Transport endpoint is not connected")) {
+ result = INPUT_DISCONNECT_FAILED_NOT_CONNECTED;
+ } else {
+ result = INPUT_OPERATION_GENERIC_FAILURE;
+ }
+ } else {
+ result = INPUT_OPERATION_GENERIC_FAILURE;
+ }
LOG_AND_FREE_DBUS_ERROR(&err);
- result = JNI_FALSE;
}
+
LOGV("... Device Path = %s, result = %d", path, result);
jstring jPath = env->NewStringUTF(path);
env->CallVoidMethod(nat->me,
@@ -1431,11 +1435,25 @@
JNIEnv *env;
nat->vm->GetEnv((void**)&env, nat->envVer);
- bool result = JNI_TRUE;
+ jint result = PAN_OPERATION_SUCCESS;
if (dbus_set_error_from_message(&err, msg)) {
+ if (!strcmp(err.name, BLUEZ_ERROR_IFC ".ConnectionAttemptFailed")) {
+ result = PAN_CONNECT_FAILED_ATTEMPT_FAILED;
+ } else if (!strcmp(err.name, BLUEZ_ERROR_IFC ".Failed")) {
+ // TODO():This is flaky, need to change Bluez to add new error codes
+ if (!strcmp(err.message, "Device already connected")) {
+ result = PAN_CONNECT_FAILED_ALREADY_CONNECTED;
+ } else if (!strcmp(err.message, "Device not connected")) {
+ result = PAN_DISCONNECT_FAILED_NOT_CONNECTED;
+ } else {
+ result = PAN_OPERATION_GENERIC_FAILURE;
+ }
+ } else {
+ result = PAN_OPERATION_GENERIC_FAILURE;
+ }
LOG_AND_FREE_DBUS_ERROR(&err);
- result = JNI_FALSE;
}
+
LOGV("... Pan Device Path = %s, result = %d", path, result);
jstring jPath = env->NewStringUTF(path);
env->CallVoidMethod(nat->me,
diff --git a/drm/common/IDrmManagerService.cpp b/drm/common/IDrmManagerService.cpp
index 75edac6..ddbd220 100644
--- a/drm/common/IDrmManagerService.cpp
+++ b/drm/common/IDrmManagerService.cpp
@@ -382,7 +382,7 @@
}
data.writeInt32(playbackStatus);
- data.writeInt32(position);
+ data.writeInt64(position);
remote()->transact(SET_PLAYBACK_STATUS, data, &reply);
return reply.readInt32();
@@ -1111,7 +1111,7 @@
}
const status_t status
- = setPlaybackStatus(uniqueId, &handle, data.readInt32(), data.readInt32());
+ = setPlaybackStatus(uniqueId, &handle, data.readInt32(), data.readInt64());
reply->writeInt32(status);
delete handle.decryptInfo; handle.decryptInfo = NULL;
diff --git a/graphics/java/android/graphics/Region.java b/graphics/java/android/graphics/Region.java
index e540806..27ea0f0 100644
--- a/graphics/java/android/graphics/Region.java
+++ b/graphics/java/android/graphics/Region.java
@@ -287,6 +287,10 @@
region2.mNativeRegion, op.nativeInt);
}
+ public String toString() {
+ return nativeToString(mNativeRegion);
+ }
+
//////////////////////////////////////////////////////////////////////////
public static final Parcelable.Creator<Region> CREATOR
@@ -357,6 +361,8 @@
return mNativeRegion;
}
+ private static native boolean nativeEquals(int native_r1, int native_r2);
+
private static native int nativeConstructor();
private static native void nativeDestructor(int native_region);
@@ -381,5 +387,5 @@
private static native boolean nativeWriteToParcel(int native_region,
Parcel p);
- private static native boolean nativeEquals(int native_r1, int native_r2);
+ private static native String nativeToString(int native_region);
}
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index c080501..c43e40d 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -298,8 +298,10 @@
// FontRenderer
///////////////////////////////////////////////////////////////////////////////
+static bool sLogFontRendererCreate = true;
+
FontRenderer::FontRenderer() {
- LOGD("Creating FontRenderer");
+ if (sLogFontRendererCreate) LOGD("Creating FontRenderer");
mGammaTable = NULL;
mInitialized = false;
@@ -317,18 +319,24 @@
char property[PROPERTY_VALUE_MAX];
if (property_get(PROPERTY_TEXT_CACHE_WIDTH, property, NULL) > 0) {
- LOGD(" Setting text cache width to %s pixels", property);
+ if (sLogFontRendererCreate) LOGD(" Setting text cache width to %s pixels", property);
mCacheWidth = atoi(property);
} else {
- LOGD(" Using default text cache width of %i pixels", mCacheWidth);
+ if (sLogFontRendererCreate) {
+ LOGD(" Using default text cache width of %i pixels", mCacheWidth);
+ }
}
if (property_get(PROPERTY_TEXT_CACHE_HEIGHT, property, NULL) > 0) {
- LOGD(" Setting text cache width to %s pixels", property);
+ if (sLogFontRendererCreate) LOGD(" Setting text cache width to %s pixels", property);
mCacheHeight = atoi(property);
} else {
- LOGD(" Using default text cache height of %i pixels", mCacheHeight);
+ if (sLogFontRendererCreate) {
+ LOGD(" Using default text cache height of %i pixels", mCacheHeight);
+ }
}
+
+ sLogFontRendererCreate = false;
}
FontRenderer::~FontRenderer() {
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index e6bea78..a167429 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -29,7 +29,6 @@
void LayerRenderer::prepare(bool opaque) {
LAYER_RENDERER_LOGD("Rendering into layer, fbo = %d", mLayer->fbo);
- glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*) &mPreviousFbo);
glBindFramebuffer(GL_FRAMEBUFFER, mLayer->fbo);
OpenGLRenderer::prepare(opaque);
@@ -37,11 +36,17 @@
void LayerRenderer::finish() {
OpenGLRenderer::finish();
- glBindFramebuffer(GL_FRAMEBUFFER, mPreviousFbo);
generateMesh();
LAYER_RENDERER_LOGD("Finished rendering into layer, fbo = %d", mLayer->mFbo);
+
+ // No need to unbind our FBO, this will be taken care of by the caller
+ // who will invoke OpenGLRenderer::resume()
+}
+
+GLint LayerRenderer::getTargetFbo() {
+ return mLayer->fbo;
}
///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/LayerRenderer.h b/libs/hwui/LayerRenderer.h
index f2fb898..1e39847 100644
--- a/libs/hwui/LayerRenderer.h
+++ b/libs/hwui/LayerRenderer.h
@@ -51,6 +51,7 @@
bool hasLayer();
Region* getRegion();
+ GLint getTargetFbo();
static Layer* createLayer(uint32_t width, uint32_t height, bool isOpaque = false);
static bool resizeLayer(Layer* layer, uint32_t width, uint32_t height);
@@ -61,8 +62,6 @@
void generateMesh();
Layer* mLayer;
- GLuint mPreviousFbo;
-
}; // class LayerRenderer
}; // namespace uirenderer
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 2067acc1..6477eb0 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -200,7 +200,7 @@
glDisable(GL_DITHER);
- glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ glBindFramebuffer(GL_FRAMEBUFFER, getTargetFbo());
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
mCaches.blend = true;
@@ -430,18 +430,18 @@
} else {
// Copy the framebuffer into the layer
glBindTexture(GL_TEXTURE_2D, layer->texture);
-
- if (layer->empty) {
- glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bounds.left,
- snapshot->height - bounds.bottom, layer->width, layer->height, 0);
- layer->empty = false;
- } else {
- glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bounds.left,
- snapshot->height - bounds.bottom, bounds.getWidth(), bounds.getHeight());
+ if (!bounds.isEmpty()) {
+ if (layer->empty) {
+ glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bounds.left,
+ snapshot->height - bounds.bottom, layer->width, layer->height, 0);
+ layer->empty = false;
+ } else {
+ glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bounds.left,
+ snapshot->height - bounds.bottom, bounds.getWidth(), bounds.getHeight());
+ }
+ // Enqueue the buffer coordinates to clear the corresponding region later
+ mLayers.push(new Rect(bounds));
}
-
- // Enqueue the buffer coordinates to clear the corresponding region later
- mLayers.push(new Rect(bounds));
}
return true;
@@ -565,8 +565,10 @@
resetColorFilter();
}
} else {
- dirtyLayer(rect.left, rect.top, rect.right, rect.bottom);
- composeLayerRect(layer, rect, true);
+ if (!rect.isEmpty()) {
+ dirtyLayer(rect.left, rect.top, rect.right, rect.bottom);
+ composeLayerRect(layer, rect, true);
+ }
}
if (fboLayer) {
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 272c5c2..4150ddc 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -145,14 +145,27 @@
return mSnapshot;
}
+ /**
+ * Returns the region of the current layer.
+ */
virtual Region* getRegion() {
return mSnapshot->region;
}
+ /**
+ * Indicates whether rendering is currently targeted at a layer.
+ */
virtual bool hasLayer() {
return (mSnapshot->flags & Snapshot::kFlagFboTarget) && mSnapshot->region;
}
+ /**
+ * Returns the name of the FBO this renderer is rendering into.
+ */
+ virtual GLint getTargetFbo() {
+ return 0;
+ }
+
private:
/**
* Saves the current state of the renderer as a new snapshot.
diff --git a/media/java/android/media/videoeditor/MediaImageItem.java b/media/java/android/media/videoeditor/MediaImageItem.java
index b03588f..1c02878 100755
--- a/media/java/android/media/videoeditor/MediaImageItem.java
+++ b/media/java/android/media/videoeditor/MediaImageItem.java
@@ -93,29 +93,28 @@
*
* @throws IOException
*/
- public MediaImageItem(VideoEditor editor, String mediaItemId,
- String filename, long durationMs,
- int renderingMode) throws IOException {
+ public MediaImageItem(VideoEditor editor, String mediaItemId, String filename, long durationMs,
+ int renderingMode) throws IOException {
super(editor, mediaItemId, filename, renderingMode);
mMANativeHelper = ((VideoEditorImpl)editor).getNativeContext();
mVideoEditor = ((VideoEditorImpl)editor);
try {
- final Properties properties =
- mMANativeHelper.getMediaProperties(filename);
+ final Properties properties = mMANativeHelper.getMediaProperties(filename);
switch (mMANativeHelper.getFileType(properties.fileType)) {
case MediaProperties.FILE_JPEG:
+ case MediaProperties.FILE_PNG: {
break;
- case MediaProperties.FILE_PNG:
- break;
+ }
- default:
- throw new IllegalArgumentException("Unsupported Input File Type");
+ default: {
+ throw new IllegalArgumentException("Unsupported Input File Type");
+ }
}
} catch (Exception e) {
- throw new IllegalArgumentException("Unsupported file or file not found");
+ throw new IllegalArgumentException("Unsupported file or file not found: " + filename);
}
/**
@@ -130,13 +129,13 @@
mDurationMs = durationMs;
mDecodedFilename = String.format(mMANativeHelper.getProjectPath() +
"/" + "decoded" + getId()+ ".rgb");
- final FileOutputStream fl = new FileOutputStream(mDecodedFilename);
- final DataOutputStream dos = new DataOutputStream(fl);
+
try {
mAspectRatio = mMANativeHelper.getAspectRatio(mWidth, mHeight);
} catch(IllegalArgumentException e) {
throw new IllegalArgumentException ("Null width and height");
}
+
mGeneratedClipHeight = 0;
mGeneratedClipWidth = 0;
@@ -146,9 +145,12 @@
*/
final Pair<Integer, Integer>[] resolutions =
MediaProperties.getSupportedResolutions(mAspectRatio);
+
/**
* Get the highest resolution
*/
+ final FileOutputStream fl = new FileOutputStream(mDecodedFilename);
+ final DataOutputStream dos = new DataOutputStream(fl);
final Pair<Integer, Integer> maxResolution = resolutions[resolutions.length - 1];
if (mHeight > maxResolution.second) {
/**
@@ -171,16 +173,16 @@
int mNewHeight = 0;
if ((mScaledWidth % 2 ) != 0) {
mNewWidth = mScaledWidth - 1;
- }
- else {
+ } else {
mNewWidth = mScaledWidth;
}
+
if ((mScaledHeight % 2 ) != 0) {
mNewHeight = mScaledHeight - 1;
- }
- else {
+ } else {
mNewHeight = mScaledHeight;
}
+
final int [] framingBuffer = new int[mNewWidth];
final ByteBuffer byteBuffer = ByteBuffer.allocate(framingBuffer.length * 4);
IntBuffer intBuffer;
@@ -195,6 +197,7 @@
dos.write(array);
tmp += 1;
}
+
mScaledWidth = mNewWidth;
mScaledHeight = mNewHeight;
scaledImage.recycle();
@@ -204,10 +207,11 @@
+ "/" + "scaled" + getId()+ ".JPG");
if (!((new File(mScaledFilename)).exists())) {
super.mRegenerateClip = true;
- FileOutputStream f1 = new FileOutputStream(mScaledFilename);
+ final FileOutputStream f1 = new FileOutputStream(mScaledFilename);
scaledImage.compress(Bitmap.CompressFormat.JPEG, 50,f1);
f1.close();
}
+
mScaledWidth = scaledImage.getWidth();
mScaledHeight = scaledImage.getHeight();
@@ -215,17 +219,17 @@
int mNewheight = 0;
if ((mScaledWidth % 2 ) != 0) {
mNewWidth = mScaledWidth - 1;
- }
- else {
+ } else {
mNewWidth = mScaledWidth;
}
+
if ((mScaledHeight % 2 ) != 0) {
mNewheight = mScaledHeight - 1;
- }
- else {
+ } else {
mNewheight = mScaledHeight;
}
- Bitmap imageBitmap = BitmapFactory.decodeFile(mScaledFilename);
+
+ final Bitmap imageBitmap = BitmapFactory.decodeFile(mScaledFilename);
final int [] framingBuffer = new int[mNewWidth];
ByteBuffer byteBuffer = ByteBuffer.allocate(framingBuffer.length * 4);
IntBuffer intBuffer;
@@ -240,10 +244,12 @@
dos.write(array);
tmp += 1;
}
+
mScaledWidth = mNewWidth;
mScaledHeight = mNewheight;
imageBitmap.recycle();
}
+
fl.close();
System.gc();
}
@@ -286,7 +292,7 @@
/**
* @return The file name of image which is decoded and stored
- * in rgb format
+ * in RGB format
*/
String getDecodedImageFileName() {
return mDecodedFilename;
@@ -447,7 +453,7 @@
* Check if the effect overlaps with the end transition
*/
if (effect.getStartTime() + effect.getDuration() >
- mDurationMs - transitionDurationMs) {
+ mDurationMs - transitionDurationMs) {
mEndTransition.invalidate();
break;
}
@@ -464,7 +470,7 @@
* Check if the overlay overlaps with the end transition
*/
if (overlay.getStartTime() + overlay.getDuration() >
- mDurationMs - transitionDurationMs) {
+ mDurationMs - transitionDurationMs) {
mEndTransition.invalidate();
break;
}
@@ -648,23 +654,24 @@
for (int i = 0; i < thumbnailCount; i++) {
thumbnailArray[i] = thumbnail;
}
+
return thumbnailArray;
-
-
- }
- else {
+ } else {
if (startMs > endMs) {
throw new IllegalArgumentException("Start time is greater than end time");
}
+
if (endMs > mDurationMs) {
throw new IllegalArgumentException("End time is greater than file duration");
}
+
if (startMs == endMs) {
Bitmap[] bitmap = new Bitmap[1];
bitmap[0] = mMANativeHelper.getPixels(getGeneratedImageClip(),
width, height,startMs);
return bitmap;
}
+
return mMANativeHelper.getPixelsList(getGeneratedImageClip(), width,
height,startMs,endMs,thumbnailCount);
}
@@ -704,31 +711,51 @@
*/
if (mBeginTransition != null) {
final long transitionDurationMs = mBeginTransition.getDuration();
+ final boolean oldOverlap = isOverlapping(oldStartTimeMs, oldDurationMs, 0,
+ transitionDurationMs);
+ final boolean newOverlap = isOverlapping(newStartTimeMs, newDurationMs, 0,
+ transitionDurationMs);
/**
- * If the start time has changed and if the old or the new item
- * overlaps with the begin transition, invalidate the transition.
+ * Invalidate transition if:
+ *
+ * 1. New item overlaps the transition, the old one did not
+ * 2. New item does not overlap the transition, the old one did
+ * 3. New and old item overlap the transition if begin or end
+ * time changed
*/
- if (((oldStartTimeMs != newStartTimeMs)
- || (oldDurationMs != newDurationMs) )&&
- (isOverlapping(oldStartTimeMs, oldDurationMs, 0, transitionDurationMs) ||
- isOverlapping(newStartTimeMs, newDurationMs, 0,
- transitionDurationMs))) {
+ if (newOverlap != oldOverlap) { // Overlap has changed
mBeginTransition.invalidate();
+ } else if (newOverlap) { // Both old and new overlap
+ if ((oldStartTimeMs != newStartTimeMs) ||
+ !(oldStartTimeMs + oldDurationMs > transitionDurationMs &&
+ newStartTimeMs + newDurationMs > transitionDurationMs)) {
+ mBeginTransition.invalidate();
+ }
}
}
if (mEndTransition != null) {
final long transitionDurationMs = mEndTransition.getDuration();
+ final boolean oldOverlap = isOverlapping(oldStartTimeMs, oldDurationMs,
+ mDurationMs - transitionDurationMs, transitionDurationMs);
+ final boolean newOverlap = isOverlapping(newStartTimeMs, newDurationMs,
+ mDurationMs - transitionDurationMs, transitionDurationMs);
/**
- * If the start time + duration has changed and if the old or the new
- * item overlaps the end transition, invalidate the transition
+ * Invalidate transition if:
+ *
+ * 1. New item overlaps the transition, the old one did not
+ * 2. New item does not overlap the transition, the old one did
+ * 3. New and old item overlap the transition if begin or end
+ * time changed
*/
- if (oldStartTimeMs + oldDurationMs != newStartTimeMs + newDurationMs &&
- (isOverlapping(oldStartTimeMs, oldDurationMs,
- mDurationMs - transitionDurationMs, transitionDurationMs) ||
- isOverlapping(newStartTimeMs, newDurationMs,
- mDurationMs - transitionDurationMs, transitionDurationMs))) {
+ if (newOverlap != oldOverlap) { // Overlap has changed
mEndTransition.invalidate();
+ } else if (newOverlap) { // Both old and new overlap
+ if ((oldStartTimeMs + oldDurationMs != newStartTimeMs + newDurationMs) ||
+ ((oldStartTimeMs > mDurationMs - transitionDurationMs) ||
+ newStartTimeMs > mDurationMs - transitionDurationMs)) {
+ mEndTransition.invalidate();
+ }
}
}
}
@@ -743,10 +770,12 @@
setGeneratedImageClip(null);
setRegenerateClip(true);
}
+
if (mScaledFilename != null) {
new File(mScaledFilename).delete();
mScaledFilename = null;
}
+
if (mDecodedFilename != null) {
new File(mDecodedFilename).delete();
mDecodedFilename = null;
diff --git a/media/java/android/media/videoeditor/MediaVideoItem.java b/media/java/android/media/videoeditor/MediaVideoItem.java
index 772b360..2981b41 100755
--- a/media/java/android/media/videoeditor/MediaVideoItem.java
+++ b/media/java/android/media/videoeditor/MediaVideoItem.java
@@ -78,12 +78,9 @@
*
* @throws IOException if the file cannot be opened for reading
*/
- public MediaVideoItem(VideoEditor editor, String mediaItemId,
- String filename,
- int renderingMode)
- throws IOException {
- this(editor, mediaItemId, filename, renderingMode, 0, END_OF_FILE,
- 100, false, null);
+ public MediaVideoItem(VideoEditor editor, String mediaItemId, String filename,
+ int renderingMode) throws IOException {
+ this(editor, mediaItemId, filename, renderingMode, 0, END_OF_FILE, 100, false, null);
}
/**
@@ -105,20 +102,22 @@
* @throws IOException if the file cannot be opened for reading
*/
MediaVideoItem(VideoEditor editor, String mediaItemId, String filename,
- int renderingMode,
- long beginMs, long endMs, int volumePercent, boolean muted,
+ int renderingMode, long beginMs, long endMs, int volumePercent, boolean muted,
String audioWaveformFilename) throws IOException {
super(editor, mediaItemId, filename, renderingMode);
+
if (editor instanceof VideoEditorImpl) {
mMANativeHelper = ((VideoEditorImpl)editor).getNativeContext();
mVideoEditor = ((VideoEditorImpl)editor);
}
- Properties properties = null;
+
+ final Properties properties;
try {
properties = mMANativeHelper.getMediaProperties(filename);
} catch ( Exception e) {
- throw new IllegalArgumentException("Unsupported file or file not found");
+ throw new IllegalArgumentException("Unsupported file or file not found: " + filename);
}
+
switch (mMANativeHelper.getFileType(properties.fileType)) {
case MediaProperties.FILE_3GP:
break;
@@ -163,8 +162,7 @@
mMuted = muted;
mAudioWaveformFilename = audioWaveformFilename;
if (audioWaveformFilename != null) {
- mWaveformData =
- new SoftReference<WaveformData>(
+ mWaveformData = new SoftReference<WaveformData>(
new WaveformData(audioWaveformFilename));
} else {
mWaveformData = null;
@@ -190,9 +188,11 @@
if (beginMs > mDurationMs) {
throw new IllegalArgumentException("setExtractBoundaries: Invalid start time");
}
+
if (endMs > mDurationMs) {
throw new IllegalArgumentException("setExtractBoundaries: Invalid end time");
}
+
if ((endMs != -1) && (beginMs >= endMs) ) {
throw new IllegalArgumentException("setExtractBoundaries: Start time is greater than end time");
}
@@ -255,18 +255,18 @@
*/
@Override
public Bitmap getThumbnail(int width, int height, long timeMs) {
- if (timeMs > mDurationMs)
- {
+ if (timeMs > mDurationMs) {
throw new IllegalArgumentException("Time Exceeds duration");
}
- if (timeMs < 0)
- {
+
+ if (timeMs < 0) {
throw new IllegalArgumentException("Invalid Time duration");
}
- if ((width <=0) || (height <= 0))
- {
+
+ if ((width <=0) || (height <= 0)) {
throw new IllegalArgumentException("Invalid Dimensions");
}
+
return mMANativeHelper.getPixels(super.getFilename(),
width, height,timeMs);
}
@@ -280,18 +280,21 @@
if (startMs > endMs) {
throw new IllegalArgumentException("Start time is greater than end time");
}
+
if (endMs > mDurationMs) {
throw new IllegalArgumentException("End time is greater than file duration");
}
+
if ((height <= 0) || (width <= 0)) {
throw new IllegalArgumentException("Invalid dimension");
}
+
if (startMs == endMs) {
- Bitmap[] bitmap = new Bitmap[1];
- bitmap[0] = mMANativeHelper.getPixels(super.getFilename(),
- width, height,startMs);
+ final Bitmap[] bitmap = new Bitmap[1];
+ bitmap[0] = mMANativeHelper.getPixels(super.getFilename(), width, height,startMs);
return bitmap;
}
+
return mMANativeHelper.getPixelsList(super.getFilename(), width,
height,startMs,endMs,thumbnailCount);
}
@@ -324,40 +327,58 @@
* {@inheritDoc}
*/
@Override
- void invalidateTransitions(long oldStartTimeMs, long oldDurationMs,
- long newStartTimeMs,
+ void invalidateTransitions(long oldStartTimeMs, long oldDurationMs, long newStartTimeMs,
long newDurationMs) {
/**
* Check if the item overlaps with the beginning and end transitions
*/
if (mBeginTransition != null) {
final long transitionDurationMs = mBeginTransition.getDuration();
+ final boolean oldOverlap = isOverlapping(oldStartTimeMs, oldDurationMs,
+ mBeginBoundaryTimeMs, transitionDurationMs);
+ final boolean newOverlap = isOverlapping(newStartTimeMs, newDurationMs,
+ mBeginBoundaryTimeMs, transitionDurationMs);
/**
- * If the start time has changed and if the old or the new item
- * overlaps with the begin transition, invalidate the transition.
+ * Invalidate transition if:
+ *
+ * 1. New item overlaps the transition, the old one did not
+ * 2. New item does not overlap the transition, the old one did
+ * 3. New and old item overlap the transition if begin or end
+ * time changed
*/
- if (((oldStartTimeMs != newStartTimeMs)
- || (oldDurationMs != newDurationMs) )&&
- (isOverlapping(oldStartTimeMs, oldDurationMs,
- mBeginBoundaryTimeMs, transitionDurationMs) ||
- isOverlapping(newStartTimeMs, newDurationMs,
- mBeginBoundaryTimeMs, transitionDurationMs))) {
+ if (newOverlap != oldOverlap) { // Overlap has changed
mBeginTransition.invalidate();
+ } else if (newOverlap) { // Both old and new overlap
+ if ((oldStartTimeMs != newStartTimeMs) ||
+ !(oldStartTimeMs + oldDurationMs > transitionDurationMs &&
+ newStartTimeMs + newDurationMs > transitionDurationMs)) {
+ mBeginTransition.invalidate();
+ }
}
}
if (mEndTransition != null) {
final long transitionDurationMs = mEndTransition.getDuration();
+ final boolean oldOverlap = isOverlapping(oldStartTimeMs, oldDurationMs,
+ mEndBoundaryTimeMs - transitionDurationMs, transitionDurationMs);
+ final boolean newOverlap = isOverlapping(newStartTimeMs, newDurationMs,
+ mEndBoundaryTimeMs - transitionDurationMs, transitionDurationMs);
/**
- * If the start time + duration has changed and if the old or the new
- * item overlaps the end transition, invalidate the transition
+ * Invalidate transition if:
+ *
+ * 1. New item overlaps the transition, the old one did not
+ * 2. New item does not overlap the transition, the old one did
+ * 3. New and old item overlap the transition if begin or end
+ * time changed
*/
- if (oldStartTimeMs + oldDurationMs != newStartTimeMs + newDurationMs &&
- (isOverlapping(oldStartTimeMs, oldDurationMs,
- mEndBoundaryTimeMs - transitionDurationMs, transitionDurationMs) ||
- isOverlapping(newStartTimeMs, newDurationMs,
- mEndBoundaryTimeMs - transitionDurationMs, transitionDurationMs))) {
+ if (newOverlap != oldOverlap) { // Overlap has changed
mEndTransition.invalidate();
+ } else if (newOverlap) { // Both old and new overlap
+ if ((oldStartTimeMs + oldDurationMs != newStartTimeMs + newDurationMs) ||
+ ((oldStartTimeMs > mEndBoundaryTimeMs - transitionDurationMs) ||
+ newStartTimeMs > mEndBoundaryTimeMs - transitionDurationMs)) {
+ mEndTransition.invalidate();
+ }
}
}
}
@@ -434,7 +455,7 @@
throw new IllegalArgumentException("requested time not correct");
}
- Surface surface = surfaceHolder.getSurface();
+ final Surface surface = surfaceHolder.getSurface();
if (surface == null) {
throw new RuntimeException("Surface could not be retrieved from Surface holder");
}
@@ -442,8 +463,7 @@
if (mFilename != null) {
return mMANativeHelper.renderMediaItemPreviewFrame(surface,
mFilename,timeMs,mWidth,mHeight);
- }
- else {
+ } else {
return 0;
}
}
@@ -462,7 +482,7 @@
* Audio track
*/
public void extractAudioWaveform(ExtractAudioWaveformProgressListener listener)
- throws IOException {
+ throws IOException {
int frameDuration = 0;
int sampleCount = 0;
final String projectPath = mMANativeHelper.getProjectPath();
@@ -481,19 +501,17 @@
* Logic to get frame duration = (no. of frames per sample * 1000)/
* sampling frequency
*/
- if ( mMANativeHelper.getAudioCodecType(mAudioType) ==
+ if (mMANativeHelper.getAudioCodecType(mAudioType) ==
MediaProperties.ACODEC_AMRNB ) {
frameDuration = (MediaProperties.SAMPLES_PER_FRAME_AMRNB*1000)/
MediaProperties.DEFAULT_SAMPLING_FREQUENCY;
sampleCount = MediaProperties.SAMPLES_PER_FRAME_AMRNB;
- }
- else if ( mMANativeHelper.getAudioCodecType(mAudioType) ==
+ } else if (mMANativeHelper.getAudioCodecType(mAudioType) ==
MediaProperties.ACODEC_AMRWB ) {
frameDuration = (MediaProperties.SAMPLES_PER_FRAME_AMRWB * 1000)/
MediaProperties.DEFAULT_SAMPLING_FREQUENCY;
sampleCount = MediaProperties.SAMPLES_PER_FRAME_AMRWB;
- }
- else if ( mMANativeHelper.getAudioCodecType(mAudioType) ==
+ } else if (mMANativeHelper.getAudioCodecType(mAudioType) ==
MediaProperties.ACODEC_AAC_LC ) {
frameDuration = (MediaProperties.SAMPLES_PER_FRAME_AAC * 1000)/
MediaProperties.DEFAULT_SAMPLING_FREQUENCY;
@@ -682,5 +700,4 @@
return clipSettings;
}
-
}
diff --git a/media/jni/mediaeditor/Android.mk b/media/jni/mediaeditor/Android.mk
index 27c41be..0a01fb2 100755
--- a/media/jni/mediaeditor/Android.mk
+++ b/media/jni/mediaeditor/Android.mk
@@ -85,6 +85,6 @@
# to add this library to the prelink map and set this to true.
LOCAL_PRELINK_MODULE := false
-LOCAL_MODULE_TAGS := eng development
+LOCAL_MODULE_TAGS := optional
include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 58c4a2e..11ac56c 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -58,6 +58,8 @@
static int64_t kLowWaterMarkUs = 2000000ll; // 2secs
static int64_t kHighWaterMarkUs = 10000000ll; // 10secs
+static const size_t kLowWaterMarkBytes = 40000;
+static const size_t kHighWaterMarkBytes = 200000;
struct AwesomeEvent : public TimedEventQueue::Event {
AwesomeEvent(
@@ -610,9 +612,6 @@
// We don't know the bitrate of the stream, use absolute size
// limits to maintain the cache.
- const size_t kLowWaterMarkBytes = 40000;
- const size_t kHighWaterMarkBytes = 200000;
-
if ((mFlags & PLAYING) && !eos
&& (cachedDataRemaining < kLowWaterMarkBytes)) {
LOGI("cache is running low (< %d) , pausing.",
@@ -1535,6 +1534,34 @@
mConnectingDataSource.clear();
dataSource = mCachedSource;
+
+ // We're going to prefill the cache before trying to instantiate
+ // the extractor below, as the latter is an operation that otherwise
+ // could block on the datasource for a significant amount of time.
+ // During that time we'd be unable to abort the preparation phase
+ // without this prefill.
+
+ mLock.unlock();
+
+ for (;;) {
+ status_t finalStatus;
+ size_t cachedDataRemaining =
+ mCachedSource->approxDataRemaining(&finalStatus);
+
+ if (finalStatus != OK || cachedDataRemaining >= kHighWaterMarkBytes
+ || (mFlags & PREPARE_CANCELLED)) {
+ break;
+ }
+
+ usleep(200000);
+ }
+
+ mLock.lock();
+
+ if (mFlags & PREPARE_CANCELLED) {
+ LOGI("Prepare cancelled while waiting for initial cache fill.");
+ return UNKNOWN_ERROR;
+ }
} else if (!strncasecmp(mUri.string(), "httplive://", 11)) {
String8 uri("http://");
uri.append(mUri.string() + 11);
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 06c4c98..a47ee3a 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -590,6 +590,7 @@
status_t err = OK;
int64_t maxDurationUs = 0;
+ int64_t minDurationUs = 0x7fffffffffffffffLL;
for (List<Track *>::iterator it = mTracks.begin();
it != mTracks.end(); ++it) {
status_t status = (*it)->stop();
@@ -601,6 +602,14 @@
if (durationUs > maxDurationUs) {
maxDurationUs = durationUs;
}
+ if (durationUs < minDurationUs) {
+ minDurationUs = durationUs;
+ }
+ }
+
+ if (mTracks.size() > 1) {
+ LOGD("Duration from tracks range is [%lld, %lld] us",
+ minDurationUs, maxDurationUs);
}
stopWriterThread();
diff --git a/media/libstagefright/NuCachedSource2.cpp b/media/libstagefright/NuCachedSource2.cpp
index 20f1655..741aa1c 100644
--- a/media/libstagefright/NuCachedSource2.cpp
+++ b/media/libstagefright/NuCachedSource2.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+//#define LOG_NDEBUG 0
#define LOG_TAG "NuCachedSource2"
#include <utils/Log.h>
@@ -487,4 +488,5 @@
String8 NuCachedSource2::getUri() {
return mSource->getUri();
}
+
} // namespace android
diff --git a/packages/SystemUI/res/layout-xlarge/status_bar.xml b/packages/SystemUI/res/layout-xlarge/status_bar.xml
index 0533b6f..852b729 100644
--- a/packages/SystemUI/res/layout-xlarge/status_bar.xml
+++ b/packages/SystemUI/res/layout-xlarge/status_bar.xml
@@ -78,15 +78,14 @@
</LinearLayout>
<!-- fake space bar zone -->
- <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/fake_space_bar"
+ <com.android.systemui.statusbar.policy.EventHole android:id="@+id/fake_space_bar"
android:layout_height="match_parent"
- android:layout_width="match_parent"
+ android:layout_width="0dp"
android:paddingLeft="8dip"
android:paddingRight="8dip"
android:layout_toRightOf="@+id/navigationArea"
android:layout_toLeftOf="@+id/notificationArea"
android:visibility="gone"
- systemui:keyCode="62"
/>
</RelativeLayout>
</FrameLayout>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/EventHole.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/EventHole.java
new file mode 100644
index 0000000..47e758c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/EventHole.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Region;
+import android.graphics.drawable.AnimationDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.ServiceManager;
+import android.util.AttributeSet;
+import android.util.Slog;
+import android.view.HapticFeedbackConstants;
+import android.view.IWindowManager;
+import android.view.InputDevice;
+import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewTreeObserver;
+import android.widget.RemoteViews.RemoteView;
+
+import com.android.systemui.R;
+
+public class EventHole extends View implements ViewTreeObserver.OnComputeInternalInsetsListener {
+ private static final String TAG = "StatusBar.EventHole";
+
+ private boolean mWindowVis;
+ private int[] mLoc = new int[2];
+
+ public EventHole(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public EventHole(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onWindowVisibilityChanged(int visibility) {
+ super.onWindowVisibilityChanged(visibility);
+ mWindowVis = visibility == View.VISIBLE;
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ getViewTreeObserver().addOnComputeInternalInsetsListener(this);
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ getViewTreeObserver().removeOnComputeInternalInsetsListener(this);
+ }
+
+ public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo info) {
+ final boolean visible = isShown() && mWindowVis && getWidth() > 0 && getHeight() > 0;
+ final int[] loc = mLoc;
+ getLocationInWindow(loc);
+ final int l = loc[0];
+ final int r = l + getWidth();
+ final int t = loc[1];
+ final int b = t + getHeight();
+
+ View top = this;
+ while (top.getParent() instanceof View) {
+ top = (View)top.getParent();
+ }
+
+ if (visible) {
+ info.setTouchableInsets(
+ ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
+ info.touchableRegion.set(0, 0, top.getWidth(), top.getHeight());
+ info.touchableRegion.op(l, t, r, b, Region.Op.DIFFERENCE);
+ } else {
+ info.setTouchableInsets(
+ ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME);
+ }
+ }
+}
+
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java
index 45a22b6..800f4b4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java
@@ -52,7 +52,7 @@
View mNotificationScroller;
View mNotificationGlow;
ViewGroup mContentFrame;
- Rect mContentArea;
+ Rect mContentArea = new Rect();
View mSettingsView;
View mScrim, mGlow;
ViewGroup mContentParent;
@@ -136,7 +136,6 @@
@Override
public void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
- mContentArea = null;
}
public void onClick(View v) {
@@ -165,13 +164,11 @@
}
public boolean isInContentArea(int x, int y) {
- if (mContentArea == null) {
- mContentArea = new Rect(mContentFrame.getLeft(),
- mTitleArea.getTop(),
- mContentFrame.getRight(),
- mContentFrame.getBottom());
- offsetDescendantRectToMyCoords(mContentParent, mContentArea);
- }
+ mContentArea.left = mContentFrame.getLeft();
+ mContentArea.top = mTitleArea.getTop();
+ mContentArea.right = mContentFrame.getRight();
+ mContentArea.bottom = mContentFrame.getBottom();
+ offsetDescendantRectToMyCoords(mContentParent, mContentArea);
return mContentArea.contains(x, y);
}
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 3e930ae..bbb2228 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -583,7 +583,7 @@
void broadcastDragStartedLw(final float touchX, final float touchY) {
// Cache a base-class instance of the clip metadata so that parceling
// works correctly in calling out to the apps.
- mDataDescription = mData.getDescription();
+ mDataDescription = (mData != null) ? mData.getDescription() : null;
mNotifiedWindows.clear();
mDragInProgress = true;
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 2ef85d5..9e9a4f2 100755
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -6817,6 +6817,9 @@
if (info.durationMillis != -1) {
sb.append("Duration-Millis: ").append(info.durationMillis).append("\n");
}
+ if (info.numInstances != -1) {
+ sb.append("Instance-Count: ").append(info.numInstances).append("\n");
+ }
if (info.tags != null) {
for (String tag : info.tags) {
sb.append("Span-Tag: ").append(tag).append("\n");
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index 691aff28..7a61b3c 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -53,6 +53,15 @@
</activity>
<activity
+ android:name="ViewLayersActivity3"
+ android:label="_ViewLayers3">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
+ <activity
android:name="AlphaLayersActivity"
android:label="_αLayers">
<intent-filter>
diff --git a/tests/HwAccelerationTest/res/layout/view_layers_3.xml b/tests/HwAccelerationTest/res/layout/view_layers_3.xml
new file mode 100644
index 0000000..a820f5f
--- /dev/null
+++ b/tests/HwAccelerationTest/res/layout/view_layers_3.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <LinearLayout
+ android:background="#30ff0000"
+ android:layout_width="0dip"
+ android:layout_height="match_parent"
+ android:layout_weight="1" />
+
+ <LinearLayout
+ android:background="#3000ff00"
+ android:layout_width="0dip"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:padding="12dip">
+
+ <ListView
+ android:id="@+id/list1"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:background="#300000ff"
+ android:layout_width="0dip"
+ android:layout_height="match_parent"
+ android:layout_weight="1" />
+
+</LinearLayout>
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ViewLayersActivity3.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ViewLayersActivity3.java
new file mode 100644
index 0000000..c8ae75b
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ViewLayersActivity3.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.hwui;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.util.DisplayMetrics;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+import android.widget.TextView;
+
+@SuppressWarnings({"UnusedDeclaration"})
+public class ViewLayersActivity3 extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.view_layers_3);
+
+ setupList(R.id.list1);
+ }
+
+ private void setupList(int listId) {
+ final ListView list = (ListView) findViewById(listId);
+ list.setAdapter(new SimpleListAdapter(this));
+ list.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ ((View) list.getParent()).setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ }
+
+ private static class SimpleListAdapter extends ArrayAdapter<String> {
+ public SimpleListAdapter(Context context) {
+ super(context, android.R.layout.simple_list_item_1, DATA_LIST);
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ TextView v = (TextView) super.getView(position, convertView, parent);
+ final Resources r = getContext().getResources();
+ final DisplayMetrics metrics = r.getDisplayMetrics();
+ v.setCompoundDrawablePadding((int) (6 * metrics.density + 0.5f));
+ v.setCompoundDrawablesWithIntrinsicBounds(r.getDrawable(R.drawable.icon),
+ null, null, null);
+ return v;
+ }
+ }
+
+ private static final String[] DATA_LIST = {
+ "Afghanistan", "Albania", "Algeria", "American Samoa", "Andorra",
+ "Angola", "Anguilla", "Antarctica", "Antigua and Barbuda", "Argentina",
+ "Armenia", "Aruba", "Australia", "Austria", "Azerbaijan",
+ "Bahrain", "Bangladesh", "Barbados", "Belarus", "Belgium",
+ "Belize", "Benin", "Bermuda", "Bhutan", "Bolivia",
+ "Bosnia and Herzegovina", "Botswana", "Bouvet Island", "Brazil",
+ "British Indian Ocean Territory", "British Virgin Islands", "Brunei", "Bulgaria",
+ "Burkina Faso", "Burundi", "Cote d'Ivoire", "Cambodia", "Cameroon", "Canada", "Cape Verde",
+ "Cayman Islands", "Central African Republic", "Chad", "Chile", "China",
+ "Christmas Island", "Cocos (Keeling) Islands", "Colombia", "Comoros", "Congo",
+ "Cook Islands", "Costa Rica", "Croatia", "Cuba", "Cyprus", "Czech Republic",
+ "Democratic Republic of the Congo", "Denmark", "Djibouti", "Dominica", "Dominican Republic",
+ "East Timor", "Ecuador", "Egypt", "El Salvador", "Equatorial Guinea", "Eritrea",
+ "Estonia", "Ethiopia", "Faeroe Islands", "Falkland Islands", "Fiji", "Finland",
+ "Former Yugoslav Republic of Macedonia", "France", "French Guiana", "French Polynesia",
+ "French Southern Territories", "Gabon", "Georgia", "Germany", "Ghana", "Gibraltar",
+ "Greece", "Greenland", "Grenada", "Guadeloupe", "Guam", "Guatemala", "Guinea", "Guinea-Bissau",
+ "Guyana", "Haiti", "Heard Island and McDonald Islands", "Honduras", "Hong Kong", "Hungary",
+ "Iceland", "India", "Indonesia", "Iran", "Iraq", "Ireland", "Israel", "Italy", "Jamaica",
+ "Japan", "Jordan", "Kazakhstan", "Kenya", "Kiribati", "Kuwait", "Kyrgyzstan", "Laos",
+ "Latvia", "Lebanon", "Lesotho", "Liberia", "Libya", "Liechtenstein", "Lithuania", "Luxembourg",
+ "Macau", "Madagascar", "Malawi", "Malaysia", "Maldives", "Mali", "Malta", "Marshall Islands",
+ "Martinique", "Mauritania", "Mauritius", "Mayotte", "Mexico", "Micronesia", "Moldova",
+ "Monaco", "Mongolia", "Montserrat", "Morocco", "Mozambique", "Myanmar", "Namibia",
+ "Nauru", "Nepal", "Netherlands", "Netherlands Antilles", "New Caledonia", "New Zealand",
+ "Nicaragua", "Niger", "Nigeria", "Niue", "Norfolk Island", "North Korea", "Northern Marianas",
+ "Norway", "Oman", "Pakistan", "Palau", "Panama", "Papua New Guinea", "Paraguay", "Peru",
+ "Philippines", "Pitcairn Islands", "Poland", "Portugal", "Puerto Rico", "Qatar",
+ "Reunion", "Romania", "Russia", "Rwanda", "Sqo Tome and Principe", "Saint Helena",
+ "Saint Kitts and Nevis", "Saint Lucia", "Saint Pierre and Miquelon",
+ "Saint Vincent and the Grenadines", "Samoa", "San Marino", "Saudi Arabia", "Senegal",
+ "Seychelles", "Sierra Leone", "Singapore", "Slovakia", "Slovenia", "Solomon Islands",
+ "Somalia", "South Africa", "South Georgia and the South Sandwich Islands", "South Korea",
+ "Spain", "Sri Lanka", "Sudan", "Suriname", "Svalbard and Jan Mayen", "Swaziland", "Sweden",
+ "Switzerland", "Syria", "Taiwan", "Tajikistan", "Tanzania", "Thailand", "The Bahamas",
+ "The Gambia", "Togo", "Tokelau", "Tonga", "Trinidad and Tobago", "Tunisia", "Turkey",
+ "Turkmenistan", "Turks and Caicos Islands", "Tuvalu", "Virgin Islands", "Uganda",
+ "Ukraine", "United Arab Emirates", "United Kingdom",
+ "United States", "United States Minor Outlying Islands", "Uruguay", "Uzbekistan",
+ "Vanuatu", "Vatican City", "Venezuela", "Vietnam", "Wallis and Futuna", "Western Sahara",
+ "Yemen", "Yugoslavia", "Zambia", "Zimbabwe"
+ };
+}