Merge "Import revised translations."
diff --git a/api/current.xml b/api/current.xml
index 22d82ce..2b10d42 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -10025,6 +10025,39 @@
visibility="public"
>
</field>
+<field name="textEditSuggestionItemLayout"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843626"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="textEditSuggestionsBottomWindowLayout"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843624"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="textEditSuggestionsTopWindowLayout"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843625"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="textFilterEnabled"
type="int"
transient="false"
@@ -10146,6 +10179,17 @@
visibility="public"
>
</field>
+<field name="textSuggestionsWindowStyle"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843623"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="textViewStyle"
type="int"
transient="false"
@@ -213125,6 +213169,17 @@
visibility="public"
>
</method>
+<method name="getModifiers"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getNumber"
return="char"
abstract="false"
@@ -267841,7 +267896,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="arg0" type="T">
+<parameter name="t" type="T">
</parameter>
</method>
</interface>
diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java
index fa55520..8a9bef0 100644
--- a/core/java/android/bluetooth/BluetoothHeadset.java
+++ b/core/java/android/bluetooth/BluetoothHeadset.java
@@ -603,7 +603,7 @@
*/
public boolean setAudioState(BluetoothDevice device, int state) {
if (DBG) log("setAudioState");
- if (mService != null && isEnabled()) {
+ if (mService != null && !isDisabled()) {
try {
return mService.setAudioState(device, state);
} catch (RemoteException e) {Log.e(TAG, e.toString());}
@@ -622,7 +622,7 @@
*/
public int getAudioState(BluetoothDevice device) {
if (DBG) log("getAudioState");
- if (mService != null && isEnabled()) {
+ if (mService != null && !isDisabled()) {
try {
return mService.getAudioState(device);
} catch (RemoteException e) {Log.e(TAG, e.toString());}
@@ -705,6 +705,11 @@
return false;
}
+ private boolean isDisabled() {
+ if (mAdapter.getState() == BluetoothAdapter.STATE_OFF) return true;
+ return false;
+ }
+
private boolean isValidDevice(BluetoothDevice device) {
if (device == null) return false;
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 7bdd1b9..afc2722 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1908,6 +1908,21 @@
"android.intent.action.HDMI_AUDIO_PLUG";
/**
+ * <p>Broadcast Action: The user has switched on advanced settings in the settings app:</p>
+ * <ul>
+ * <li><em>state</em> - A boolean value indicating whether the settings is on or off.</li>
+ * </ul>
+ *
+ * <p class="note">This is a protected intent that can only be sent
+ * by the system.
+ *
+ * @hide
+ */
+ //@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_ADVANCED_SETTINGS_CHANGED
+ = "android.intent.action.ADVANCED_SETTINGS";
+
+ /**
* Broadcast Action: An outgoing call is about to be placed.
*
* <p>The Intent will have the following extra value:
diff --git a/core/java/android/net/LinkAddress.java b/core/java/android/net/LinkAddress.java
index 9c36b12..f6a114c 100644
--- a/core/java/android/net/LinkAddress.java
+++ b/core/java/android/net/LinkAddress.java
@@ -78,6 +78,14 @@
this.prefixLength == linkAddress.prefixLength;
}
+ @Override
+ /*
+ * generate hashcode based on significant fields
+ */
+ public int hashCode() {
+ return ((null == address) ? 0 : address.hashCode()) + prefixLength;
+ }
+
/**
* Returns the InetAddress for this address.
*/
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index 81d62a0..e88292f 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -19,11 +19,9 @@
import android.net.ProxyProperties;
import android.os.Parcelable;
import android.os.Parcel;
-import android.util.Log;
+import android.text.TextUtils;
import java.net.InetAddress;
-import java.net.NetworkInterface;
-import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collection;
@@ -141,7 +139,7 @@
String ifaceName = (mIfaceName == null ? "" : "InterfaceName: " + mIfaceName + " ");
String linkAddresses = "LinkAddresses: [";
- for (LinkAddress addr : mLinkAddresses) linkAddresses += addr.toString();
+ for (LinkAddress addr : mLinkAddresses) linkAddresses += addr.toString() + ",";
linkAddresses += "] ";
String dns = "DnsAddresses: [";
@@ -156,6 +154,67 @@
return ifaceName + linkAddresses + gateways + dns + proxy;
}
+
+ @Override
+ /**
+ * Compares this {@code LinkProperties} instance against the target
+ * LinkProperties in {@code obj}. Two LinkPropertieses are equal if
+ * all their fields are equal in values.
+ *
+ * For collection fields, such as mDnses, containsAll() is used to check
+ * if two collections contains the same elements, independent of order.
+ * There are two thoughts regarding containsAll()
+ * 1. Duplicated elements. eg, (A, B, B) and (A, A, B) are equal.
+ * 2. Worst case performance is O(n^2).
+ *
+ * @param obj the object to be tested for equality.
+ * @return {@code true} if both objects are equal, {@code false} otherwise.
+ */
+ public boolean equals(Object obj) {
+ if (this == obj) return true;
+
+ if (!(obj instanceof LinkProperties)) return false;
+
+ boolean sameAddresses;
+ boolean sameDnses;
+ boolean sameGateways;
+
+ LinkProperties target = (LinkProperties) obj;
+
+ Collection<InetAddress> targetAddresses = target.getAddresses();
+ Collection<InetAddress> sourceAddresses = getAddresses();
+ sameAddresses = (sourceAddresses.size() == targetAddresses.size()) ?
+ sourceAddresses.containsAll(targetAddresses) : false;
+
+ Collection<InetAddress> targetDnses = target.getDnses();
+ sameDnses = (mDnses.size() == targetDnses.size()) ?
+ mDnses.containsAll(targetDnses) : false;
+
+ Collection<InetAddress> targetGateways = target.getGateways();
+ sameGateways = (mGateways.size() == targetGateways.size()) ?
+ mGateways.containsAll(targetGateways) : false;
+
+ return
+ sameAddresses && sameDnses && sameGateways
+ && TextUtils.equals(getInterfaceName(), target.getInterfaceName())
+ && (getHttpProxy() == null ? target.getHttpProxy() == null :
+ getHttpProxy().equals(target.getHttpProxy()));
+ }
+
+ @Override
+ /**
+ * generate hashcode based on significant fields
+ * Equal objects must produce the same hash code, while unequal objects
+ * may have the same hash codes.
+ */
+ public int hashCode() {
+ return ((null == mIfaceName) ? 0 : mIfaceName.hashCode()
+ + mLinkAddresses.size() * 31
+ + mDnses.size() * 37
+ + mGateways.size() * 41
+ + ((null == mHttpProxy) ? 0 : mHttpProxy.hashCode()));
+ }
+
/**
* Implement the Parcelable interface.
* @hide
diff --git a/core/java/android/net/ProxyProperties.java b/core/java/android/net/ProxyProperties.java
index cbe4445..44dbec1 100644
--- a/core/java/android/net/ProxyProperties.java
+++ b/core/java/android/net/ProxyProperties.java
@@ -163,6 +163,16 @@
return 0;
}
+ @Override
+ /*
+ * generate hashcode based on significant fields
+ */
+ public int hashCode() {
+ return ((null == mHost) ? 0 : mHost.hashCode())
+ + ((null == mExclusionList) ? 0 : mExclusionList.hashCode())
+ + mPort;
+ }
+
/**
* Implement the Parcelable interface.
* @hide
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index c75b0fe..8a19456 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1103,6 +1103,18 @@
public static final int END_BUTTON_BEHAVIOR_DEFAULT = END_BUTTON_BEHAVIOR_SLEEP;
/**
+ * Is advanced settings mode turned on. 0 == no, 1 == yes
+ * @hide
+ */
+ public static final String ADVANCED_SETTINGS = "advanced_settings";
+
+ /**
+ * ADVANCED_SETTINGS default value.
+ * @hide
+ */
+ public static final int ADVANCED_SETTINGS_DEFAULT = 0;
+
+ /**
* Whether Airplane Mode is on.
*/
public static final String AIRPLANE_MODE_ON = "airplane_mode_on";
diff --git a/core/java/android/server/BluetoothA2dpService.java b/core/java/android/server/BluetoothA2dpService.java
index 132c346..ca2212c 100644
--- a/core/java/android/server/BluetoothA2dpService.java
+++ b/core/java/android/server/BluetoothA2dpService.java
@@ -83,19 +83,6 @@
onBluetoothDisable();
break;
}
- } else if (action.equals(BluetoothDevice.ACTION_BOND_STATE_CHANGED)) {
- int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE,
- BluetoothDevice.ERROR);
- switch(bondState) {
- case BluetoothDevice.BOND_BONDED:
- if (getPriority(device) == BluetoothA2dp.PRIORITY_UNDEFINED) {
- setPriority(device, BluetoothA2dp.PRIORITY_ON);
- }
- break;
- case BluetoothDevice.BOND_NONE:
- setPriority(device, BluetoothA2dp.PRIORITY_UNDEFINED);
- break;
- }
} else if (action.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)) {
synchronized (this) {
if (mAudioDevices.containsKey(device)) {
@@ -158,7 +145,6 @@
mAdapter = BluetoothAdapter.getDefaultAdapter();
mIntentFilter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
- mIntentFilter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
mIntentFilter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
mIntentFilter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
mIntentFilter.addAction(AudioManager.VOLUME_CHANGED_ACTION);
diff --git a/core/java/android/server/BluetoothBondState.java b/core/java/android/server/BluetoothBondState.java
index 2304a70..a36cd24 100644
--- a/core/java/android/server/BluetoothBondState.java
+++ b/core/java/android/server/BluetoothBondState.java
@@ -18,6 +18,9 @@
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothA2dp;
+import android.bluetooth.BluetoothHeadset;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
@@ -68,6 +71,8 @@
private final Context mContext;
private final BluetoothService mService;
private final BluetoothInputProfileHandler mBluetoothInputProfileHandler;
+ private BluetoothA2dp mA2dpProxy;
+ private BluetoothHeadset mHeadsetProxy;
BluetoothBondState(Context context, BluetoothService service) {
mContext = context;
@@ -126,14 +131,15 @@
if (state == BluetoothDevice.BOND_BONDED) {
mService.addProfileState(address);
+ } else if (state == BluetoothDevice.BOND_BONDING) {
+ if (mA2dpProxy == null || mHeadsetProxy == null) {
+ getProfileProxy();
+ }
} else if (state == BluetoothDevice.BOND_NONE) {
mService.removeProfileState(address);
}
- // HID is handled by BluetoothService, other profiles
- // will be handled by their respective services.
- mBluetoothInputProfileHandler.setInitialInputDevicePriority(
- mService.getRemoteDevice(address), state);
+ setProfilePriorities(address, state);
if (DBG) {
Log.d(TAG, address + " bond state " + oldState + " -> " + state
@@ -261,6 +267,52 @@
mPinAttempt.put(address, new Integer(newAttempt));
}
+ private void getProfileProxy() {
+ BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+
+ if (mA2dpProxy == null) {
+ bluetoothAdapter.getProfileProxy(mContext, mProfileServiceListener,
+ BluetoothProfile.A2DP);
+ }
+
+ if (mHeadsetProxy == null) {
+ bluetoothAdapter.getProfileProxy(mContext, mProfileServiceListener,
+ BluetoothProfile.HEADSET);
+ }
+ }
+
+ private void closeProfileProxy() {
+ BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+
+ if (mA2dpProxy != null) {
+ bluetoothAdapter.closeProfileProxy(BluetoothProfile.A2DP, mA2dpProxy);
+ }
+
+ if (mHeadsetProxy != null) {
+ bluetoothAdapter.closeProfileProxy(BluetoothProfile.HEADSET, mHeadsetProxy);
+ }
+ }
+
+ private BluetoothProfile.ServiceListener mProfileServiceListener =
+ new BluetoothProfile.ServiceListener() {
+
+ public void onServiceConnected(int profile, BluetoothProfile proxy) {
+ if (profile == BluetoothProfile.A2DP) {
+ mA2dpProxy = (BluetoothA2dp) proxy;
+ } else if (profile == BluetoothProfile.HEADSET) {
+ mHeadsetProxy = (BluetoothHeadset) proxy;
+ }
+ }
+
+ public void onServiceDisconnected(int profile) {
+ if (profile == BluetoothProfile.A2DP) {
+ mA2dpProxy = null;
+ } else if (profile == BluetoothProfile.HEADSET) {
+ mHeadsetProxy = null;
+ }
+ }
+ };
+
private void copyAutoPairingData() {
FileInputStream in = null;
FileOutputStream out = null;
@@ -365,4 +417,30 @@
}
}
}
+
+ // Set service priority of Hid, A2DP and Headset profiles depending on
+ // the bond state change
+ private void setProfilePriorities(String address, int state) {
+ BluetoothDevice remoteDevice = mService.getRemoteDevice(address);
+ // HID is handled by BluetoothService
+ mBluetoothInputProfileHandler.setInitialInputDevicePriority(remoteDevice, state);
+
+ // Set service priority of A2DP and Headset
+ // We used to do the priority change in the 2 services after the broadcast
+ // intent reach them. But that left a small time gap that could reject
+ // incoming connection due to undefined priorities.
+ if (state == BluetoothDevice.BOND_BONDED) {
+ if (mA2dpProxy.getPriority(remoteDevice) == BluetoothProfile.PRIORITY_UNDEFINED) {
+ mA2dpProxy.setPriority(remoteDevice, BluetoothProfile.PRIORITY_ON);
+ }
+
+ if (mHeadsetProxy.getPriority(remoteDevice) == BluetoothProfile.PRIORITY_UNDEFINED) {
+ mHeadsetProxy.setPriority(remoteDevice, BluetoothProfile.PRIORITY_ON);
+ }
+ } else if (state == BluetoothDevice.BOND_NONE) {
+ mA2dpProxy.setPriority(remoteDevice, BluetoothProfile.PRIORITY_UNDEFINED);
+ mHeadsetProxy.setPriority(remoteDevice, BluetoothProfile.PRIORITY_UNDEFINED);
+ }
+ }
+
}
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 28541fe..66f37f2 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -645,8 +645,21 @@
}
attachInfo.mIgnoreDirtyState = false;
-
+
+ final long swapBuffersStartTime;
+ if (ViewDebug.DEBUG_LATENCY) {
+ swapBuffersStartTime = System.nanoTime();
+ }
+
sEgl.eglSwapBuffers(sEglDisplay, mEglSurface);
+
+ if (ViewDebug.DEBUG_LATENCY) {
+ long now = System.nanoTime();
+ Log.d(LOG_TAG, "Latency: Spent "
+ + ((now - swapBuffersStartTime) * 0.000001f)
+ + "ms waiting for eglSwapBuffers()");
+ }
+
checkEglErrors();
}
}
diff --git a/core/java/android/view/InputEvent.java b/core/java/android/view/InputEvent.java
index 87e7ea7..01ddcc9 100755
--- a/core/java/android/view/InputEvent.java
+++ b/core/java/android/view/InputEvent.java
@@ -106,6 +106,13 @@
*/
public abstract void setTainted(boolean tainted);
+ /**
+ * Returns the time (in ns) when this specific event was generated.
+ * The value is in nanosecond precision but it may not have nanosecond accuracy.
+ * @hide
+ */
+ public abstract long getEventTimeNano();
+
public int describeContents() {
return 0;
}
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 4320160..13d8809 100755
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -1807,12 +1807,33 @@
* @see #META_CAPS_LOCK_ON
* @see #META_NUM_LOCK_ON
* @see #META_SCROLL_LOCK_ON
+ * @see #getModifiers
*/
public final int getMetaState() {
return mMetaState;
}
/**
+ * Returns the state of the modifier keys.
+ * <p>
+ * For the purposes of this function, {@link #KEYCODE_CAPS_LOCK},
+ * {@link #KEYCODE_SCROLL_LOCK}, and {@link #KEYCODE_NUM_LOCK} are
+ * not considered modifier keys. Consequently, this function specifically masks out
+ * {@link #META_CAPS_LOCK_ON}, {@link #META_SCROLL_LOCK_ON} and {@link #META_NUM_LOCK_ON}.
+ * </p><p>
+ * The value returned consists of the meta state (from {@link #getMetaState})
+ * normalized using {@link #normalizeMetaState(int)} and then masked with
+ * {@link #getModifierMetaStateMask} so that only valid modifier bits are retained.
+ * </p>
+ *
+ * @return An integer in which each bit set to 1 represents a pressed modifier key.
+ * @see #getMetaState
+ */
+ public final int getModifiers() {
+ return normalizeMetaState(mMetaState) & META_MODIFIER_MASK;
+ }
+
+ /**
* Returns the flags for this key event.
*
* @see #FLAG_WOKE_HERE
@@ -2319,6 +2340,12 @@
return mEventTime;
}
+ /** @hide */
+ @Override
+ public final long getEventTimeNano() {
+ return mEventTime * 1000000L;
+ }
+
/**
* Renamed to {@link #getDeviceId}.
*
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index c19a107..89736d6 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -141,6 +141,22 @@
public static final boolean DEBUG_DRAG = false;
/**
+ * Enables logging of factors that affect the latency and responsiveness of an application.
+ *
+ * Logs the relative difference between the time an event was created and the time it
+ * was delivered.
+ *
+ * Logs the time spent waiting for Surface.lockCanvas() or eglSwapBuffers().
+ * This is time that the event loop spends blocked and unresponsive. Ideally, drawing
+ * and animations should be perfectly synchronized with VSYNC so that swap buffers
+ * is instantaneous.
+ *
+ * Logs the time spent in ViewRoot.performTraversals() or ViewRoot.draw().
+ * @hide
+ */
+ public static final boolean DEBUG_LATENCY = false;
+
+ /**
* <p>Enables or disables views consistency check. Even when this property is enabled,
* view consistency checks happen only if {@link android.util.Config#DEBUG} is set
* to true. The value of this property can be configured externally in one of the
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index 2f9d501..a899b46 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -186,6 +186,8 @@
final Rect mVisRect; // used to retrieve visible rect of focused view.
boolean mTraversalScheduled;
+ long mLastTraversalFinishedTimeNanos;
+ long mLastDrawDurationNanos;
boolean mWillDrawSoon;
boolean mLayoutRequested;
boolean mFirst;
@@ -671,6 +673,14 @@
public void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
+
+ if (ViewDebug.DEBUG_LATENCY && mLastTraversalFinishedTimeNanos != 0) {
+ final long now = System.nanoTime();
+ Log.d(TAG, "Latency: Scheduled traversal, it has been "
+ + ((now - mLastTraversalFinishedTimeNanos) * 0.000001f)
+ + "ms since the last traversal finished.");
+ }
+
sendEmptyMessage(DO_TRAVERSAL);
}
}
@@ -1389,8 +1399,18 @@
if (!cancelDraw && !newSurface) {
mFullRedrawNeeded = false;
+
+ final long drawStartTime;
+ if (ViewDebug.DEBUG_LATENCY) {
+ drawStartTime = System.nanoTime();
+ }
+
draw(fullRedrawNeeded);
+ if (ViewDebug.DEBUG_LATENCY) {
+ mLastDrawDurationNanos = System.nanoTime() - drawStartTime;
+ }
+
if ((relayoutResult&WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0
|| mReportNextDraw) {
if (LOCAL_LOGV) {
@@ -1601,8 +1621,20 @@
int right = dirty.right;
int bottom = dirty.bottom;
+ final long lockCanvasStartTime;
+ if (ViewDebug.DEBUG_LATENCY) {
+ lockCanvasStartTime = System.nanoTime();
+ }
+
canvas = surface.lockCanvas(dirty);
+ if (ViewDebug.DEBUG_LATENCY) {
+ long now = System.nanoTime();
+ Log.d(TAG, "Latency: Spent "
+ + ((now - lockCanvasStartTime) * 0.000001f)
+ + "ms waiting for surface.lockCanvas()");
+ }
+
if (left != dirty.left || top != dirty.top || right != dirty.right ||
bottom != dirty.bottom) {
mAttachInfo.mIgnoreDirtyState = true;
@@ -2011,8 +2043,24 @@
Debug.startMethodTracing("ViewRoot");
}
+ final long traversalStartTime;
+ if (ViewDebug.DEBUG_LATENCY) {
+ traversalStartTime = System.nanoTime();
+ mLastDrawDurationNanos = 0;
+ }
+
performTraversals();
+ if (ViewDebug.DEBUG_LATENCY) {
+ long now = System.nanoTime();
+ Log.d(TAG, "Latency: Spent "
+ + ((now - traversalStartTime) * 0.000001f)
+ + "ms in performTraversals(), with "
+ + (mLastDrawDurationNanos * 0.000001f)
+ + "ms of that time in draw()");
+ mLastTraversalFinishedTimeNanos = now;
+ }
+
if (mProfile) {
Debug.stopMethodTracing();
mProfile = false;
@@ -2180,25 +2228,68 @@
}
}
- private void startInputEvent(InputQueue.FinishedCallback finishedCallback) {
+ private void startInputEvent(InputEvent event, InputQueue.FinishedCallback finishedCallback) {
if (mFinishedCallback != null) {
Slog.w(TAG, "Received a new input event from the input queue but there is "
+ "already an unfinished input event in progress.");
}
+ if (ViewDebug.DEBUG_LATENCY) {
+ mInputEventReceiveTimeNanos = System.nanoTime();
+ mInputEventDeliverTimeNanos = 0;
+ mInputEventDeliverPostImeTimeNanos = 0;
+ }
+
mFinishedCallback = finishedCallback;
}
- private void finishInputEvent(boolean handled) {
+ private void finishInputEvent(InputEvent event, boolean handled) {
if (LOCAL_LOGV) Log.v(TAG, "Telling window manager input event is finished");
- if (mFinishedCallback != null) {
- mFinishedCallback.finished(handled);
- mFinishedCallback = null;
- } else {
+ if (mFinishedCallback == null) {
Slog.w(TAG, "Attempted to tell the input queue that the current input event "
+ "is finished but there is no input event actually in progress.");
+ return;
}
+
+ if (ViewDebug.DEBUG_LATENCY) {
+ final long now = System.nanoTime();
+ final long eventTime = event.getEventTimeNano();
+ final StringBuilder msg = new StringBuilder();
+ msg.append("Latency: Spent ");
+ msg.append((now - mInputEventReceiveTimeNanos) * 0.000001f);
+ msg.append("ms processing ");
+ if (event instanceof KeyEvent) {
+ final KeyEvent keyEvent = (KeyEvent)event;
+ msg.append("key event, action=");
+ msg.append(KeyEvent.actionToString(keyEvent.getAction()));
+ } else {
+ final MotionEvent motionEvent = (MotionEvent)event;
+ msg.append("motion event, action=");
+ msg.append(MotionEvent.actionToString(motionEvent.getAction()));
+ msg.append(", historySize=");
+ msg.append(motionEvent.getHistorySize());
+ }
+ msg.append(", handled=");
+ msg.append(handled);
+ msg.append(", received at +");
+ msg.append((mInputEventReceiveTimeNanos - eventTime) * 0.000001f);
+ if (mInputEventDeliverTimeNanos != 0) {
+ msg.append("ms, delivered at +");
+ msg.append((mInputEventDeliverTimeNanos - eventTime) * 0.000001f);
+ }
+ if (mInputEventDeliverPostImeTimeNanos != 0) {
+ msg.append("ms, delivered post IME at +");
+ msg.append((mInputEventDeliverPostImeTimeNanos - eventTime) * 0.000001f);
+ }
+ msg.append("ms, finished at +");
+ msg.append((now - eventTime) * 0.000001f);
+ msg.append("ms.");
+ Log.d(TAG, msg.toString());
+ }
+
+ mFinishedCallback.finished(handled);
+ mFinishedCallback = null;
}
/**
@@ -2323,6 +2414,10 @@
}
private void deliverPointerEvent(MotionEvent event, boolean sendDone) {
+ if (ViewDebug.DEBUG_LATENCY) {
+ mInputEventDeliverTimeNanos = System.nanoTime();
+ }
+
if (mInputEventConsistencyVerifier != null) {
if (event.isTouchEvent()) {
mInputEventConsistencyVerifier.onTouchEvent(event, 0);
@@ -2425,7 +2520,7 @@
private void finishMotionEvent(MotionEvent event, boolean sendDone, boolean handled) {
event.recycle();
if (sendDone) {
- finishInputEvent(handled);
+ finishInputEvent(event, handled);
}
if (LOCAL_LOGV || WATCH_POINTER) {
if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
@@ -2435,6 +2530,10 @@
}
private void deliverTrackballEvent(MotionEvent event, boolean sendDone) {
+ if (ViewDebug.DEBUG_LATENCY) {
+ mInputEventDeliverTimeNanos = System.nanoTime();
+ }
+
if (DEBUG_TRACKBALL) Log.v(TAG, "Motion event:" + event);
if (mInputEventConsistencyVerifier != null) {
@@ -2569,6 +2668,10 @@
}
private void deliverGenericMotionEvent(MotionEvent event, boolean sendDone) {
+ if (ViewDebug.DEBUG_LATENCY) {
+ mInputEventDeliverTimeNanos = System.nanoTime();
+ }
+
if (mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onGenericMotionEvent(event, 0);
}
@@ -2808,6 +2911,10 @@
}
private void deliverKeyEvent(KeyEvent event, boolean sendDone) {
+ if (ViewDebug.DEBUG_LATENCY) {
+ mInputEventDeliverTimeNanos = System.nanoTime();
+ }
+
if (mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onKeyEvent(event, 0);
}
@@ -2858,6 +2965,10 @@
}
private void deliverKeyEventPostIme(KeyEvent event, boolean sendDone) {
+ if (ViewDebug.DEBUG_LATENCY) {
+ mInputEventDeliverPostImeTimeNanos = System.nanoTime();
+ }
+
// If the view went away, then the event will not be handled.
if (mView == null || !mAdded) {
finishKeyEvent(event, sendDone, false);
@@ -2971,7 +3082,7 @@
private void finishKeyEvent(KeyEvent event, boolean sendDone, boolean handled) {
if (sendDone) {
- finishInputEvent(handled);
+ finishInputEvent(event, handled);
}
}
@@ -3262,16 +3373,19 @@
sendMessage(msg);
}
+ private long mInputEventReceiveTimeNanos;
+ private long mInputEventDeliverTimeNanos;
+ private long mInputEventDeliverPostImeTimeNanos;
private InputQueue.FinishedCallback mFinishedCallback;
private final InputHandler mInputHandler = new InputHandler() {
public void handleKey(KeyEvent event, InputQueue.FinishedCallback finishedCallback) {
- startInputEvent(finishedCallback);
+ startInputEvent(event, finishedCallback);
dispatchKey(event, true);
}
public void handleMotion(MotionEvent event, InputQueue.FinishedCallback finishedCallback) {
- startInputEvent(finishedCallback);
+ startInputEvent(event, finishedCallback);
dispatchMotion(event, true);
}
};
diff --git a/core/java/android/webkit/HTML5VideoFullScreen.java b/core/java/android/webkit/HTML5VideoFullScreen.java
index 3d15968..0918683 100644
--- a/core/java/android/webkit/HTML5VideoFullScreen.java
+++ b/core/java/android/webkit/HTML5VideoFullScreen.java
@@ -114,13 +114,6 @@
return mVideoSurfaceView;
}
- @Override
- public void start() {
- if (getAutostart()) {
- super.start();
- }
- }
-
HTML5VideoFullScreen(Context context, int videoLayerId, int position,
boolean autoStart) {
mVideoSurfaceView = new VideoSurfaceView(context);
diff --git a/core/java/android/webkit/HTML5VideoViewProxy.java b/core/java/android/webkit/HTML5VideoViewProxy.java
index 14157c2..060c0bb 100644
--- a/core/java/android/webkit/HTML5VideoViewProxy.java
+++ b/core/java/android/webkit/HTML5VideoViewProxy.java
@@ -232,8 +232,9 @@
}
public static void onPrepared() {
- // The VideoView will decide whether to really kick off to play.
- mHTML5VideoView.start();
+ if (!mHTML5VideoView.isFullScreenMode() || mHTML5VideoView.getAutostart()) {
+ mHTML5VideoView.start();
+ }
if (mBaseLayer != 0) {
setBaseLayer(mBaseLayer);
}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index e0783f3..f55608c 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -2382,6 +2382,8 @@
*/
public void setTitleBarGravity(int gravity) {
mTitleGravity = gravity;
+ // force refresh
+ invalidate();
}
/**
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 86dfb9b..dc10624 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -43,7 +43,6 @@
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
-import android.os.IBinder;
import android.os.Message;
import android.os.Parcel;
import android.os.Parcelable;
@@ -88,6 +87,7 @@
import android.text.style.UpdateAppearance;
import android.text.util.Linkify;
import android.util.AttributeSet;
+import android.util.DisplayMetrics;
import android.util.FloatMath;
import android.util.Log;
import android.util.TypedValue;
@@ -311,6 +311,10 @@
private int mTextEditPasteWindowLayout, mTextEditSidePasteWindowLayout;
private int mTextEditNoPasteWindowLayout, mTextEditSideNoPasteWindowLayout;
+ private int mTextEditSuggestionsBottomWindowLayout, mTextEditSuggestionsTopWindowLayout;
+ private int mTextEditSuggestionItemLayout;
+ private SuggestionsPopupWindow mSuggestionsPopupWindow;
+
private int mCursorDrawableRes;
private final Drawable[] mCursorDrawable = new Drawable[2];
private int mCursorCount; // Actual current number of used mCursorDrawable: 0, 1 or 2
@@ -779,6 +783,18 @@
mTextEditSideNoPasteWindowLayout = a.getResourceId(attr, 0);
break;
+ case com.android.internal.R.styleable.TextView_textEditSuggestionsBottomWindowLayout:
+ mTextEditSuggestionsBottomWindowLayout = a.getResourceId(attr, 0);
+ break;
+
+ case com.android.internal.R.styleable.TextView_textEditSuggestionsTopWindowLayout:
+ mTextEditSuggestionsTopWindowLayout = a.getResourceId(attr, 0);
+ break;
+
+ case com.android.internal.R.styleable.TextView_textEditSuggestionItemLayout:
+ mTextEditSuggestionItemLayout = a.getResourceId(attr, 0);
+ break;
+
case com.android.internal.R.styleable.TextView_textIsSelectable:
mTextIsSelectable = a.getBoolean(attr, false);
break;
@@ -7343,6 +7359,7 @@
startSelectionActionMode();
} else {
stopSelectionActionMode();
+ hideSuggestions();
if (hasInsertionController() && !selectAllGotFocus && mText.length() > 0) {
getInsertionController().show();
}
@@ -7776,7 +7793,7 @@
// Cases where the text ends with a '.' and we select from the end of the line
// (right after the dot), or when we select from the space character in "aaa, bbb".
continue;
- }
+ }
if (type == Character.SURROGATE) { // Two Character codepoint
end = start - 1; // Recheck as a pair when scanning forward
continue;
@@ -8221,6 +8238,201 @@
return ((minOffset >= selectionStart) && (maxOffset < selectionEnd));
}
+ private class SuggestionsPopupWindow implements OnClickListener {
+ private static final int MAX_NUMBER_SUGGESTIONS = 5;
+ private static final long NO_SUGGESTIONS = -1L;
+ private final PopupWindow mContainer;
+ private final ViewGroup[] mSuggestionViews = new ViewGroup[2];
+ private final int[] mSuggestionViewLayouts = new int[] {
+ mTextEditSuggestionsBottomWindowLayout, mTextEditSuggestionsTopWindowLayout};
+
+ public SuggestionsPopupWindow() {
+ mContainer = new PopupWindow(TextView.this.mContext, null,
+ com.android.internal.R.attr.textSuggestionsWindowStyle);
+ mContainer.setSplitTouchEnabled(true);
+ mContainer.setClippingEnabled(false);
+ mContainer.setWindowLayoutType(WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL);
+
+ mContainer.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT);
+ mContainer.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
+ }
+
+ private ViewGroup getViewGroup(boolean under) {
+ final int viewIndex = under ? 0 : 1;
+ ViewGroup viewGroup = mSuggestionViews[viewIndex];
+
+ if (viewGroup == null) {
+ final int layout = mSuggestionViewLayouts[viewIndex];
+ LayoutInflater inflater = (LayoutInflater) TextView.this.mContext.
+ getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+ if (inflater == null) {
+ throw new IllegalArgumentException(
+ "Unable to create TextEdit suggestion window inflater");
+ }
+
+ View view = inflater.inflate(layout, null);
+
+ if (! (view instanceof ViewGroup)) {
+ throw new IllegalArgumentException(
+ "Inflated TextEdit suggestion window is not a ViewGroup: " + view);
+ }
+
+ viewGroup = (ViewGroup) view;
+
+ // Inflate the suggestion items once and for all.
+ for (int i = 0; i < MAX_NUMBER_SUGGESTIONS; i++) {
+ View childView = inflater.inflate(mTextEditSuggestionItemLayout, viewGroup,
+ false);
+
+ if (! (childView instanceof TextView)) {
+ throw new IllegalArgumentException(
+ "Inflated TextEdit suggestion item is not a TextView: " + childView);
+ }
+
+ viewGroup.addView(childView);
+ childView.setOnClickListener(this);
+ }
+
+ mSuggestionViews[viewIndex] = viewGroup;
+ }
+
+ return viewGroup;
+ }
+
+ public void show() {
+ if (!(mText instanceof Editable)) return;
+
+ final int pos = TextView.this.getSelectionStart();
+ Spannable spannable = (Spannable)TextView.this.mText;
+ CorrectionSpan[] correctionSpans = spannable.getSpans(pos, pos, CorrectionSpan.class);
+ final int nbSpans = correctionSpans.length;
+
+ ViewGroup viewGroup = getViewGroup(true);
+ mContainer.setContentView(viewGroup);
+
+ int totalNbSuggestions = 0;
+ for (int spanIndex = 0; spanIndex < nbSpans; spanIndex++) {
+ CorrectionSpan correctionSpan = correctionSpans[spanIndex];
+ final int spanStart = spannable.getSpanStart(correctionSpan);
+ final int spanEnd = spannable.getSpanEnd(correctionSpan);
+ final Long spanRange = packRangeInLong(spanStart, spanEnd);
+
+ String[] suggestions = correctionSpan.getSuggestions();
+ int nbSuggestions = suggestions.length;
+ for (int suggestionIndex = 0; suggestionIndex < nbSuggestions; suggestionIndex++) {
+ TextView textView = (TextView) viewGroup.getChildAt(totalNbSuggestions);
+ textView.setText(suggestions[suggestionIndex]);
+ textView.setTag(spanRange);
+
+ totalNbSuggestions++;
+ if (totalNbSuggestions == MAX_NUMBER_SUGGESTIONS) {
+ spanIndex = nbSpans;
+ break;
+ }
+ }
+ }
+
+ if (totalNbSuggestions == 0) {
+ // TODO Replace by final text, use a dedicated layout, add a fade out timer...
+ TextView textView = (TextView) viewGroup.getChildAt(0);
+ textView.setText("No suggestions available");
+ textView.setTag(NO_SUGGESTIONS);
+ totalNbSuggestions++;
+ }
+
+ for (int i = 0; i < MAX_NUMBER_SUGGESTIONS; i++) {
+ viewGroup.getChildAt(i).setVisibility(i < totalNbSuggestions ? VISIBLE : GONE);
+ }
+
+ final int size = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
+ viewGroup.measure(size, size);
+
+ positionAtCursor();
+ }
+
+ public void hide() {
+ mContainer.dismiss();
+ }
+
+ @Override
+ public void onClick(View view) {
+ if (view instanceof TextView) {
+ TextView textView = (TextView) view;
+ Long range = ((Long) view.getTag());
+ if (range != NO_SUGGESTIONS) {
+ final int spanStart = extractRangeStartFromLong(range);
+ final int spanEnd = extractRangeEndFromLong(range);
+ ((Editable) mText).replace(spanStart, spanEnd, textView.getText());
+ }
+ }
+ hide();
+ }
+
+ void positionAtCursor() {
+ View contentView = mContainer.getContentView();
+ int width = contentView.getMeasuredWidth();
+ int height = contentView.getMeasuredHeight();
+ final int offset = TextView.this.getSelectionStart();
+ final int line = mLayout.getLineForOffset(offset);
+ final int lineBottom = mLayout.getLineBottom(line);
+ float primaryHorizontal = mLayout.getPrimaryHorizontal(offset);
+
+ final Rect bounds = sCursorControllerTempRect;
+ bounds.left = (int) (primaryHorizontal - width / 2.0f);
+ bounds.top = lineBottom;
+
+ bounds.right = bounds.left + width;
+ bounds.bottom = bounds.top + height;
+
+ convertFromViewportToContentCoordinates(bounds);
+
+ final int[] coords = mTempCoords;
+ TextView.this.getLocationInWindow(coords);
+ coords[0] += bounds.left;
+ coords[1] += bounds.top;
+
+ final DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();
+ final int screenHeight = displayMetrics.heightPixels;
+
+ // Vertical clipping
+ if (coords[1] + height > screenHeight) {
+ // Try to position above current line instead
+ // TODO use top layout instead, reverse suggestion order,
+ // try full screen vertical down if it still does not fit. TBD with designers.
+
+ // Update dimensions from new view
+ contentView = mContainer.getContentView();
+ width = contentView.getMeasuredWidth();
+ height = contentView.getMeasuredHeight();
+
+ final int lineTop = mLayout.getLineTop(line);
+ final int lineHeight = lineBottom - lineTop;
+ coords[1] -= height + lineHeight;
+ }
+
+ // Horizontal clipping
+ coords[0] = Math.max(0, coords[0]);
+ coords[0] = Math.min(displayMetrics.widthPixels - width, coords[0]);
+
+ mContainer.showAtLocation(TextView.this, Gravity.NO_GRAVITY, coords[0], coords[1]);
+ }
+ }
+
+ void showSuggestions() {
+ if (mSuggestionsPopupWindow == null) {
+ mSuggestionsPopupWindow = new SuggestionsPopupWindow();
+ }
+ hideControllers();
+ mSuggestionsPopupWindow.show();
+ }
+
+ void hideSuggestions() {
+ if (mSuggestionsPopupWindow != null) {
+ mSuggestionsPopupWindow.hide();
+ }
+ }
+
/**
* If provided, this ActionMode.Callback will be used to create the ActionMode when text
* selection is initiated in this View.
@@ -8429,16 +8641,14 @@
}
}
- private class PastePopupMenu implements OnClickListener {
+ private class PastePopupWindow implements OnClickListener {
private final PopupWindow mContainer;
- private int mPositionX;
- private int mPositionY;
private final View[] mPasteViews = new View[4];
private final int[] mPasteViewLayouts = new int[] {
mTextEditPasteWindowLayout, mTextEditNoPasteWindowLayout,
mTextEditSidePasteWindowLayout, mTextEditSideNoPasteWindowLayout };
- public PastePopupMenu() {
+ public PastePopupWindow() {
mContainer = new PopupWindow(TextView.this.mContext, null,
com.android.internal.R.attr.textSelectHandleWindowStyle);
mContainer.setSplitTouchEnabled(true);
@@ -8521,14 +8731,10 @@
convertFromViewportToContentCoordinates(bounds);
- mPositionX = bounds.left;
- mPositionY = bounds.top;
-
-
final int[] coords = mTempCoords;
TextView.this.getLocationInWindow(coords);
- coords[0] += mPositionX;
- coords[1] += mPositionY;
+ coords[0] += bounds.left;
+ coords[1] += bounds.top;
final int screenWidth = mContext.getResources().getDisplayMetrics().widthPixels;
if (coords[1] < 0) {
@@ -8873,7 +9079,7 @@
void hideAssociatedPopupWindow() {
// No associated popup window by default
}
-
+
public void onDetached() {
// Should be overriden to clean possible Runnable
}
@@ -8883,10 +9089,10 @@
private static final int DELAY_BEFORE_FADE_OUT = 4000;
private static final int RECENT_CUT_COPY_DURATION = 15 * 1000; // seconds
- // Used to detect taps on the insertion handle, which will affect the PastePopupMenu
+ // Used to detect taps on the insertion handle, which will affect the PastePopupWindow
private long mTouchTimer;
private float mDownPositionX, mDownPositionY;
- private PastePopupMenu mPastePopupWindow;
+ private PastePopupWindow mPastePopupWindow;
private Runnable mHider;
private Runnable mPastePopupShower;
@@ -9026,7 +9232,7 @@
void showAssociatedPopupWindow() {
if (mPastePopupWindow == null) {
// Lazy initialisation: create when actually shown only.
- mPastePopupWindow = new PastePopupMenu();
+ mPastePopupWindow = new PastePopupWindow();
}
mPastePopupWindow.show();
}
@@ -9237,6 +9443,7 @@
mEndHandle.show();
hideInsertionPointCursorController();
+ hideSuggestions();
}
public void hide() {
@@ -9264,7 +9471,7 @@
final int deltaY = y - mPreviousTapPositionY;
final int distanceSquared = deltaX * deltaX + deltaY * deltaY;
if (distanceSquared < mSquaredTouchSlopDistance) {
- startSelectionActionMode();
+ showSuggestions();
mDiscardNextActionUp = true;
}
}
@@ -9354,6 +9561,7 @@
private void hideControllers() {
hideInsertionPointCursorController();
stopSelectionActionMode();
+ hideSuggestions();
}
/**
diff --git a/core/res/res/drawable-mdpi/text_edit_suggestions_bottom_window.9.png b/core/res/res/drawable-mdpi/text_edit_suggestions_bottom_window.9.png
new file mode 100644
index 0000000..88be6e1
--- /dev/null
+++ b/core/res/res/drawable-mdpi/text_edit_suggestions_bottom_window.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/text_edit_suggestions_top_window.9.png b/core/res/res/drawable-mdpi/text_edit_suggestions_top_window.9.png
new file mode 100644
index 0000000..41886eb
--- /dev/null
+++ b/core/res/res/drawable-mdpi/text_edit_suggestions_top_window.9.png
Binary files differ
diff --git a/core/res/res/layout/text_edit_suggestion_item.xml b/core/res/res/layout/text_edit_suggestion_item.xml
new file mode 100644
index 0000000..a54cad2
--- /dev/null
+++ b/core/res/res/layout/text_edit_suggestion_item.xml
@@ -0,0 +1,27 @@
+<?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.
+-->
+
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingLeft="16dip"
+ android:paddingRight="16dip"
+ android:paddingTop="8dip"
+ android:paddingBottom="8dip"
+ android:layout_gravity="center"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="@android:color/black" />
+
diff --git a/core/res/res/layout/text_edit_suggestions_bottom_window.xml b/core/res/res/layout/text_edit_suggestions_bottom_window.xml
new file mode 100644
index 0000000..588bfbd
--- /dev/null
+++ b/core/res/res/layout/text_edit_suggestions_bottom_window.xml
@@ -0,0 +1,23 @@
+<?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:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:background="@android:drawable/text_edit_suggestions_bottom_window">
+
+</LinearLayout>
diff --git a/core/res/res/layout/text_edit_suggestions_top_window.xml b/core/res/res/layout/text_edit_suggestions_top_window.xml
new file mode 100644
index 0000000..67faa37
--- /dev/null
+++ b/core/res/res/layout/text_edit_suggestions_top_window.xml
@@ -0,0 +1,23 @@
+<?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:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:background="@android:drawable/text_edit_suggestions_top_window">
+
+</LinearLayout>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index b7849bb..819ce58 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -525,6 +525,9 @@
<!-- Reference to a style that will be used for the window containing a text
selection anchor. -->
<attr name="textSelectHandleWindowStyle" format="reference" />
+ <!-- Reference to a style that will be used for the window containing a list of possible
+ text suggestions in an EditText. -->
+ <attr name="textSuggestionsWindowStyle" format="reference" />
<!-- Default ListPopupWindow style. -->
<attr name="listPopupWindowStyle" format="reference" />
<!-- Default PopupMenu style. -->
@@ -675,6 +678,15 @@
<!-- Variation of textEditSidePasteWindowLayout displayed when the clipboard is empty. -->
<attr name="textEditSideNoPasteWindowLayout" format="reference" />
+ <!-- Layout of a the view that is used to create the text suggestions popup window in an
+ EditText. This window will be displayed below the text line. -->
+ <attr name="textEditSuggestionsBottomWindowLayout" format="reference" />
+ <!-- Same as textEditSuggestionsBottomWindowLayout, but used when the popup is displayed
+ above the current line of text instead of below. -->
+ <attr name="textEditSuggestionsTopWindowLayout" format="reference" />
+ <!-- Layout of the TextView item that will populate the suggestion popup window. -->
+ <attr name="textEditSuggestionItemLayout" format="reference" />
+
<!-- Theme to use for dialogs spawned from this theme. -->
<attr name="dialogTheme" format="reference" />
<!-- Window decor layout to use in dialog mode with icons -->
@@ -2819,6 +2831,16 @@
<!-- Variation of textEditSidePasteWindowLayout displayed when the clipboard is empty. -->
<attr name="textEditSideNoPasteWindowLayout" />
+ <!-- Layout of a the view that is used to create the text suggestions popup window in an
+ EditText. This window will be displayed below the text line. -->
+ <attr name="textEditSuggestionsBottomWindowLayout" />
+ <!-- Same as textEditSuggestionsBottomWindowLayout, but used when the popup is displayed
+ above the current line of text instead of below. -->
+ <attr name="textEditSuggestionsTopWindowLayout" />
+ <!-- Layout of the TextView item that will populate the suggestion popup window. -->
+ <attr name="textEditSuggestionItemLayout" />
+
+
<!-- Reference to a drawable that will be drawn under the insertion cursor. -->
<attr name="textCursorDrawable" />
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 4109ae1..d5c374d 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1659,4 +1659,9 @@
<public type="style" name="Theme.Holo.Light.NoActionBar" />
+ <public type="attr" name="textSuggestionsWindowStyle" />
+ <public type="attr" name="textEditSuggestionsBottomWindowLayout" />
+ <public type="attr" name="textEditSuggestionsTopWindowLayout" />
+ <public type="attr" name="textEditSuggestionItemLayout" />
+
</resources>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index f6a3979..bf4c6d7 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -426,6 +426,9 @@
<item name="android:textEditNoPasteWindowLayout">?android:attr/textEditNoPasteWindowLayout</item>
<item name="android:textEditSidePasteWindowLayout">?android:attr/textEditSidePasteWindowLayout</item>
<item name="android:textEditSideNoPasteWindowLayout">?android:attr/textEditSideNoPasteWindowLayout</item>
+ <item name="android:textEditSuggestionsBottomWindowLayout">?android:attr/textEditSuggestionsBottomWindowLayout</item>
+ <item name="android:textEditSuggestionsTopWindowLayout">?android:attr/textEditSuggestionsTopWindowLayout</item>
+ <item name="android:textEditSuggestionItemLayout">?android:attr/textEditSuggestionItemLayout</item>
<item name="android:textCursorDrawable">?android:attr/textCursorDrawable</item>
</style>
@@ -1047,6 +1050,17 @@
<item name="windowExitAnimation">@android:anim/fade_out</item>
</style>
+ <!-- Style for the popup window that contains text suggestions. -->
+ <style name="Widget.TextSuggestions">
+ <item name="android:popupAnimationStyle">@android:style/Animation.TextSuggestions</item>
+ </style>
+
+ <!-- Animation effects when showing/hiding the text suggestions popup window. -->
+ <style name="Animation.TextSuggestions">
+ <item name="windowEnterAnimation">@android:anim/fade_in</item>
+ <item name="windowExitAnimation">@android:anim/fade_out</item>
+ </style>
+
<style name="Widget.ActionBar">
<item name="android:background">@android:drawable/action_bar_background</item>
<item name="android:displayOptions">useLogo|showHome|showTitle</item>
@@ -1465,6 +1479,9 @@
<style name="Widget.Holo.TextSelectHandle" parent="Widget.TextSelectHandle">
</style>
+ <style name="Widget.Holo.TextSuggestions" parent="Widget.TextSuggestions">
+ </style>
+
<style name="Widget.Holo.AbsListView" parent="Widget.AbsListView">
</style>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index fdeb229..b1e4f0f 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -180,6 +180,10 @@
<item name="textEditNoPasteWindowLayout">@android:layout/text_edit_no_paste_window</item>
<item name="textEditSidePasteWindowLayout">@android:layout/text_edit_side_paste_window</item>
<item name="textEditSideNoPasteWindowLayout">@android:layout/text_edit_side_no_paste_window</item>
+ <item name="textSuggestionsWindowStyle">@android:style/Widget.TextSuggestions</item>
+ <item name="textEditSuggestionsBottomWindowLayout">@android:layout/text_edit_suggestions_bottom_window</item>
+ <item name="textEditSuggestionsTopWindowLayout">@android:layout/text_edit_suggestions_top_window</item>
+ <item name="textEditSuggestionItemLayout">@android:layout/text_edit_suggestion_item</item>
<item name="textCursorDrawable">@null</item>
<!-- Widget styles -->
@@ -917,6 +921,7 @@
<item name="textSelectHandleRight">@android:drawable/text_select_handle_right</item>
<item name="textSelectHandle">@android:drawable/text_select_handle_middle</item>
<item name="textSelectHandleWindowStyle">@android:style/Widget.Holo.TextSelectHandle</item>
+ <item name="textSuggestionsWindowStyle">@android:style/Widget.Holo.TextSuggestions</item>
<item name="textCursorDrawable">@android:drawable/text_cursor_holo_dark</item>
<!-- Widget styles -->
@@ -1201,6 +1206,7 @@
<item name="textSelectHandleRight">@android:drawable/text_select_handle_right</item>
<item name="textSelectHandle">@android:drawable/text_select_handle_middle</item>
<item name="textSelectHandleWindowStyle">@android:style/Widget.Holo.TextSelectHandle</item>
+ <item name="textSuggestionsWindowStyle">@android:style/Widget.Holo.TextSuggestions</item>
<item name="textCursorDrawable">@android:drawable/text_cursor_holo_light</item>
<!-- Widget styles -->
diff --git a/core/tests/coretests/src/android/net/LinkPropertiesTest.java b/core/tests/coretests/src/android/net/LinkPropertiesTest.java
new file mode 100644
index 0000000..50666b4
--- /dev/null
+++ b/core/tests/coretests/src/android/net/LinkPropertiesTest.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2010 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 android.net;
+
+import android.net.LinkProperties;
+import android.test.suitebuilder.annotation.SmallTest;
+import junit.framework.TestCase;
+
+import java.net.InetAddress;
+
+public class LinkPropertiesTest extends TestCase {
+ private static String ADDRV4 = "75.208.6.1";
+ private static String ADDRV6 = "2001:0db8:85a3:0000:0000:8a2e:0370:7334";
+ private static String DNS1 = "75.208.7.1";
+ private static String DNS2 = "69.78.7.1";
+ private static String GATEWAY1 = "75.208.8.1";
+ private static String GATEWAY2 = "69.78.8.1";
+ private static String NAME = "qmi0";
+
+ @SmallTest
+ public void testEqualsNull() {
+ LinkProperties source = new LinkProperties();
+ LinkProperties target = new LinkProperties();
+
+ assertFalse(source == target);
+ assertTrue(source.equals(target));
+ assertTrue(source.hashCode() == target.hashCode());
+ }
+
+ @SmallTest
+ public void testEqualsSameOrder() {
+ try {
+ LinkProperties source = new LinkProperties();
+ source.setInterfaceName(NAME);
+ // set 2 link addresses
+ source.addLinkAddress(new LinkAddress(
+ NetworkUtils.numericToInetAddress(ADDRV4), 32));
+ source.addLinkAddress(new LinkAddress(
+ NetworkUtils.numericToInetAddress(ADDRV6), 128));
+ // set 2 dnses
+ source.addDns(NetworkUtils.numericToInetAddress(DNS1));
+ source.addDns(NetworkUtils.numericToInetAddress(DNS2));
+ // set 2 gateways
+ source.addGateway(NetworkUtils.numericToInetAddress(GATEWAY1));
+ source.addGateway(NetworkUtils.numericToInetAddress(GATEWAY2));
+
+ LinkProperties target = new LinkProperties();
+
+ // All fields are same
+ target.setInterfaceName(NAME);
+ target.addLinkAddress(new LinkAddress(
+ NetworkUtils.numericToInetAddress(ADDRV4), 32));
+ target.addLinkAddress(new LinkAddress(
+ NetworkUtils.numericToInetAddress(ADDRV6), 128));
+ target.addDns(NetworkUtils.numericToInetAddress(DNS1));
+ target.addDns(NetworkUtils.numericToInetAddress(DNS2));
+ target.addGateway(NetworkUtils.numericToInetAddress(GATEWAY1));
+ target.addGateway(NetworkUtils.numericToInetAddress(GATEWAY2));
+
+ assertTrue(source.equals(target));
+ assertTrue(source.hashCode() == target.hashCode());
+
+ target.clear();
+ // change Interface Name
+ target.setInterfaceName("qmi1");
+ target.addLinkAddress(new LinkAddress(
+ NetworkUtils.numericToInetAddress(ADDRV4), 32));
+ target.addLinkAddress(new LinkAddress(
+ NetworkUtils.numericToInetAddress(ADDRV6), 128));
+ target.addDns(NetworkUtils.numericToInetAddress(DNS1));
+ target.addDns(NetworkUtils.numericToInetAddress(DNS2));
+ target.addGateway(NetworkUtils.numericToInetAddress(GATEWAY1));
+ target.addGateway(NetworkUtils.numericToInetAddress(GATEWAY2));
+ assertFalse(source.equals(target));
+
+ target.clear();
+ target.setInterfaceName(NAME);
+ // change link addresses
+ target.addLinkAddress(new LinkAddress(
+ NetworkUtils.numericToInetAddress("75.208.6.2"), 32));
+ target.addLinkAddress(new LinkAddress(
+ NetworkUtils.numericToInetAddress(ADDRV6), 128));
+ target.addDns(NetworkUtils.numericToInetAddress(DNS1));
+ target.addDns(NetworkUtils.numericToInetAddress(DNS2));
+ target.addGateway(NetworkUtils.numericToInetAddress(GATEWAY1));
+ target.addGateway(NetworkUtils.numericToInetAddress(GATEWAY2));
+ assertFalse(source.equals(target));
+
+ target.clear();
+ target.setInterfaceName(NAME);
+ target.addLinkAddress(new LinkAddress(
+ NetworkUtils.numericToInetAddress(ADDRV4), 32));
+ target.addLinkAddress(new LinkAddress(
+ NetworkUtils.numericToInetAddress(ADDRV6), 128));
+ // change dnses
+ target.addDns(NetworkUtils.numericToInetAddress("75.208.7.2"));
+ target.addDns(NetworkUtils.numericToInetAddress(DNS2));
+ target.addGateway(NetworkUtils.numericToInetAddress(GATEWAY1));
+ target.addGateway(NetworkUtils.numericToInetAddress(GATEWAY2));
+ assertFalse(source.equals(target));
+
+ target.clear();
+ target.setInterfaceName(NAME);
+ target.addLinkAddress(new LinkAddress(
+ NetworkUtils.numericToInetAddress(ADDRV4), 32));
+ target.addLinkAddress(new LinkAddress(
+ NetworkUtils.numericToInetAddress(ADDRV6), 128));
+ target.addDns(NetworkUtils.numericToInetAddress(DNS1));
+ target.addDns(NetworkUtils.numericToInetAddress(DNS2));
+ // change gateway
+ target.addGateway(NetworkUtils.numericToInetAddress("75.208.8.2"));
+ target.addGateway(NetworkUtils.numericToInetAddress(GATEWAY2));
+ assertFalse(source.equals(target));
+
+ } catch (Exception e) {
+ throw new RuntimeException(e.toString());
+ //fail();
+ }
+ }
+
+ @SmallTest
+ public void testEqualsDifferentOrder() {
+ try {
+ LinkProperties source = new LinkProperties();
+ source.setInterfaceName(NAME);
+ // set 2 link addresses
+ source.addLinkAddress(new LinkAddress(
+ NetworkUtils.numericToInetAddress(ADDRV4), 32));
+ source.addLinkAddress(new LinkAddress(
+ NetworkUtils.numericToInetAddress(ADDRV6), 128));
+ // set 2 dnses
+ source.addDns(NetworkUtils.numericToInetAddress(DNS1));
+ source.addDns(NetworkUtils.numericToInetAddress(DNS2));
+ // set 2 gateways
+ source.addGateway(NetworkUtils.numericToInetAddress(GATEWAY1));
+ source.addGateway(NetworkUtils.numericToInetAddress(GATEWAY2));
+
+ LinkProperties target = new LinkProperties();
+ // Exchange order
+ target.setInterfaceName(NAME);
+ target.addLinkAddress(new LinkAddress(
+ NetworkUtils.numericToInetAddress(ADDRV6), 128));
+ target.addLinkAddress(new LinkAddress(
+ NetworkUtils.numericToInetAddress(ADDRV4), 32));
+ target.addDns(NetworkUtils.numericToInetAddress(DNS2));
+ target.addDns(NetworkUtils.numericToInetAddress(DNS1));
+ target.addGateway(NetworkUtils.numericToInetAddress(GATEWAY2));
+ target.addGateway(NetworkUtils.numericToInetAddress(GATEWAY1));
+
+ assertTrue(source.equals(target));
+ assertTrue(source.hashCode() == target.hashCode());
+ } catch (Exception e) {
+ fail();
+ }
+ }
+
+ @SmallTest
+ public void testEqualsDuplicated() {
+ try {
+ LinkProperties source = new LinkProperties();
+ // set 3 link addresses, eg, [A, A, B]
+ source.addLinkAddress(new LinkAddress(
+ NetworkUtils.numericToInetAddress(ADDRV4), 32));
+ source.addLinkAddress(new LinkAddress(
+ NetworkUtils.numericToInetAddress(ADDRV4), 32));
+ source.addLinkAddress(new LinkAddress(
+ NetworkUtils.numericToInetAddress(ADDRV6), 128));
+
+ LinkProperties target = new LinkProperties();
+ // set 3 link addresses, eg, [A, B, B]
+ target.addLinkAddress(new LinkAddress(
+ NetworkUtils.numericToInetAddress(ADDRV4), 32));
+ target.addLinkAddress(new LinkAddress(
+ NetworkUtils.numericToInetAddress(ADDRV6), 128));
+ target.addLinkAddress(new LinkAddress(
+ NetworkUtils.numericToInetAddress(ADDRV6), 128));
+
+ assertTrue(source.equals(target));
+ assertTrue(source.hashCode() == target.hashCode());
+ } catch (Exception e) {
+ fail();
+ }
+ }
+
+}
diff --git a/data/keyboards/Generic.kcm b/data/keyboards/Generic.kcm
index ef0a4e6..b5f6897 100644
--- a/data/keyboards/Generic.kcm
+++ b/data/keyboards/Generic.kcm
@@ -300,8 +300,7 @@
key TAB {
label: '\t'
base: '\t'
- ctrl: none
- alt, meta: fallback APP_SWITCH
+ ctrl, alt, meta: none
}
key COMMA {
diff --git a/docs/html/guide/appendix/media-formats.jd b/docs/html/guide/appendix/media-formats.jd
index 7f77b5f..e128a1c 100644
--- a/docs/html/guide/appendix/media-formats.jd
+++ b/docs/html/guide/appendix/media-formats.jd
@@ -50,6 +50,8 @@
<p class="note"><strong>Note:</strong> Media codecs that are not guaranteed to be available on all Android platform versions are accordingly noted in parentheses—for example "(Android 3.0+)".</p>
+<p class="table-caption" id="formats-table"><strong>Table 1.</strong> Core media format and codec support.</p>
+
<table>
<tbody>
@@ -218,81 +220,61 @@
<h2 id="recommendations">Video Encoding Recommendations</h2>
-<p>Below are examples of video encoding profiles and parameters that the Android media framework supports for playback.</p>
+<p>Table 2, below, lists examples of video encoding profiles and parameters that the Android media framework supports for playback. In addition to these encoding parameter recommendations, a device's available video recording profiles can be used as a proxy for media playback capabilities. These profiles can be inspected using the {@link android.media.CamcorderProfile CamcorderProfile} class, which is available since API level 8.</p>
+
+<p class="table-caption" id="encoding-recommendations-table"><strong>Table 2.</strong> Examples of supported video encoding parameters.</p>
+
+<table>
+ <thead>
+ <tr>
+ <th> </th>
+ <th style="background-color:#f3f3f3;font-weight:normal">Lower quality</th>
+ <th style="background-color:#f3f3f3;font-weight:normal">Higher quality</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <th>Video codec</th>
+ <td>H.264 Baseline Profile</th>
+ <td>H.264 Baseline Profile</th>
+ </tr>
+ <tr>
+ <th>Video resolution</th>
+ <td>176 x 144 px</th>
+ <td>480 x 360 px</th>
+ </tr>
+ <tr>
+ <th>Video frame rate</th>
+ <td>12 fps</th>
+ <td>30 fps</th>
+ </tr>
+ <tr>
+ <th>Video bitrate</th>
+ <td>56 Kbps</th>
+ <td>500 Kbps</th>
+ </tr>
+ <tr>
+ <th>Audio codec</th>
+ <td>AAC-LC</th>
+ <td>AAC-LC</th>
+ </tr>
+ <tr>
+ <th>Audio channels</th>
+ <td>1 (mono)</th>
+ <td>2 (stereo)</th>
+ </tr>
+ <tr>
+ <th>Audio bitrate</th>
+ <td>24 Kbps</th>
+ <td>128 Kbps</th>
+ </tr>
+ </tbody>
+</table>
+
+<p style="margin-top: 2em">For video content that is streamed over HTTP or RTSP, there are additional requirements:</p>
<ul>
- <li><strong>Lower quality video</strong><br>
-
- <table style="margin-top: 4px">
- <tbody>
- <tr>
- <th>Video codec</th>
- <td>H.264 Baseline Profile</th>
- </tr>
- <tr>
- <th>Video resolution</th>
- <td>176 x 144 px</th>
- </tr>
- <tr>
- <th>Video frame rate</th>
- <td>12 fps</th>
- </tr>
- <tr>
- <th>Video bitrate</th>
- <td>56 Kbps</th>
- </tr>
- <tr>
- <th>Audio codec</th>
- <td>AAC-LC</th>
- </tr>
- <tr>
- <th>Audio channels</th>
- <td>1 (mono)</th>
- </tr>
- <tr>
- <th>Audio bitrate</th>
- <td>24 Kbps</th>
- </tr>
- </tbody>
- </table>
- </li>
-
- <li><strong>Higher quality video</strong><br>
-
- <table style="margin-top: 4px">
- <tbody>
- <tr>
- <th>Video codec</th>
- <td>H.264 Baseline Profile</th>
- </tr>
- <tr>
- <th>Video resolution</th>
- <td>480 x 360 px</th>
- </tr>
- <tr>
- <th>Video frame rate</th>
- <td>30 fps</th>
- </tr>
- <tr>
- <th>Video bitrate</th>
- <td>500 Kbps</th>
- </tr>
- <tr>
- <th>Audio codec</th>
- <td>AAC-LC</th>
- </tr>
- <tr>
- <th>Audio channels</th>
- <td>2 (stereo)</th>
- </tr>
- <tr>
- <th>Audio bitrate</th>
- <td>128 Kbps</th>
- </tr>
- </tbody>
- </table>
-
- </li>
+ <li>For 3GPP and MPEG-4 containers, the <code>moov</code> atom must precede any <code>mdat</code> atoms.</li>
+ <li>For 3GPP, MPEG-4, and WebM containers, audio and video samples corresponding to the same time offset may be no more than 500 KB apart.
+ To minimize this audio/video drift, consider interleaving audio and video in smaller chunk sizes.</li>
</ul>
-
-<p>In addition to the encoding parameters above, a device's available video recording profiles can be used as a proxy for media playback capabilities. These profiles can be inspected using the {@link android.media.CamcorderProfile CamcorderProfile} class, which is available since API level 8.</p>
diff --git a/libs/rs/Android.mk b/libs/rs/Android.mk
index 3362c7d..ea7f477 100644
--- a/libs/rs/Android.mk
+++ b/libs/rs/Android.mk
@@ -117,6 +117,7 @@
rsVertexArray.cpp \
driver/rsdBcc.cpp \
driver/rsdCore.cpp \
+ driver/rsdGL.cpp \
driver/rsdProgramRaster.cpp \
driver/rsdProgramStore.cpp
diff --git a/libs/rs/driver/rsdCore.cpp b/libs/rs/driver/rsdCore.cpp
index 00d62ba..75f4d6b 100644
--- a/libs/rs/driver/rsdCore.cpp
+++ b/libs/rs/driver/rsdCore.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 The Android Open Source Project
+ * 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.
@@ -16,6 +16,7 @@
#include "rsdCore.h"
#include "rsdBcc.h"
+#include "rsdGL.h"
#include "rsdProgramStore.h"
#include "rsdProgramRaster.h"
@@ -37,6 +38,11 @@
static void SetPriority(const Context *rsc, int32_t priority);
static RsdHalFunctions FunctionTable = {
+ rsdGLInit,
+ rsdGLShutdown,
+ rsdGLSetSurface,
+ rsdGLSwap,
+
Shutdown,
NULL,
SetPriority,
diff --git a/libs/rs/driver/rsdCore.h b/libs/rs/driver/rsdCore.h
index 02b2fbc..e37698b 100644
--- a/libs/rs/driver/rsdCore.h
+++ b/libs/rs/driver/rsdCore.h
@@ -23,6 +23,7 @@
#include "rsMutex.h"
#include "rsSignal.h"
+#include "rsdGL.h"
typedef void (* InvokeFunc_t)(void);
typedef void (*WorkerCallback_t)(void *usr, uint32_t idx);
@@ -45,6 +46,8 @@
};
Workers mWorkers;
bool mExit;
+
+ RsdGL gl;
} RsHal;
diff --git a/libs/rs/driver/rsdGL.cpp b/libs/rs/driver/rsdGL.cpp
new file mode 100644
index 0000000..86dfa0f
--- /dev/null
+++ b/libs/rs/driver/rsdGL.cpp
@@ -0,0 +1,333 @@
+/*
+ * 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.
+ */
+
+#include <ui/FramebufferNativeWindow.h>
+#include <ui/PixelFormat.h>
+#include <ui/EGLUtils.h>
+#include <ui/egl/android_natives.h>
+
+#include <sys/types.h>
+#include <sys/resource.h>
+#include <sched.h>
+
+#include <cutils/properties.h>
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+//#include <cutils/sched_policy.h>
+//#include <sys/syscall.h>
+#include <string.h>
+
+
+#include "rsdCore.h"
+#include "rsdGL.h"
+
+#include <malloc.h>
+#include "rsContext.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+static int32_t gGLContextCount = 0;
+
+static void checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE) {
+ if (returnVal != EGL_TRUE) {
+ fprintf(stderr, "%s() returned %d\n", op, returnVal);
+ }
+
+ for (EGLint error = eglGetError(); error != EGL_SUCCESS; error
+ = eglGetError()) {
+ fprintf(stderr, "after %s() eglError %s (0x%x)\n", op, EGLUtils::strerror(error),
+ error);
+ }
+}
+
+static void printEGLConfiguration(EGLDisplay dpy, EGLConfig config) {
+
+#define X(VAL) {VAL, #VAL}
+ struct {EGLint attribute; const char* name;} names[] = {
+ X(EGL_BUFFER_SIZE),
+ X(EGL_ALPHA_SIZE),
+ X(EGL_BLUE_SIZE),
+ X(EGL_GREEN_SIZE),
+ X(EGL_RED_SIZE),
+ X(EGL_DEPTH_SIZE),
+ X(EGL_STENCIL_SIZE),
+ X(EGL_CONFIG_CAVEAT),
+ X(EGL_CONFIG_ID),
+ X(EGL_LEVEL),
+ X(EGL_MAX_PBUFFER_HEIGHT),
+ X(EGL_MAX_PBUFFER_PIXELS),
+ X(EGL_MAX_PBUFFER_WIDTH),
+ X(EGL_NATIVE_RENDERABLE),
+ X(EGL_NATIVE_VISUAL_ID),
+ X(EGL_NATIVE_VISUAL_TYPE),
+ X(EGL_SAMPLES),
+ X(EGL_SAMPLE_BUFFERS),
+ X(EGL_SURFACE_TYPE),
+ X(EGL_TRANSPARENT_TYPE),
+ X(EGL_TRANSPARENT_RED_VALUE),
+ X(EGL_TRANSPARENT_GREEN_VALUE),
+ X(EGL_TRANSPARENT_BLUE_VALUE),
+ X(EGL_BIND_TO_TEXTURE_RGB),
+ X(EGL_BIND_TO_TEXTURE_RGBA),
+ X(EGL_MIN_SWAP_INTERVAL),
+ X(EGL_MAX_SWAP_INTERVAL),
+ X(EGL_LUMINANCE_SIZE),
+ X(EGL_ALPHA_MASK_SIZE),
+ X(EGL_COLOR_BUFFER_TYPE),
+ X(EGL_RENDERABLE_TYPE),
+ X(EGL_CONFORMANT),
+ };
+#undef X
+
+ for (size_t j = 0; j < sizeof(names) / sizeof(names[0]); j++) {
+ EGLint value = -1;
+ EGLint returnVal = eglGetConfigAttrib(dpy, config, names[j].attribute, &value);
+ EGLint error = eglGetError();
+ if (returnVal && error == EGL_SUCCESS) {
+ LOGV(" %s: %d (0x%x)", names[j].name, value, value);
+ }
+ }
+}
+
+static void DumpDebug(RsHal *dc) {
+ LOGE(" EGL ver %i %i", dc->gl.egl.majorVersion, dc->gl.egl.minorVersion);
+ LOGE(" EGL context %p surface %p, Display=%p", dc->gl.egl.context, dc->gl.egl.surface,
+ dc->gl.egl.display);
+ LOGE(" GL vendor: %s", dc->gl.gl.vendor);
+ LOGE(" GL renderer: %s", dc->gl.gl.renderer);
+ LOGE(" GL Version: %s", dc->gl.gl.version);
+ LOGE(" GL Extensions: %s", dc->gl.gl.extensions);
+ LOGE(" GL int Versions %i %i", dc->gl.gl.majorVersion, dc->gl.gl.minorVersion);
+
+ LOGV("MAX Textures %i, %i %i", dc->gl.gl.maxVertexTextureUnits,
+ dc->gl.gl.maxFragmentTextureImageUnits, dc->gl.gl.maxTextureImageUnits);
+ LOGV("MAX Attribs %i", dc->gl.gl.maxVertexAttribs);
+ LOGV("MAX Uniforms %i, %i", dc->gl.gl.maxVertexUniformVectors,
+ dc->gl.gl.maxFragmentUniformVectors);
+ LOGV("MAX Varyings %i", dc->gl.gl.maxVaryingVectors);
+}
+
+void rsdGLShutdown(const Context *rsc) {
+ RsHal *dc = (RsHal *)rsc->mHal.drv;
+
+ LOGV("%p, deinitEGL", rsc);
+
+ if (dc->gl.egl.context != EGL_NO_CONTEXT) {
+ eglMakeCurrent(dc->gl.egl.display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ eglDestroySurface(dc->gl.egl.display, dc->gl.egl.surfaceDefault);
+ if (dc->gl.egl.surface != EGL_NO_SURFACE) {
+ eglDestroySurface(dc->gl.egl.display, dc->gl.egl.surface);
+ }
+ eglDestroyContext(dc->gl.egl.display, dc->gl.egl.context);
+ checkEglError("eglDestroyContext");
+ }
+
+ gGLContextCount--;
+ if (!gGLContextCount) {
+ eglTerminate(dc->gl.egl.display);
+ }
+}
+
+bool rsdGLInit(const Context *rsc) {
+ RsHal *dc = (RsHal *)rsc->mHal.drv;
+
+ dc->gl.egl.numConfigs = -1;
+ EGLint configAttribs[128];
+ EGLint *configAttribsPtr = configAttribs;
+ EGLint context_attribs2[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
+
+ memset(configAttribs, 0, sizeof(configAttribs));
+
+ configAttribsPtr[0] = EGL_SURFACE_TYPE;
+ configAttribsPtr[1] = EGL_WINDOW_BIT;
+ configAttribsPtr += 2;
+
+ configAttribsPtr[0] = EGL_RENDERABLE_TYPE;
+ configAttribsPtr[1] = EGL_OPENGL_ES2_BIT;
+ configAttribsPtr += 2;
+
+ if (rsc->mUserSurfaceConfig.depthMin > 0) {
+ configAttribsPtr[0] = EGL_DEPTH_SIZE;
+ configAttribsPtr[1] = rsc->mUserSurfaceConfig.depthMin;
+ configAttribsPtr += 2;
+ }
+
+ if (rsc->mDev->mForceSW) {
+ configAttribsPtr[0] = EGL_CONFIG_CAVEAT;
+ configAttribsPtr[1] = EGL_SLOW_CONFIG;
+ configAttribsPtr += 2;
+ }
+
+ configAttribsPtr[0] = EGL_NONE;
+ rsAssert(configAttribsPtr < (configAttribs + (sizeof(configAttribs) / sizeof(EGLint))));
+
+ LOGV("%p initEGL start", rsc);
+ dc->gl.egl.display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ checkEglError("eglGetDisplay");
+
+ eglInitialize(dc->gl.egl.display, &dc->gl.egl.majorVersion, &dc->gl.egl.minorVersion);
+ checkEglError("eglInitialize");
+
+ PixelFormat pf = PIXEL_FORMAT_RGBA_8888;
+ if (rsc->mUserSurfaceConfig.alphaMin == 0) {
+ pf = PIXEL_FORMAT_RGBX_8888;
+ }
+
+ status_t err = EGLUtils::selectConfigForPixelFormat(dc->gl.egl.display, configAttribs,
+ pf, &dc->gl.egl.config);
+ if (err) {
+ LOGE("%p, couldn't find an EGLConfig matching the screen format\n", rsc);
+ }
+ //if (props.mLogVisual) {
+ printEGLConfiguration(dc->gl.egl.display, dc->gl.egl.config);
+ //}
+
+ dc->gl.egl.context = eglCreateContext(dc->gl.egl.display, dc->gl.egl.config,
+ EGL_NO_CONTEXT, context_attribs2);
+ checkEglError("eglCreateContext");
+ if (dc->gl.egl.context == EGL_NO_CONTEXT) {
+ LOGE("%p, eglCreateContext returned EGL_NO_CONTEXT", rsc);
+ return false;
+ }
+ gGLContextCount++;
+
+
+ EGLint pbuffer_attribs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE };
+ dc->gl.egl.surfaceDefault = eglCreatePbufferSurface(dc->gl.egl.display, dc->gl.egl.config,
+ pbuffer_attribs);
+ checkEglError("eglCreatePbufferSurface");
+ if (dc->gl.egl.surfaceDefault == EGL_NO_SURFACE) {
+ LOGE("eglCreatePbufferSurface returned EGL_NO_SURFACE");
+ rsdGLShutdown(rsc);
+ return false;
+ }
+
+ EGLBoolean ret = eglMakeCurrent(dc->gl.egl.display, dc->gl.egl.surfaceDefault,
+ dc->gl.egl.surfaceDefault, dc->gl.egl.context);
+ if (ret == EGL_FALSE) {
+ LOGE("eglMakeCurrent returned EGL_FALSE");
+ checkEglError("eglMakeCurrent", ret);
+ rsdGLShutdown(rsc);
+ return false;
+ }
+
+ dc->gl.gl.version = glGetString(GL_VERSION);
+ dc->gl.gl.vendor = glGetString(GL_VENDOR);
+ dc->gl.gl.renderer = glGetString(GL_RENDERER);
+ dc->gl.gl.extensions = glGetString(GL_EXTENSIONS);
+
+ //LOGV("EGL Version %i %i", mEGL.mMajorVersion, mEGL.mMinorVersion);
+ //LOGV("GL Version %s", mGL.mVersion);
+ //LOGV("GL Vendor %s", mGL.mVendor);
+ //LOGV("GL Renderer %s", mGL.mRenderer);
+ //LOGV("GL Extensions %s", mGL.mExtensions);
+
+ const char *verptr = NULL;
+ if (strlen((const char *)dc->gl.gl.version) > 9) {
+ if (!memcmp(dc->gl.gl.version, "OpenGL ES-CM", 12)) {
+ verptr = (const char *)dc->gl.gl.version + 12;
+ }
+ if (!memcmp(dc->gl.gl.version, "OpenGL ES ", 10)) {
+ verptr = (const char *)dc->gl.gl.version + 9;
+ }
+ }
+
+ if (!verptr) {
+ LOGE("Error, OpenGL ES Lite not supported");
+ rsdGLShutdown(rsc);
+ return false;
+ } else {
+ sscanf(verptr, " %i.%i", &dc->gl.gl.majorVersion, &dc->gl.gl.minorVersion);
+ }
+
+ glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &dc->gl.gl.maxVertexAttribs);
+ glGetIntegerv(GL_MAX_VERTEX_UNIFORM_VECTORS, &dc->gl.gl.maxVertexUniformVectors);
+ glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &dc->gl.gl.maxVertexTextureUnits);
+
+ glGetIntegerv(GL_MAX_VARYING_VECTORS, &dc->gl.gl.maxVaryingVectors);
+ glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &dc->gl.gl.maxTextureImageUnits);
+
+ glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &dc->gl.gl.maxFragmentTextureImageUnits);
+ glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_VECTORS, &dc->gl.gl.maxFragmentUniformVectors);
+
+ dc->gl.gl.OES_texture_npot = NULL != strstr((const char *)dc->gl.gl.extensions,
+ "GL_OES_texture_npot");
+ dc->gl.gl.GL_IMG_texture_npot = NULL != strstr((const char *)dc->gl.gl.extensions,
+ "GL_IMG_texture_npot");
+ dc->gl.gl.GL_NV_texture_npot_2D_mipmap = NULL != strstr((const char *)dc->gl.gl.extensions,
+ "GL_NV_texture_npot_2D_mipmap");
+ dc->gl.gl.EXT_texture_max_aniso = 1.0f;
+ bool hasAniso = NULL != strstr((const char *)dc->gl.gl.extensions,
+ "GL_EXT_texture_filter_anisotropic");
+ if (hasAniso) {
+ glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &dc->gl.gl.EXT_texture_max_aniso);
+ }
+
+ DumpDebug(dc);
+
+ LOGV("initGLThread end %p", rsc);
+ return true;
+}
+
+
+bool rsdGLSetSurface(const Context *rsc, uint32_t w, uint32_t h, ANativeWindow *sur) {
+ RsHal *dc = (RsHal *)rsc->mHal.drv;
+
+ EGLBoolean ret;
+ // WAR: Some drivers fail to handle 0 size surfaces correcntly.
+ // Use the pbuffer to avoid this pitfall.
+ if ((dc->gl.egl.surface != NULL) || (w == 0) || (h == 0)) {
+ ret = eglMakeCurrent(dc->gl.egl.display, dc->gl.egl.surfaceDefault,
+ dc->gl.egl.surfaceDefault, dc->gl.egl.context);
+ checkEglError("eglMakeCurrent", ret);
+
+ ret = eglDestroySurface(dc->gl.egl.display, dc->gl.egl.surface);
+ checkEglError("eglDestroySurface", ret);
+
+ dc->gl.egl.surface = NULL;
+ dc->gl.width = 1;
+ dc->gl.height = 1;
+ }
+
+ dc->gl.wndSurface = sur;
+ if (dc->gl.wndSurface != NULL) {
+ dc->gl.width = w;
+ dc->gl.height = h;
+
+ dc->gl.egl.surface = eglCreateWindowSurface(dc->gl.egl.display, dc->gl.egl.config,
+ dc->gl.wndSurface, NULL);
+ checkEglError("eglCreateWindowSurface");
+ if (dc->gl.egl.surface == EGL_NO_SURFACE) {
+ LOGE("eglCreateWindowSurface returned EGL_NO_SURFACE");
+ }
+
+ ret = eglMakeCurrent(dc->gl.egl.display, dc->gl.egl.surface,
+ dc->gl.egl.surface, dc->gl.egl.context);
+ checkEglError("eglMakeCurrent", ret);
+ }
+ return true;
+}
+
+void rsdGLSwap(const android::renderscript::Context *rsc) {
+ RsHal *dc = (RsHal *)rsc->mHal.drv;
+ eglSwapBuffers(dc->gl.egl.display, dc->gl.egl.surface);
+}
+
diff --git a/libs/rs/driver/rsdGL.h b/libs/rs/driver/rsdGL.h
new file mode 100644
index 0000000..246931f
--- /dev/null
+++ b/libs/rs/driver/rsdGL.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef RSD_GL_H
+#define RSD_GL_H
+
+#include <rs_hal.h>
+
+
+
+typedef void (* InvokeFunc_t)(void);
+typedef void (*WorkerCallback_t)(void *usr, uint32_t idx);
+
+typedef struct RsdGLRec {
+ struct {
+ EGLint numConfigs;
+ EGLint majorVersion;
+ EGLint minorVersion;
+ EGLConfig config;
+ EGLContext context;
+ EGLSurface surface;
+ EGLSurface surfaceDefault;
+ EGLDisplay display;
+ } egl;
+
+ struct {
+ const uint8_t * vendor;
+ const uint8_t * renderer;
+ const uint8_t * version;
+ const uint8_t * extensions;
+
+ uint32_t majorVersion;
+ uint32_t minorVersion;
+
+ int32_t maxVaryingVectors;
+ int32_t maxTextureImageUnits;
+
+ int32_t maxFragmentTextureImageUnits;
+ int32_t maxFragmentUniformVectors;
+
+ int32_t maxVertexAttribs;
+ int32_t maxVertexUniformVectors;
+ int32_t maxVertexTextureUnits;
+
+ bool OES_texture_npot;
+ bool GL_IMG_texture_npot;
+ bool GL_NV_texture_npot_2D_mipmap;
+ float EXT_texture_max_aniso;
+ } gl;
+
+ ANativeWindow *wndSurface;
+ uint32_t width;
+ uint32_t height;
+} RsdGL;
+
+
+
+bool rsdGLInit(const android::renderscript::Context *rsc);
+void rsdGLShutdown(const android::renderscript::Context *rsc);
+bool rsdGLSetSurface(const android::renderscript::Context *rsc,
+ uint32_t w, uint32_t h, ANativeWindow *sur);
+void rsdGLSwap(const android::renderscript::Context *rsc);
+
+#endif
+
diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp
index c9a7060..0f61789 100644
--- a/libs/rs/rsContext.cpp
+++ b/libs/rs/rsContext.cpp
@@ -19,7 +19,6 @@
#include "rsThreadIO.h"
#include <ui/FramebufferNativeWindow.h>
#include <ui/PixelFormat.h>
-#include <ui/EGLUtils.h>
#include <ui/egl/android_natives.h>
#include <sys/types.h>
@@ -42,188 +41,22 @@
pthread_key_t Context::gThreadTLSKey = 0;
uint32_t Context::gThreadTLSKeyCount = 0;
-uint32_t Context::gGLContextCount = 0;
pthread_mutex_t Context::gInitMutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t Context::gLibMutex = PTHREAD_MUTEX_INITIALIZER;
-static void checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE) {
- if (returnVal != EGL_TRUE) {
- fprintf(stderr, "%s() returned %d\n", op, returnVal);
- }
-
- for (EGLint error = eglGetError(); error != EGL_SUCCESS; error
- = eglGetError()) {
- fprintf(stderr, "after %s() eglError %s (0x%x)\n", op, EGLUtils::strerror(error),
- error);
- }
-}
-
-void printEGLConfiguration(EGLDisplay dpy, EGLConfig config) {
-
-#define X(VAL) {VAL, #VAL}
- struct {EGLint attribute; const char* name;} names[] = {
- X(EGL_BUFFER_SIZE),
- X(EGL_ALPHA_SIZE),
- X(EGL_BLUE_SIZE),
- X(EGL_GREEN_SIZE),
- X(EGL_RED_SIZE),
- X(EGL_DEPTH_SIZE),
- X(EGL_STENCIL_SIZE),
- X(EGL_CONFIG_CAVEAT),
- X(EGL_CONFIG_ID),
- X(EGL_LEVEL),
- X(EGL_MAX_PBUFFER_HEIGHT),
- X(EGL_MAX_PBUFFER_PIXELS),
- X(EGL_MAX_PBUFFER_WIDTH),
- X(EGL_NATIVE_RENDERABLE),
- X(EGL_NATIVE_VISUAL_ID),
- X(EGL_NATIVE_VISUAL_TYPE),
- X(EGL_SAMPLES),
- X(EGL_SAMPLE_BUFFERS),
- X(EGL_SURFACE_TYPE),
- X(EGL_TRANSPARENT_TYPE),
- X(EGL_TRANSPARENT_RED_VALUE),
- X(EGL_TRANSPARENT_GREEN_VALUE),
- X(EGL_TRANSPARENT_BLUE_VALUE),
- X(EGL_BIND_TO_TEXTURE_RGB),
- X(EGL_BIND_TO_TEXTURE_RGBA),
- X(EGL_MIN_SWAP_INTERVAL),
- X(EGL_MAX_SWAP_INTERVAL),
- X(EGL_LUMINANCE_SIZE),
- X(EGL_ALPHA_MASK_SIZE),
- X(EGL_COLOR_BUFFER_TYPE),
- X(EGL_RENDERABLE_TYPE),
- X(EGL_CONFORMANT),
- };
-#undef X
-
- for (size_t j = 0; j < sizeof(names) / sizeof(names[0]); j++) {
- EGLint value = -1;
- EGLint returnVal = eglGetConfigAttrib(dpy, config, names[j].attribute, &value);
- EGLint error = eglGetError();
- if (returnVal && error == EGL_SUCCESS) {
- LOGV(" %s: %d (0x%x)", names[j].name, value, value);
- }
- }
-}
bool Context::initGLThread() {
pthread_mutex_lock(&gInitMutex);
LOGV("initGLThread start %p", this);
- mEGL.mNumConfigs = -1;
- EGLint configAttribs[128];
- EGLint *configAttribsPtr = configAttribs;
- EGLint context_attribs2[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
-
- memset(configAttribs, 0, sizeof(configAttribs));
-
- configAttribsPtr[0] = EGL_SURFACE_TYPE;
- configAttribsPtr[1] = EGL_WINDOW_BIT;
- configAttribsPtr += 2;
-
- configAttribsPtr[0] = EGL_RENDERABLE_TYPE;
- configAttribsPtr[1] = EGL_OPENGL_ES2_BIT;
- configAttribsPtr += 2;
-
- if (mUserSurfaceConfig.depthMin > 0) {
- configAttribsPtr[0] = EGL_DEPTH_SIZE;
- configAttribsPtr[1] = mUserSurfaceConfig.depthMin;
- configAttribsPtr += 2;
- }
-
- if (mDev->mForceSW) {
- configAttribsPtr[0] = EGL_CONFIG_CAVEAT;
- configAttribsPtr[1] = EGL_SLOW_CONFIG;
- configAttribsPtr += 2;
- }
-
- configAttribsPtr[0] = EGL_NONE;
- rsAssert(configAttribsPtr < (configAttribs + (sizeof(configAttribs) / sizeof(EGLint))));
-
- LOGV("%p initEGL start", this);
- mEGL.mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- checkEglError("eglGetDisplay");
-
- eglInitialize(mEGL.mDisplay, &mEGL.mMajorVersion, &mEGL.mMinorVersion);
- checkEglError("eglInitialize");
-
-#if 1
- PixelFormat pf = PIXEL_FORMAT_RGBA_8888;
- if (mUserSurfaceConfig.alphaMin == 0) {
- pf = PIXEL_FORMAT_RGBX_8888;
- }
-
- status_t err = EGLUtils::selectConfigForPixelFormat(mEGL.mDisplay, configAttribs, pf, &mEGL.mConfig);
- if (err) {
- LOGE("%p, couldn't find an EGLConfig matching the screen format\n", this);
- }
- if (props.mLogVisual) {
- printEGLConfiguration(mEGL.mDisplay, mEGL.mConfig);
- }
-#else
- eglChooseConfig(mEGL.mDisplay, configAttribs, &mEGL.mConfig, 1, &mEGL.mNumConfigs);
-#endif
-
- mEGL.mContext = eglCreateContext(mEGL.mDisplay, mEGL.mConfig, EGL_NO_CONTEXT, context_attribs2);
- checkEglError("eglCreateContext");
- if (mEGL.mContext == EGL_NO_CONTEXT) {
+ if (!mHal.funcs.initGraphics(this)) {
pthread_mutex_unlock(&gInitMutex);
- LOGE("%p, eglCreateContext returned EGL_NO_CONTEXT", this);
- return false;
- }
- gGLContextCount++;
-
-
- EGLint pbuffer_attribs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE };
- mEGL.mSurfaceDefault = eglCreatePbufferSurface(mEGL.mDisplay, mEGL.mConfig, pbuffer_attribs);
- checkEglError("eglCreatePbufferSurface");
- if (mEGL.mSurfaceDefault == EGL_NO_SURFACE) {
- LOGE("eglCreatePbufferSurface returned EGL_NO_SURFACE");
- pthread_mutex_unlock(&gInitMutex);
- deinitEGL();
+ LOGE("%p, initGraphics failed", this);
return false;
}
- EGLBoolean ret = eglMakeCurrent(mEGL.mDisplay, mEGL.mSurfaceDefault, mEGL.mSurfaceDefault, mEGL.mContext);
- if (ret == EGL_FALSE) {
- LOGE("eglMakeCurrent returned EGL_FALSE");
- checkEglError("eglMakeCurrent", ret);
- pthread_mutex_unlock(&gInitMutex);
- deinitEGL();
- return false;
- }
-
- mGL.mVersion = glGetString(GL_VERSION);
- mGL.mVendor = glGetString(GL_VENDOR);
- mGL.mRenderer = glGetString(GL_RENDERER);
- mGL.mExtensions = glGetString(GL_EXTENSIONS);
-
- //LOGV("EGL Version %i %i", mEGL.mMajorVersion, mEGL.mMinorVersion);
- //LOGV("GL Version %s", mGL.mVersion);
- //LOGV("GL Vendor %s", mGL.mVendor);
- //LOGV("GL Renderer %s", mGL.mRenderer);
- //LOGV("GL Extensions %s", mGL.mExtensions);
-
- const char *verptr = NULL;
- if (strlen((const char *)mGL.mVersion) > 9) {
- if (!memcmp(mGL.mVersion, "OpenGL ES-CM", 12)) {
- verptr = (const char *)mGL.mVersion + 12;
- }
- if (!memcmp(mGL.mVersion, "OpenGL ES ", 10)) {
- verptr = (const char *)mGL.mVersion + 9;
- }
- }
-
- if (!verptr) {
- LOGE("Error, OpenGL ES Lite not supported");
- pthread_mutex_unlock(&gInitMutex);
- deinitEGL();
- return false;
- } else {
- sscanf(verptr, " %i.%i", &mGL.mMajorVersion, &mGL.mMinorVersion);
- }
+ const char * ext = (const char *)glGetString(GL_EXTENSIONS);
glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &mGL.mMaxVertexAttribs);
glGetIntegerv(GL_MAX_VERTEX_UNIFORM_VECTORS, &mGL.mMaxVertexUniformVectors);
@@ -235,11 +68,11 @@
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &mGL.mMaxFragmentTextureImageUnits);
glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_VECTORS, &mGL.mMaxFragmentUniformVectors);
- mGL.OES_texture_npot = NULL != strstr((const char *)mGL.mExtensions, "GL_OES_texture_npot");
- mGL.GL_IMG_texture_npot = NULL != strstr((const char *)mGL.mExtensions, "GL_IMG_texture_npot");
- mGL.GL_NV_texture_npot_2D_mipmap = NULL != strstr((const char *)mGL.mExtensions, "GL_NV_texture_npot_2D_mipmap");
+ mGL.OES_texture_npot = NULL != strstr(ext, "GL_OES_texture_npot");
+ mGL.GL_IMG_texture_npot = NULL != strstr(ext, "GL_IMG_texture_npot");
+ mGL.GL_NV_texture_npot_2D_mipmap = NULL != strstr(ext, "GL_NV_texture_npot_2D_mipmap");
mGL.EXT_texture_max_aniso = 1.0f;
- bool hasAniso = NULL != strstr((const char *)mGL.mExtensions, "GL_EXT_texture_filter_anisotropic");
+ bool hasAniso = NULL != strstr(ext, "GL_EXT_texture_filter_anisotropic");
if (hasAniso) {
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &mGL.EXT_texture_max_aniso);
}
@@ -251,21 +84,7 @@
void Context::deinitEGL() {
LOGV("%p, deinitEGL", this);
-
- if (mEGL.mContext != EGL_NO_CONTEXT) {
- eglMakeCurrent(mEGL.mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
- eglDestroySurface(mEGL.mDisplay, mEGL.mSurfaceDefault);
- if (mEGL.mSurface != EGL_NO_SURFACE) {
- eglDestroySurface(mEGL.mDisplay, mEGL.mSurface);
- }
- eglDestroyContext(mEGL.mDisplay, mEGL.mContext);
- checkEglError("eglDestroyContext");
- }
-
- gGLContextCount--;
- if (!gGLContextCount) {
- eglTerminate(mEGL.mDisplay);
- }
+ mHal.funcs.shutdownGraphics(this);
}
Context::PushState::PushState(Context *con) {
@@ -507,7 +326,7 @@
mDraw = targetTime && !rsc->mPaused;
rsc->timerSet(RS_TIMER_CLEAR_SWAP);
- eglSwapBuffers(rsc->mEGL.mDisplay, rsc->mEGL.mSurface);
+ rsc->mHal.funcs.swap(rsc);
rsc->timerFrame();
rsc->timerSet(RS_TIMER_INTERNAL);
rsc->timerPrint();
@@ -604,7 +423,6 @@
memset(&mUserSurfaceConfig, 0, sizeof(mUserSurfaceConfig));
}
- memset(&mEGL, 0, sizeof(mEGL));
memset(&mGL, 0, sizeof(mGL));
mIsGraphicsContext = sc != NULL;
@@ -693,36 +511,13 @@
void Context::setSurface(uint32_t w, uint32_t h, ANativeWindow *sur) {
rsAssert(mIsGraphicsContext);
-
- EGLBoolean ret;
- // WAR: Some drivers fail to handle 0 size surfaces correcntly.
- // Use the pbuffer to avoid this pitfall.
- if ((mEGL.mSurface != NULL) || (w == 0) || (h == 0)) {
- ret = eglMakeCurrent(mEGL.mDisplay, mEGL.mSurfaceDefault, mEGL.mSurfaceDefault, mEGL.mContext);
- checkEglError("eglMakeCurrent", ret);
-
- ret = eglDestroySurface(mEGL.mDisplay, mEGL.mSurface);
- checkEglError("eglDestroySurface", ret);
-
- mEGL.mSurface = NULL;
- mWidth = 1;
- mHeight = 1;
- }
+ mHal.funcs.setSurface(this, w, h, sur);
mWndSurface = sur;
- if (mWndSurface != NULL) {
- mWidth = w;
- mHeight = h;
+ mWidth = w;
+ mHeight = h;
- mEGL.mSurface = eglCreateWindowSurface(mEGL.mDisplay, mEGL.mConfig, mWndSurface, NULL);
- checkEglError("eglCreateWindowSurface");
- if (mEGL.mSurface == EGL_NO_SURFACE) {
- LOGE("eglCreateWindowSurface returned EGL_NO_SURFACE");
- }
-
- ret = eglMakeCurrent(mEGL.mDisplay, mEGL.mSurface, mEGL.mSurface, mEGL.mContext);
- checkEglError("eglMakeCurrent", ret);
-
+ if (mWidth && mHeight) {
mStateVertex.updateSize(this);
}
}
@@ -887,21 +682,9 @@
LOGE("RS Context debug %p", this);
LOGE("RS Context debug");
- LOGE(" EGL ver %i %i", mEGL.mMajorVersion, mEGL.mMinorVersion);
- LOGE(" EGL context %p surface %p, Display=%p", mEGL.mContext, mEGL.mSurface, mEGL.mDisplay);
- LOGE(" GL vendor: %s", mGL.mVendor);
- LOGE(" GL renderer: %s", mGL.mRenderer);
- LOGE(" GL Version: %s", mGL.mVersion);
- LOGE(" GL Extensions: %s", mGL.mExtensions);
- LOGE(" GL int Versions %i %i", mGL.mMajorVersion, mGL.mMinorVersion);
LOGE(" RS width %i, height %i", mWidth, mHeight);
LOGE(" RS running %i, exit %i, paused %i", mRunning, mExit, mPaused);
LOGE(" RS pThreadID %li, nativeThreadID %i", mThreadId, mNativeThreadId);
-
- LOGV("MAX Textures %i, %i %i", mGL.mMaxVertexTextureUnits, mGL.mMaxFragmentTextureImageUnits, mGL.mMaxTextureImageUnits);
- LOGV("MAX Attribs %i", mGL.mMaxVertexAttribs);
- LOGV("MAX Uniforms %i, %i", mGL.mMaxVertexUniformVectors, mGL.mMaxFragmentUniformVectors);
- LOGV("MAX Varyings %i", mGL.mMaxVaryingVectors);
}
///////////////////////////////////////////////////////////////////////////////////////////
diff --git a/libs/rs/rsContext.h b/libs/rs/rsContext.h
index eacfdf7..4dd186c 100644
--- a/libs/rs/rsContext.h
+++ b/libs/rs/rsContext.h
@@ -222,29 +222,10 @@
uint32_t getDPI() const {return mDPI;}
void setDPI(uint32_t dpi) {mDPI = dpi;}
-protected:
Device *mDev;
+protected:
struct {
- EGLint mNumConfigs;
- EGLint mMajorVersion;
- EGLint mMinorVersion;
- EGLConfig mConfig;
- EGLContext mContext;
- EGLSurface mSurface;
- EGLSurface mSurfaceDefault;
- EGLDisplay mDisplay;
- } mEGL;
-
- struct {
- const uint8_t * mVendor;
- const uint8_t * mRenderer;
- const uint8_t * mVersion;
- const uint8_t * mExtensions;
-
- uint32_t mMajorVersion;
- uint32_t mMinorVersion;
-
int32_t mMaxVaryingVectors;
int32_t mMaxTextureImageUnits;
diff --git a/libs/rs/rs_hal.h b/libs/rs/rs_hal.h
index 93d7476..a4ca936 100644
--- a/libs/rs/rs_hal.h
+++ b/libs/rs/rs_hal.h
@@ -18,6 +18,7 @@
#define RS_HAL_H
#include <RenderScriptDefines.h>
+#include <ui/egl/android_natives.h>
namespace android {
namespace renderscript {
@@ -44,6 +45,11 @@
* Script management functions
*/
typedef struct {
+ bool (*initGraphics)(const Context *);
+ void (*shutdownGraphics)(const Context *);
+ bool (*setSurface)(const Context *, uint32_t w, uint32_t h, ANativeWindow *);
+ void (*swap)(const Context *);
+
void (*shutdownDriver)(Context *);
void (*getVersion)(unsigned int *major, unsigned int *minor);
void (*setPriority)(const Context *, int32_t priority);
@@ -87,7 +93,6 @@
void (*destroy)(const Context *rsc, Script *s);
} script;
-
struct {
bool (*init)(const Context *rsc, const ProgramStore *ps);
void (*setActive)(const Context *rsc, const ProgramStore *ps);
diff --git a/libs/ui/InputTransport.cpp b/libs/ui/InputTransport.cpp
index 9d1b8b9..93d0d1f 100644
--- a/libs/ui/InputTransport.cpp
+++ b/libs/ui/InputTransport.cpp
@@ -27,8 +27,14 @@
namespace android {
+#define ROUND_UP(value, boundary) (((value) + (boundary) - 1) & ~((boundary) - 1))
+#define MIN_HISTORY_DEPTH 20
+
// Must be at least sizeof(InputMessage) + sufficient space for pointer data
-static const int DEFAULT_MESSAGE_BUFFER_SIZE = 16384;
+static const int DEFAULT_MESSAGE_BUFFER_SIZE = ROUND_UP(
+ sizeof(InputMessage) + MIN_HISTORY_DEPTH
+ * (sizeof(InputMessage::SampleData) + MAX_POINTERS * sizeof(PointerCoords)),
+ 4096);
// Signal sent by the producer to the consumer to inform it that a new message is
// available to be consumed in the shared memory buffer.
diff --git a/media/jni/android_media_MediaMetadataRetriever.cpp b/media/jni/android_media_MediaMetadataRetriever.cpp
index 27b37b7..a219623 100644
--- a/media/jni/android_media_MediaMetadataRetriever.cpp
+++ b/media/jni/android_media_MediaMetadataRetriever.cpp
@@ -34,11 +34,11 @@
struct fields_t {
jfieldID context;
- jclass bitmapClazz;
+ jclass bitmapClazz; // Must be a global ref
jfieldID nativeBitmap;
jmethodID createBitmapMethod;
jmethodID createScaledBitmapMethod;
- jclass configClazz;
+ jclass configClazz; // Must be a global ref
jmethodID createConfigMethod;
};
@@ -120,33 +120,71 @@
if (headers) {
// Get the Map's entry Set.
jclass mapClass = env->FindClass("java/util/Map");
+ if (mapClass == NULL) {
+ return;
+ }
jmethodID entrySet =
env->GetMethodID(mapClass, "entrySet", "()Ljava/util/Set;");
+ if (entrySet == NULL) {
+ return;
+ }
jobject set = env->CallObjectMethod(headers, entrySet);
+ if (set == NULL) {
+ return;
+ }
+
// Obtain an iterator over the Set
jclass setClass = env->FindClass("java/util/Set");
+ if (setClass == NULL) {
+ return;
+ }
jmethodID iterator =
env->GetMethodID(setClass, "iterator", "()Ljava/util/Iterator;");
+ if (iterator == NULL) {
+ return;
+ }
jobject iter = env->CallObjectMethod(set, iterator);
+ if (iter == NULL) {
+ return;
+ }
+
// Get the Iterator method IDs
jclass iteratorClass = env->FindClass("java/util/Iterator");
+ if (iteratorClass == NULL) {
+ return;
+ }
jmethodID hasNext = env->GetMethodID(iteratorClass, "hasNext", "()Z");
+ if (hasNext == NULL) {
+ return;
+ }
jmethodID next =
env->GetMethodID(iteratorClass, "next", "()Ljava/lang/Object;");
+ if (next == NULL) {
+ return;
+ }
// Get the Entry class method IDs
jclass entryClass = env->FindClass("java/util/Map$Entry");
+ if (entryClass == NULL) {
+ return;
+ }
jmethodID getKey =
env->GetMethodID(entryClass, "getKey", "()Ljava/lang/Object;");
+ if (getKey == NULL) {
+ return;
+ }
jmethodID getValue =
env->GetMethodID(entryClass, "getValue", "()Ljava/lang/Object;");
+ if (getValue == NULL) {
+ return;
+ }
// Iterate over the entry Set
while (env->CallBooleanMethod(iter, hasNext)) {
@@ -161,6 +199,7 @@
const char* valueStr = env->GetStringUTFChars(value, NULL);
if (!valueStr) { // Out of memory
+ env->ReleaseStringUTFChars(key, keyStr);
return;
}
@@ -171,14 +210,8 @@
env->DeleteLocalRef(key);
env->ReleaseStringUTFChars(value, valueStr);
env->DeleteLocalRef(value);
- }
+ }
- env->DeleteLocalRef(entryClass);
- env->DeleteLocalRef(iteratorClass);
- env->DeleteLocalRef(iter);
- env->DeleteLocalRef(setClass);
- env->DeleteLocalRef(set);
- env->DeleteLocalRef(mapClass);
}
process_media_retriever_call(
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index 0f9cbec..ecbd288 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -1,4 +1,4 @@
-/* //device/libs/android_runtime/android_media_MediaPlayer.cpp
+/*
**
** Copyright 2007, The Android Open Source Project
**
@@ -185,45 +185,87 @@
return;
}
- const char *pathStr = env->GetStringUTFChars(path, NULL);
- if (pathStr == NULL) { // Out of memory
- jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
+ const char *tmp = env->GetStringUTFChars(path, NULL);
+ if (tmp == NULL) { // Out of memory
return;
}
+ String8 pathStr(tmp);
+ env->ReleaseStringUTFChars(path, tmp);
+ tmp = NULL;
+
// headers is a Map<String, String>.
// We build a similar KeyedVector out of it.
KeyedVector<String8, String8> headersVector;
if (headers) {
// Get the Map's entry Set.
jclass mapClass = env->FindClass("java/util/Map");
+ if (mapClass == NULL) {
+ return;
+ }
jmethodID entrySet =
env->GetMethodID(mapClass, "entrySet", "()Ljava/util/Set;");
+ if (entrySet == NULL) {
+ return;
+ }
jobject set = env->CallObjectMethod(headers, entrySet);
+ if (set == NULL) {
+ return;
+ }
+
// Obtain an iterator over the Set
jclass setClass = env->FindClass("java/util/Set");
+ if (setClass == NULL) {
+ return;
+ }
jmethodID iterator =
env->GetMethodID(setClass, "iterator", "()Ljava/util/Iterator;");
+ if (iterator == NULL) {
+ return;
+ }
jobject iter = env->CallObjectMethod(set, iterator);
+ if (iter == NULL) {
+ return;
+ }
+
// Get the Iterator method IDs
jclass iteratorClass = env->FindClass("java/util/Iterator");
+ if (iteratorClass == NULL) {
+ return;
+ }
+
jmethodID hasNext = env->GetMethodID(iteratorClass, "hasNext", "()Z");
+ if (hasNext == NULL) {
+ return;
+ }
jmethodID next =
env->GetMethodID(iteratorClass, "next", "()Ljava/lang/Object;");
+ if (next == NULL) {
+ return;
+ }
// Get the Entry class method IDs
jclass entryClass = env->FindClass("java/util/Map$Entry");
+ if (entryClass == NULL) {
+ return;
+ }
jmethodID getKey =
env->GetMethodID(entryClass, "getKey", "()Ljava/lang/Object;");
+ if (getKey == NULL) {
+ return;
+ }
jmethodID getValue =
env->GetMethodID(entryClass, "getValue", "()Ljava/lang/Object;");
+ if (getValue == NULL) {
+ return;
+ }
// Iterate over the entry Set
while (env->CallBooleanMethod(iter, hasNext)) {
@@ -233,15 +275,12 @@
const char* keyStr = env->GetStringUTFChars(key, NULL);
if (!keyStr) { // Out of memory
- jniThrowException(
- env, "java/lang/RuntimeException", "Out of memory");
return;
}
const char* valueStr = env->GetStringUTFChars(value, NULL);
if (!valueStr) { // Out of memory
- jniThrowException(
- env, "java/lang/RuntimeException", "Out of memory");
+ env->ReleaseStringUTFChars(key, keyStr);
return;
}
@@ -252,25 +291,16 @@
env->DeleteLocalRef(key);
env->ReleaseStringUTFChars(value, valueStr);
env->DeleteLocalRef(value);
- }
+ }
- env->DeleteLocalRef(entryClass);
- env->DeleteLocalRef(iteratorClass);
- env->DeleteLocalRef(iter);
- env->DeleteLocalRef(setClass);
- env->DeleteLocalRef(set);
- env->DeleteLocalRef(mapClass);
}
LOGV("setDataSource: path %s", pathStr);
status_t opStatus =
mp->setDataSource(
- String8(pathStr),
+ pathStr,
headers ? &headersVector : NULL);
- // Make sure that local ref is released before a potential exception
- env->ReleaseStringUTFChars(path, pathStr);
-
process_media_player_call(
env, thiz, opStatus, "java/io/IOException",
"setDataSource failed." );
@@ -628,62 +658,49 @@
clazz = env->FindClass("android/media/MediaPlayer");
if (clazz == NULL) {
- jniThrowException(env, "java/lang/RuntimeException", "Can't find android/media/MediaPlayer");
return;
}
fields.context = env->GetFieldID(clazz, "mNativeContext", "I");
if (fields.context == NULL) {
- jniThrowException(env, "java/lang/RuntimeException", "Can't find MediaPlayer.mNativeContext");
return;
}
fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative",
"(Ljava/lang/Object;IIILjava/lang/Object;)V");
if (fields.post_event == NULL) {
- jniThrowException(env, "java/lang/RuntimeException", "Can't find MediaPlayer.postEventFromNative");
return;
}
fields.surface = env->GetFieldID(clazz, "mSurface", "Landroid/view/Surface;");
if (fields.surface == NULL) {
- jniThrowException(env, "java/lang/RuntimeException", "Can't find MediaPlayer.mSurface");
return;
}
jclass surface = env->FindClass("android/view/Surface");
if (surface == NULL) {
- jniThrowException(env, "java/lang/RuntimeException", "Can't find android/view/Surface");
return;
}
fields.surface_native = env->GetFieldID(surface, ANDROID_VIEW_SURFACE_JNI_ID, "I");
if (fields.surface_native == NULL) {
- jniThrowException(env, "java/lang/RuntimeException",
- "Can't find Surface." ANDROID_VIEW_SURFACE_JNI_ID);
return;
}
fields.surfaceTexture = env->GetFieldID(clazz, "mSurfaceTexture",
"Landroid/graphics/SurfaceTexture;");
if (fields.surfaceTexture == NULL) {
- jniThrowException(env, "java/lang/RuntimeException",
- "Can't find MediaPlayer.mSurfaceTexture");
return;
}
jclass surfaceTexture = env->FindClass("android/graphics/SurfaceTexture");
if (surfaceTexture == NULL) {
- jniThrowException(env, "java/lang/RuntimeException",
- "Can't find android/graphics/SurfaceTexture");
return;
}
fields.surfaceTexture_native = env->GetFieldID(surfaceTexture,
ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID, "I");
if (fields.surfaceTexture_native == NULL) {
- jniThrowException(env, "java/lang/RuntimeException",
- "Can't find SurfaceTexture." ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID);
return;
}
diff --git a/media/jni/android_media_MediaScanner.cpp b/media/jni/android_media_MediaScanner.cpp
index 9d7bf2c..06058dc 100644
--- a/media/jni/android_media_MediaScanner.cpp
+++ b/media/jni/android_media_MediaScanner.cpp
@@ -213,7 +213,6 @@
const char *pathStr = env->GetStringUTFChars(path, NULL);
if (pathStr == NULL) { // Out of memory
- jniThrowException(env, kRunTimeException, "Out of memory");
return;
}
@@ -243,15 +242,14 @@
const char *pathStr = env->GetStringUTFChars(path, NULL);
if (pathStr == NULL) { // Out of memory
- jniThrowException(env, kRunTimeException, "Out of memory");
return;
}
const char *mimeTypeStr =
(mimeType ? env->GetStringUTFChars(mimeType, NULL) : NULL);
if (mimeType && mimeTypeStr == NULL) { // Out of memory
+ // ReleaseStringUTFChars can be called with an exception pending.
env->ReleaseStringUTFChars(path, pathStr);
- jniThrowException(env, kRunTimeException, "Out of memory");
return;
}
@@ -281,7 +279,6 @@
}
const char *localeStr = env->GetStringUTFChars(locale, NULL);
if (localeStr == NULL) { // Out of memory
- jniThrowException(env, kRunTimeException, "Out of memory");
return;
}
mp->setLocale(localeStr);
diff --git a/media/jni/android_mtp_MtpDatabase.cpp b/media/jni/android_mtp_MtpDatabase.cpp
index 17d39e3..2f88fd1 100644
--- a/media/jni/android_mtp_MtpDatabase.cpp
+++ b/media/jni/android_mtp_MtpDatabase.cpp
@@ -427,6 +427,9 @@
jstring stringValue = (jstring)env->GetObjectArrayElement(stringValuesArray, 0);
if (stringValue) {
const char* str = env->GetStringUTFChars(stringValue, NULL);
+ if (str == NULL) {
+ return MTP_RESPONSE_GENERAL_ERROR;
+ }
packet.putString(str);
env->ReleaseStringUTFChars(stringValue, str);
} else {
diff --git a/media/jni/android_mtp_MtpDevice.cpp b/media/jni/android_mtp_MtpDevice.cpp
index f5fcb4e..40bbaa3 100644
--- a/media/jni/android_mtp_MtpDevice.cpp
+++ b/media/jni/android_mtp_MtpDevice.cpp
@@ -110,6 +110,10 @@
#ifdef HAVE_ANDROID_OS
LOGD("open\n");
const char *deviceNameStr = env->GetStringUTFChars(deviceName, NULL);
+ if (deviceNameStr == NULL) {
+ return false;
+ }
+
MtpDevice* device = MtpDevice::open(deviceNameStr, fd);
env->ReleaseStringUTFChars(deviceName, deviceNameStr);
@@ -426,12 +430,16 @@
MtpDevice* device = get_device_from_object(env, thiz);
if (device) {
const char *destPathStr = env->GetStringUTFChars(dest_path, NULL);
+ if (destPathStr == NULL) {
+ return false;
+ }
+
bool result = device->readObject(object_id, destPathStr, AID_SDCARD_RW, 0664);
env->ReleaseStringUTFChars(dest_path, destPathStr);
return result;
}
#endif
- return NULL;
+ return false;
}
// ----------------------------------------------------------------------------
diff --git a/media/jni/android_mtp_MtpServer.cpp b/media/jni/android_mtp_MtpServer.cpp
index c55189f..84c2c7e 100644
--- a/media/jni/android_mtp_MtpServer.cpp
+++ b/media/jni/android_mtp_MtpServer.cpp
@@ -97,7 +97,7 @@
void removeStorage(MtpStorageID id) {
MtpStorage* storage = mServer->getStorage(id);
if (storage) {
- for (int i = 0; i < mStorageList.size(); i++) {
+ for (size_t i = 0; i < mStorageList.size(); i++) {
if (mStorageList[i] == storage) {
mStorageList.removeAt(i);
break;
@@ -122,7 +122,7 @@
(mUsePtp ? MTP_INTERFACE_MODE_PTP : MTP_INTERFACE_MODE_MTP));
mServer = new MtpServer(mFd, mDatabase, AID_MEDIA_RW, 0664, 0775);
- for (int i = 0; i < mStorageList.size(); i++) {
+ for (size_t i = 0; i < mStorageList.size(); i++) {
mServer->addStorage(mStorageList[i]);
}
} else {
@@ -247,13 +247,17 @@
jlong reserveSpace = env->GetLongField(jstorage, field_MtpStorage_reserveSpace);
const char *pathStr = env->GetStringUTFChars(path, NULL);
- const char *descriptionStr = env->GetStringUTFChars(description, NULL);
-
- MtpStorage* storage = new MtpStorage(storageID, pathStr, descriptionStr, reserveSpace);
- thread->addStorage(storage);
-
- env->ReleaseStringUTFChars(path, pathStr);
- env->ReleaseStringUTFChars(description, descriptionStr);
+ if (pathStr != NULL) {
+ const char *descriptionStr = env->GetStringUTFChars(description, NULL);
+ if (descriptionStr != NULL) {
+ MtpStorage* storage = new MtpStorage(storageID, pathStr, descriptionStr, reserveSpace);
+ thread->addStorage(storage);
+ env->ReleaseStringUTFChars(path, pathStr);
+ env->ReleaseStringUTFChars(description, descriptionStr);
+ } else {
+ env->ReleaseStringUTFChars(path, pathStr);
+ }
+ }
} else {
LOGE("MtpThread is null in add_storage");
}
diff --git a/media/libmedia/AudioEffect.cpp b/media/libmedia/AudioEffect.cpp
index aadeba5..a043329 100644
--- a/media/libmedia/AudioEffect.cpp
+++ b/media/libmedia/AudioEffect.cpp
@@ -170,7 +170,6 @@
LOGV("Destructor %p", this);
if (mStatus == NO_ERROR || mStatus == ALREADY_EXISTS) {
- setEnabled(false);
if (mIEffect != NULL) {
mIEffect->disconnect();
mIEffect->asBinder()->unlinkToDeath(mIEffectClient);
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4g.png
index 84ac927..ade3716 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4g.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4g.png
Binary files differ
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 768c0cd..5f84547 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -626,7 +626,7 @@
}
if (mLongPressOnHomeBehavior == LONG_PRESS_HOME_RECENT_DIALOG) {
- showRecentAppsDialog(0);
+ showOrHideRecentAppsDialog(0, true /*dismissIfShown*/);
} else if (mLongPressOnHomeBehavior == LONG_PRESS_HOME_RECENT_ACTIVITY) {
try {
Intent intent = new Intent();
@@ -643,16 +643,24 @@
}
/**
- * Create (if necessary) and launch the recent apps dialog
+ * Create (if necessary) and launch the recent apps dialog, or hide it if it is
+ * already shown.
*/
- void showRecentAppsDialog(final int initialModifiers) {
+ void showOrHideRecentAppsDialog(final int heldModifiers, final boolean dismissIfShown) {
mHandler.post(new Runnable() {
@Override
public void run() {
if (mRecentAppsDialog == null) {
- mRecentAppsDialog = new RecentApplicationsDialog(mContext, initialModifiers);
+ mRecentAppsDialog = new RecentApplicationsDialog(mContext);
}
- mRecentAppsDialog.show();
+ if (mRecentAppsDialog.isShowing()) {
+ if (dismissIfShown) {
+ mRecentAppsDialog.dismiss();
+ }
+ } else {
+ mRecentAppsDialog.setHeldModifiers(heldModifiers);
+ mRecentAppsDialog.show();
+ }
}
});
}
@@ -1388,7 +1396,7 @@
return false;
} else if (keyCode == KeyEvent.KEYCODE_APP_SWITCH) {
if (down && repeatCount == 0) {
- showRecentAppsDialog(event.getMetaState() & KeyEvent.getModifierMetaStateMask());
+ showOrHideRecentAppsDialog(0, true /*dismissIfShown*/);
}
return true;
}
@@ -1430,6 +1438,7 @@
/** {@inheritDoc} */
@Override
public KeyEvent dispatchUnhandledKey(WindowState win, KeyEvent event, int policyFlags) {
+ // Note: This method is only called if the initial down was unhandled.
if (DEBUG_FALLBACK) {
Slog.d(TAG, "Unhandled key: win=" + win + ", action=" + event.getAction()
+ ", flags=" + event.getFlags()
@@ -1441,28 +1450,44 @@
}
if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
- // Invoke shortcuts using Meta as a fallback.
final KeyCharacterMap kcm = event.getKeyCharacterMap();
final int keyCode = event.getKeyCode();
final int metaState = event.getMetaState();
- if ((metaState & KeyEvent.META_META_ON) != 0) {
- Intent shortcutIntent = mShortcutManager.getIntent(kcm, keyCode,
- metaState & ~(KeyEvent.META_META_ON
- | KeyEvent.META_META_LEFT_ON | KeyEvent.META_META_RIGHT_ON));
- if (shortcutIntent != null) {
- shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- try {
- mContext.startActivity(shortcutIntent);
- } catch (ActivityNotFoundException ex) {
- Slog.w(TAG, "Dropping shortcut key combination because "
- + "the activity to which it is registered was not found: "
- + "META+" + KeyEvent.keyCodeToString(keyCode), ex);
+ final boolean initialDown = event.getAction() == KeyEvent.ACTION_DOWN
+ && event.getRepeatCount() == 0;
+
+ if (initialDown) {
+ // Invoke shortcuts using Meta as a fallback.
+ if ((metaState & KeyEvent.META_META_ON) != 0) {
+ Intent shortcutIntent = mShortcutManager.getIntent(kcm, keyCode,
+ metaState & ~(KeyEvent.META_META_ON
+ | KeyEvent.META_META_LEFT_ON | KeyEvent.META_META_RIGHT_ON));
+ if (shortcutIntent != null) {
+ shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ try {
+ mContext.startActivity(shortcutIntent);
+ } catch (ActivityNotFoundException ex) {
+ Slog.w(TAG, "Dropping shortcut key combination because "
+ + "the activity to which it is registered was not found: "
+ + "META+" + KeyEvent.keyCodeToString(keyCode), ex);
+ }
+ return null;
}
- return null;
+ }
+
+ // Display task switcher for ALT-TAB or Meta-TAB.
+ if (keyCode == KeyEvent.KEYCODE_TAB) {
+ final int shiftlessModifiers = event.getModifiers() & ~KeyEvent.META_SHIFT_MASK;
+ if (KeyEvent.metaStateHasModifiers(shiftlessModifiers, KeyEvent.META_ALT_ON)
+ || KeyEvent.metaStateHasModifiers(
+ shiftlessModifiers, KeyEvent.META_META_ON)) {
+ showOrHideRecentAppsDialog(shiftlessModifiers, false /*dismissIfShown*/);
+ return null;
+ }
}
}
- // Check for fallback actions.
+ // Check for fallback actions specified by the key character map.
if (getFallbackAction(kcm, keyCode, metaState, mFallbackAction)) {
if (DEBUG_FALLBACK) {
Slog.d(TAG, "Fallback: keyCode=" + mFallbackAction.keyCode
diff --git a/policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java b/policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java
index c4b7822..aa00fbdd 100644
--- a/policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java
+++ b/policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java
@@ -71,12 +71,11 @@
}
};
- private int mInitialModifiers;
+ private int mHeldModifiers;
- public RecentApplicationsDialog(Context context, int initialModifiers) {
+ public RecentApplicationsDialog(Context context) {
super(context, com.android.internal.R.style.Theme_Dialog_RecentApplications);
- mInitialModifiers = initialModifiers;
}
/**
@@ -125,9 +124,20 @@
}
}
+ /**
+ * Sets the modifier keys that are being held to keep the dialog open, or 0 if none.
+ * Used to make the recent apps dialog automatically dismiss itself when the modifiers
+ * all go up.
+ * @param heldModifiers The held key modifiers, such as {@link KeyEvent#META_ALT_ON}.
+ * Should exclude shift.
+ */
+ public void setHeldModifiers(int heldModifiers) {
+ mHeldModifiers = heldModifiers;
+ }
+
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
- if (keyCode == KeyEvent.KEYCODE_APP_SWITCH || keyCode == KeyEvent.KEYCODE_TAB) {
+ if (keyCode == KeyEvent.KEYCODE_TAB) {
// Ignore all meta keys other than SHIFT. The app switch key could be a
// fallback action chorded with ALT, META or even CTRL depending on the key map.
// DPad navigation is handled by the ViewRoot elsewhere.
@@ -166,7 +176,7 @@
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
- if (mInitialModifiers != 0 && event.hasNoModifiers()) {
+ if (mHeldModifiers != 0 && (event.getModifiers() & mHeldModifiers) == 0) {
final int numIcons = mIcons.length;
RecentTag tag = null;
for (int i = 0; i < numIcons; i++) {
diff --git a/services/input/EventHub.cpp b/services/input/EventHub.cpp
index 9a9d9e5..ff4b11a 100644
--- a/services/input/EventHub.cpp
+++ b/services/input/EventHub.cpp
@@ -539,7 +539,24 @@
(int) iev.time.tv_sec, (int) iev.time.tv_usec,
iev.type, iev.code, iev.value);
+#ifdef HAVE_POSIX_CLOCKS
+ // Use the time specified in the event instead of the current time
+ // so that downstream code can get more accurate estimates of
+ // event dispatch latency from the time the event is enqueued onto
+ // the evdev client buffer.
+ //
+ // The event's timestamp fortuitously uses the same monotonic clock
+ // time base as the rest of Android. The kernel event device driver
+ // (drivers/input/evdev.c) obtains timestamps using ktime_get_ts().
+ // The systemTime(SYSTEM_TIME_MONOTONIC) function we use everywhere
+ // calls clock_gettime(CLOCK_MONOTONIC) which is implemented as a
+ // system call that also queries ktime_get_ts().
+ event->when = nsecs_t(iev.time.tv_sec) * 1000000000LL
+ + nsecs_t(iev.time.tv_usec) * 1000LL;
+ LOGV("event time %lld, now %lld", event->when, now);
+#else
event->when = now;
+#endif
event->deviceId = deviceId;
event->type = iev.type;
event->scanCode = iev.code;
diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp
index 253d070..46de933 100644
--- a/services/input/InputDispatcher.cpp
+++ b/services/input/InputDispatcher.cpp
@@ -79,6 +79,22 @@
// before considering it stale and dropping it.
const nsecs_t STALE_EVENT_TIMEOUT = 10000 * 1000000LL; // 10sec
+// Motion samples that are received within this amount of time are simply coalesced
+// when batched instead of being appended. This is done because some drivers update
+// the location of pointers one at a time instead of all at once.
+// For example, when there are 10 fingers down, the input dispatcher may receive 10
+// samples in quick succession with only one finger's location changed in each sample.
+//
+// This value effectively imposes an upper bound on the touch sampling rate.
+// Touch sensors typically have a 50Hz - 200Hz sampling rate, so we expect distinct
+// samples to become available 5-20ms apart but individual finger reports can trickle
+// in over a period of 2-4ms or so.
+//
+// Empirical testing shows that a 2ms coalescing interval (500Hz) is not enough,
+// a 3ms coalescing interval (333Hz) works well most of the time and doesn't introduce
+// significant quantization noise on current hardware.
+const nsecs_t MOTION_SAMPLE_COALESCE_INTERVAL = 3 * 1000000LL; // 3ms, 333Hz
+
static inline nsecs_t now() {
return systemTime(SYSTEM_TIME_MONOTONIC);
@@ -2505,25 +2521,43 @@
continue;
}
- if (motionEntry->action != action
- || motionEntry->pointerCount != pointerCount
- || motionEntry->isInjected()) {
+ if (!motionEntry->canAppendSamples(action, pointerCount, pointerIds)) {
// Last motion event in the queue for this device and source is
// not compatible for appending new samples. Stop here.
goto NoBatchingOrStreaming;
}
- // The last motion event is a move and is compatible for appending.
// Do the batching magic.
- mAllocator.appendMotionSample(motionEntry, eventTime, pointerCoords);
-#if DEBUG_BATCHING
- LOGD("Appended motion sample onto batch for most recent "
- "motion event for this device in the inbound queue.");
-#endif
+ batchMotionLocked(motionEntry, eventTime, metaState, pointerCoords,
+ "most recent motion event for this device and source in the inbound queue");
mLock.unlock();
return; // done!
}
+ // BATCHING ONTO PENDING EVENT CASE
+ //
+ // Try to append a move sample to the currently pending event, if there is one.
+ // We can do this as long as we are still waiting to find the targets for the
+ // event. Once the targets are locked-in we can only do streaming.
+ if (mPendingEvent
+ && (!mPendingEvent->dispatchInProgress || !mCurrentInputTargetsValid)
+ && mPendingEvent->type == EventEntry::TYPE_MOTION) {
+ MotionEntry* motionEntry = static_cast<MotionEntry*>(mPendingEvent);
+ if (motionEntry->deviceId == deviceId && motionEntry->source == source) {
+ if (!motionEntry->canAppendSamples(action, pointerCount, pointerIds)) {
+ // Pending motion event is for this device and source but it is
+ // not compatible for appending new samples. Stop here.
+ goto NoBatchingOrStreaming;
+ }
+
+ // Do the batching magic.
+ batchMotionLocked(motionEntry, eventTime, metaState, pointerCoords,
+ "pending motion event");
+ mLock.unlock();
+ return; // done!
+ }
+ }
+
// STREAMING CASE
//
// There is no pending motion event (of any kind) for this device in the inbound queue.
@@ -2601,7 +2635,7 @@
mAllocator.appendMotionSample(motionEntry, eventTime, pointerCoords);
#if DEBUG_BATCHING
LOGD("Appended motion sample onto batch for most recently dispatched "
- "motion event for this device in the outbound queues. "
+ "motion event for this device and source in the outbound queues. "
"Attempting to stream the motion sample.");
#endif
nsecs_t currentTime = now();
@@ -2632,6 +2666,36 @@
}
}
+void InputDispatcher::batchMotionLocked(MotionEntry* entry, nsecs_t eventTime,
+ int32_t metaState, const PointerCoords* pointerCoords, const char* eventDescription) {
+ // Combine meta states.
+ entry->metaState |= metaState;
+
+ // Coalesce this sample if not enough time has elapsed since the last sample was
+ // initially appended to the batch.
+ MotionSample* lastSample = entry->lastSample;
+ long interval = eventTime - lastSample->eventTimeBeforeCoalescing;
+ if (interval <= MOTION_SAMPLE_COALESCE_INTERVAL) {
+ uint32_t pointerCount = entry->pointerCount;
+ for (uint32_t i = 0; i < pointerCount; i++) {
+ lastSample->pointerCoords[i].copyFrom(pointerCoords[i]);
+ }
+ lastSample->eventTime = eventTime;
+#if DEBUG_BATCHING
+ LOGD("Coalesced motion into last sample of batch for %s, events were %0.3f ms apart",
+ eventDescription, interval * 0.000001f);
+#endif
+ return;
+ }
+
+ // Append the sample.
+ mAllocator.appendMotionSample(entry, eventTime, pointerCoords);
+#if DEBUG_BATCHING
+ LOGD("Appended motion sample onto batch for %s, events were %0.3f ms apart",
+ eventDescription, interval * 0.000001f);
+#endif
+}
+
void InputDispatcher::notifySwitch(nsecs_t when, int32_t switchCode, int32_t switchValue,
uint32_t policyFlags) {
#if DEBUG_INBOUND_EVENT_DETAILS
@@ -3727,6 +3791,7 @@
entry->downTime = downTime;
entry->pointerCount = pointerCount;
entry->firstSample.eventTime = eventTime;
+ entry->firstSample.eventTimeBeforeCoalescing = eventTime;
entry->firstSample.next = NULL;
entry->lastSample = & entry->firstSample;
for (uint32_t i = 0; i < pointerCount; i++) {
@@ -3836,6 +3901,7 @@
nsecs_t eventTime, const PointerCoords* pointerCoords) {
MotionSample* sample = mMotionSamplePool.alloc();
sample->eventTime = eventTime;
+ sample->eventTimeBeforeCoalescing = eventTime;
uint32_t pointerCount = motionEntry->pointerCount;
for (uint32_t i = 0; i < pointerCount; i++) {
sample->pointerCoords[i].copyFrom(pointerCoords[i]);
@@ -3865,6 +3931,21 @@
return count;
}
+bool InputDispatcher::MotionEntry::canAppendSamples(int32_t action, uint32_t pointerCount,
+ const int32_t* pointerIds) const {
+ if (this->action != action
+ || this->pointerCount != pointerCount
+ || this->isInjected()) {
+ return false;
+ }
+ for (uint32_t i = 0; i < pointerCount; i++) {
+ if (this->pointerIds[i] != pointerIds[i]) {
+ return false;
+ }
+ }
+ return true;
+}
+
// --- InputDispatcher::InputState ---
diff --git a/services/input/InputDispatcher.h b/services/input/InputDispatcher.h
index 162e606..af0153b 100644
--- a/services/input/InputDispatcher.h
+++ b/services/input/InputDispatcher.h
@@ -409,7 +409,7 @@
bool dispatchInProgress; // initially false, set to true while dispatching
- inline bool isInjected() { return injectionState != NULL; }
+ inline bool isInjected() const { return injectionState != NULL; }
};
struct ConfigurationChangedEntry : EventEntry {
@@ -439,7 +439,8 @@
struct MotionSample {
MotionSample* next;
- nsecs_t eventTime;
+ nsecs_t eventTime; // may be updated during coalescing
+ nsecs_t eventTimeBeforeCoalescing; // not updated during coalescing
PointerCoords pointerCoords[MAX_POINTERS];
};
@@ -461,6 +462,10 @@
MotionSample* lastSample;
uint32_t countSamples() const;
+
+ // Checks whether we can append samples, assuming the device id and source are the same.
+ bool canAppendSamples(int32_t action, uint32_t pointerCount,
+ const int32_t* pointerIds) const;
};
// Tracks the progress of dispatching a particular event to a particular connection.
@@ -802,6 +807,11 @@
void dispatchOnceInnerLocked(nsecs_t keyRepeatTimeout, nsecs_t keyRepeatDelay,
nsecs_t* nextWakeupTime);
+ // Batches a new sample onto a motion entry.
+ // Assumes that the we have already checked that we can append samples.
+ void batchMotionLocked(MotionEntry* entry, nsecs_t eventTime, int32_t metaState,
+ const PointerCoords* pointerCoords, const char* eventDescription);
+
// Enqueues an inbound event. Returns true if mLooper->wake() should be called.
bool enqueueInboundEventLocked(EventEntry* entry);
diff --git a/services/java/com/android/server/BatteryService.java b/services/java/com/android/server/BatteryService.java
index 47599c8..1aff9a2 100644
--- a/services/java/com/android/server/BatteryService.java
+++ b/services/java/com/android/server/BatteryService.java
@@ -390,7 +390,7 @@
intent.putExtra(BatteryManager.EXTRA_TECHNOLOGY, mBatteryTechnology);
intent.putExtra(BatteryManager.EXTRA_INVALID_CHARGER, mInvalidCharger);
- if (true) {
+ if (false) {
Slog.d(TAG, "level:" + mBatteryLevel +
" scale:" + BATTERY_SCALE + " status:" + mBatteryStatus +
" health:" + mBatteryHealth + " present:" + mBatteryPresent +
diff --git a/telephony/java/com/android/internal/telephony/CommandsInterface.java b/telephony/java/com/android/internal/telephony/CommandsInterface.java
index 9e1e0c6..99217b3 100644
--- a/telephony/java/com/android/internal/telephony/CommandsInterface.java
+++ b/telephony/java/com/android/internal/telephony/CommandsInterface.java
@@ -1441,6 +1441,12 @@
void setCdmaSubscriptionSource(int cdmaSubscriptionType, Message response);
/**
+ * Requests to get the CDMA subscription srouce
+ * @param response is callback message
+ */
+ void getCdmaSubscriptionSource(Message response);
+
+ /**
* Set the TTY mode
*
* @param ttyMode one of the following:
diff --git a/telephony/java/com/android/internal/telephony/DataCallState.java b/telephony/java/com/android/internal/telephony/DataCallState.java
index fda1e47..a883e8e 100644
--- a/telephony/java/com/android/internal/telephony/DataCallState.java
+++ b/telephony/java/com/android/internal/telephony/DataCallState.java
@@ -17,11 +17,26 @@
package com.android.internal.telephony;
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+import android.net.NetworkUtils;
+import android.os.SystemProperties;
+import android.util.Log;
+
+import com.android.internal.telephony.DataConnection.FailCause;
+
+import java.net.Inet4Address;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
/**
* This is RIL_Data_Call_Response_v5 from ril.h
* TODO: Rename to DataCallResponse.
*/
public class DataCallState {
+ private final boolean DBG = true;
+ private final String LOG_TAG = "GSM";
+
public int version = 0;
public int status = 0;
public int cid = 0;
@@ -32,6 +47,29 @@
public String [] dnses = new String[0];
public String[] gateways = new String[0];
+ /**
+ * Class returned by onSetupConnectionCompleted.
+ */
+ protected enum SetupResult {
+ SUCCESS,
+ ERR_BadCommand,
+ ERR_UnacceptableParameter,
+ ERR_GetLastErrorFromRil,
+ ERR_Stale,
+ ERR_RilError;
+
+ public FailCause mFailCause;
+
+ SetupResult() {
+ mFailCause = FailCause.fromInt(0);
+ }
+
+ @Override
+ public String toString() {
+ return name() + " SetupResult.mFailCause=" + mFailCause;
+ }
+ }
+
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
@@ -63,4 +101,127 @@
sb.append("]}");
return sb.toString();
}
+
+ public SetupResult setLinkProperties(LinkProperties linkProperties,
+ boolean okToUseSystemPropertyDns) {
+ SetupResult result;
+
+ // Start with clean network properties and if we have
+ // a failure we'll clear again at the bottom of this code.
+ if (linkProperties == null)
+ linkProperties = new LinkProperties();
+ else
+ linkProperties.clear();
+
+ if (status == FailCause.NONE.getErrorCode()) {
+ String propertyPrefix = "net." + ifname + ".";
+
+ try {
+ // set interface name
+ linkProperties.setInterfaceName(ifname);
+
+ // set link addresses
+ if (addresses != null && addresses.length > 0) {
+ for (String addr : addresses) {
+ LinkAddress la;
+ int addrPrefixLen;
+
+ String [] ap = addr.split("/");
+ if (ap.length == 2) {
+ addr = ap[0];
+ addrPrefixLen = Integer.parseInt(ap[1]);
+ } else {
+ addrPrefixLen = 0;
+ }
+ InetAddress ia;
+ try {
+ ia = NetworkUtils.numericToInetAddress(addr);
+ } catch (IllegalArgumentException e) {
+ throw new UnknownHostException("Non-numeric ip addr=" + addr);
+ }
+ if (addrPrefixLen == 0) {
+ // Assume point to point
+ addrPrefixLen = (ia instanceof Inet4Address) ? 32 : 128;
+ }
+ if (DBG) Log.d(LOG_TAG, "addr/pl=" + addr + "/" + addrPrefixLen);
+ la = new LinkAddress(ia, addrPrefixLen);
+ linkProperties.addLinkAddress(la);
+ }
+ } else {
+ throw new UnknownHostException("no address for ifname=" + ifname);
+ }
+
+ // set dns servers
+ if (dnses != null && dnses.length > 0) {
+ for (String addr : dnses) {
+ InetAddress ia;
+ try {
+ ia = NetworkUtils.numericToInetAddress(addr);
+ } catch (IllegalArgumentException e) {
+ throw new UnknownHostException("Non-numeric dns addr=" + addr);
+ }
+ linkProperties.addDns(ia);
+ }
+ } else if (okToUseSystemPropertyDns){
+ String dnsServers[] = new String[2];
+ dnsServers[0] = SystemProperties.get(propertyPrefix + "dns1");
+ dnsServers[1] = SystemProperties.get(propertyPrefix + "dns2");
+ for (String dnsAddr : dnsServers) {
+ InetAddress ia;
+ try {
+ ia = NetworkUtils.numericToInetAddress(dnsAddr);
+ } catch (IllegalArgumentException e) {
+ throw new UnknownHostException("Non-numeric dns addr="
+ + dnsAddr);
+ }
+ linkProperties.addDns(ia);
+ }
+ } else {
+ throw new UnknownHostException("Empty dns response and no system default dns");
+ }
+
+ // set gateways
+ if ((gateways == null) || (gateways.length == 0)) {
+ String sysGateways = SystemProperties.get(propertyPrefix + "gw");
+ if (sysGateways != null) {
+ gateways = sysGateways.split(" ");
+ } else {
+ gateways = new String[0];
+ }
+ }
+ for (String addr : gateways) {
+ InetAddress ia;
+ try {
+ ia = NetworkUtils.numericToInetAddress(addr);
+ } catch (IllegalArgumentException e) {
+ throw new UnknownHostException("Non-numeric gateway addr=" + addr);
+ }
+ linkProperties.addGateway(ia);
+ }
+
+ result = SetupResult.SUCCESS;
+ } catch (UnknownHostException e) {
+ Log.d(LOG_TAG, "onSetupCompleted: UnknownHostException " + e);
+ e.printStackTrace();
+ result = SetupResult.ERR_UnacceptableParameter;
+ }
+ } else {
+ if (version < 4) {
+ result = SetupResult.ERR_GetLastErrorFromRil;
+ } else {
+ result = SetupResult.ERR_RilError;
+ }
+ }
+
+ // An error occurred so clear properties
+ if (result != SetupResult.SUCCESS) {
+ if(DBG) Log.d(LOG_TAG,
+ "onSetupConnectionCompleted with an error, clearing LinkProperties");
+ linkProperties.clear();
+ }
+
+ return result;
+ }
}
+
+
diff --git a/telephony/java/com/android/internal/telephony/DataConnection.java b/telephony/java/com/android/internal/telephony/DataConnection.java
index e21e951..aafe5ef 100644
--- a/telephony/java/com/android/internal/telephony/DataConnection.java
+++ b/telephony/java/com/android/internal/telephony/DataConnection.java
@@ -62,29 +62,6 @@
protected static int mCount;
/**
- * Class returned by onSetupConnectionCompleted.
- */
- protected enum SetupResult {
- SUCCESS,
- ERR_BadCommand,
- ERR_UnacceptableParameter,
- ERR_GetLastErrorFromRil,
- ERR_Stale,
- ERR_RilError;
-
- public FailCause mFailCause;
-
- SetupResult() {
- mFailCause = FailCause.fromInt(0);
- }
-
- @Override
- public String toString() {
- return name() + " SetupResult.mFailCause=" + mFailCause;
- }
- }
-
- /**
* Used internally for saving connecting parameters.
*/
protected static class ConnectionParams {
@@ -445,10 +422,10 @@
* @param ar is the result
* @return SetupResult.
*/
- private SetupResult onSetupConnectionCompleted(AsyncResult ar) {
+ private DataCallState.SetupResult onSetupConnectionCompleted(AsyncResult ar) {
DataCallState response = (DataCallState) ar.result;
ConnectionParams cp = (ConnectionParams) ar.userObj;
- SetupResult result;
+ DataCallState.SetupResult result;
if (ar.exception != null) {
if (DBG) {
@@ -459,148 +436,35 @@
if (ar.exception instanceof CommandException
&& ((CommandException) (ar.exception)).getCommandError()
== CommandException.Error.RADIO_NOT_AVAILABLE) {
- result = SetupResult.ERR_BadCommand;
+ result = DataCallState.SetupResult.ERR_BadCommand;
result.mFailCause = FailCause.RADIO_NOT_AVAILABLE;
} else if ((response == null) || (response.version < 4)) {
- result = SetupResult.ERR_GetLastErrorFromRil;
+ result = DataCallState.SetupResult.ERR_GetLastErrorFromRil;
} else {
- result = SetupResult.ERR_RilError;
+ result = DataCallState.SetupResult.ERR_RilError;
result.mFailCause = FailCause.fromInt(response.status);
}
} else if (cp.tag != mTag) {
if (DBG) {
log("BUG: onSetupConnectionCompleted is stale cp.tag=" + cp.tag + ", mtag=" + mTag);
}
- result = SetupResult.ERR_Stale;
+ result = DataCallState.SetupResult.ERR_Stale;
} else {
log("onSetupConnectionCompleted received DataCallState: " + response);
- // Start with clean network properties and if we have
- // a failure we'll clear again at the bottom of this code.
- LinkProperties linkProperties = new LinkProperties();
- if (response.status == FailCause.NONE.getErrorCode()) {
- String propertyPrefix = "net." + response.ifname + ".";
+ // Check if system property dns usable
+ boolean okToUseSystemPropertyDns = false;
+ String propertyPrefix = "net." + response.ifname + ".";
+ String dnsServers[] = new String[2];
+ dnsServers[0] = SystemProperties.get(propertyPrefix + "dns1");
+ dnsServers[1] = SystemProperties.get(propertyPrefix + "dns2");
+ okToUseSystemPropertyDns = isDnsOk(dnsServers);
- try {
- cid = response.cid;
- linkProperties.setInterfaceName(response.ifname);
- if (response.addresses != null && response.addresses.length > 0) {
- for (String addr : response.addresses) {
- LinkAddress la;
- int addrPrefixLen;
-
- String [] ap = addr.split("/");
- if (ap.length == 2) {
- addr = ap[0];
- addrPrefixLen = Integer.parseInt(ap[1]);
- } else {
- addrPrefixLen = 0;
- }
- InetAddress ia;
- try {
- ia = NetworkUtils.numericToInetAddress(addr);
- } catch (IllegalArgumentException e) {
- EventLogTags.writeBadIpAddress(addr);
- throw new UnknownHostException("Non-numeric ip addr=" + addr);
- }
- if (addrPrefixLen == 0) {
- // Assume point to point
- addrPrefixLen = (ia instanceof Inet4Address) ? 32 : 128;
- }
- if (DBG) log("addr/pl=" + addr + "/" + addrPrefixLen);
- la = new LinkAddress(ia, addrPrefixLen);
- linkProperties.addLinkAddress(la);
- }
- } else {
- EventLogTags.writeBadIpAddress("no address for ifname=" + response.ifname);
- throw new UnknownHostException("no address for ifname=" + response.ifname);
- }
- if (response.dnses != null && response.dnses.length > 0) {
- for (String addr : response.dnses) {
- InetAddress ia;
- try {
- ia = NetworkUtils.numericToInetAddress(addr);
- } catch (IllegalArgumentException e) {
- EventLogTags.writePdpBadDnsAddress("dns=" + addr);
- throw new UnknownHostException("Non-numeric dns addr=" + addr);
- }
- linkProperties.addDns(ia);
- }
- result = SetupResult.SUCCESS;
- } else {
- String dnsServers[] = new String[2];
- dnsServers[0] = SystemProperties.get(propertyPrefix + "dns1");
- dnsServers[1] = SystemProperties.get(propertyPrefix + "dns2");
- if (isDnsOk(dnsServers)) {
- for (String dnsAddr : dnsServers) {
- InetAddress ia;
- try {
- ia = NetworkUtils.numericToInetAddress(dnsAddr);
- } catch (IllegalArgumentException e) {
- EventLogTags.writePdpBadDnsAddress("dnsAddr=" + dnsAddr);
- throw new UnknownHostException("Non-numeric dns addr="
- + dnsAddr);
- }
- linkProperties.addDns(ia);
- }
- result = SetupResult.SUCCESS;
- } else {
- StringBuilder sb = new StringBuilder();
- for (String dnsAddr : dnsServers) {
- sb.append(dnsAddr);
- sb.append(" ");
- }
- EventLogTags.writePdpBadDnsAddress("Unacceptable dns addresses=" + sb);
- throw new UnknownHostException("Unacceptable dns addresses=" + sb);
- }
- }
- if ((response.gateways == null) || (response.gateways.length == 0)) {
- String gateways = SystemProperties.get(propertyPrefix + "gw");
- if (gateways != null) {
- response.gateways = gateways.split(" ");
- } else {
- response.gateways = new String[0];
- }
- }
- for (String addr : response.gateways) {
- InetAddress ia;
- try {
- ia = NetworkUtils.numericToInetAddress(addr);
- } catch (IllegalArgumentException e) {
- EventLogTags.writePdpBadDnsAddress("gateway=" + addr);
- throw new UnknownHostException("Non-numeric gateway addr=" + addr);
- }
- linkProperties.addGateway(ia);
- }
- result = SetupResult.SUCCESS;
- } catch (UnknownHostException e) {
- log("onSetupCompleted: UnknownHostException " + e);
- e.printStackTrace();
- result = SetupResult.ERR_UnacceptableParameter;
- }
- } else {
- if (response.version < 4) {
- result = SetupResult.ERR_GetLastErrorFromRil;
- } else {
- result = SetupResult.ERR_RilError;
- }
- }
-
- // An error occurred so clear properties
- if (result != SetupResult.SUCCESS) {
- log("onSetupConnectionCompleted with an error, clearing LinkProperties");
- linkProperties.clear();
- }
- mLinkProperties = linkProperties;
+ // set link properties based on data call response
+ result = response.setLinkProperties(mLinkProperties,
+ okToUseSystemPropertyDns);
}
- if (DBG) {
- log("onSetupConnectionCompleted: DataConnection setup result='"
- + result + "' on cid=" + cid);
- if (result == SetupResult.SUCCESS) {
- log("onSetupConnectionCompleted: LinkProperties: " + mLinkProperties.toString());
- }
- }
return result;
}
@@ -746,7 +610,7 @@
ar = (AsyncResult) msg.obj;
cp = (ConnectionParams) ar.userObj;
- SetupResult result = onSetupConnectionCompleted(ar);
+ DataCallState.SetupResult result = onSetupConnectionCompleted(ar);
if (DBG) log("DcActivatingState onSetupConnectionCompleted result=" + result);
switch (result) {
case SUCCESS:
@@ -780,7 +644,7 @@
// Request is stale, ignore.
break;
default:
- throw new RuntimeException("Unkown SetupResult, should not happen");
+ throw new RuntimeException("Unknown SetupResult, should not happen");
}
retVal = true;
break;
diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java
index 1d47405..b0a265b 100644
--- a/telephony/java/com/android/internal/telephony/RIL.java
+++ b/telephony/java/com/android/internal/telephony/RIL.java
@@ -3634,12 +3634,12 @@
/**
* {@inheritDoc}
*/
- public void getCdmaSubscriptionSource(int cdmaSubscription , Message response) {
+ @Override
+ public void getCdmaSubscriptionSource(Message response) {
RILRequest rr = RILRequest.obtain(
RILConstants.RIL_REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE, response);
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
- + " : " + cdmaSubscription);
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
send(rr);
}
diff --git a/telephony/java/com/android/internal/telephony/sip/SipCommandInterface.java b/telephony/java/com/android/internal/telephony/sip/SipCommandInterface.java
index f2ece7f..5208ccd 100644
--- a/telephony/java/com/android/internal/telephony/sip/SipCommandInterface.java
+++ b/telephony/java/com/android/internal/telephony/sip/SipCommandInterface.java
@@ -326,6 +326,10 @@
public void reportStkServiceIsRunning(Message result) {
}
+ @Override
+ public void getCdmaSubscriptionSource(Message response) {
+ }
+
public void getGsmBroadcastConfig(Message response) {
}
diff --git a/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java b/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java
index d9bd7e8..80de9f3 100644
--- a/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java
+++ b/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java
@@ -1001,6 +1001,11 @@
resultSuccess(result, null);
}
+ @Override
+ public void getCdmaSubscriptionSource(Message result) {
+ unimplemented(result);
+ }
+
private boolean isSimLocked() {
if (mSimLockedState != SimLockState.NONE) {
return true;