diff options
54 files changed, 2180 insertions, 646 deletions
diff --git a/api/current.xml b/api/current.xml index 2d7c02e2a048..8549080621dc 100644 --- a/api/current.xml +++ b/api/current.xml @@ -51424,7 +51424,7 @@ <parameter name="key" type="java.lang.String"> </parameter> </method> -<method name="startCommit" +<method name="apply" return="void" abstract="true" native="false" @@ -186729,14 +186729,19 @@ deprecated="not deprecated" visibility="public" > -<constructor name="InputDevice" - type="android.view.InputDevice" +<implements name="android.os.Parcelable"> +</implements> +<method name="describeContents" + return="int" + abstract="false" + native="false" + synchronized="false" static="false" final="false" deprecated="not deprecated" visibility="public" > -</constructor> +</method> <method name="getDevice" return="android.view.InputDevice" abstract="false" @@ -186750,6 +186755,28 @@ <parameter name="id" type="int"> </parameter> </method> +<method name="getDeviceIds" + return="int[]" + abstract="false" + native="false" + synchronized="false" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="getId" + return="int" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> <method name="getKeyCharacterMap" return="android.view.KeyCharacterMap" abstract="false" @@ -186782,7 +186809,7 @@ deprecated="not deprecated" visibility="public" > -<parameter name="range" type="int"> +<parameter name="rangeType" type="int"> </parameter> </method> <method name="getName" @@ -186807,8 +186834,8 @@ visibility="public" > </method> -<method name="hasKey" - return="boolean" +<method name="writeToParcel" + return="void" abstract="false" native="false" synchronized="false" @@ -186817,9 +186844,21 @@ deprecated="not deprecated" visibility="public" > -<parameter name="keyCode" type="int"> +<parameter name="out" type="android.os.Parcel"> +</parameter> +<parameter name="flags" type="int"> </parameter> </method> +<field name="CREATOR" + type="android.os.Parcelable.Creator" + transient="false" + volatile="false" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="KEYBOARD_TYPE_ALPHABETIC" type="int" transient="false" @@ -187148,14 +187187,6 @@ deprecated="not deprecated" visibility="public" > -<constructor name="InputDevice.MotionRange" - type="android.view.InputDevice.MotionRange" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</constructor> <method name="getFlat" return="float" abstract="false" diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 775c9f2ab99d..00d769f9a85f 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -124,7 +124,6 @@ import java.util.Set; import java.util.WeakHashMap; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; -import java.util.concurrent.atomic.AtomicBoolean; class ReceiverRestrictedContext extends ContextWrapper { ReceiverRestrictedContext(Context base) { @@ -2852,8 +2851,6 @@ class ContextImpl extends Context { private final Map<String, Object> mModified = Maps.newHashMap(); private boolean mClear = false; - private AtomicBoolean mCommitInFlight = new AtomicBoolean(false); - public Editor putString(String key, String value) { synchronized (this) { mModified.put(key, value); @@ -2905,11 +2902,7 @@ class ContextImpl extends Context { } } - public void startCommit() { - if (!mCommitInFlight.compareAndSet(false, true)) { - throw new IllegalStateException("can't call startCommit() twice"); - } - + public void apply() { final MemoryCommitResult mcr = commitToMemory(); final Runnable awaitCommit = new Runnable() { public void run() { @@ -2925,7 +2918,6 @@ class ContextImpl extends Context { Runnable postWriteRunnable = new Runnable() { public void run() { awaitCommit.run(); - mCommitInFlight.set(false); QueuedWork.remove(awaitCommit); } }; @@ -3049,13 +3041,13 @@ class ContextImpl extends Context { * that they're enqueued. * * @param postWriteRunnable if non-null, we're being called - * from startCommit() and this is the runnable to run after + * from apply() and this is the runnable to run after * the write proceeds. if null (from a regular commit()), * then we're allowed to do this disk write on the main * thread (which in addition to reducing allocations and * creating a background thread, this has the advantage that * we catch them in userdebug StrictMode reports to convert - * them where possible to startCommit...) + * them where possible to apply() ...) */ private void enqueueDiskWrite(final MemoryCommitResult mcr, final Runnable postWriteRunnable) { diff --git a/core/java/android/content/SharedPreferences.java b/core/java/android/content/SharedPreferences.java index 23ed62c0aaf0..c0788f53dd2a 100644 --- a/core/java/android/content/SharedPreferences.java +++ b/core/java/android/content/SharedPreferences.java @@ -55,13 +55,13 @@ public interface SharedPreferences { /** * Interface used for modifying values in a {@link SharedPreferences} * object. All changes you make in an editor are batched, and not copied - * back to the original {@link SharedPreferences} or persistent storage - * until you call {@link #commit}. + * back to the original {@link SharedPreferences} until you call {@link #commit} + * or {@link #apply} */ public interface Editor { /** * Set a String value in the preferences editor, to be written back once - * {@link #commit} is called. + * {@link #commit} or {@link #apply} are called. * * @param key The name of the preference to modify. * @param value The new value for the preference. @@ -84,7 +84,7 @@ public interface SharedPreferences { /** * Set an int value in the preferences editor, to be written back once - * {@link #commit} is called. + * {@link #commit} or {@link #apply} are called. * * @param key The name of the preference to modify. * @param value The new value for the preference. @@ -96,7 +96,7 @@ public interface SharedPreferences { /** * Set a long value in the preferences editor, to be written back once - * {@link #commit} is called. + * {@link #commit} or {@link #apply} are called. * * @param key The name of the preference to modify. * @param value The new value for the preference. @@ -108,7 +108,7 @@ public interface SharedPreferences { /** * Set a float value in the preferences editor, to be written back once - * {@link #commit} is called. + * {@link #commit} or {@link #apply} are called. * * @param key The name of the preference to modify. * @param value The new value for the preference. @@ -120,7 +120,7 @@ public interface SharedPreferences { /** * Set a boolean value in the preferences editor, to be written back - * once {@link #commit} is called. + * once {@link #commit} or {@link #apply} are called. * * @param key The name of the preference to modify. * @param value The new value for the preference. @@ -171,7 +171,7 @@ public interface SharedPreferences { * * <p>If you don't care about the return value and you're * using this from your application's main thread, consider - * using {@link #startCommit} instead. + * using {@link #apply} instead. * * @return Returns true if the new values were successfully written * to persistent storage. @@ -185,16 +185,16 @@ public interface SharedPreferences { * in the SharedPreferences. * * <p>Note that when two editors are modifying preferences at the same - * time, the last one to call commit wins. + * time, the last one to call apply wins. * * <p>Unlike {@link #commit}, which writes its preferences out - * to persistent storage synchronously, {@link #startCommit} + * to persistent storage synchronously, {@link #apply} * commits its changes to the in-memory * {@link SharedPreferences} immediately but starts an * asynchronous commit to disk and you won't be notified of * any failures. If another editor on this * {@link SharedPreferences} does a regular {@link #commit} - * while a {@link #startCommit} is still outstanding, the + * while a {@link #apply} is still outstanding, the * {@link #commit} will block until all async commits are * completed as well as the commit itself. * @@ -202,7 +202,7 @@ public interface SharedPreferences { * the base class will wait for any async commits to finish in * its {@link android.app.Activity#onPause}.</p> */ - void startCommit(); + void apply(); } /** diff --git a/core/java/android/net/NetworkProperties.aidl b/core/java/android/net/LinkProperties.aidl index 07aac6ec101f..73c798804146 100644 --- a/core/java/android/net/NetworkProperties.aidl +++ b/core/java/android/net/LinkProperties.aidl @@ -18,5 +18,5 @@ package android.net; -parcelable NetworkProperties; +parcelable LinkProperties; diff --git a/core/java/android/net/NetworkProperties.java b/core/java/android/net/LinkProperties.java index 03c0a2eb5e85..24aebfcd2feb 100644 --- a/core/java/android/net/NetworkProperties.java +++ b/core/java/android/net/LinkProperties.java @@ -16,6 +16,7 @@ package android.net; +import android.net.ProxyProperties; import android.os.Parcelable; import android.os.Parcel; import android.util.Log; @@ -26,14 +27,14 @@ import java.net.SocketException; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; /** - * Describes the properties of a network interface or single address - * of an interface. + * Describes the properties of a network link. * TODO - consider adding optional fields like Apn and ApnType * @hide */ -public class NetworkProperties implements Parcelable { +public class LinkProperties implements Parcelable { private NetworkInterface mIface; private Collection<InetAddress> mAddresses; @@ -41,49 +42,60 @@ public class NetworkProperties implements Parcelable { private InetAddress mGateway; private ProxyProperties mHttpProxy; - public NetworkProperties() { + public LinkProperties() { clear(); } - public synchronized void setInterface(NetworkInterface iface) { + // copy constructor instead of clone + public LinkProperties(LinkProperties source) { + if (source != null) { + mIface = source.getInterface(); + mAddresses = source.getAddresses(); + mDnses = source.getDnses(); + mGateway = source.getGateway(); + mHttpProxy = new ProxyProperties(source.getHttpProxy()); + } + } + + public void setInterface(NetworkInterface iface) { mIface = iface; } - public synchronized NetworkInterface getInterface() { + public NetworkInterface getInterface() { return mIface; } - public synchronized String getInterfaceName() { + public String getInterfaceName() { return (mIface == null ? null : mIface.getName()); } - public synchronized void addAddress(InetAddress address) { + public void addAddress(InetAddress address) { mAddresses.add(address); } - public synchronized Collection<InetAddress> getAddresses() { - return mAddresses; + public Collection<InetAddress> getAddresses() { + return Collections.unmodifiableCollection(mAddresses); } - public synchronized void addDns(InetAddress dns) { + public void addDns(InetAddress dns) { mDnses.add(dns); } - public synchronized Collection<InetAddress> getDnses() { - return mDnses; + public Collection<InetAddress> getDnses() { + return Collections.unmodifiableCollection(mDnses); } - public synchronized void setGateway(InetAddress gateway) { + public void setGateway(InetAddress gateway) { mGateway = gateway; } - public synchronized InetAddress getGateway() { + public InetAddress getGateway() { return mGateway; } - public synchronized void setHttpProxy(ProxyProperties proxy) { + public void setHttpProxy(ProxyProperties proxy) { mHttpProxy = proxy; } - public synchronized ProxyProperties getHttpProxy() { + public ProxyProperties getHttpProxy() { return mHttpProxy; } - public synchronized void clear() { + public void clear() { mIface = null; mAddresses = new ArrayList<InetAddress>(); mDnses = new ArrayList<InetAddress>(); @@ -100,7 +112,7 @@ public class NetworkProperties implements Parcelable { } @Override - public synchronized String toString() { + public String toString() { String ifaceName = (mIface == null ? "" : "InterfaceName: " + mIface.getName() + " "); String ip = "IpAddresses: ["; @@ -121,7 +133,7 @@ public class NetworkProperties implements Parcelable { * Implement the Parcelable interface. * @hide */ - public synchronized void writeToParcel(Parcel dest, int flags) { + public void writeToParcel(Parcel dest, int flags) { dest.writeString(getInterfaceName()); dest.writeInt(mAddresses.size()); //TODO: explore an easy alternative to preserve hostname @@ -151,10 +163,10 @@ public class NetworkProperties implements Parcelable { * Implement the Parcelable interface. * @hide */ - public static final Creator<NetworkProperties> CREATOR = - new Creator<NetworkProperties>() { - public NetworkProperties createFromParcel(Parcel in) { - NetworkProperties netProp = new NetworkProperties(); + public static final Creator<LinkProperties> CREATOR = + new Creator<LinkProperties>() { + public LinkProperties createFromParcel(Parcel in) { + LinkProperties netProp = new LinkProperties(); String iface = in.readString(); if (iface != null) { try { @@ -186,8 +198,8 @@ public class NetworkProperties implements Parcelable { return netProp; } - public NetworkProperties[] newArray(int size) { - return new NetworkProperties[size]; + public LinkProperties[] newArray(int size) { + return new LinkProperties[size]; } }; } diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java index 6dfd3bc8aad1..0498fff41733 100644 --- a/core/java/android/net/MobileDataStateTracker.java +++ b/core/java/android/net/MobileDataStateTracker.java @@ -16,8 +16,6 @@ package android.net; -import java.net.InetAddress; - import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -32,7 +30,7 @@ import com.android.internal.telephony.Phone; import com.android.internal.telephony.TelephonyIntents; import android.net.NetworkInfo.DetailedState; import android.net.NetworkInfo; -import android.net.NetworkProperties; +import android.net.LinkProperties; import android.telephony.TelephonyManager; import android.util.Log; import android.text.TextUtils; @@ -58,7 +56,7 @@ public class MobileDataStateTracker implements NetworkStateTracker { private boolean mTeardownRequested = false; private Handler mTarget; private Context mContext; - private NetworkProperties mNetworkProperties; + private LinkProperties mLinkProperties; private boolean mPrivateDnsRouteSet = false; private int mDefaultGatewayAddr = 0; private boolean mDefaultRouteSet = false; @@ -213,8 +211,8 @@ public class MobileDataStateTracker implements NetworkStateTracker { + e); } } - if (doReset && mNetworkProperties != null) { - String iface = mNetworkProperties.getInterfaceName(); + if (doReset && mLinkProperties != null) { + String iface = mLinkProperties.getInterfaceName(); if (iface != null) NetworkUtils.resetConnections(iface); } // TODO - check this @@ -233,11 +231,11 @@ public class MobileDataStateTracker implements NetworkStateTracker { setDetailedState(DetailedState.SUSPENDED, reason, apnName); break; case CONNECTED: - mNetworkProperties = intent.getParcelableExtra( - Phone.DATA_NETWORK_PROPERTIES_KEY); - if (mNetworkProperties == null) { + mLinkProperties = intent.getParcelableExtra( + Phone.DATA_LINK_PROPERTIES_KEY); + if (mLinkProperties == null) { Log.d(TAG, - "CONNECTED event did not supply network properties."); + "CONNECTED event did not supply link properties."); } setDetailedState(DetailedState.CONNECTED, reason, apnName); break; @@ -563,7 +561,7 @@ public class MobileDataStateTracker implements NetworkStateTracker { } } - public NetworkProperties getNetworkProperties() { - return mNetworkProperties; + public LinkProperties getLinkProperties() { + return new LinkProperties(mLinkProperties); } } diff --git a/core/java/android/net/NetworkStateTracker.java b/core/java/android/net/NetworkStateTracker.java index 0048a2e88193..420992b3bf16 100644 --- a/core/java/android/net/NetworkStateTracker.java +++ b/core/java/android/net/NetworkStateTracker.java @@ -91,9 +91,9 @@ public interface NetworkStateTracker { public NetworkInfo getNetworkInfo(); /** - * Fetch NetworkProperties for the network + * Fetch LinkProperties for the network */ - public NetworkProperties getNetworkProperties(); + public LinkProperties getLinkProperties(); /** * Return the system properties name associated with the tcp buffer sizes diff --git a/core/java/android/net/ProxyProperties.java b/core/java/android/net/ProxyProperties.java index 207fb5134a85..ba27221ed134 100644 --- a/core/java/android/net/ProxyProperties.java +++ b/core/java/android/net/ProxyProperties.java @@ -36,24 +36,33 @@ public class ProxyProperties implements Parcelable { public ProxyProperties() { } - public synchronized InetAddress getAddress() { + // copy constructor instead of clone + public ProxyProperties(ProxyProperties source) { + if (source != null) { + mProxy = source.getAddress(); + mPort = source.getPort(); + mExclusionList = new String(source.getExclusionList()); + } + } + + public InetAddress getAddress() { return mProxy; } - public synchronized void setAddress(InetAddress proxy) { + public void setAddress(InetAddress proxy) { mProxy = proxy; } - public synchronized int getPort() { + public int getPort() { return mPort; } - public synchronized void setPort(int port) { + public void setPort(int port) { mPort = port; } - public synchronized String getExclusionList() { + public String getExclusionList() { return mExclusionList; } - public synchronized void setExclusionList(String exclusionList) { + public void setExclusionList(String exclusionList) { mExclusionList = exclusionList; } @@ -77,7 +86,7 @@ public class ProxyProperties implements Parcelable { * Implement the Parcelable interface. * @hide */ - public synchronized void writeToParcel(Parcel dest, int flags) { + public void writeToParcel(Parcel dest, int flags) { if (mProxy != null) { dest.writeByte((byte)1); dest.writeString(mProxy.getHostName()); diff --git a/core/java/android/preference/Preference.java b/core/java/android/preference/Preference.java index 418fe1015cd4..17b2e82d09f9 100644 --- a/core/java/android/preference/Preference.java +++ b/core/java/android/preference/Preference.java @@ -1242,7 +1242,7 @@ public class Preference implements Comparable<Preference>, OnDependencyChangeLis private void tryCommit(SharedPreferences.Editor editor) { if (mPreferenceManager.shouldCommit()) { - editor.startCommit(); + editor.apply(); } } diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java index d52632b98542..bf051f58a286 100644 --- a/core/java/android/provider/CallLog.java +++ b/core/java/android/provider/CallLog.java @@ -88,6 +88,17 @@ public class CallLog { public static final String NUMBER = "number"; /** + * The ISO 3166-1 two letters country code of the country where the + * user received or made the call. + * <P> + * Type: TEXT + * </P> + * + * @hide + */ + public static final String COUNTRY_ISO = "countryiso"; + + /** * The date the call occured, in milliseconds since the epoch * <P>Type: INTEGER (long)</P> */ diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java index b87e0ec0116d..9f9a4d462e2e 100644 --- a/core/java/android/provider/ContactsContract.java +++ b/core/java/android/provider/ContactsContract.java @@ -3301,6 +3301,14 @@ public final class ContactsContract { * <P>Type: TEXT</P> */ public static final String LABEL = "label"; + + /** + * The phone number's E164 representation. + * <P>Type: TEXT</P> + * + * @hide + */ + public static final String NORMALIZED_NUMBER = "normalized_number"; } /** @@ -4153,6 +4161,14 @@ public final class ContactsContract { public static final String NUMBER = DATA; /** + * The phone number's E164 representation. + * <P>Type: TEXT</P> + * + * @hide + */ + public static final String NORMALIZED_NUMBER = DATA4; + + /** * @deprecated use {@link #getTypeLabel(Resources, int, CharSequence)} instead. * @hide */ diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java index b732675c6c13..fa5f156eefe7 100644 --- a/core/java/android/server/BluetoothService.java +++ b/core/java/android/server/BluetoothService.java @@ -2138,7 +2138,7 @@ public class BluetoothService extends IBluetooth.Stub { mContext.getSharedPreferences(SHARED_PREFERENCES_NAME, mContext.MODE_PRIVATE).edit(); editor.putBoolean(SHARED_PREFERENCE_DOCK_ADDRESS + mDockAddress, true); - editor.startCommit(); + editor.apply(); } } } diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index e86e3bf3bcba..d4dd05c19adc 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -29,6 +29,7 @@ import android.view.KeyEvent; import android.view.InputEvent; import android.view.MotionEvent; import android.view.InputChannel; +import android.view.InputDevice; /** * System private interface to the window manager. @@ -125,6 +126,10 @@ interface IWindowManager // Report whether the hardware supports the given keys; returns true if successful boolean hasKeys(in int[] keycodes, inout boolean[] keyExists); + // Get input device information. + InputDevice getInputDevice(int deviceId); + int[] getInputDeviceIds(); + // For testing void setInTouchMode(boolean showFocus); diff --git a/core/java/android/view/InputDevice.aidl b/core/java/android/view/InputDevice.aidl new file mode 100644 index 000000000000..dbc40c131642 --- /dev/null +++ b/core/java/android/view/InputDevice.aidl @@ -0,0 +1,20 @@ +/* //device/java/android/android.view.InputDevice.aidl +** +** Copyright 2007, 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.view; + +parcelable InputDevice; diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java index d5b2121ea3dd..fb47b9c7b7f3 100755 --- a/core/java/android/view/InputDevice.java +++ b/core/java/android/view/InputDevice.java @@ -16,6 +16,12 @@ package android.view; +import android.os.Parcel; +import android.os.Parcelable; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.util.Log; + /** * Describes the capabilities of a particular input device. * <p> @@ -32,12 +38,14 @@ package android.view; * the appropriate interpretation. * </p> */ -public final class InputDevice { +public final class InputDevice implements Parcelable { private int mId; private String mName; private int mSources; private int mKeyboardType; + private MotionRange[] mMotionRanges; + /** * A mask for input source classes. * @@ -246,6 +254,8 @@ public final class InputDevice { */ public static final int MOTION_RANGE_ORIENTATION = 8; + private static final int MOTION_RANGE_LAST = MOTION_RANGE_ORIENTATION; + /** * There is no keyboard. */ @@ -261,6 +271,11 @@ public final class InputDevice { * The keyboard supports a complement of alphabetic keys. */ public static final int KEYBOARD_TYPE_ALPHABETIC = 2; + + // Called by native code. + private InputDevice() { + mMotionRanges = new MotionRange[MOTION_RANGE_LAST + 1]; + } /** * Gets information about the input device with the specified id. @@ -268,8 +283,35 @@ public final class InputDevice { * @return The input device or null if not found. */ public static InputDevice getDevice(int id) { - // TODO - return null; + IWindowManager wm = IWindowManager.Stub.asInterface(ServiceManager.getService("window")); + try { + return wm.getInputDevice(id); + } catch (RemoteException ex) { + throw new RuntimeException( + "Could not get input device information from Window Manager.", ex); + } + } + + /** + * Gets the ids of all input devices in the system. + * @return The input device ids. + */ + public static int[] getDeviceIds() { + IWindowManager wm = IWindowManager.Stub.asInterface(ServiceManager.getService("window")); + try { + return wm.getInputDeviceIds(); + } catch (RemoteException ex) { + throw new RuntimeException( + "Could not get input device ids from Window Manager.", ex); + } + } + + /** + * Gets the input device id. + * @return The input device id. + */ + public int getId() { + return mId; } /** @@ -307,23 +349,23 @@ public final class InputDevice { /** * Gets information about the range of values for a particular {@link MotionEvent} * coordinate. - * @param range The motion range constant. + * @param rangeType The motion range constant. * @return The range of values, or null if the requested coordinate is not * supported by the device. */ - public MotionRange getMotionRange(int range) { - // TODO - return null; + public MotionRange getMotionRange(int rangeType) { + if (rangeType < 0 || rangeType > MOTION_RANGE_LAST) { + throw new IllegalArgumentException("Requested range is out of bounds."); + } + + return mMotionRanges[rangeType]; } - /** - * Returns true if the device supports a particular button or key. - * @param keyCode The key code. - * @return True if the device supports the key. - */ - public boolean hasKey(int keyCode) { - // TODO - return false; + private void addMotionRange(int rangeType, float min, float max, float flat, float fuzz) { + if (rangeType >= 0 && rangeType <= MOTION_RANGE_LAST) { + MotionRange range = new MotionRange(min, max, flat, fuzz); + mMotionRanges[rangeType] = range; + } } /** @@ -331,13 +373,24 @@ public final class InputDevice { * coordinate. */ public static final class MotionRange { + private float mMin; + private float mMax; + private float mFlat; + private float mFuzz; + + private MotionRange(float min, float max, float flat, float fuzz) { + mMin = min; + mMax = max; + mFlat = flat; + mFuzz = fuzz; + } + /** * Gets the minimum value for the coordinate. * @return The minimum value. */ public float getMin() { - // TODO - return 0; + return mMin; } /** @@ -345,8 +398,7 @@ public final class InputDevice { * @return The minimum value. */ public float getMax() { - // TODO - return 0; + return mMax; } /** @@ -354,8 +406,7 @@ public final class InputDevice { * @return The range of values. */ public float getRange() { - // TODO - return 0; + return mMax - mMin; } /** @@ -365,8 +416,7 @@ public final class InputDevice { * @return The extent of the center flat position. */ public float getFlat() { - // TODO - return 0; + return mFlat; } /** @@ -376,8 +426,127 @@ public final class InputDevice { * @return The error tolerance. */ public float getFuzz() { - // TODO - return 0; + return mFuzz; + } + } + + public static final Parcelable.Creator<InputDevice> CREATOR + = new Parcelable.Creator<InputDevice>() { + public InputDevice createFromParcel(Parcel in) { + InputDevice result = new InputDevice(); + result.readFromParcel(in); + return result; + } + + public InputDevice[] newArray(int size) { + return new InputDevice[size]; + } + }; + + private void readFromParcel(Parcel in) { + mId = in.readInt(); + mName = in.readString(); + mSources = in.readInt(); + mKeyboardType = in.readInt(); + + for (;;) { + int rangeType = in.readInt(); + if (rangeType < 0) { + break; + } + + addMotionRange(rangeType, + in.readFloat(), in.readFloat(), in.readFloat(), in.readFloat()); + } + } + + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeInt(mId); + out.writeString(mName); + out.writeInt(mSources); + out.writeInt(mKeyboardType); + + for (int i = 0; i <= MOTION_RANGE_LAST; i++) { + MotionRange range = mMotionRanges[i]; + if (range != null) { + out.writeInt(i); + out.writeFloat(range.mMin); + out.writeFloat(range.mMax); + out.writeFloat(range.mFlat); + out.writeFloat(range.mFuzz); + } + } + out.writeInt(-1); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public String toString() { + StringBuilder description = new StringBuilder(); + description.append("Input Device ").append(mId).append(": ").append(mName).append("\n"); + + description.append(" Keyboard Type: "); + switch (mKeyboardType) { + case KEYBOARD_TYPE_NONE: + description.append("none"); + break; + case KEYBOARD_TYPE_NON_ALPHABETIC: + description.append("non-alphabetic"); + break; + case KEYBOARD_TYPE_ALPHABETIC: + description.append("alphabetic"); + break; + } + description.append("\n"); + + description.append(" Sources:"); + appendSourceDescriptionIfApplicable(description, SOURCE_KEYBOARD, "keyboard"); + appendSourceDescriptionIfApplicable(description, SOURCE_DPAD, "dpad"); + appendSourceDescriptionIfApplicable(description, SOURCE_GAMEPAD, "gamepad"); + appendSourceDescriptionIfApplicable(description, SOURCE_TOUCHSCREEN, "touchscreen"); + appendSourceDescriptionIfApplicable(description, SOURCE_MOUSE, "mouse"); + appendSourceDescriptionIfApplicable(description, SOURCE_TRACKBALL, "trackball"); + appendSourceDescriptionIfApplicable(description, SOURCE_TOUCHPAD, "touchpad"); + appendSourceDescriptionIfApplicable(description, SOURCE_JOYSTICK_LEFT, "joystick_left"); + appendSourceDescriptionIfApplicable(description, SOURCE_JOYSTICK_RIGHT, "joystick_right"); + description.append("\n"); + + appendRangeDescriptionIfApplicable(description, MOTION_RANGE_X, "x"); + appendRangeDescriptionIfApplicable(description, MOTION_RANGE_Y, "y"); + appendRangeDescriptionIfApplicable(description, MOTION_RANGE_PRESSURE, "pressure"); + appendRangeDescriptionIfApplicable(description, MOTION_RANGE_SIZE, "size"); + appendRangeDescriptionIfApplicable(description, MOTION_RANGE_TOUCH_MAJOR, "touchMajor"); + appendRangeDescriptionIfApplicable(description, MOTION_RANGE_TOUCH_MINOR, "touchMinor"); + appendRangeDescriptionIfApplicable(description, MOTION_RANGE_TOOL_MAJOR, "toolMajor"); + appendRangeDescriptionIfApplicable(description, MOTION_RANGE_TOOL_MINOR, "toolMinor"); + appendRangeDescriptionIfApplicable(description, MOTION_RANGE_ORIENTATION, "orientation"); + + return description.toString(); + } + + private void appendSourceDescriptionIfApplicable(StringBuilder description, int source, + String sourceName) { + if ((mSources & source) == source) { + description.append(" "); + description.append(sourceName); + } + } + + private void appendRangeDescriptionIfApplicable(StringBuilder description, + int rangeType, String rangeName) { + MotionRange range = mMotionRanges[rangeType]; + if (range != null) { + description.append(" Range[").append(rangeName); + description.append("]: min=").append(range.mMin); + description.append(" max=").append(range.mMax); + description.append(" flat=").append(range.mFlat); + description.append(" fuzz=").append(range.mFuzz); + description.append("\n"); } } } diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java index e20fee5b38d4..ab7542079a90 100644 --- a/core/java/android/widget/AdapterView.java +++ b/core/java/android/widget/AdapterView.java @@ -808,7 +808,6 @@ public abstract class AdapterView<T extends Adapter> extends ViewGroup { mNextSelectedPosition = INVALID_POSITION; mNextSelectedRowId = INVALID_ROW_ID; mNeedSync = false; - checkSelectionChanged(); checkFocus(); requestLayout(); @@ -819,13 +818,21 @@ public abstract class AdapterView<T extends Adapter> extends ViewGroup { } } - private class SelectionNotifier extends Handler implements Runnable { + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + removeCallbacks(mSelectionNotifier); + } + + private class SelectionNotifier implements Runnable { public void run() { if (mDataChanged) { // Data has changed between when this SelectionNotifier // was posted and now. We need to wait until the AdapterView // has been synched to the new data. - post(this); + if (getAdapter() != null) { + post(this); + } } else { fireOnSelected(); } @@ -842,7 +849,7 @@ public abstract class AdapterView<T extends Adapter> extends ViewGroup { if (mSelectionNotifier == null) { mSelectionNotifier = new SelectionNotifier(); } - mSelectionNotifier.post(mSelectionNotifier); + post(mSelectionNotifier); } else { fireOnSelected(); } diff --git a/core/java/com/android/internal/widget/PointerLocationView.java b/core/java/com/android/internal/widget/PointerLocationView.java index d5a99798fa18..939f1182f1fa 100644 --- a/core/java/com/android/internal/widget/PointerLocationView.java +++ b/core/java/com/android/internal/widget/PointerLocationView.java @@ -19,8 +19,10 @@ package com.android.internal.widget; import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; +import android.graphics.RectF; import android.graphics.Paint.FontMetricsInt; import android.util.Log; +import android.view.InputDevice; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.View; @@ -29,17 +31,45 @@ import android.view.ViewConfiguration; import java.util.ArrayList; public class PointerLocationView extends View { + private static final String TAG = "Pointer"; + public static class PointerState { - private final ArrayList<Float> mXs = new ArrayList<Float>(); - private final ArrayList<Float> mYs = new ArrayList<Float>(); + // Trace of previous points. + private float[] mTraceX = new float[32]; + private float[] mTraceY = new float[32]; + private int mTraceCount; + + // True if the pointer is down. private boolean mCurDown; - private int mCurX; - private int mCurY; - private float mCurPressure; - private float mCurSize; - private int mCurWidth; + + // Most recent coordinates. + private MotionEvent.PointerCoords mCoords = new MotionEvent.PointerCoords(); + + // Most recent velocity. private float mXVelocity; private float mYVelocity; + + public void clearTrace() { + mTraceCount = 0; + } + + public void addTrace(float x, float y) { + int traceCapacity = mTraceX.length; + if (mTraceCount == traceCapacity) { + traceCapacity *= 2; + float[] newTraceX = new float[traceCapacity]; + System.arraycopy(mTraceX, 0, newTraceX, 0, mTraceCount); + mTraceX = newTraceX; + + float[] newTraceY = new float[traceCapacity]; + System.arraycopy(mTraceY, 0, newTraceY, 0, mTraceCount); + mTraceY = newTraceY; + } + + mTraceX[mTraceCount] = x; + mTraceY[mTraceCount] = y; + mTraceCount += 1; + } } private final ViewConfiguration mVC; @@ -54,11 +84,12 @@ public class PointerLocationView extends View { private boolean mCurDown; private int mCurNumPointers; private int mMaxNumPointers; - private final ArrayList<PointerState> mPointers - = new ArrayList<PointerState>(); + private final ArrayList<PointerState> mPointers = new ArrayList<PointerState>(); private final VelocityTracker mVelocity; + private final FasterStringBuilder mText = new FasterStringBuilder(); + private boolean mPrintCoords = true; public PointerLocationView(Context c) { @@ -94,6 +125,18 @@ public class PointerLocationView extends View { mPointers.add(ps); mVelocity = VelocityTracker.obtain(); + + logInputDeviceCapabilities(); + } + + private void logInputDeviceCapabilities() { + int[] deviceIds = InputDevice.getDeviceIds(); + for (int i = 0; i < deviceIds.length; i++) { + InputDevice device = InputDevice.getDevice(deviceIds[i]); + if (device != null) { + Log.i(TAG, device.toString()); + } + } } public void setPrintCoords(boolean state) { @@ -113,6 +156,21 @@ public class PointerLocationView extends View { + " bottom=" + mTextMetrics.bottom); } } + + // Draw an oval. When angle is 0 radians, orients the major axis vertically, + // angles less than or greater than 0 radians rotate the major axis left or right. + private RectF mReusableOvalRect = new RectF(); + private void drawOval(Canvas canvas, float x, float y, float major, float minor, + float angle, Paint paint) { + canvas.save(Canvas.MATRIX_SAVE_FLAG); + canvas.rotate((float) (angle * 180 / Math.PI), x, y); + mReusableOvalRect.left = x - minor / 2; + mReusableOvalRect.right = x + minor / 2; + mReusableOvalRect.top = y - major / 2; + mReusableOvalRect.bottom = y + major / 2; + canvas.drawOval(mReusableOvalRect, paint); + canvas.restore(); + } @Override protected void onDraw(Canvas canvas) { @@ -124,76 +182,80 @@ public class PointerLocationView extends View { final int NP = mPointers.size(); + // Labels if (NP > 0) { final PointerState ps = mPointers.get(0); canvas.drawRect(0, 0, itemW-1, bottom,mTextBackgroundPaint); - canvas.drawText("P: " + mCurNumPointers + " / " + mMaxNumPointers, - 1, base, mTextPaint); + canvas.drawText(mText.clear() + .append("P: ").append(mCurNumPointers) + .append(" / ").append(mMaxNumPointers) + .toString(), 1, base, mTextPaint); - final int N = ps.mXs.size(); + final int N = ps.mTraceCount; if ((mCurDown && ps.mCurDown) || N == 0) { canvas.drawRect(itemW, 0, (itemW * 2) - 1, bottom, mTextBackgroundPaint); - canvas.drawText("X: " + ps.mCurX, 1 + itemW, base, mTextPaint); + canvas.drawText(mText.clear() + .append("X: ").append(ps.mCoords.x, 1) + .toString(), 1 + itemW, base, mTextPaint); canvas.drawRect(itemW * 2, 0, (itemW * 3) - 1, bottom, mTextBackgroundPaint); - canvas.drawText("Y: " + ps.mCurY, 1 + itemW * 2, base, mTextPaint); + canvas.drawText(mText.clear() + .append("Y: ").append(ps.mCoords.y, 1) + .toString(), 1 + itemW * 2, base, mTextPaint); } else { - float dx = ps.mXs.get(N-1) - ps.mXs.get(0); - float dy = ps.mYs.get(N-1) - ps.mYs.get(0); + float dx = ps.mTraceX[N - 1] - ps.mTraceX[0]; + float dy = ps.mTraceY[N - 1] - ps.mTraceY[0]; canvas.drawRect(itemW, 0, (itemW * 2) - 1, bottom, Math.abs(dx) < mVC.getScaledTouchSlop() ? mTextBackgroundPaint : mTextLevelPaint); - canvas.drawText("dX: " + String.format("%.1f", dx), 1 + itemW, base, mTextPaint); + canvas.drawText(mText.clear() + .append("dX: ").append(dx, 1) + .toString(), 1 + itemW, base, mTextPaint); canvas.drawRect(itemW * 2, 0, (itemW * 3) - 1, bottom, Math.abs(dy) < mVC.getScaledTouchSlop() ? mTextBackgroundPaint : mTextLevelPaint); - canvas.drawText("dY: " + String.format("%.1f", dy), 1 + itemW * 2, base, mTextPaint); + canvas.drawText(mText.clear() + .append("dY: ").append(dy, 1) + .toString(), 1 + itemW * 2, base, mTextPaint); } canvas.drawRect(itemW * 3, 0, (itemW * 4) - 1, bottom, mTextBackgroundPaint); - int velocity = (int) (ps.mXVelocity * 1000); - canvas.drawText("Xv: " + velocity, 1 + itemW * 3, base, mTextPaint); + canvas.drawText(mText.clear() + .append("Xv: ").append(ps.mXVelocity, 3) + .toString(), 1 + itemW * 3, base, mTextPaint); canvas.drawRect(itemW * 4, 0, (itemW * 5) - 1, bottom, mTextBackgroundPaint); - velocity = (int) (ps.mYVelocity * 1000); - canvas.drawText("Yv: " + velocity, 1 + itemW * 4, base, mTextPaint); + canvas.drawText(mText.clear() + .append("Yv: ").append(ps.mYVelocity, 3) + .toString(), 1 + itemW * 4, base, mTextPaint); canvas.drawRect(itemW * 5, 0, (itemW * 6) - 1, bottom, mTextBackgroundPaint); - canvas.drawRect(itemW * 5, 0, (itemW * 5) + (ps.mCurPressure * itemW) - 1, + canvas.drawRect(itemW * 5, 0, (itemW * 5) + (ps.mCoords.pressure * itemW) - 1, bottom, mTextLevelPaint); - canvas.drawText("Prs: " + String.format("%.2f", ps.mCurPressure), 1 + itemW * 5, - base, mTextPaint); + canvas.drawText(mText.clear() + .append("Prs: ").append(ps.mCoords.pressure, 2) + .toString(), 1 + itemW * 5, base, mTextPaint); canvas.drawRect(itemW * 6, 0, w, bottom, mTextBackgroundPaint); - canvas.drawRect(itemW * 6, 0, (itemW * 6) + (ps.mCurSize * itemW) - 1, + canvas.drawRect(itemW * 6, 0, (itemW * 6) + (ps.mCoords.size * itemW) - 1, bottom, mTextLevelPaint); - canvas.drawText("Size: " + String.format("%.2f", ps.mCurSize), 1 + itemW * 6, - base, mTextPaint); + canvas.drawText(mText.clear() + .append("Size: ").append(ps.mCoords.size, 2) + .toString(), 1 + itemW * 6, base, mTextPaint); } - for (int p=0; p<NP; p++) { + // Pointer trace. + for (int p = 0; p < NP; p++) { final PointerState ps = mPointers.get(p); - if (mCurDown && ps.mCurDown) { - canvas.drawLine(0, (int)ps.mCurY, getWidth(), (int)ps.mCurY, mTargetPaint); - canvas.drawLine((int)ps.mCurX, 0, (int)ps.mCurX, getHeight(), mTargetPaint); - int pressureLevel = (int)(ps.mCurPressure*255); - mPaint.setARGB(255, pressureLevel, 128, 255-pressureLevel); - canvas.drawPoint(ps.mCurX, ps.mCurY, mPaint); - canvas.drawCircle(ps.mCurX, ps.mCurY, ps.mCurWidth, mPaint); - } - } - - for (int p=0; p<NP; p++) { - final PointerState ps = mPointers.get(p); - - final int N = ps.mXs.size(); - float lastX=0, lastY=0; + // Draw path. + final int N = ps.mTraceCount; + float lastX = 0, lastY = 0; boolean haveLast = false; boolean drawn = false; mPaint.setARGB(255, 128, 255, 255); - for (int i=0; i<N; i++) { - float x = ps.mXs.get(i); - float y = ps.mYs.get(i); + for (int i=0; i < N; i++) { + float x = ps.mTraceX[i]; + float y = ps.mTraceY[i]; if (Float.isNaN(x)) { haveLast = false; continue; @@ -208,21 +270,57 @@ public class PointerLocationView extends View { haveLast = true; } + // Draw velocity vector. if (drawn) { mPaint.setARGB(255, 255, 64, 128); - float xVel = ps.mXVelocity * (1000/60); - float yVel = ps.mYVelocity * (1000/60); - canvas.drawLine(lastX, lastY, lastX+xVel, lastY+yVel, mPaint); + float xVel = ps.mXVelocity * (1000 / 60); + float yVel = ps.mYVelocity * (1000 / 60); + canvas.drawLine(lastX, lastY, lastX + xVel, lastY + yVel, mPaint); + } + + if (mCurDown && ps.mCurDown) { + // Draw crosshairs. + canvas.drawLine(0, ps.mCoords.y, getWidth(), ps.mCoords.y, mTargetPaint); + canvas.drawLine(ps.mCoords.x, 0, ps.mCoords.x, getHeight(), mTargetPaint); + + // Draw current point. + int pressureLevel = (int)(ps.mCoords.pressure * 255); + mPaint.setARGB(255, pressureLevel, 255, 255 - pressureLevel); + canvas.drawPoint(ps.mCoords.x, ps.mCoords.y, mPaint); + + // Draw current touch ellipse. + mPaint.setARGB(255, pressureLevel, 255 - pressureLevel, 128); + drawOval(canvas, ps.mCoords.x, ps.mCoords.y, ps.mCoords.touchMajor, + ps.mCoords.touchMinor, ps.mCoords.orientation, mPaint); + + // Draw current tool ellipse. + mPaint.setARGB(255, pressureLevel, 128, 255 - pressureLevel); + drawOval(canvas, ps.mCoords.x, ps.mCoords.y, ps.mCoords.toolMajor, + ps.mCoords.toolMinor, ps.mCoords.orientation, mPaint); } } } } + + private void logPointerCoords(MotionEvent.PointerCoords coords, int id) { + Log.i(TAG, mText.clear() + .append("Pointer ").append(id + 1) + .append(": (").append(coords.x, 3).append(", ").append(coords.y, 3) + .append(") Pressure=").append(coords.pressure, 3) + .append(" Size=").append(coords.size, 3) + .append(" TouchMajor=").append(coords.touchMajor, 3) + .append(" TouchMinor=").append(coords.touchMinor, 3) + .append(" ToolMajor=").append(coords.toolMajor, 3) + .append(" ToolMinor=").append(coords.toolMinor, 3) + .append(" Orientation=").append((float)(coords.orientation * 180 / Math.PI), 1) + .append("deg").toString()); + } public void addTouchEvent(MotionEvent event) { synchronized (mPointers) { int action = event.getAction(); - //Log.i("Pointer", "Motion: action=0x" + Integer.toHexString(action) + //Log.i(TAG, "Motion: action=0x" + Integer.toHexString(action) // + " pointers=" + event.getPointerCount()); int NP = mPointers.size(); @@ -235,35 +333,33 @@ public class PointerLocationView extends View { //} else { // mRect.setEmpty(); //} - if (action == MotionEvent.ACTION_DOWN) { - mVelocity.clear(); - - for (int p=0; p<NP; p++) { - final PointerState ps = mPointers.get(p); - ps.mXs.clear(); - ps.mYs.clear(); - ps.mCurDown = false; - } - mPointers.get(0).mCurDown = true; - mMaxNumPointers = 0; - if (mPrintCoords) { - Log.i("Pointer", "Pointer 1: DOWN"); + if (action == MotionEvent.ACTION_DOWN + || (action & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_POINTER_DOWN) { + final int index = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) + >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; // will be 0 for down + if (action == MotionEvent.ACTION_DOWN) { + for (int p=0; p<NP; p++) { + final PointerState ps = mPointers.get(p); + ps.clearTrace(); + ps.mCurDown = false; + } + mCurDown = true; + mMaxNumPointers = 0; + mVelocity.clear(); } - } - - if ((action&MotionEvent.ACTION_MASK) == MotionEvent.ACTION_POINTER_DOWN) { - final int index = (action&MotionEvent.ACTION_POINTER_INDEX_MASK) - >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; + final int id = event.getPointerId(index); while (NP <= id) { PointerState ps = new PointerState(); mPointers.add(ps); NP++; } + final PointerState ps = mPointers.get(id); ps.mCurDown = true; if (mPrintCoords) { - Log.i("Pointer", "Pointer " + (id+1) + ": DOWN"); + Log.i(TAG, mText.clear().append("Pointer ") + .append(id + 1).append(": DOWN").toString()); } } @@ -284,58 +380,38 @@ public class PointerLocationView extends View { final PointerState ps = mPointers.get(id); final int N = event.getHistorySize(); for (int j=0; j<N; j++) { + event.getHistoricalPointerCoords(i, j, ps.mCoords); if (mPrintCoords) { - Log.i("Pointer", "Pointer " + (id+1) + ": (" - + event.getHistoricalX(i, j) - + ", " + event.getHistoricalY(i, j) + ")" - + " Prs=" + event.getHistoricalPressure(i, j) - + " Size=" + event.getHistoricalSize(i, j)); + logPointerCoords(ps.mCoords, id); } - ps.mXs.add(event.getHistoricalX(i, j)); - ps.mYs.add(event.getHistoricalY(i, j)); + ps.addTrace(event.getHistoricalX(i, j), event.getHistoricalY(i, j)); } + event.getPointerCoords(i, ps.mCoords); if (mPrintCoords) { - Log.i("Pointer", "Pointer " + (id+1) + ": (" - + event.getX(i) + ", " + event.getY(i) + ")" - + " Prs=" + event.getPressure(i) - + " Size=" + event.getSize(i)); + logPointerCoords(ps.mCoords, id); } - ps.mXs.add(event.getX(i)); - ps.mYs.add(event.getY(i)); - ps.mCurX = (int)event.getX(i); - ps.mCurY = (int)event.getY(i); - //Log.i("Pointer", "Pointer #" + p + ": (" + ps.mCurX - // + "," + ps.mCurY + ")"); - ps.mCurPressure = event.getPressure(i); - ps.mCurSize = event.getSize(i); - ps.mCurWidth = (int)(ps.mCurSize*(getWidth()/3)); + ps.addTrace(ps.mCoords.x, ps.mCoords.y); ps.mXVelocity = mVelocity.getXVelocity(id); ps.mYVelocity = mVelocity.getYVelocity(id); } - if ((action&MotionEvent.ACTION_MASK) == MotionEvent.ACTION_POINTER_UP) { - final int index = (action&MotionEvent.ACTION_POINTER_INDEX_MASK) - >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; + if (action == MotionEvent.ACTION_UP + || (action & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_POINTER_UP) { + final int index = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) + >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; // will be 0 for UP + final int id = event.getPointerId(index); final PointerState ps = mPointers.get(id); - ps.mXs.add(Float.NaN); - ps.mYs.add(Float.NaN); ps.mCurDown = false; if (mPrintCoords) { - Log.i("Pointer", "Pointer " + (id+1) + ": UP"); + Log.i(TAG, mText.clear().append("Pointer ") + .append(id + 1).append(": UP").toString()); } - } - - if (action == MotionEvent.ACTION_UP) { - for (int i=0; i<NI; i++) { - final int id = event.getPointerId(i); - final PointerState ps = mPointers.get(id); - if (ps.mCurDown) { - ps.mCurDown = false; - if (mPrintCoords) { - Log.i("Pointer", "Pointer " + (id+1) + ": UP"); - } - } + + if (action == MotionEvent.ACTION_UP) { + mCurDown = false; + } else { + ps.addTrace(Float.NaN, Float.NaN); } } @@ -356,8 +432,120 @@ public class PointerLocationView extends View { @Override public boolean onTrackballEvent(MotionEvent event) { - Log.i("Pointer", "Trackball: " + event); + Log.i(TAG, "Trackball: " + event); return super.onTrackballEvent(event); } + // HACK + // A quick and dirty string builder implementation optimized for GC. + // Using the basic StringBuilder implementation causes the application grind to a halt when + // more than a couple of pointers are down due to the number of temporary objects allocated + // while formatting strings for drawing or logging. + private static final class FasterStringBuilder { + private char[] mChars; + private int mLength; + + public FasterStringBuilder() { + mChars = new char[64]; + } + + public FasterStringBuilder clear() { + mLength = 0; + return this; + } + + public FasterStringBuilder append(String value) { + final int valueLength = value.length(); + final int index = reserve(valueLength); + value.getChars(0, valueLength, mChars, index); + mLength += valueLength; + return this; + } + + public FasterStringBuilder append(int value) { + return append(value, 0); + } + + public FasterStringBuilder append(int value, int zeroPadWidth) { + final boolean negative = value < 0; + if (negative) { + value = - value; + if (value < 0) { + append("-2147483648"); + return this; + } + } + + int index = reserve(11); + final char[] chars = mChars; + + if (value == 0) { + chars[index++] = '0'; + mLength += 1; + return this; + } + + if (negative) { + chars[index++] = '-'; + } + + int divisor = 1000000000; + int numberWidth = 10; + while (value < divisor) { + divisor /= 10; + numberWidth -= 1; + if (numberWidth < zeroPadWidth) { + chars[index++] = '0'; + } + } + + do { + int digit = value / divisor; + value -= digit * divisor; + divisor /= 10; + chars[index++] = (char) (digit + '0'); + } while (divisor != 0); + + mLength = index; + return this; + } + + public FasterStringBuilder append(float value, int precision) { + int scale = 1; + for (int i = 0; i < precision; i++) { + scale *= 10; + } + value = (float) (Math.rint(value * scale) / scale); + + append((int) value); + + if (precision != 0) { + append("."); + value = Math.abs(value); + value -= Math.floor(value); + append((int) (value * scale), precision); + } + + return this; + } + + @Override + public String toString() { + return new String(mChars, 0, mLength); + } + + private int reserve(int length) { + final int oldLength = mLength; + final int newLength = mLength + length; + final char[] oldChars = mChars; + final int oldCapacity = oldChars.length; + if (newLength > oldCapacity) { + final int newCapacity = oldCapacity * 2; + final char[] newChars = new char[newCapacity]; + System.arraycopy(oldChars, 0, newChars, 0, oldLength); + mChars = newChars; + } + return oldLength; + } + } } diff --git a/include/ui/EventHub.h b/include/ui/EventHub.h index 3d428563359f..25d5afbf905e 100644 --- a/include/ui/EventHub.h +++ b/include/ui/EventHub.h @@ -82,6 +82,14 @@ struct RawAbsoluteAxisInfo { int32_t fuzz; // error tolerance, eg. fuzz == 4 means value is +/- 4 due to noise inline int32_t getRange() { return maxValue - minValue; } + + inline void clear() { + valid = false; + minValue = 0; + maxValue = 0; + flat = 0; + fuzz = 0; + } }; /* diff --git a/include/ui/Input.h b/include/ui/Input.h index 2385973e6926..49347d3f8916 100644 --- a/include/ui/Input.h +++ b/include/ui/Input.h @@ -453,6 +453,10 @@ public: inline void setKeyboardType(int32_t keyboardType) { mKeyboardType = keyboardType; } inline int32_t getKeyboardType() const { return mKeyboardType; } + inline const KeyedVector<int32_t, MotionRange> getMotionRanges() const { + return mMotionRanges; + } + private: int32_t mId; String8 mName; diff --git a/include/ui/InputReader.h b/include/ui/InputReader.h index 56d27651528a..7a089a45a1af 100644 --- a/include/ui/InputReader.h +++ b/include/ui/InputReader.h @@ -35,6 +35,34 @@ namespace android { class InputDevice; class InputMapper; +/* Describes a virtual key. */ +struct VirtualKeyDefinition { + int32_t scanCode; + + // configured position data, specified in display coords + int32_t centerX; + int32_t centerY; + int32_t width; + int32_t height; +}; + + +/* Specifies input device calibration settings. */ +class InputDeviceCalibration { +public: + InputDeviceCalibration(); + + void clear(); + void addProperty(const String8& key, const String8& value); + + bool tryGetProperty(const String8& key, String8& outValue) const; + bool tryGetProperty(const String8& key, int32_t& outValue) const; + bool tryGetProperty(const String8& key, float& outValue) const; + +private: + KeyedVector<String8, String8> mProperties; +}; + /* * Input reader policy interface. @@ -73,17 +101,6 @@ public: ACTION_APP_SWITCH_COMING = 0x00000002, }; - /* Describes a virtual key. */ - struct VirtualKeyDefinition { - int32_t scanCode; - - // configured position data, specified in display coords - int32_t centerX; - int32_t centerY; - int32_t width; - int32_t height; - }; - /* Gets information about the display with the specified id. * Returns true if the display info is available, false otherwise. */ @@ -135,6 +152,10 @@ public: virtual void getVirtualKeyDefinitions(const String8& deviceName, Vector<VirtualKeyDefinition>& outVirtualKeyDefinitions) = 0; + /* Gets the calibration for an input device. */ + virtual void getInputDeviceCalibration(const String8& deviceName, + InputDeviceCalibration& outCalibration) = 0; + /* Gets the excluded device names for the platform. */ virtual void getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames) = 0; }; @@ -327,6 +348,10 @@ public: int32_t getMetaState(); + inline const InputDeviceCalibration& getCalibration() { + return mCalibration; + } + private: InputReaderContext* mContext; int32_t mId; @@ -338,6 +363,8 @@ private: typedef int32_t (InputMapper::*GetStateFunc)(uint32_t sourceMask, int32_t code); int32_t getState(uint32_t sourceMask, int32_t code, GetStateFunc getStateFunc); + + InputDeviceCalibration mCalibration; }; @@ -538,12 +565,12 @@ protected: } }; + // Raw data for a single pointer. struct PointerData { uint32_t id; int32_t x; int32_t y; int32_t pressure; - int32_t size; int32_t touchMajor; int32_t touchMinor; int32_t toolMajor; @@ -551,6 +578,7 @@ protected: int32_t orientation; }; + // Raw data for a collection of pointers including a pointer id mapping table. struct TouchData { uint32_t pointerCount; PointerData pointers[MAX_POINTERS]; @@ -584,18 +612,82 @@ protected: bool useAveragingTouchFilter; } mParameters; - // Raw axis information. - struct Axes { + // Immutable calibration parameters in parsed form. + struct Calibration { + // Touch Area + enum TouchAreaCalibration { + TOUCH_AREA_CALIBRATION_DEFAULT, + TOUCH_AREA_CALIBRATION_NONE, + TOUCH_AREA_CALIBRATION_GEOMETRIC, + TOUCH_AREA_CALIBRATION_PRESSURE, + }; + + TouchAreaCalibration touchAreaCalibration; + + // Tool Area + enum ToolAreaCalibration { + TOOL_AREA_CALIBRATION_DEFAULT, + TOOL_AREA_CALIBRATION_NONE, + TOOL_AREA_CALIBRATION_GEOMETRIC, + TOOL_AREA_CALIBRATION_LINEAR, + }; + + ToolAreaCalibration toolAreaCalibration; + bool haveToolAreaLinearScale; + float toolAreaLinearScale; + bool haveToolAreaLinearBias; + float toolAreaLinearBias; + bool haveToolAreaIsSummed; + int32_t toolAreaIsSummed; + + // Pressure + enum PressureCalibration { + PRESSURE_CALIBRATION_DEFAULT, + PRESSURE_CALIBRATION_NONE, + PRESSURE_CALIBRATION_PHYSICAL, + PRESSURE_CALIBRATION_AMPLITUDE, + }; + enum PressureSource { + PRESSURE_SOURCE_DEFAULT, + PRESSURE_SOURCE_PRESSURE, + PRESSURE_SOURCE_TOUCH, + }; + + PressureCalibration pressureCalibration; + PressureSource pressureSource; + bool havePressureScale; + float pressureScale; + + // Size + enum SizeCalibration { + SIZE_CALIBRATION_DEFAULT, + SIZE_CALIBRATION_NONE, + SIZE_CALIBRATION_NORMALIZED, + }; + + SizeCalibration sizeCalibration; + + // Orientation + enum OrientationCalibration { + ORIENTATION_CALIBRATION_DEFAULT, + ORIENTATION_CALIBRATION_NONE, + ORIENTATION_CALIBRATION_INTERPOLATED, + }; + + OrientationCalibration orientationCalibration; + } mCalibration; + + // Raw axis information from the driver. + struct RawAxes { RawAbsoluteAxisInfo x; RawAbsoluteAxisInfo y; RawAbsoluteAxisInfo pressure; - RawAbsoluteAxisInfo size; RawAbsoluteAxisInfo touchMajor; RawAbsoluteAxisInfo touchMinor; RawAbsoluteAxisInfo toolMajor; RawAbsoluteAxisInfo toolMinor; RawAbsoluteAxisInfo orientation; - } mAxes; + } mRawAxes; // Current and previous touch sample data. TouchData mCurrentTouch; @@ -620,10 +712,13 @@ protected: float yScale; float yPrecision; - int32_t pressureOrigin; + float geometricScale; + + float toolAreaLinearScale; + float toolAreaLinearBias; + float pressureScale; - int32_t sizeOrigin; float sizeScale; float orientationScale; @@ -632,12 +727,22 @@ protected: struct OrientedRanges { InputDeviceInfo::MotionRange x; InputDeviceInfo::MotionRange y; + + bool havePressure; InputDeviceInfo::MotionRange pressure; + + bool haveSize; InputDeviceInfo::MotionRange size; + + bool haveTouchArea; InputDeviceInfo::MotionRange touchMajor; InputDeviceInfo::MotionRange touchMinor; + + bool haveToolArea; InputDeviceInfo::MotionRange toolMajor; InputDeviceInfo::MotionRange toolMinor; + + bool haveOrientation; InputDeviceInfo::MotionRange orientation; } orientedRanges; @@ -653,9 +758,14 @@ protected: } currentVirtualKey; } mLocked; - virtual void configureAxes(); + virtual void configureParameters(); + virtual void configureRawAxes(); + virtual void logRawAxes(); virtual bool configureSurfaceLocked(); virtual void configureVirtualKeysLocked(); + virtual void parseCalibration(); + virtual void resolveCalibration(); + virtual void logCalibration(); enum TouchResult { // Dispatch the touch normally. @@ -713,7 +823,8 @@ private: TouchResult consumeOffScreenTouches(nsecs_t when, uint32_t policyFlags); void dispatchTouches(nsecs_t when, uint32_t policyFlags); void dispatchTouch(nsecs_t when, uint32_t policyFlags, TouchData* touch, - BitSet32 idBits, uint32_t changedId, int32_t motionEventAction); + BitSet32 idBits, uint32_t changedId, uint32_t pointerCount, + int32_t motionEventAction); void applyPolicyAndDispatchVirtualKey(nsecs_t when, uint32_t policyFlags, int32_t keyEventAction, int32_t keyEventFlags, @@ -738,7 +849,7 @@ public: virtual void process(const RawEvent* rawEvent); protected: - virtual void configureAxes(); + virtual void configureRawAxes(); private: struct Accumulator { @@ -767,7 +878,7 @@ private: int32_t mX; int32_t mY; int32_t mPressure; - int32_t mSize; + int32_t mToolWidth; void initialize(); @@ -784,7 +895,7 @@ public: virtual void process(const RawEvent* rawEvent); protected: - virtual void configureAxes(); + virtual void configureRawAxes(); private: struct Accumulator { diff --git a/libs/ui/EventHub.cpp b/libs/ui/EventHub.cpp index 891661d690ac..1d38b4ba8ff0 100644 --- a/libs/ui/EventHub.cpp +++ b/libs/ui/EventHub.cpp @@ -139,11 +139,7 @@ uint32_t EventHub::getDeviceClasses(int32_t deviceId) const status_t EventHub::getAbsoluteAxisInfo(int32_t deviceId, int axis, RawAbsoluteAxisInfo* outAxisInfo) const { - outAxisInfo->valid = false; - outAxisInfo->minValue = 0; - outAxisInfo->maxValue = 0; - outAxisInfo->flat = 0; - outAxisInfo->fuzz = 0; + outAxisInfo->clear(); AutoMutex _l(mLock); device_t* device = getDevice(deviceId); @@ -709,8 +705,7 @@ int EventHub::open_device(const char *deviceName) LOGV("Getting absolute controllers..."); if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bitmask)), abs_bitmask) >= 0) { // Is this a new modern multi-touch driver? - if (test_bit(ABS_MT_TOUCH_MAJOR, abs_bitmask) - && test_bit(ABS_MT_POSITION_X, abs_bitmask) + if (test_bit(ABS_MT_POSITION_X, abs_bitmask) && test_bit(ABS_MT_POSITION_Y, abs_bitmask)) { device->classes |= INPUT_DEVICE_CLASS_TOUCHSCREEN | INPUT_DEVICE_CLASS_TOUCHSCREEN_MT; diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp index e35050cb6e4c..886c7856debb 100644 --- a/libs/ui/InputDispatcher.cpp +++ b/libs/ui/InputDispatcher.cpp @@ -405,12 +405,15 @@ void InputDispatcher::processMotionLockedInterruptible( sampleCount += 1; } for (uint32_t i = 0; i < entry->pointerCount; i++) { - LOGD(" Pointer %d: id=%d, x=%f, y=%f, pressure=%f, size=%f", + LOGD(" Pointer %d: id=%d, x=%f, y=%f, pressure=%f, size=%f, " + "touchMajor=%f, touchMinor=%d, toolMajor=%f, toolMinor=%f, " + "orientation=%f", i, entry->pointerIds[i], - sample->pointerCoords[i].x, - sample->pointerCoords[i].y, - sample->pointerCoords[i].pressure, - sample->pointerCoords[i].size); + sample->pointerCoords[i].x, sample->pointerCoords[i].y, + sample->pointerCoords[i].pressure, sample->pointerCoords[i].size, + sample->pointerCoords[i].touchMajor, sample->pointerCoords[i].touchMinor, + sample->pointerCoords[i].toolMajor, sample->pointerCoords[i].toolMinor, + sample->pointerCoords[i].orientation); } // Keep in mind that due to batching, it is possible for the number of samples actually @@ -1080,9 +1083,14 @@ void InputDispatcher::notifyMotion(nsecs_t eventTime, int32_t deviceId, int32_t eventTime, deviceId, source, policyFlags, action, metaState, edgeFlags, xPrecision, yPrecision, downTime); for (uint32_t i = 0; i < pointerCount; i++) { - LOGD(" Pointer %d: id=%d, x=%f, y=%f, pressure=%f, size=%f", + LOGD(" Pointer %d: id=%d, x=%f, y=%f, pressure=%f, size=%f, " + "touchMajor=%f, touchMinor=%d, toolMajor=%f, toolMinor=%f, " + "orientation=%f", i, pointerIds[i], pointerCoords[i].x, pointerCoords[i].y, - pointerCoords[i].pressure, pointerCoords[i].size); + pointerCoords[i].pressure, pointerCoords[i].size, + pointerCoords[i].touchMajor, pointerCoords[i].touchMinor, + pointerCoords[i].toolMajor, pointerCoords[i].toolMinor, + pointerCoords[i].orientation); } #endif diff --git a/libs/ui/InputReader.cpp b/libs/ui/InputReader.cpp index 6f042ec7e8e4..8ffb48debe8f 100644 --- a/libs/ui/InputReader.cpp +++ b/libs/ui/InputReader.cpp @@ -26,11 +26,14 @@ #include <ui/InputReader.h> #include <stddef.h> +#include <stdlib.h> #include <unistd.h> #include <errno.h> #include <limits.h> #include <math.h> +#define INDENT " " + namespace android { // --- Static Functions --- @@ -52,6 +55,14 @@ inline static void swap(T& a, T& b) { b = temp; } +inline static float avg(float x, float y) { + return (x + y) / 2; +} + +inline static float pythag(float x, float y) { + return sqrtf(x * x + y * y); +} + int32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState) { int32_t mask; @@ -116,6 +127,64 @@ static inline bool sourcesMatchMask(uint32_t sources, uint32_t sourceMask) { } +// --- InputDeviceCalibration --- + +InputDeviceCalibration::InputDeviceCalibration() { +} + +void InputDeviceCalibration::clear() { + mProperties.clear(); +} + +void InputDeviceCalibration::addProperty(const String8& key, const String8& value) { + mProperties.add(key, value); +} + +bool InputDeviceCalibration::tryGetProperty(const String8& key, String8& outValue) const { + ssize_t index = mProperties.indexOfKey(key); + if (index < 0) { + return false; + } + + outValue = mProperties.valueAt(index); + return true; +} + +bool InputDeviceCalibration::tryGetProperty(const String8& key, int32_t& outValue) const { + String8 stringValue; + if (! tryGetProperty(key, stringValue) || stringValue.length() == 0) { + return false; + } + + char* end; + int value = strtol(stringValue.string(), & end, 10); + if (*end != '\0') { + LOGW("Input device calibration key '%s' has invalid value '%s'. Expected an integer.", + key.string(), stringValue.string()); + return false; + } + outValue = value; + return true; +} + +bool InputDeviceCalibration::tryGetProperty(const String8& key, float& outValue) const { + String8 stringValue; + if (! tryGetProperty(key, stringValue) || stringValue.length() == 0) { + return false; + } + + char* end; + float value = strtof(stringValue.string(), & end); + if (*end != '\0') { + LOGW("Input device calibration key '%s' has invalid value '%s'. Expected a float.", + key.string(), stringValue.string()); + return false; + } + outValue = value; + return true; +} + + // --- InputReader --- InputReader::InputReader(const sp<EventHubInterface>& eventHub, @@ -167,9 +236,18 @@ void InputReader::addDevice(nsecs_t when, int32_t deviceId) { String8 name = mEventHub->getDeviceName(deviceId); uint32_t classes = mEventHub->getDeviceClasses(deviceId); + // Write a log message about the added device as a heading for subsequent log messages. + LOGI("Device added: id=0x%x, name=%s", deviceId, name.string()); + InputDevice* device = createDevice(deviceId, name, classes); device->configure(); + if (device->isIgnored()) { + LOGI(INDENT "Sources: none (device is ignored)"); + } else { + LOGI(INDENT "Sources: 0x%08x", device->getSources()); + } + bool added = false; { // acquire device registry writer lock RWLock::AutoWLock _wl(mDeviceRegistryLock); @@ -187,14 +265,6 @@ void InputReader::addDevice(nsecs_t when, int32_t deviceId) { return; } - if (device->isIgnored()) { - LOGI("Device added: id=0x%x, name=%s (ignored non-input device)", - deviceId, name.string()); - } else { - LOGI("Device added: id=0x%x, name=%s, sources=%08x", - deviceId, name.string(), device->getSources()); - } - handleConfigurationChanged(when); } @@ -217,8 +287,7 @@ void InputReader::removeDevice(nsecs_t when, int32_t deviceId) { return; } - device->reset(); - + // Write a log message about the removed device as a heading for subsequent log messages. if (device->isIgnored()) { LOGI("Device removed: id=0x%x, name=%s (ignored non-input device)", device->getId(), device->getName().string()); @@ -227,6 +296,8 @@ void InputReader::removeDevice(nsecs_t when, int32_t deviceId) { device->getId(), device->getName().string(), device->getSources()); } + device->reset(); + delete device; handleConfigurationChanged(when); @@ -537,6 +608,10 @@ void InputDevice::addMapper(InputMapper* mapper) { } void InputDevice::configure() { + if (! isIgnored()) { + mContext->getPolicy()->getInputDeviceCalibration(mName, mCalibration); + } + mSources = 0; size_t numMappers = mMappers.size(); @@ -1121,13 +1196,35 @@ void TouchInputMapper::populateDeviceInfo(InputDeviceInfo* info) { info->addMotionRange(AINPUT_MOTION_RANGE_X, mLocked.orientedRanges.x); info->addMotionRange(AINPUT_MOTION_RANGE_Y, mLocked.orientedRanges.y); - info->addMotionRange(AINPUT_MOTION_RANGE_PRESSURE, mLocked.orientedRanges.pressure); - info->addMotionRange(AINPUT_MOTION_RANGE_SIZE, mLocked.orientedRanges.size); - info->addMotionRange(AINPUT_MOTION_RANGE_TOUCH_MAJOR, mLocked.orientedRanges.touchMajor); - info->addMotionRange(AINPUT_MOTION_RANGE_TOUCH_MINOR, mLocked.orientedRanges.touchMinor); - info->addMotionRange(AINPUT_MOTION_RANGE_TOOL_MAJOR, mLocked.orientedRanges.toolMajor); - info->addMotionRange(AINPUT_MOTION_RANGE_TOOL_MINOR, mLocked.orientedRanges.toolMinor); - info->addMotionRange(AINPUT_MOTION_RANGE_ORIENTATION, mLocked.orientedRanges.orientation); + + if (mLocked.orientedRanges.havePressure) { + info->addMotionRange(AINPUT_MOTION_RANGE_PRESSURE, + mLocked.orientedRanges.pressure); + } + + if (mLocked.orientedRanges.haveSize) { + info->addMotionRange(AINPUT_MOTION_RANGE_SIZE, + mLocked.orientedRanges.size); + } + + if (mLocked.orientedRanges.haveTouchArea) { + info->addMotionRange(AINPUT_MOTION_RANGE_TOUCH_MAJOR, + mLocked.orientedRanges.touchMajor); + info->addMotionRange(AINPUT_MOTION_RANGE_TOUCH_MINOR, + mLocked.orientedRanges.touchMinor); + } + + if (mLocked.orientedRanges.haveToolArea) { + info->addMotionRange(AINPUT_MOTION_RANGE_TOOL_MAJOR, + mLocked.orientedRanges.toolMajor); + info->addMotionRange(AINPUT_MOTION_RANGE_TOOL_MINOR, + mLocked.orientedRanges.toolMinor); + } + + if (mLocked.orientedRanges.haveOrientation) { + info->addMotionRange(AINPUT_MOTION_RANGE_ORIENTATION, + mLocked.orientedRanges.orientation); + } } // release lock } @@ -1144,77 +1241,72 @@ void TouchInputMapper::initializeLocked() { mJumpyTouchFilter.jumpyPointsDropped = 0; mLocked.currentVirtualKey.down = false; + + mLocked.orientedRanges.havePressure = false; + mLocked.orientedRanges.haveSize = false; + mLocked.orientedRanges.haveTouchArea = false; + mLocked.orientedRanges.haveToolArea = false; + mLocked.orientedRanges.haveOrientation = false; +} + +static void logAxisInfo(RawAbsoluteAxisInfo axis, const char* name) { + if (axis.valid) { + LOGI(INDENT "Raw %s axis: min=%d, max=%d, flat=%d, fuzz=%d", + name, axis.minValue, axis.maxValue, axis.flat, axis.fuzz); + } else { + LOGI(INDENT "Raw %s axis: unknown range", name); + } } void TouchInputMapper::configure() { InputMapper::configure(); // Configure basic parameters. - mParameters.useBadTouchFilter = getPolicy()->filterTouchEvents(); - mParameters.useAveragingTouchFilter = getPolicy()->filterTouchEvents(); - mParameters.useJumpyTouchFilter = getPolicy()->filterJumpyTouchEvents(); + configureParameters(); // Configure absolute axis information. - configureAxes(); + configureRawAxes(); + logRawAxes(); + + // Prepare input device calibration. + parseCalibration(); + resolveCalibration(); + logCalibration(); { // acquire lock AutoMutex _l(mLock); - // Configure pressure factors. - if (mAxes.pressure.valid) { - mLocked.pressureOrigin = mAxes.pressure.minValue; - mLocked.pressureScale = 1.0f / mAxes.pressure.getRange(); - } else { - mLocked.pressureOrigin = 0; - mLocked.pressureScale = 1.0f; - } - - mLocked.orientedRanges.pressure.min = 0.0f; - mLocked.orientedRanges.pressure.max = 1.0f; - mLocked.orientedRanges.pressure.flat = 0.0f; - mLocked.orientedRanges.pressure.fuzz = mLocked.pressureScale; - - // Configure size factors. - if (mAxes.size.valid) { - mLocked.sizeOrigin = mAxes.size.minValue; - mLocked.sizeScale = 1.0f / mAxes.size.getRange(); - } else { - mLocked.sizeOrigin = 0; - mLocked.sizeScale = 1.0f; - } - - mLocked.orientedRanges.size.min = 0.0f; - mLocked.orientedRanges.size.max = 1.0f; - mLocked.orientedRanges.size.flat = 0.0f; - mLocked.orientedRanges.size.fuzz = mLocked.sizeScale; - - // Configure orientation factors. - if (mAxes.orientation.valid && mAxes.orientation.maxValue > 0) { - mLocked.orientationScale = float(M_PI_2) / mAxes.orientation.maxValue; - } else { - mLocked.orientationScale = 0.0f; - } - - mLocked.orientedRanges.orientation.min = - M_PI_2; - mLocked.orientedRanges.orientation.max = M_PI_2; - mLocked.orientedRanges.orientation.flat = 0; - mLocked.orientedRanges.orientation.fuzz = mLocked.orientationScale; - - // Configure surface dimensions and orientation. + // Configure surface dimensions and orientation. configureSurfaceLocked(); } // release lock } -void TouchInputMapper::configureAxes() { - mAxes.x.valid = false; - mAxes.y.valid = false; - mAxes.pressure.valid = false; - mAxes.size.valid = false; - mAxes.touchMajor.valid = false; - mAxes.touchMinor.valid = false; - mAxes.toolMajor.valid = false; - mAxes.toolMinor.valid = false; - mAxes.orientation.valid = false; +void TouchInputMapper::configureParameters() { + mParameters.useBadTouchFilter = getPolicy()->filterTouchEvents(); + mParameters.useAveragingTouchFilter = getPolicy()->filterTouchEvents(); + mParameters.useJumpyTouchFilter = getPolicy()->filterJumpyTouchEvents(); +} + +void TouchInputMapper::configureRawAxes() { + mRawAxes.x.clear(); + mRawAxes.y.clear(); + mRawAxes.pressure.clear(); + mRawAxes.touchMajor.clear(); + mRawAxes.touchMinor.clear(); + mRawAxes.toolMajor.clear(); + mRawAxes.toolMinor.clear(); + mRawAxes.orientation.clear(); +} + +void TouchInputMapper::logRawAxes() { + logAxisInfo(mRawAxes.x, "x"); + logAxisInfo(mRawAxes.y, "y"); + logAxisInfo(mRawAxes.pressure, "pressure"); + logAxisInfo(mRawAxes.touchMajor, "touchMajor"); + logAxisInfo(mRawAxes.touchMinor, "touchMinor"); + logAxisInfo(mRawAxes.toolMajor, "toolMajor"); + logAxisInfo(mRawAxes.toolMinor, "toolMinor"); + logAxisInfo(mRawAxes.orientation, "orientation"); } bool TouchInputMapper::configureSurfaceLocked() { @@ -1228,8 +1320,8 @@ bool TouchInputMapper::configureSurfaceLocked() { } } else { orientation = InputReaderPolicyInterface::ROTATION_0; - width = mAxes.x.getRange(); - height = mAxes.y.getRange(); + width = mRawAxes.x.getRange(); + height = mRawAxes.y.getRange(); } bool orientationChanged = mLocked.surfaceOrientation != orientation; @@ -1239,24 +1331,24 @@ bool TouchInputMapper::configureSurfaceLocked() { bool sizeChanged = mLocked.surfaceWidth != width || mLocked.surfaceHeight != height; if (sizeChanged) { + LOGI("Device configured: id=0x%x, name=%s (display size was changed)", + getDeviceId(), getDeviceName().string()); + mLocked.surfaceWidth = width; mLocked.surfaceHeight = height; - // Compute size-dependent translation and scaling factors and place virtual keys. - if (mAxes.x.valid && mAxes.y.valid) { - mLocked.xOrigin = mAxes.x.minValue; - mLocked.yOrigin = mAxes.y.minValue; - - LOGI("Device configured: id=0x%x, name=%s (display size was changed)", - getDeviceId(), getDeviceName().string()); - - mLocked.xScale = float(width) / mAxes.x.getRange(); - mLocked.yScale = float(height) / mAxes.y.getRange(); + // Configure X and Y factors. + if (mRawAxes.x.valid && mRawAxes.y.valid) { + mLocked.xOrigin = mRawAxes.x.minValue; + mLocked.yOrigin = mRawAxes.y.minValue; + mLocked.xScale = float(width) / mRawAxes.x.getRange(); + mLocked.yScale = float(height) / mRawAxes.y.getRange(); mLocked.xPrecision = 1.0f / mLocked.xScale; mLocked.yPrecision = 1.0f / mLocked.yScale; configureVirtualKeysLocked(); } else { + LOGW(INDENT "Touch device did not report support for X or Y axis!"); mLocked.xOrigin = 0; mLocked.yOrigin = 0; mLocked.xScale = 1.0f; @@ -1265,22 +1357,112 @@ bool TouchInputMapper::configureSurfaceLocked() { mLocked.yPrecision = 1.0f; } - // Configure touch and tool area ranges. - float diagonal = sqrt(float(width * width + height * height)); - float diagonalFuzz = sqrt(mLocked.xScale * mLocked.xScale - + mLocked.yScale * mLocked.yScale); + // Scale factor for terms that are not oriented in a particular axis. + // If the pixels are square then xScale == yScale otherwise we fake it + // by choosing an average. + mLocked.geometricScale = avg(mLocked.xScale, mLocked.yScale); + + // Size of diagonal axis. + float diagonalSize = pythag(width, height); + + // TouchMajor and TouchMinor factors. + if (mCalibration.touchAreaCalibration != Calibration::TOUCH_AREA_CALIBRATION_NONE) { + mLocked.orientedRanges.haveTouchArea = true; + mLocked.orientedRanges.touchMajor.min = 0; + mLocked.orientedRanges.touchMajor.max = diagonalSize; + mLocked.orientedRanges.touchMajor.flat = 0; + mLocked.orientedRanges.touchMajor.fuzz = 0; + mLocked.orientedRanges.touchMinor = mLocked.orientedRanges.touchMajor; + } + + // ToolMajor and ToolMinor factors. + if (mCalibration.toolAreaCalibration != Calibration::TOOL_AREA_CALIBRATION_NONE) { + mLocked.toolAreaLinearScale = 0; + mLocked.toolAreaLinearBias = 0; + if (mCalibration.toolAreaCalibration == Calibration::TOOL_AREA_CALIBRATION_LINEAR) { + if (mCalibration.haveToolAreaLinearScale) { + mLocked.toolAreaLinearScale = mCalibration.toolAreaLinearScale; + } else if (mRawAxes.toolMajor.valid && mRawAxes.toolMajor.maxValue != 0) { + mLocked.toolAreaLinearScale = float(min(width, height)) + / mRawAxes.toolMajor.maxValue; + } + + if (mCalibration.haveToolAreaLinearBias) { + mLocked.toolAreaLinearBias = mCalibration.toolAreaLinearBias; + } + } + + mLocked.orientedRanges.haveToolArea = true; + mLocked.orientedRanges.toolMajor.min = 0; + mLocked.orientedRanges.toolMajor.max = diagonalSize; + mLocked.orientedRanges.toolMajor.flat = 0; + mLocked.orientedRanges.toolMajor.fuzz = 0; + mLocked.orientedRanges.toolMinor = mLocked.orientedRanges.toolMajor; + } + + // Pressure factors. + if (mCalibration.pressureCalibration != Calibration::PRESSURE_CALIBRATION_NONE) { + RawAbsoluteAxisInfo rawPressureAxis; + switch (mCalibration.pressureSource) { + case Calibration::PRESSURE_SOURCE_PRESSURE: + rawPressureAxis = mRawAxes.pressure; + break; + case Calibration::PRESSURE_SOURCE_TOUCH: + rawPressureAxis = mRawAxes.touchMajor; + break; + default: + rawPressureAxis.clear(); + } + + mLocked.pressureScale = 0; + if (mCalibration.pressureCalibration == Calibration::PRESSURE_CALIBRATION_PHYSICAL + || mCalibration.pressureCalibration + == Calibration::PRESSURE_CALIBRATION_AMPLITUDE) { + if (mCalibration.havePressureScale) { + mLocked.pressureScale = mCalibration.pressureScale; + } else if (rawPressureAxis.valid && rawPressureAxis.maxValue != 0) { + mLocked.pressureScale = 1.0f / rawPressureAxis.maxValue; + } + } + + mLocked.orientedRanges.havePressure = true; + mLocked.orientedRanges.pressure.min = 0; + mLocked.orientedRanges.pressure.max = 1.0; + mLocked.orientedRanges.pressure.flat = 0; + mLocked.orientedRanges.pressure.fuzz = 0; + } + + // Size factors. + if (mCalibration.sizeCalibration != Calibration::SIZE_CALIBRATION_NONE) { + mLocked.sizeScale = 0; + if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_NORMALIZED) { + if (mRawAxes.toolMajor.valid && mRawAxes.toolMajor.maxValue != 0) { + mLocked.sizeScale = 1.0f / mRawAxes.toolMajor.maxValue; + } + } - InputDeviceInfo::MotionRange area; - area.min = 0.0f; - area.max = diagonal; - area.flat = 0.0f; - area.fuzz = diagonalFuzz; + mLocked.orientedRanges.haveSize = true; + mLocked.orientedRanges.size.min = 0; + mLocked.orientedRanges.size.max = 1.0; + mLocked.orientedRanges.size.flat = 0; + mLocked.orientedRanges.size.fuzz = 0; + } - mLocked.orientedRanges.touchMajor = area; - mLocked.orientedRanges.touchMinor = area; + // Orientation + if (mCalibration.orientationCalibration != Calibration::ORIENTATION_CALIBRATION_NONE) { + mLocked.orientationScale = 0; + if (mCalibration.orientationCalibration + == Calibration::ORIENTATION_CALIBRATION_INTERPOLATED) { + if (mRawAxes.orientation.valid && mRawAxes.orientation.maxValue != 0) { + mLocked.orientationScale = float(M_PI_2) / mRawAxes.orientation.maxValue; + } + } - mLocked.orientedRanges.toolMajor = area; - mLocked.orientedRanges.toolMinor = area; + mLocked.orientedRanges.orientation.min = - M_PI_2; + mLocked.orientedRanges.orientation.max = M_PI_2; + mLocked.orientedRanges.orientation.flat = 0; + mLocked.orientedRanges.orientation.fuzz = 0; + } } if (orientationChanged || sizeChanged) { @@ -1322,10 +1504,10 @@ bool TouchInputMapper::configureSurfaceLocked() { } void TouchInputMapper::configureVirtualKeysLocked() { - assert(mAxes.x.valid && mAxes.y.valid); + assert(mRawAxes.x.valid && mRawAxes.y.valid); // Note: getVirtualKeyDefinitions is non-reentrant so we can continue holding the lock. - Vector<InputReaderPolicyInterface::VirtualKeyDefinition> virtualKeyDefinitions; + Vector<VirtualKeyDefinition> virtualKeyDefinitions; getPolicy()->getVirtualKeyDefinitions(getDeviceName(), virtualKeyDefinitions); mLocked.virtualKeys.clear(); @@ -1336,13 +1518,13 @@ void TouchInputMapper::configureVirtualKeysLocked() { mLocked.virtualKeys.setCapacity(virtualKeyDefinitions.size()); - int32_t touchScreenLeft = mAxes.x.minValue; - int32_t touchScreenTop = mAxes.y.minValue; - int32_t touchScreenWidth = mAxes.x.getRange(); - int32_t touchScreenHeight = mAxes.y.getRange(); + int32_t touchScreenLeft = mRawAxes.x.minValue; + int32_t touchScreenTop = mRawAxes.y.minValue; + int32_t touchScreenWidth = mRawAxes.x.getRange(); + int32_t touchScreenHeight = mRawAxes.y.getRange(); for (size_t i = 0; i < virtualKeyDefinitions.size(); i++) { - const InputReaderPolicyInterface::VirtualKeyDefinition& virtualKeyDefinition = + const VirtualKeyDefinition& virtualKeyDefinition = virtualKeyDefinitions[i]; mLocked.virtualKeys.add(); @@ -1353,7 +1535,8 @@ void TouchInputMapper::configureVirtualKeysLocked() { uint32_t flags; if (getEventHub()->scancodeToKeycode(getDeviceId(), virtualKey.scanCode, & keyCode, & flags)) { - LOGW(" VirtualKey %d: could not obtain key code, ignoring", virtualKey.scanCode); + LOGW(INDENT "VirtualKey %d: could not obtain key code, ignoring", + virtualKey.scanCode); mLocked.virtualKeys.pop(); // drop the key continue; } @@ -1374,12 +1557,316 @@ void TouchInputMapper::configureVirtualKeysLocked() { virtualKey.hitBottom = (virtualKeyDefinition.centerY + halfHeight) * touchScreenHeight / mLocked.surfaceHeight + touchScreenTop; - LOGI(" VirtualKey %d: keyCode=%d hitLeft=%d hitRight=%d hitTop=%d hitBottom=%d", + LOGI(INDENT "VirtualKey %d: keyCode=%d hitLeft=%d hitRight=%d hitTop=%d hitBottom=%d", virtualKey.scanCode, virtualKey.keyCode, virtualKey.hitLeft, virtualKey.hitRight, virtualKey.hitTop, virtualKey.hitBottom); } } +void TouchInputMapper::parseCalibration() { + const InputDeviceCalibration& in = getDevice()->getCalibration(); + Calibration& out = mCalibration; + + // Touch Area + out.touchAreaCalibration = Calibration::TOUCH_AREA_CALIBRATION_DEFAULT; + String8 touchAreaCalibrationString; + if (in.tryGetProperty(String8("touch.touchArea.calibration"), touchAreaCalibrationString)) { + if (touchAreaCalibrationString == "none") { + out.touchAreaCalibration = Calibration::TOUCH_AREA_CALIBRATION_NONE; + } else if (touchAreaCalibrationString == "geometric") { + out.touchAreaCalibration = Calibration::TOUCH_AREA_CALIBRATION_GEOMETRIC; + } else if (touchAreaCalibrationString == "pressure") { + out.touchAreaCalibration = Calibration::TOUCH_AREA_CALIBRATION_PRESSURE; + } else if (touchAreaCalibrationString != "default") { + LOGW("Invalid value for touch.touchArea.calibration: '%s'", + touchAreaCalibrationString.string()); + } + } + + // Tool Area + out.toolAreaCalibration = Calibration::TOOL_AREA_CALIBRATION_DEFAULT; + String8 toolAreaCalibrationString; + if (in.tryGetProperty(String8("tool.toolArea.calibration"), toolAreaCalibrationString)) { + if (toolAreaCalibrationString == "none") { + out.toolAreaCalibration = Calibration::TOOL_AREA_CALIBRATION_NONE; + } else if (toolAreaCalibrationString == "geometric") { + out.toolAreaCalibration = Calibration::TOOL_AREA_CALIBRATION_GEOMETRIC; + } else if (toolAreaCalibrationString == "linear") { + out.toolAreaCalibration = Calibration::TOOL_AREA_CALIBRATION_LINEAR; + } else if (toolAreaCalibrationString != "default") { + LOGW("Invalid value for tool.toolArea.calibration: '%s'", + toolAreaCalibrationString.string()); + } + } + + out.haveToolAreaLinearScale = in.tryGetProperty(String8("touch.toolArea.linearScale"), + out.toolAreaLinearScale); + out.haveToolAreaLinearBias = in.tryGetProperty(String8("touch.toolArea.linearBias"), + out.toolAreaLinearBias); + out.haveToolAreaIsSummed = in.tryGetProperty(String8("touch.toolArea.isSummed"), + out.toolAreaIsSummed); + + // Pressure + out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_DEFAULT; + String8 pressureCalibrationString; + if (in.tryGetProperty(String8("tool.pressure.calibration"), pressureCalibrationString)) { + if (pressureCalibrationString == "none") { + out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_NONE; + } else if (pressureCalibrationString == "physical") { + out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_PHYSICAL; + } else if (pressureCalibrationString == "amplitude") { + out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_AMPLITUDE; + } else if (pressureCalibrationString != "default") { + LOGW("Invalid value for tool.pressure.calibration: '%s'", + pressureCalibrationString.string()); + } + } + + out.pressureSource = Calibration::PRESSURE_SOURCE_DEFAULT; + String8 pressureSourceString; + if (in.tryGetProperty(String8("touch.pressure.source"), pressureSourceString)) { + if (pressureSourceString == "pressure") { + out.pressureSource = Calibration::PRESSURE_SOURCE_PRESSURE; + } else if (pressureSourceString == "touch") { + out.pressureSource = Calibration::PRESSURE_SOURCE_TOUCH; + } else if (pressureSourceString != "default") { + LOGW("Invalid value for touch.pressure.source: '%s'", + pressureSourceString.string()); + } + } + + out.havePressureScale = in.tryGetProperty(String8("touch.pressure.scale"), + out.pressureScale); + + // Size + out.sizeCalibration = Calibration::SIZE_CALIBRATION_DEFAULT; + String8 sizeCalibrationString; + if (in.tryGetProperty(String8("tool.size.calibration"), sizeCalibrationString)) { + if (sizeCalibrationString == "none") { + out.sizeCalibration = Calibration::SIZE_CALIBRATION_NONE; + } else if (sizeCalibrationString == "normalized") { + out.sizeCalibration = Calibration::SIZE_CALIBRATION_NORMALIZED; + } else if (sizeCalibrationString != "default") { + LOGW("Invalid value for tool.size.calibration: '%s'", + sizeCalibrationString.string()); + } + } + + // Orientation + out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_DEFAULT; + String8 orientationCalibrationString; + if (in.tryGetProperty(String8("tool.orientation.calibration"), orientationCalibrationString)) { + if (orientationCalibrationString == "none") { + out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_NONE; + } else if (orientationCalibrationString == "interpolated") { + out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_INTERPOLATED; + } else if (orientationCalibrationString != "default") { + LOGW("Invalid value for tool.orientation.calibration: '%s'", + orientationCalibrationString.string()); + } + } +} + +void TouchInputMapper::resolveCalibration() { + // Pressure + switch (mCalibration.pressureSource) { + case Calibration::PRESSURE_SOURCE_DEFAULT: + if (mRawAxes.pressure.valid) { + mCalibration.pressureSource = Calibration::PRESSURE_SOURCE_PRESSURE; + } else if (mRawAxes.touchMajor.valid) { + mCalibration.pressureSource = Calibration::PRESSURE_SOURCE_TOUCH; + } + break; + + case Calibration::PRESSURE_SOURCE_PRESSURE: + if (! mRawAxes.pressure.valid) { + LOGW("Calibration property touch.pressure.source is 'pressure' but " + "the pressure axis is not available."); + } + break; + + case Calibration::PRESSURE_SOURCE_TOUCH: + if (! mRawAxes.touchMajor.valid) { + LOGW("Calibration property touch.pressure.source is 'touch' but " + "the touchMajor axis is not available."); + } + break; + + default: + break; + } + + switch (mCalibration.pressureCalibration) { + case Calibration::PRESSURE_CALIBRATION_DEFAULT: + if (mCalibration.pressureSource != Calibration::PRESSURE_SOURCE_DEFAULT) { + mCalibration.pressureCalibration = Calibration::PRESSURE_CALIBRATION_AMPLITUDE; + } else { + mCalibration.pressureCalibration = Calibration::PRESSURE_CALIBRATION_NONE; + } + break; + + default: + break; + } + + // Tool Area + switch (mCalibration.toolAreaCalibration) { + case Calibration::TOOL_AREA_CALIBRATION_DEFAULT: + if (mRawAxes.toolMajor.valid) { + mCalibration.toolAreaCalibration = Calibration::TOOL_AREA_CALIBRATION_LINEAR; + } else { + mCalibration.toolAreaCalibration = Calibration::TOOL_AREA_CALIBRATION_NONE; + } + break; + + default: + break; + } + + // Touch Area + switch (mCalibration.touchAreaCalibration) { + case Calibration::TOUCH_AREA_CALIBRATION_DEFAULT: + if (mCalibration.pressureCalibration != Calibration::PRESSURE_CALIBRATION_NONE + && mCalibration.toolAreaCalibration != Calibration::TOOL_AREA_CALIBRATION_NONE) { + mCalibration.touchAreaCalibration = Calibration::TOUCH_AREA_CALIBRATION_PRESSURE; + } else { + mCalibration.touchAreaCalibration = Calibration::TOUCH_AREA_CALIBRATION_NONE; + } + break; + + default: + break; + } + + // Size + switch (mCalibration.sizeCalibration) { + case Calibration::SIZE_CALIBRATION_DEFAULT: + if (mRawAxes.toolMajor.valid) { + mCalibration.sizeCalibration = Calibration::SIZE_CALIBRATION_NORMALIZED; + } else { + mCalibration.sizeCalibration = Calibration::SIZE_CALIBRATION_NONE; + } + break; + + default: + break; + } + + // Orientation + switch (mCalibration.orientationCalibration) { + case Calibration::ORIENTATION_CALIBRATION_DEFAULT: + if (mRawAxes.orientation.valid) { + mCalibration.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_INTERPOLATED; + } else { + mCalibration.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_NONE; + } + break; + + default: + break; + } +} + +void TouchInputMapper::logCalibration() { + // Touch Area + switch (mCalibration.touchAreaCalibration) { + case Calibration::TOUCH_AREA_CALIBRATION_NONE: + LOGI(INDENT " touch.touchArea.calibration: none"); + break; + case Calibration::TOUCH_AREA_CALIBRATION_GEOMETRIC: + LOGI(INDENT " touch.touchArea.calibration: geometric"); + break; + case Calibration::TOUCH_AREA_CALIBRATION_PRESSURE: + LOGI(INDENT " touch.touchArea.calibration: pressure"); + break; + default: + assert(false); + } + + // Tool Area + switch (mCalibration.toolAreaCalibration) { + case Calibration::TOOL_AREA_CALIBRATION_NONE: + LOGI(INDENT " touch.toolArea.calibration: none"); + break; + case Calibration::TOOL_AREA_CALIBRATION_GEOMETRIC: + LOGI(INDENT " touch.toolArea.calibration: geometric"); + break; + case Calibration::TOOL_AREA_CALIBRATION_LINEAR: + LOGI(INDENT " touch.toolArea.calibration: linear"); + break; + default: + assert(false); + } + + if (mCalibration.haveToolAreaLinearScale) { + LOGI(INDENT " touch.toolArea.linearScale: %f", mCalibration.toolAreaLinearScale); + } + + if (mCalibration.haveToolAreaLinearBias) { + LOGI(INDENT " touch.toolArea.linearBias: %f", mCalibration.toolAreaLinearBias); + } + + if (mCalibration.haveToolAreaIsSummed) { + LOGI(INDENT " touch.toolArea.isSummed: %d", mCalibration.toolAreaIsSummed); + } + + // Pressure + switch (mCalibration.pressureCalibration) { + case Calibration::PRESSURE_CALIBRATION_NONE: + LOGI(INDENT " touch.pressure.calibration: none"); + break; + case Calibration::PRESSURE_CALIBRATION_PHYSICAL: + LOGI(INDENT " touch.pressure.calibration: physical"); + break; + case Calibration::PRESSURE_CALIBRATION_AMPLITUDE: + LOGI(INDENT " touch.pressure.calibration: amplitude"); + break; + default: + assert(false); + } + + switch (mCalibration.pressureSource) { + case Calibration::PRESSURE_SOURCE_PRESSURE: + LOGI(INDENT " touch.pressure.source: pressure"); + break; + case Calibration::PRESSURE_SOURCE_TOUCH: + LOGI(INDENT " touch.pressure.source: touch"); + break; + case Calibration::PRESSURE_SOURCE_DEFAULT: + break; + default: + assert(false); + } + + if (mCalibration.havePressureScale) { + LOGI(INDENT " touch.pressure.scale: %f", mCalibration.pressureScale); + } + + // Size + switch (mCalibration.sizeCalibration) { + case Calibration::SIZE_CALIBRATION_NONE: + LOGI(INDENT " touch.size.calibration: none"); + break; + case Calibration::SIZE_CALIBRATION_NORMALIZED: + LOGI(INDENT " touch.size.calibration: normalized"); + break; + default: + assert(false); + } + + // Orientation + switch (mCalibration.orientationCalibration) { + case Calibration::ORIENTATION_CALIBRATION_NONE: + LOGI(INDENT " touch.orientation.calibration: none"); + break; + case Calibration::ORIENTATION_CALIBRATION_INTERPOLATED: + LOGI(INDENT " touch.orientation.calibration: interpolated"); + break; + default: + assert(false); + } +} + void TouchInputMapper::reset() { // Synthesize touch up event if touch is currently down. // This will also take care of finishing virtual key processing if needed. @@ -1584,13 +2071,14 @@ void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { // The dispatcher takes care of batching moves so we don't have to deal with that here. int32_t motionEventAction = AMOTION_EVENT_ACTION_MOVE; dispatchTouch(when, policyFlags, & mCurrentTouch, - currentIdBits, -1, motionEventAction); + currentIdBits, -1, currentPointerCount, motionEventAction); } else { // There may be pointers going up and pointers going down at the same time when pointer // ids are reported by the device driver. BitSet32 upIdBits(lastIdBits.value & ~ currentIdBits.value); BitSet32 downIdBits(currentIdBits.value & ~ lastIdBits.value); BitSet32 activeIdBits(lastIdBits.value); + uint32_t pointerCount = lastPointerCount; while (! upIdBits.isEmpty()) { uint32_t upId = upIdBits.firstMarkedBit(); @@ -1606,7 +2094,8 @@ void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { } dispatchTouch(when, policyFlags, & mLastTouch, - oldActiveIdBits, upId, motionEventAction); + oldActiveIdBits, upId, pointerCount, motionEventAction); + pointerCount -= 1; } while (! downIdBits.isEmpty()) { @@ -1623,16 +2112,16 @@ void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { motionEventAction = AMOTION_EVENT_ACTION_POINTER_DOWN; } + pointerCount += 1; dispatchTouch(when, policyFlags, & mCurrentTouch, - activeIdBits, downId, motionEventAction); + activeIdBits, downId, pointerCount, motionEventAction); } } } void TouchInputMapper::dispatchTouch(nsecs_t when, uint32_t policyFlags, - TouchData* touch, BitSet32 idBits, uint32_t changedId, + TouchData* touch, BitSet32 idBits, uint32_t changedId, uint32_t pointerCount, int32_t motionEventAction) { - uint32_t pointerCount = 0; int32_t pointerIds[MAX_POINTERS]; PointerCoords pointerCoords[MAX_POINTERS]; int32_t motionEventEdgeFlags = 0; @@ -1643,36 +2132,130 @@ void TouchInputMapper::dispatchTouch(nsecs_t when, uint32_t policyFlags, // Walk through the the active pointers and map touch screen coordinates (TouchData) into // display coordinates (PointerCoords) and adjust for display orientation. - while (! idBits.isEmpty()) { + for (uint32_t outIndex = 0; ! idBits.isEmpty(); outIndex++) { uint32_t id = idBits.firstMarkedBit(); idBits.clearBit(id); - uint32_t index = touch->idToIndex[id]; - - float x = float(touch->pointers[index].x - mLocked.xOrigin) * mLocked.xScale; - float y = float(touch->pointers[index].y - mLocked.yOrigin) * mLocked.yScale; - float pressure = float(touch->pointers[index].pressure - mLocked.pressureOrigin) - * mLocked.pressureScale; - float size = float(touch->pointers[index].size - mLocked.sizeOrigin) - * mLocked.sizeScale; - - float orientation = float(touch->pointers[index].orientation) - * mLocked.orientationScale; - - float touchMajor, touchMinor, toolMajor, toolMinor; - if (abs(orientation) <= M_PI_4) { - // Nominally vertical orientation: scale major axis by Y, and scale minor axis by X. - touchMajor = float(touch->pointers[index].touchMajor) * mLocked.yScale; - touchMinor = float(touch->pointers[index].touchMinor) * mLocked.xScale; - toolMajor = float(touch->pointers[index].toolMajor) * mLocked.yScale; - toolMinor = float(touch->pointers[index].toolMinor) * mLocked.xScale; - } else { - // Nominally horizontal orientation: scale major axis by X, and scale minor axis by Y. - touchMajor = float(touch->pointers[index].touchMajor) * mLocked.xScale; - touchMinor = float(touch->pointers[index].touchMinor) * mLocked.yScale; - toolMajor = float(touch->pointers[index].toolMajor) * mLocked.xScale; - toolMinor = float(touch->pointers[index].toolMinor) * mLocked.yScale; + uint32_t inIndex = touch->idToIndex[id]; + + const PointerData& in = touch->pointers[inIndex]; + + // X and Y + float x = float(in.x - mLocked.xOrigin) * mLocked.xScale; + float y = float(in.y - mLocked.yOrigin) * mLocked.yScale; + + // ToolMajor and ToolMinor + float toolMajor, toolMinor; + switch (mCalibration.toolAreaCalibration) { + case Calibration::TOOL_AREA_CALIBRATION_GEOMETRIC: + toolMajor = in.toolMajor * mLocked.geometricScale; + if (mRawAxes.toolMinor.valid) { + toolMinor = in.toolMinor * mLocked.geometricScale; + } else { + toolMinor = toolMajor; + } + break; + case Calibration::TOOL_AREA_CALIBRATION_LINEAR: + toolMajor = in.toolMajor != 0 + ? in.toolMajor * mLocked.toolAreaLinearScale + mLocked.toolAreaLinearBias + : 0; + if (mRawAxes.toolMinor.valid) { + toolMinor = in.toolMinor != 0 + ? in.toolMinor * mLocked.toolAreaLinearScale + + mLocked.toolAreaLinearBias + : 0; + } else { + toolMinor = toolMajor; + } + break; + default: + toolMajor = 0; + toolMinor = 0; + break; + } + + if (mCalibration.haveToolAreaIsSummed && mCalibration.toolAreaIsSummed) { + toolMajor /= pointerCount; + toolMinor /= pointerCount; + } + + // Pressure + float rawPressure; + switch (mCalibration.pressureSource) { + case Calibration::PRESSURE_SOURCE_PRESSURE: + rawPressure = in.pressure; + break; + case Calibration::PRESSURE_SOURCE_TOUCH: + rawPressure = in.touchMajor; + break; + default: + rawPressure = 0; + } + + float pressure; + switch (mCalibration.pressureCalibration) { + case Calibration::PRESSURE_CALIBRATION_PHYSICAL: + case Calibration::PRESSURE_CALIBRATION_AMPLITUDE: + pressure = rawPressure * mLocked.pressureScale; + break; + default: + pressure = 1; + break; + } + + // TouchMajor and TouchMinor + float touchMajor, touchMinor; + switch (mCalibration.touchAreaCalibration) { + case Calibration::TOUCH_AREA_CALIBRATION_GEOMETRIC: + touchMajor = in.touchMajor * mLocked.geometricScale; + if (mRawAxes.touchMinor.valid) { + touchMinor = in.touchMinor * mLocked.geometricScale; + } else { + touchMinor = touchMajor; + } + break; + case Calibration::TOUCH_AREA_CALIBRATION_PRESSURE: + touchMajor = toolMajor * pressure; + touchMinor = toolMinor * pressure; + break; + default: + touchMajor = 0; + touchMinor = 0; + break; + } + + if (touchMajor > toolMajor) { + touchMajor = toolMajor; + } + if (touchMinor > toolMinor) { + touchMinor = toolMinor; + } + + // Size + float size; + switch (mCalibration.sizeCalibration) { + case Calibration::SIZE_CALIBRATION_NORMALIZED: { + float rawSize = mRawAxes.toolMinor.valid + ? avg(in.toolMajor, in.toolMinor) + : in.toolMajor; + size = rawSize * mLocked.sizeScale; + break; + } + default: + size = 0; + break; } + // Orientation + float orientation; + switch (mCalibration.orientationCalibration) { + case Calibration::ORIENTATION_CALIBRATION_INTERPOLATED: + orientation = in.orientation * mLocked.orientationScale; + break; + default: + orientation = 0; + } + + // Adjust coords for orientation. switch (mLocked.surfaceOrientation) { case InputReaderPolicyInterface::ROTATION_90: { float xTemp = x; @@ -1702,23 +2285,23 @@ void TouchInputMapper::dispatchTouch(nsecs_t when, uint32_t policyFlags, } } - pointerIds[pointerCount] = int32_t(id); + // Write output coords. + PointerCoords& out = pointerCoords[outIndex]; + out.x = x; + out.y = y; + out.pressure = pressure; + out.size = size; + out.touchMajor = touchMajor; + out.touchMinor = touchMinor; + out.toolMajor = toolMajor; + out.toolMinor = toolMinor; + out.orientation = orientation; - pointerCoords[pointerCount].x = x; - pointerCoords[pointerCount].y = y; - pointerCoords[pointerCount].pressure = pressure; - pointerCoords[pointerCount].size = size; - pointerCoords[pointerCount].touchMajor = touchMajor; - pointerCoords[pointerCount].touchMinor = touchMinor; - pointerCoords[pointerCount].toolMajor = toolMajor; - pointerCoords[pointerCount].toolMinor = toolMinor; - pointerCoords[pointerCount].orientation = orientation; + pointerIds[outIndex] = int32_t(id); if (id == changedId) { - motionEventAction |= pointerCount << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; + motionEventAction |= outIndex << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; } - - pointerCount += 1; } // Check edge flags by looking only at the first pointer since the flags are @@ -1747,9 +2330,9 @@ void TouchInputMapper::dispatchTouch(nsecs_t when, uint32_t policyFlags, } bool TouchInputMapper::isPointInsideSurfaceLocked(int32_t x, int32_t y) { - if (mAxes.x.valid && mAxes.y.valid) { - return x >= mAxes.x.minValue && x <= mAxes.x.maxValue - && y >= mAxes.y.minValue && y <= mAxes.y.maxValue; + if (mRawAxes.x.valid && mRawAxes.y.valid) { + return x >= mRawAxes.x.minValue && x <= mRawAxes.x.maxValue + && y >= mRawAxes.y.minValue && y <= mRawAxes.y.maxValue; } return true; } @@ -1960,7 +2543,7 @@ void TouchInputMapper::calculatePointerIds() { * then drop it. */ bool TouchInputMapper::applyBadTouchFilter() { // This hack requires valid axis parameters. - if (! mAxes.y.valid) { + if (! mRawAxes.y.valid) { return false; } @@ -1982,7 +2565,7 @@ bool TouchInputMapper::applyBadTouchFilter() { // the long size of the screen to be bad. This was a magic value // determined by looking at the maximum distance it is feasible // to actually move in one sample. - int32_t maxDeltaY = mAxes.y.getRange() * 7 / 16; + int32_t maxDeltaY = mRawAxes.y.getRange() * 7 / 16; // XXX The original code in InputDevice.java included commented out // code for testing the X axis. Note that when we drop a point @@ -2044,7 +2627,7 @@ bool TouchInputMapper::applyBadTouchFilter() { */ bool TouchInputMapper::applyJumpyTouchFilter() { // This hack requires valid axis parameters. - if (! mAxes.y.valid) { + if (! mRawAxes.y.valid) { return false; } @@ -2104,7 +2687,7 @@ bool TouchInputMapper::applyJumpyTouchFilter() { } if (mJumpyTouchFilter.jumpyPointsDropped < JUMPY_DROP_LIMIT) { - int jumpyEpsilon = mAxes.y.getRange() / JUMPY_EPSILON_DIVISOR; + int jumpyEpsilon = mRawAxes.y.getRange() / JUMPY_EPSILON_DIVISOR; // We only replace the single worst jumpy point as characterized by pointer distance // in a single axis. @@ -2209,7 +2792,18 @@ void TouchInputMapper::applyAveragingTouchFilter() { uint32_t id = mCurrentTouch.pointers[currentIndex].id; int32_t x = mCurrentTouch.pointers[currentIndex].x; int32_t y = mCurrentTouch.pointers[currentIndex].y; - int32_t pressure = mCurrentTouch.pointers[currentIndex].pressure; + int32_t pressure; + switch (mCalibration.pressureSource) { + case Calibration::PRESSURE_SOURCE_PRESSURE: + pressure = mCurrentTouch.pointers[currentIndex].pressure; + break; + case Calibration::PRESSURE_SOURCE_TOUCH: + pressure = mCurrentTouch.pointers[currentIndex].touchMajor; + break; + default: + pressure = 1; + break; + } if (mLastTouch.idBits.hasBit(id)) { // Pointer was down before and is still down now. @@ -2274,17 +2868,19 @@ void TouchInputMapper::applyAveragingTouchFilter() { } } - averagedX /= totalPressure; - averagedY /= totalPressure; + if (totalPressure != 0) { + averagedX /= totalPressure; + averagedY /= totalPressure; #if DEBUG_HACKS - LOGD("AveragingTouchFilter: Pointer id %d - " - "totalPressure=%d, averagedX=%d, averagedY=%d", id, totalPressure, - averagedX, averagedY); + LOGD("AveragingTouchFilter: Pointer id %d - " + "totalPressure=%d, averagedX=%d, averagedY=%d", id, totalPressure, + averagedX, averagedY); #endif - mCurrentTouch.pointers[currentIndex].x = averagedX; - mCurrentTouch.pointers[currentIndex].y = averagedY; + mCurrentTouch.pointers[currentIndex].x = averagedX; + mCurrentTouch.pointers[currentIndex].y = averagedY; + } } else { #if DEBUG_HACKS LOGD("AveragingTouchFilter: Pointer id %d - Exceeded max distance", id); @@ -2382,8 +2978,8 @@ void SingleTouchInputMapper::initialize() { mDown = false; mX = 0; mY = 0; - mPressure = 1; // default to 1 for devices that don't report pressure - mSize = 0; // default to 0 for devices that don't report size + mPressure = 0; // default to 0 for devices that don't report pressure + mToolWidth = 0; // default to 0 for devices that don't report tool width } void SingleTouchInputMapper::reset() { @@ -2460,7 +3056,7 @@ void SingleTouchInputMapper::sync(nsecs_t when) { } if (fields & Accumulator::FIELD_ABS_TOOL_WIDTH) { - mSize = mAccumulator.absToolWidth; + mToolWidth = mAccumulator.absToolWidth; } mCurrentTouch.clear(); @@ -2471,11 +3067,10 @@ void SingleTouchInputMapper::sync(nsecs_t when) { mCurrentTouch.pointers[0].x = mX; mCurrentTouch.pointers[0].y = mY; mCurrentTouch.pointers[0].pressure = mPressure; - mCurrentTouch.pointers[0].size = mSize; - mCurrentTouch.pointers[0].touchMajor = mSize; - mCurrentTouch.pointers[0].touchMinor = mSize; - mCurrentTouch.pointers[0].toolMajor = mSize; - mCurrentTouch.pointers[0].toolMinor = mSize; + mCurrentTouch.pointers[0].touchMajor = 0; + mCurrentTouch.pointers[0].touchMinor = 0; + mCurrentTouch.pointers[0].toolMajor = mToolWidth; + mCurrentTouch.pointers[0].toolMinor = mToolWidth; mCurrentTouch.pointers[0].orientation = 0; mCurrentTouch.idToIndex[0] = 0; mCurrentTouch.idBits.markBit(0); @@ -2486,20 +3081,13 @@ void SingleTouchInputMapper::sync(nsecs_t when) { mAccumulator.clear(); } -void SingleTouchInputMapper::configureAxes() { - TouchInputMapper::configureAxes(); - - // The axes are aliased to take into account the manner in which they are presented - // as part of the TouchData during the sync. - getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_X, & mAxes.x); - getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_Y, & mAxes.y); - getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_PRESSURE, & mAxes.pressure); - getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_TOOL_WIDTH, & mAxes.size); +void SingleTouchInputMapper::configureRawAxes() { + TouchInputMapper::configureRawAxes(); - mAxes.touchMajor = mAxes.size; - mAxes.touchMinor = mAxes.size; - mAxes.toolMajor = mAxes.size; - mAxes.toolMinor = mAxes.size; + getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_X, & mRawAxes.x); + getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_Y, & mRawAxes.y); + getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_PRESSURE, & mRawAxes.pressure); + getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_TOOL_WIDTH, & mRawAxes.toolMajor); } @@ -2562,6 +3150,10 @@ void MultiTouchInputMapper::process(const RawEvent* rawEvent) { pointer->fields |= Accumulator::FIELD_ABS_MT_TRACKING_ID; pointer->absMTTrackingId = rawEvent->value; break; + case ABS_MT_PRESSURE: + pointer->fields |= Accumulator::FIELD_ABS_MT_PRESSURE; + pointer->absMTPressure = rawEvent->value; + break; } break; } @@ -2596,8 +3188,7 @@ void MultiTouchInputMapper::process(const RawEvent* rawEvent) { void MultiTouchInputMapper::sync(nsecs_t when) { static const uint32_t REQUIRED_FIELDS = - Accumulator::FIELD_ABS_MT_POSITION_X - | Accumulator::FIELD_ABS_MT_POSITION_Y; + Accumulator::FIELD_ABS_MT_POSITION_X | Accumulator::FIELD_ABS_MT_POSITION_Y; uint32_t inCount = mAccumulator.pointerCount; uint32_t outCount = 0; @@ -2619,60 +3210,59 @@ void MultiTouchInputMapper::sync(nsecs_t when) { outPointer.x = inPointer.absMTPositionX; outPointer.y = inPointer.absMTPositionY; + if (fields & Accumulator::FIELD_ABS_MT_PRESSURE) { + if (inPointer.absMTPressure <= 0) { + // Some devices send sync packets with X / Y but with a 0 presure to indicate + // a pointer up. Drop this finger. + continue; + } + outPointer.pressure = inPointer.absMTPressure; + } else { + // Default pressure to 0 if absent. + outPointer.pressure = 0; + } + if (fields & Accumulator::FIELD_ABS_MT_TOUCH_MAJOR) { - int32_t value = inPointer.absMTTouchMajor; - if (value <= 0) { + if (inPointer.absMTTouchMajor <= 0) { // Some devices send sync packets with X / Y but with a 0 touch major to indicate - // a pointer up. Drop this finger. + // a pointer going up. Drop this finger. continue; } outPointer.touchMajor = inPointer.absMTTouchMajor; } else { + // Default touch area to 0 if absent. outPointer.touchMajor = 0; } if (fields & Accumulator::FIELD_ABS_MT_TOUCH_MINOR) { outPointer.touchMinor = inPointer.absMTTouchMinor; } else { + // Assume touch area is circular. outPointer.touchMinor = outPointer.touchMajor; } if (fields & Accumulator::FIELD_ABS_MT_WIDTH_MAJOR) { outPointer.toolMajor = inPointer.absMTWidthMajor; } else { - outPointer.toolMajor = outPointer.touchMajor; + // Default tool area to 0 if absent. + outPointer.toolMajor = 0; } if (fields & Accumulator::FIELD_ABS_MT_WIDTH_MINOR) { outPointer.toolMinor = inPointer.absMTWidthMinor; } else { + // Assume tool area is circular. outPointer.toolMinor = outPointer.toolMajor; } if (fields & Accumulator::FIELD_ABS_MT_ORIENTATION) { outPointer.orientation = inPointer.absMTOrientation; } else { + // Default orientation to vertical if absent. outPointer.orientation = 0; } - if (fields & Accumulator::FIELD_ABS_MT_PRESSURE) { - outPointer.pressure = inPointer.absMTPressure; - } else { - // Derive an approximation of pressure. - // FIXME Traditionally we have just passed a normalized value based on - // ABS_MT_TOUCH_MAJOR as an estimate of pressure but the result is not - // very meaningful, particularly on large displays. We should probably let - // pressure = touch_major / tool_major but it is unclear whether that will - // break applications. - outPointer.pressure = outPointer.touchMajor; - } - - // Size is an alias for a normalized tool width. - // FIXME Normalized tool width doesn't actually make much sense since it literally - // means the approaching contact major axis is divided by its full range as - // reported by the driver. On a large display this could produce very small values. - outPointer.size = outPointer.toolMajor; - + // Assign pointer id using tracking id if available. if (havePointerIds) { if (fields & Accumulator::FIELD_ABS_MT_TRACKING_ID) { uint32_t id = uint32_t(inPointer.absMTTrackingId); @@ -2705,33 +3295,17 @@ void MultiTouchInputMapper::sync(nsecs_t when) { mAccumulator.clear(); } -void MultiTouchInputMapper::configureAxes() { - TouchInputMapper::configureAxes(); - - // The axes are aliased to take into account the manner in which they are presented - // as part of the TouchData during the sync. - getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_POSITION_X, & mAxes.x); - getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_POSITION_Y, & mAxes.y); - getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_TOUCH_MAJOR, & mAxes.touchMajor); - getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_TOUCH_MINOR, & mAxes.touchMinor); - getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_WIDTH_MAJOR, & mAxes.toolMajor); - getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_WIDTH_MINOR, & mAxes.toolMinor); - getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_ORIENTATION, & mAxes.orientation); - getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_PRESSURE, & mAxes.pressure); - - if (! mAxes.touchMinor.valid) { - mAxes.touchMinor = mAxes.touchMajor; - } - - if (! mAxes.toolMinor.valid) { - mAxes.toolMinor = mAxes.toolMajor; - } - - if (! mAxes.pressure.valid) { - mAxes.pressure = mAxes.touchMajor; - } +void MultiTouchInputMapper::configureRawAxes() { + TouchInputMapper::configureRawAxes(); - mAxes.size = mAxes.toolMajor; + getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_POSITION_X, & mRawAxes.x); + getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_POSITION_Y, & mRawAxes.y); + getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_TOUCH_MAJOR, & mRawAxes.touchMajor); + getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_TOUCH_MINOR, & mRawAxes.touchMinor); + getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_WIDTH_MAJOR, & mRawAxes.toolMajor); + getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_WIDTH_MINOR, & mRawAxes.toolMinor); + getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_ORIENTATION, & mRawAxes.orientation); + getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_PRESSURE, & mRawAxes.pressure); } diff --git a/media/libstagefright/rtsp/ARTPConnection.cpp b/media/libstagefright/rtsp/ARTPConnection.cpp index 42a22b71d9e4..12f8f323b61a 100644 --- a/media/libstagefright/rtsp/ARTPConnection.cpp +++ b/media/libstagefright/rtsp/ARTPConnection.cpp @@ -263,6 +263,10 @@ void ARTPConnection::onPollStreams() { } } + if (maxSocket == -1) { + return; + } + int res = select(maxSocket + 1, &rs, NULL, NULL, &tv); CHECK_GE(res, 0); @@ -292,6 +296,10 @@ void ARTPConnection::onPollStreams() { it != mStreams.end(); ++it) { StreamInfo *s = &*it; + if (s->mIsInjected) { + continue; + } + if (s->mNumRTCPPacketsReceived == 0) { // We have never received any RTCP packets on this stream, // we don't even know where to send a report. diff --git a/media/libstagefright/rtsp/ARTPSession.cpp b/media/libstagefright/rtsp/ARTPSession.cpp index d2c56f70ff0c..f60c1a9eea59 100644 --- a/media/libstagefright/rtsp/ARTPSession.cpp +++ b/media/libstagefright/rtsp/ARTPSession.cpp @@ -167,6 +167,7 @@ void ARTPSession::onMessageReceived(const sp<AMessage> &msg) { #endif accessUnit->meta()->setInt64("ntp-time", ntpTime); + accessUnit->meta()->setInt64("timeUs", 0); #if 0 int32_t damaged; diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h index 7c06db3077e0..3d8d86bf6cf5 100644 --- a/media/libstagefright/rtsp/MyHandler.h +++ b/media/libstagefright/rtsp/MyHandler.h @@ -31,8 +31,6 @@ #include <media/stagefright/foundation/AMessage.h> #include <media/stagefright/MediaErrors.h> -#define USE_TCP_INTERLEAVED 0 - // If no access units are received within 3 secs, assume that the rtp // stream has ended and signal end of stream. static int64_t kAccessUnitTimeoutUs = 3000000ll; @@ -83,7 +81,8 @@ struct MyHandler : public AHandler { mFirstAccessUnit(true), mFirstAccessUnitNTP(0), mNumAccessUnitsReceived(0), - mCheckPending(false) { + mCheckPending(false), + mTryTCPInterleaving(false) { mNetLooper->setName("rtsp net"); mNetLooper->start(false /* runOnCallingThread */, false /* canCallJava */, @@ -158,7 +157,13 @@ struct MyHandler : public AHandler { case 'disc': { - (new AMessage('quit', id()))->post(); + int32_t reconnect; + if (msg->findInt32("reconnect", &reconnect) && reconnect) { + sp<AMessage> reply = new AMessage('conn', id()); + mConn->connect(mSessionURL.c_str(), reply); + } else { + (new AMessage('quit', id()))->post(); + } break; } @@ -325,10 +330,6 @@ struct MyHandler : public AHandler { parsePlayResponse(response); - mDoneMsg->setInt32("result", OK); - mDoneMsg->post(); - mDoneMsg = NULL; - sp<AMessage> timeout = new AMessage('tiou', id()); timeout->post(kStartupTimeoutUs); } else { @@ -342,12 +343,26 @@ struct MyHandler : public AHandler { case 'abor': { for (size_t i = 0; i < mTracks.size(); ++i) { - mTracks.editItemAt(i).mPacketSource->signalEOS( - ERROR_END_OF_STREAM); + TrackInfo *info = &mTracks.editItemAt(i); + + info->mPacketSource->signalEOS(ERROR_END_OF_STREAM); + + if (!info->mUsingInterleavedTCP) { + mRTPConn->removeStream(info->mRTPSocket, info->mRTCPSocket); + + close(info->mRTPSocket); + close(info->mRTCPSocket); + } } + mTracks.clear(); sp<AMessage> reply = new AMessage('tear', id()); + int32_t reconnect; + if (msg->findInt32("reconnect", &reconnect) && reconnect) { + reply->setInt32("reconnect", true); + } + AString request; request = "TEARDOWN "; @@ -374,6 +389,12 @@ struct MyHandler : public AHandler { << result << " (" << strerror(-result) << ")"; sp<AMessage> reply = new AMessage('disc', id()); + + int32_t reconnect; + if (msg->findInt32("reconnect", &reconnect) && reconnect) { + reply->setInt32("reconnect", true); + } + mConn->disconnect(reply); break; } @@ -414,6 +435,11 @@ struct MyHandler : public AHandler { size_t trackIndex; CHECK(msg->findSize("track-index", &trackIndex)); + if (trackIndex >= mTracks.size()) { + LOG(ERROR) << "late packets ignored."; + break; + } + TrackInfo *track = &mTracks.editItemAt(trackIndex); int32_t eos; @@ -457,6 +483,10 @@ struct MyHandler : public AHandler { } if (mFirstAccessUnit) { + mDoneMsg->setInt32("result", OK); + mDoneMsg->post(); + mDoneMsg = NULL; + mFirstAccessUnit = false; mFirstAccessUnitNTP = ntpTime; } @@ -583,8 +613,19 @@ struct MyHandler : public AHandler { case 'tiou': { if (mFirstAccessUnit) { - LOG(WARNING) << "Never received any data, disconnecting."; - (new AMessage('abor', id()))->post(); + if (mTryTCPInterleaving) { + LOG(WARNING) << "Never received any data, disconnecting."; + (new AMessage('abor', id()))->post(); + } else { + LOG(WARNING) + << "Never received any data, switching transports."; + + mTryTCPInterleaving = true; + + sp<AMessage> msg = new AMessage('abor', id()); + msg->setInt32("reconnect", true); + msg->post(); + } } break; } @@ -705,6 +746,7 @@ private: uint64_t mFirstAccessUnitNTP; int64_t mNumAccessUnitsReceived; bool mCheckPending; + bool mTryTCPInterleaving; struct TrackInfo { AString mURL; @@ -723,6 +765,7 @@ private: void setupTrack(size_t index) { sp<APacketSource> source = new APacketSource(mSessionDesc, index); + if (source->initCheck() != OK) { LOG(WARNING) << "Unsupported format. Ignoring track #" << index << "."; @@ -754,26 +797,26 @@ private: request.append(trackURL); request.append(" RTSP/1.0\r\n"); -#if USE_TCP_INTERLEAVED - size_t interleaveIndex = 2 * (mTracks.size() - 1); - info->mUsingInterleavedTCP = true; - info->mRTPSocket = interleaveIndex; - info->mRTCPSocket = interleaveIndex + 1; - - request.append("Transport: RTP/AVP/TCP;interleaved="); - request.append(interleaveIndex); - request.append("-"); - request.append(interleaveIndex + 1); -#else - unsigned rtpPort; - ARTPConnection::MakePortPair( - &info->mRTPSocket, &info->mRTCPSocket, &rtpPort); - - request.append("Transport: RTP/AVP/UDP;unicast;client_port="); - request.append(rtpPort); - request.append("-"); - request.append(rtpPort + 1); -#endif + if (mTryTCPInterleaving) { + size_t interleaveIndex = 2 * (mTracks.size() - 1); + info->mUsingInterleavedTCP = true; + info->mRTPSocket = interleaveIndex; + info->mRTCPSocket = interleaveIndex + 1; + + request.append("Transport: RTP/AVP/TCP;interleaved="); + request.append(interleaveIndex); + request.append("-"); + request.append(interleaveIndex + 1); + } else { + unsigned rtpPort; + ARTPConnection::MakePortPair( + &info->mRTPSocket, &info->mRTCPSocket, &rtpPort); + + request.append("Transport: RTP/AVP/UDP;unicast;client_port="); + request.append(rtpPort); + request.append("-"); + request.append(rtpPort + 1); + } request.append("\r\n"); diff --git a/native/include/android/input.h b/native/include/android/input.h index 243c33c3a714..d9486e5a7170 100644 --- a/native/include/android/input.h +++ b/native/include/android/input.h @@ -718,8 +718,6 @@ int32_t AInputDevice_getKeyboardType(AInputDevice* device); int32_t AInputDevice_getMotionRange(AInputDevice* device, int32_t rangeType, float* outMin, float* outMax, float* outFlat, float* outFuzz); -//TODO hasKey, keymap stuff, etc... - #ifdef __cplusplus } #endif diff --git a/packages/SystemUI/proguard.flags b/packages/SystemUI/proguard.flags index 9ccc5a95633b..72bd77666aff 100644 --- a/packages/SystemUI/proguard.flags +++ b/packages/SystemUI/proguard.flags @@ -1,4 +1,5 @@ -keep class com.android.systemui.statusbar.tablet.TabletStatusBarService { public void notificationIconsClicked(android.view.View); public void systemInfoClicked(android.view.View); + public void recentButtonClicked(android.view.View); } diff --git a/packages/SystemUI/res/drawable/status_bar_recent.xml b/packages/SystemUI/res/drawable/status_bar_recent.xml new file mode 100755 index 000000000000..d708455f0cb5 --- /dev/null +++ b/packages/SystemUI/res/drawable/status_bar_recent.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2008 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_pressed="true" android:drawable="@drawable/status_bar_recent_pressed" /> + <item android:drawable="@drawable/status_bar_recent_default" /> +</selector> + diff --git a/packages/SystemUI/res/layout-xlarge/status_bar.xml b/packages/SystemUI/res/layout-xlarge/status_bar.xml index 481bcde0a500..a0c2c9504004 100644 --- a/packages/SystemUI/res/layout-xlarge/status_bar.xml +++ b/packages/SystemUI/res/layout-xlarge/status_bar.xml @@ -118,12 +118,21 @@ <com.android.systemui.statusbar.KeyButtonView android:id="@+id/menu" android:layout_width="wrap_content" android:layout_height="match_parent" - android:layout_toLeftOf="@+id/home" + android:layout_toLeftOf="@+id/recent" android:src="@drawable/status_bar_menu" android:paddingLeft="4dip" android:paddingRight="4dip" systemui:keyCode="82" /> + <Button android:id="@+id/recent" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:layout_toLeftOf="@+id/home" + android:background="@drawable/status_bar_recent" + android:paddingLeft="4dip" + android:paddingRight="4dip" + android:onClick="recentButtonClicked" + /> <com.android.systemui.statusbar.KeyButtonView android:id="@+id/home" android:layout_width="wrap_content" android:layout_height="match_parent" diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SystemPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SystemPanel.java index dfa2d10ae358..a32b01fd8f9e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SystemPanel.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SystemPanel.java @@ -78,7 +78,7 @@ import com.android.systemui.R; public class SystemPanel extends LinearLayout { private static final String TAG = "SystemPanel"; private static final boolean DEBUG = TabletStatusBarService.DEBUG; - private static final boolean DEBUG_SIGNAL = true; + private static final boolean DEBUG_SIGNAL = false; private static final int MINIMUM_BACKLIGHT = android.os.Power.BRIGHTNESS_DIM + 5; private static final int MAXIMUM_BACKLIGHT = android.os.Power.BRIGHTNESS_ON; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarService.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarService.java index 087671ac7814..312c5f44a807 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarService.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarService.java @@ -22,6 +22,7 @@ import android.app.Notification; import android.app.PendingIntent; import android.app.Service; import android.app.StatusBarManager; +import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; import android.content.res.Resources; @@ -495,6 +496,15 @@ public class TabletStatusBarService extends StatusBarService { mHandler.sendEmptyMessage(msg); } + public void recentButtonClicked(View v) { + if (DEBUG) Slog.d(TAG, "clicked recent apps"); + Intent intent = new Intent(); + intent.setClass(this, RecentApplicationsActivity.class); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); + startActivity(intent); + } + /** * Cancel this notification and tell the status bar service about the failure. Hold no locks. */ diff --git a/services/java/com/android/server/BootReceiver.java b/services/java/com/android/server/BootReceiver.java index d15a05832db2..b9ff8d0ce7bb 100644 --- a/services/java/com/android/server/BootReceiver.java +++ b/services/java/com/android/server/BootReceiver.java @@ -167,7 +167,7 @@ public class BootReceiver extends BroadcastReceiver { if (lastTime == fileTime) return; // Already logged this particular file // TODO: move all these SharedPreferences Editor commits // outside this function to the end of logBootEvents - prefs.edit().putLong(filename, fileTime).startCommit(); + prefs.edit().putLong(filename, fileTime).apply(); } Slog.i(TAG, "Copying " + filename + " to DropBox (" + tag + ")"); diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 57e8e021fe20..6f23805c0e9a 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -26,7 +26,7 @@ import android.net.ConnectivityManager; import android.net.IConnectivityManager; import android.net.MobileDataStateTracker; import android.net.NetworkInfo; -import android.net.NetworkProperties; +import android.net.LinkProperties; import android.net.NetworkStateTracker; import android.net.NetworkUtils; import android.net.wifi.WifiStateTracker; @@ -756,7 +756,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { * specified host is to be routed * @param hostAddress the IP address of the host to which the route is * desired - * todo - deprecate (only v4!) * @return {@code true} on success, {@code false} on failure */ public boolean requestRouteToHost(int networkType, int hostAddress) { @@ -813,7 +812,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { return false; } - NetworkProperties p = nt.getNetworkProperties(); + LinkProperties p = nt.getLinkProperties(); if (p == null) return false; String interfaceName = p.getInterfaceName(); @@ -1258,7 +1257,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { private void addPrivateDnsRoutes(NetworkStateTracker nt) { boolean privateDnsRouteSet = nt.isPrivateDnsRouteSet(); - NetworkProperties p = nt.getNetworkProperties(); + LinkProperties p = nt.getLinkProperties(); if (p == null) return; String interfaceName = p.getInterfaceName(); @@ -1279,7 +1278,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { private void removePrivateDnsRoutes(NetworkStateTracker nt) { // TODO - we should do this explicitly but the NetUtils api doesnt // support this yet - must remove all. No worse than before - NetworkProperties p = nt.getNetworkProperties(); + LinkProperties p = nt.getLinkProperties(); if (p == null) return; String interfaceName = p.getInterfaceName(); boolean privateDnsRouteSet = nt.isPrivateDnsRouteSet(); @@ -1295,7 +1294,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { private void addDefaultRoute(NetworkStateTracker nt) { - NetworkProperties p = nt.getNetworkProperties(); + LinkProperties p = nt.getLinkProperties(); if (p == null) return; String interfaceName = p.getInterfaceName(); InetAddress defaultGatewayAddr = p.getGateway(); @@ -1311,7 +1310,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { public void removeDefaultRoute(NetworkStateTracker nt) { - NetworkProperties p = nt.getNetworkProperties(); + LinkProperties p = nt.getLinkProperties(); if (p == null) return; String interfaceName = p.getInterfaceName(); @@ -1410,7 +1409,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { NetworkStateTracker nt = mNetTrackers[i]; if (nt.getNetworkInfo().isConnected() && !nt.isTeardownRequested()) { - NetworkProperties p = nt.getNetworkProperties(); + LinkProperties p = nt.getLinkProperties(); if (p == null) continue; List pids = mNetRequestersPids[i]; for (int j=0; j<pids.size(); j++) { @@ -1465,7 +1464,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { // add default net's dns entries NetworkStateTracker nt = mNetTrackers[netType]; if (nt != null && nt.getNetworkInfo().isConnected() && !nt.isTeardownRequested()) { - NetworkProperties p = nt.getNetworkProperties(); + LinkProperties p = nt.getLinkProperties(); if (p == null) return; Collection<InetAddress> dnses = p.getDnses(); if (mNetAttributes[netType].isDefault()) { diff --git a/services/java/com/android/server/InputManager.java b/services/java/com/android/server/InputManager.java index f330d40a80f6..314dd8a70a8a 100644 --- a/services/java/com/android/server/InputManager.java +++ b/services/java/com/android/server/InputManager.java @@ -30,6 +30,7 @@ import android.os.SystemProperties; import android.util.Slog; import android.util.Xml; import android.view.InputChannel; +import android.view.InputDevice; import android.view.InputEvent; import android.view.KeyEvent; import android.view.MotionEvent; @@ -45,6 +46,7 @@ import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.Properties; /* * Wraps the C++ InputManager and provides its callbacks. @@ -82,6 +84,8 @@ public class InputManager { private static native void nativeSetInputDispatchMode(boolean enabled, boolean frozen); private static native void nativeSetFocusedApplication(InputApplication application); private static native void nativePreemptInputDispatch(); + private static native InputDevice nativeGetInputDevice(int deviceId); + private static native int[] nativeGetInputDeviceIds(); private static native String nativeDump(); // Input event injection constants defined in InputDispatcher.h. @@ -302,6 +306,23 @@ public class InputManager { return nativeInjectInputEvent(event, injectorPid, injectorUid, syncMode, timeoutMillis); } + /** + * Gets information about the input device with the specified id. + * @param id The device id. + * @return The input device or null if not found. + */ + public InputDevice getInputDevice(int deviceId) { + return nativeGetInputDevice(deviceId); + } + + /** + * Gets the ids of all input devices in the system. + * @return The input device ids. + */ + public int[] getInputDeviceIds() { + return nativeGetInputDeviceIds(); + } + public void setInputWindows(InputWindow[] windows) { nativeSetInputWindows(windows); } @@ -335,6 +356,11 @@ public class InputManager { public int height; } + private static final class InputDeviceCalibration { + public String[] keys; + public String[] values; + } + /* * Callbacks from native. */ @@ -343,6 +369,7 @@ public class InputManager { private static final boolean DEBUG_VIRTUAL_KEYS = false; private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml"; + private static final String CALIBRATION_DIR_PATH = "usr/idc/"; @SuppressWarnings("unused") public void virtualKeyDownFeedback() { @@ -438,8 +465,8 @@ public class InputManager { final int N = it.length-6; for (int i=0; i<=N; i+=6) { if (!"0x01".equals(it[i])) { - Slog.w(TAG, "Unknown virtual key type at elem #" + i - + ": " + it[i]); + Slog.w(TAG, "Unknown virtual key type at elem #" + + i + ": " + it[i] + " for device " + deviceName); continue; } try { @@ -455,22 +482,47 @@ public class InputManager { + key.height); keys.add(key); } catch (NumberFormatException e) { - Slog.w(TAG, "Bad number at region " + i + " in: " - + str, e); + Slog.w(TAG, "Bad number in virtual key definition at region " + + i + " in: " + str + " for device " + deviceName, e); } } } br.close(); } catch (FileNotFoundException e) { - Slog.i(TAG, "No virtual keys found"); + Slog.i(TAG, "No virtual keys found for device " + deviceName + "."); } catch (IOException e) { - Slog.w(TAG, "Error reading virtual keys", e); + Slog.w(TAG, "Error reading virtual keys for device " + deviceName + ".", e); } return keys.toArray(new VirtualKeyDefinition[keys.size()]); } @SuppressWarnings("unused") + public InputDeviceCalibration getInputDeviceCalibration(String deviceName) { + // Calibration is specified as a sequence of colon-delimited key value pairs. + Properties properties = new Properties(); + File calibrationFile = new File(Environment.getRootDirectory(), + CALIBRATION_DIR_PATH + deviceName + ".idc"); + if (calibrationFile.exists()) { + try { + properties.load(new FileInputStream(calibrationFile)); + } catch (IOException ex) { + Slog.w(TAG, "Error reading input device calibration properties for device " + + deviceName + " from " + calibrationFile + ".", ex); + } + } else { + Slog.i(TAG, "No input device calibration properties found for device " + + deviceName + "."); + return null; + } + + InputDeviceCalibration calibration = new InputDeviceCalibration(); + calibration.keys = properties.keySet().toArray(new String[properties.size()]); + calibration.values = properties.values().toArray(new String[properties.size()]); + return calibration; + } + + @SuppressWarnings("unused") public String[] getExcludedDeviceNames() { ArrayList<String> names = new ArrayList<String>(); diff --git a/services/java/com/android/server/TelephonyRegistry.java b/services/java/com/android/server/TelephonyRegistry.java index 73234df297ab..0a90a4cde285 100644 --- a/services/java/com/android/server/TelephonyRegistry.java +++ b/services/java/com/android/server/TelephonyRegistry.java @@ -19,7 +19,7 @@ package com.android.server; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; -import android.net.NetworkProperties; +import android.net.LinkProperties; import android.os.Binder; import android.os.Bundle; import android.os.IBinder; @@ -92,7 +92,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { private ArrayList<String> mConnectedApns; - private NetworkProperties mDataConnectionProperties; + private LinkProperties mDataConnectionProperties; private Bundle mCellLocation = new Bundle(); @@ -355,7 +355,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { } public void notifyDataConnection(int state, boolean isDataConnectivityPossible, - String reason, String apn, String apnType, NetworkProperties networkProperties, + String reason, String apn, String apnType, LinkProperties linkProperties, int networkType) { if (!checkNotifyPermission("notifyDataConnection()" )) { return; @@ -383,7 +383,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { mDataConnectionPossible = isDataConnectivityPossible; mDataConnectionReason = reason; mDataConnectionApn = apn; - mDataConnectionProperties = networkProperties; + mDataConnectionProperties = linkProperties; if (mDataConnectionNetworkType != networkType) { mDataConnectionNetworkType = networkType; modified = true; @@ -403,7 +403,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { } } broadcastDataConnectionStateChanged(state, isDataConnectivityPossible, reason, apn, - apnType, networkProperties); + apnType, linkProperties); } public void notifyDataConnectionFailed(String reason, String apnType) { @@ -564,7 +564,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { private void broadcastDataConnectionStateChanged(int state, boolean isDataConnectivityPossible, - String reason, String apn, String apnType, NetworkProperties networkProperties) { + String reason, String apn, String apnType, LinkProperties linkProperties) { // Note: not reporting to the battery stats service here, because the // status bar takes care of that after taking into account all of the // required info. @@ -577,9 +577,9 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { if (reason != null) { intent.putExtra(Phone.STATE_CHANGE_REASON_KEY, reason); } - if (networkProperties != null) { - intent.putExtra(Phone.DATA_NETWORK_PROPERTIES_KEY, networkProperties); - NetworkInterface iface = networkProperties.getInterface(); + if (linkProperties != null) { + intent.putExtra(Phone.DATA_LINK_PROPERTIES_KEY, linkProperties); + NetworkInterface iface = linkProperties.getInterface(); if (iface != null) { intent.putExtra(Phone.DATA_IFACE_NAME_KEY, iface.getName()); } diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java index 4407e96490e4..79bde7c2523f 100644 --- a/services/java/com/android/server/WindowManagerService.java +++ b/services/java/com/android/server/WindowManagerService.java @@ -4383,6 +4383,14 @@ public class WindowManagerService extends IWindowManager.Stub return mInputManager.monitorInput(inputChannelName); } + public InputDevice getInputDevice(int deviceId) { + return mInputManager.getInputDevice(deviceId); + } + + public int[] getInputDeviceIds() { + return mInputManager.getInputDeviceIds(); + } + public void enableScreenAfterBoot() { synchronized(mWindowMap) { if (mSystemBooted) { diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp index 3addc0d2e208..a237ee94bfb3 100644 --- a/services/jni/com_android_server_InputManager.cpp +++ b/services/jni/com_android_server_InputManager.cpp @@ -138,6 +138,7 @@ static struct { jmethodID filterTouchEvents; jmethodID filterJumpyTouchEvents; jmethodID getVirtualKeyDefinitions; + jmethodID getInputDeviceCalibration; jmethodID getExcludedDeviceNames; jmethodID getMaxEventsPerSecond; } gCallbacksClassInfo; @@ -155,6 +156,13 @@ static struct { static struct { jclass clazz; + jfieldID keys; + jfieldID values; +} gInputDeviceCalibrationClassInfo; + +static struct { + jclass clazz; + jfieldID inputChannel; jfieldID layoutParamsFlags; jfieldID layoutParamsType; @@ -189,6 +197,19 @@ static struct { jclass clazz; } gMotionEventClassInfo; +static struct { + jclass clazz; + + jmethodID ctor; + jmethodID addMotionRange; + + jfieldID mId; + jfieldID mName; + jfieldID mSources; + jfieldID mKeyboardType; + jfieldID mMotionRanges; +} gInputDeviceClassInfo; + // ---------------------------------------------------------------------------- static inline nsecs_t now() { @@ -235,7 +256,9 @@ public: virtual bool filterTouchEvents(); virtual bool filterJumpyTouchEvents(); virtual void getVirtualKeyDefinitions(const String8& deviceName, - Vector<InputReaderPolicyInterface::VirtualKeyDefinition>& outVirtualKeyDefinitions); + Vector<VirtualKeyDefinition>& outVirtualKeyDefinitions); + virtual void getInputDeviceCalibration(const String8& deviceName, + InputDeviceCalibration& outCalibration); virtual void getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames); /* --- InputDispatcherPolicyInterface implementation --- */ @@ -761,7 +784,9 @@ bool NativeInputManager::filterJumpyTouchEvents() { } void NativeInputManager::getVirtualKeyDefinitions(const String8& deviceName, - Vector<InputReaderPolicyInterface::VirtualKeyDefinition>& outVirtualKeyDefinitions) { + Vector<VirtualKeyDefinition>& outVirtualKeyDefinitions) { + outVirtualKeyDefinitions.clear(); + JNIEnv* env = jniEnv(); jstring deviceNameStr = env->NewStringUTF(deviceName.string()); @@ -793,7 +818,51 @@ void NativeInputManager::getVirtualKeyDefinitions(const String8& deviceName, } } +void NativeInputManager::getInputDeviceCalibration(const String8& deviceName, + InputDeviceCalibration& outCalibration) { + outCalibration.clear(); + + JNIEnv* env = jniEnv(); + + jstring deviceNameStr = env->NewStringUTF(deviceName.string()); + if (! checkAndClearExceptionFromCallback(env, "getInputDeviceCalibration")) { + jobject result = env->CallObjectMethod(mCallbacksObj, + gCallbacksClassInfo.getInputDeviceCalibration, deviceNameStr); + if (! checkAndClearExceptionFromCallback(env, "getInputDeviceCalibration") && result) { + jobjectArray keys = jobjectArray(env->GetObjectField(result, + gInputDeviceCalibrationClassInfo.keys)); + jobjectArray values = jobjectArray(env->GetObjectField(result, + gInputDeviceCalibrationClassInfo.values)); + + jsize length = env->GetArrayLength(keys); + for (jsize i = 0; i < length; i++) { + jstring keyStr = jstring(env->GetObjectArrayElement(keys, i)); + jstring valueStr = jstring(env->GetObjectArrayElement(values, i)); + + const char* keyChars = env->GetStringUTFChars(keyStr, NULL); + String8 key(keyChars); + env->ReleaseStringUTFChars(keyStr, keyChars); + + const char* valueChars = env->GetStringUTFChars(valueStr, NULL); + String8 value(valueChars); + env->ReleaseStringUTFChars(valueStr, valueChars); + + outCalibration.addProperty(key, value); + + env->DeleteLocalRef(keyStr); + env->DeleteLocalRef(valueStr); + } + env->DeleteLocalRef(keys); + env->DeleteLocalRef(values); + env->DeleteLocalRef(result); + } + env->DeleteLocalRef(deviceNameStr); + } +} + void NativeInputManager::getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames) { + outExcludedDeviceNames.clear(); + JNIEnv* env = jniEnv(); jobjectArray result = jobjectArray(env->CallObjectMethod(mCallbacksObj, @@ -2199,6 +2268,66 @@ static void android_server_InputManager_nativePreemptInputDispatch(JNIEnv* env, gNativeInputManager->preemptInputDispatch(); } +static jobject android_server_InputManager_nativeGetInputDevice(JNIEnv* env, + jclass clazz, jint deviceId) { + if (checkInputManagerUnitialized(env)) { + return NULL; + } + + InputDeviceInfo deviceInfo; + status_t status = gNativeInputManager->getInputManager()->getInputDeviceInfo( + deviceId, & deviceInfo); + if (status) { + return NULL; + } + + jobject deviceObj = env->NewObject(gInputDeviceClassInfo.clazz, gInputDeviceClassInfo.ctor); + if (! deviceObj) { + return NULL; + } + + jstring deviceNameObj = env->NewStringUTF(deviceInfo.getName().string()); + if (! deviceNameObj) { + return NULL; + } + + env->SetIntField(deviceObj, gInputDeviceClassInfo.mId, deviceInfo.getId()); + env->SetObjectField(deviceObj, gInputDeviceClassInfo.mName, deviceNameObj); + env->SetIntField(deviceObj, gInputDeviceClassInfo.mSources, deviceInfo.getSources()); + env->SetIntField(deviceObj, gInputDeviceClassInfo.mKeyboardType, deviceInfo.getKeyboardType()); + + const KeyedVector<int, InputDeviceInfo::MotionRange>& ranges = deviceInfo.getMotionRanges(); + for (size_t i = 0; i < ranges.size(); i++) { + int rangeType = ranges.keyAt(i); + const InputDeviceInfo::MotionRange& range = ranges.valueAt(i); + env->CallVoidMethod(deviceObj, gInputDeviceClassInfo.addMotionRange, + rangeType, range.min, range.max, range.flat, range.fuzz); + if (env->ExceptionCheck()) { + return NULL; + } + } + + return deviceObj; +} + +static jintArray android_server_InputManager_nativeGetInputDeviceIds(JNIEnv* env, + jclass clazz) { + if (checkInputManagerUnitialized(env)) { + return NULL; + } + + Vector<int> deviceIds; + gNativeInputManager->getInputManager()->getInputDeviceIds(deviceIds); + + jintArray deviceIdsObj = env->NewIntArray(deviceIds.size()); + if (! deviceIdsObj) { + return NULL; + } + + env->SetIntArrayRegion(deviceIdsObj, 0, deviceIds.size(), deviceIds.array()); + return deviceIdsObj; +} + static jstring android_server_InputManager_nativeDump(JNIEnv* env, jclass clazz) { if (checkInputManagerUnitialized(env)) { return NULL; @@ -2242,6 +2371,10 @@ static JNINativeMethod gInputManagerMethods[] = { (void*) android_server_InputManager_nativeSetInputDispatchMode }, { "nativePreemptInputDispatch", "()V", (void*) android_server_InputManager_nativePreemptInputDispatch }, + { "nativeGetInputDevice", "(I)Landroid/view/InputDevice;", + (void*) android_server_InputManager_nativeGetInputDevice }, + { "nativeGetInputDeviceIds", "()[I", + (void*) android_server_InputManager_nativeGetInputDeviceIds }, { "nativeDump", "()Ljava/lang/String;", (void*) android_server_InputManager_nativeDump }, }; @@ -2311,6 +2444,10 @@ int register_android_server_InputManager(JNIEnv* env) { "getVirtualKeyDefinitions", "(Ljava/lang/String;)[Lcom/android/server/InputManager$VirtualKeyDefinition;"); + GET_METHOD_ID(gCallbacksClassInfo.getInputDeviceCalibration, gCallbacksClassInfo.clazz, + "getInputDeviceCalibration", + "(Ljava/lang/String;)Lcom/android/server/InputManager$InputDeviceCalibration;"); + GET_METHOD_ID(gCallbacksClassInfo.getExcludedDeviceNames, gCallbacksClassInfo.clazz, "getExcludedDeviceNames", "()[Ljava/lang/String;"); @@ -2337,6 +2474,17 @@ int register_android_server_InputManager(JNIEnv* env) { GET_FIELD_ID(gVirtualKeyDefinitionClassInfo.height, gVirtualKeyDefinitionClassInfo.clazz, "height", "I"); + // InputDeviceCalibration + + FIND_CLASS(gInputDeviceCalibrationClassInfo.clazz, + "com/android/server/InputManager$InputDeviceCalibration"); + + GET_FIELD_ID(gInputDeviceCalibrationClassInfo.keys, gInputDeviceCalibrationClassInfo.clazz, + "keys", "[Ljava/lang/String;"); + + GET_FIELD_ID(gInputDeviceCalibrationClassInfo.values, gInputDeviceCalibrationClassInfo.clazz, + "values", "[Ljava/lang/String;"); + // InputWindow FIND_CLASS(gInputWindowClassInfo.clazz, "com/android/server/InputWindow"); @@ -2407,10 +2555,35 @@ int register_android_server_InputManager(JNIEnv* env) { FIND_CLASS(gKeyEventClassInfo.clazz, "android/view/KeyEvent"); - // MotionEVent + // MotionEvent FIND_CLASS(gMotionEventClassInfo.clazz, "android/view/MotionEvent"); + // InputDevice + + FIND_CLASS(gInputDeviceClassInfo.clazz, "android/view/InputDevice"); + + GET_METHOD_ID(gInputDeviceClassInfo.ctor, gInputDeviceClassInfo.clazz, + "<init>", "()V"); + + GET_METHOD_ID(gInputDeviceClassInfo.addMotionRange, gInputDeviceClassInfo.clazz, + "addMotionRange", "(IFFFF)V"); + + GET_FIELD_ID(gInputDeviceClassInfo.mId, gInputDeviceClassInfo.clazz, + "mId", "I"); + + GET_FIELD_ID(gInputDeviceClassInfo.mName, gInputDeviceClassInfo.clazz, + "mName", "Ljava/lang/String;"); + + GET_FIELD_ID(gInputDeviceClassInfo.mSources, gInputDeviceClassInfo.clazz, + "mSources", "I"); + + GET_FIELD_ID(gInputDeviceClassInfo.mKeyboardType, gInputDeviceClassInfo.clazz, + "mKeyboardType", "I"); + + GET_FIELD_ID(gInputDeviceClassInfo.mMotionRanges, gInputDeviceClassInfo.clazz, + "mMotionRanges", "[Landroid/view/InputDevice$MotionRange;"); + return 0; } diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java index b0fa0f51a24c..4f2d90f06761 100644 --- a/telephony/java/android/telephony/PhoneNumberUtils.java +++ b/telephony/java/android/telephony/PhoneNumberUtils.java @@ -1374,7 +1374,7 @@ public class PhoneNumberUtils PhoneNumberUtil util = PhoneNumberUtil.getInstance(); String result = null; try { - PhoneNumber pn = util.parse(phoneNumber, defaultCountryIso); + PhoneNumber pn = util.parseAndKeepRawInput(phoneNumber, defaultCountryIso); result = util.formatInOriginalFormat(pn, defaultCountryIso); } catch (NumberParseException e) { } @@ -1382,6 +1382,50 @@ public class PhoneNumberUtils } /** + * Format the phone number only if the given number hasn't been formatted. + * <p> + * The number which has only dailable character is treated as not being + * formatted. + * + * @param phoneNumber + * the number to be formatted. + * @param phoneNumberE164 + * the E164 format number whose country code is used if the given + * phoneNumber doesn't have the country code. + * @param defaultCountryIso + * the ISO 3166-1 two letters country code whose convention will + * be used if the phoneNumberE164 is null or invalid. + * @return the formatted number if the given number has been formatted, + * otherwise, return the given number. + * + * @hide + */ + public static String formatNumber( + String phoneNumber, String phoneNumberE164, String defaultCountryIso) { + int len = phoneNumber.length(); + for (int i = 0; i < len; i++) { + if (!isDialable(phoneNumber.charAt(i))) { + return phoneNumber; + } + } + PhoneNumberUtil util = PhoneNumberUtil.getInstance(); + // Get the country code from phoneNumberE164 + if (phoneNumberE164 != null && phoneNumberE164.length() >= 2 + && phoneNumberE164.charAt(0) == '+') { + try { + PhoneNumber pn = util.parse(phoneNumberE164, defaultCountryIso); + String regionCode = util.getRegionCodeForNumber(pn); + if (!TextUtils.isEmpty(regionCode)) { + defaultCountryIso = regionCode; + } + } catch (NumberParseException e) { + } + } + String result = formatNumber(phoneNumber, defaultCountryIso); + return result != null ? result : phoneNumber; + } + + /** * Normalize a phone number by removing the characters other than digits. If * the given number has keypad letters, the letters will be converted to * digits first. diff --git a/telephony/java/com/android/internal/telephony/DataConnection.java b/telephony/java/com/android/internal/telephony/DataConnection.java index 7e722cbeb51e..521d90c5c141 100644 --- a/telephony/java/com/android/internal/telephony/DataConnection.java +++ b/telephony/java/com/android/internal/telephony/DataConnection.java @@ -21,7 +21,7 @@ import com.android.internal.telephony.gsm.ApnSetting; import com.android.internal.util.HierarchicalState; import com.android.internal.util.HierarchicalStateMachine; -import android.net.NetworkProperties; +import android.net.LinkProperties; import android.os.AsyncResult; import android.os.Message; import android.os.SystemProperties; @@ -261,7 +261,7 @@ public abstract class DataConnection extends HierarchicalStateMachine { protected int mTag; protected PhoneBase phone; protected int cid; - protected NetworkProperties mNetworkProperties = new NetworkProperties(); + protected LinkProperties mLinkProperties = new LinkProperties(); protected long createTime; protected long lastFailTime; protected FailCause lastFailCause; @@ -378,7 +378,7 @@ public abstract class DataConnection extends HierarchicalStateMachine { this.lastFailTime = -1; this.lastFailCause = FailCause.NONE; - mNetworkProperties.clear(); + mLinkProperties = new LinkProperties(); } /** @@ -416,7 +416,7 @@ public abstract class DataConnection extends HierarchicalStateMachine { // Start with clean network properties and if we have // a failure we'll clear again at the bottom of this code. - mNetworkProperties.clear(); + LinkProperties linkProperties = new LinkProperties(); if (response.length >= 2) { cid = Integer.parseInt(response[0]); String interfaceName = response[1]; @@ -425,23 +425,23 @@ public abstract class DataConnection extends HierarchicalStateMachine { try { String prefix = "net." + interfaceName + "."; - mNetworkProperties.setInterface(NetworkInterface.getByName(interfaceName)); + linkProperties.setInterface(NetworkInterface.getByName(interfaceName)); // TODO: Get gateway and dns via RIL interface not property? String gatewayAddress = SystemProperties.get(prefix + "gw"); - mNetworkProperties.setGateway(InetAddress.getByName(gatewayAddress)); + linkProperties.setGateway(InetAddress.getByName(gatewayAddress)); if (response.length > 2) { String ipAddress = response[2]; - mNetworkProperties.addAddress(InetAddress.getByName(ipAddress)); + linkProperties.addAddress(InetAddress.getByName(ipAddress)); // TODO: Get gateway and dns via RIL interface not property? String dnsServers[] = new String[2]; dnsServers[0] = SystemProperties.get(prefix + "dns1"); dnsServers[1] = SystemProperties.get(prefix + "dns2"); if (isDnsOk(dnsServers)) { - mNetworkProperties.addDns(InetAddress.getByName(dnsServers[0])); - mNetworkProperties.addDns(InetAddress.getByName(dnsServers[1])); + linkProperties.addDns(InetAddress.getByName(dnsServers[0])); + linkProperties.addDns(InetAddress.getByName(dnsServers[1])); } else { result = SetupResult.ERR_BadDns; } @@ -463,15 +463,16 @@ public abstract class DataConnection extends HierarchicalStateMachine { // An error occurred so clear properties if (result != SetupResult.SUCCESS) { - log("onSetupCompleted with an error clearing NetworkProperties"); - mNetworkProperties.clear(); + log("onSetupCompleted with an error clearing LinkProperties"); + linkProperties.clear(); } + mLinkProperties = linkProperties; } if (DBG) { log("DataConnection setup result='" + result + "' on cid=" + cid); if (result == SetupResult.SUCCESS) { - log("NetworkProperties: " + mNetworkProperties.toString()); + log("LinkProperties: " + mLinkProperties.toString()); } } return result; @@ -636,7 +637,7 @@ public abstract class DataConnection extends HierarchicalStateMachine { case ERR_BadDns: // Connection succeeded but DNS info is bad so disconnect StringBuilder dnsAddressesSb = new StringBuilder(); - for (InetAddress addr : mNetworkProperties.getDnses()) { + for (InetAddress addr : mLinkProperties.getDnses()) { if (dnsAddressesSb.length() != 0) dnsAddressesSb.append(" "); dnsAddressesSb.append(addr.toString()); } @@ -911,10 +912,10 @@ public abstract class DataConnection extends HierarchicalStateMachine { } /** - * @return the connections NetworkProperties + * @return the connections LinkProperties */ - public NetworkProperties getNetworkProperties() { - return mNetworkProperties; + public LinkProperties getLinkProperties() { + return new LinkProperties(mLinkProperties); } /** diff --git a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java index 14cb58474287..765f64bcb1cf 100644 --- a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java +++ b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java @@ -17,7 +17,7 @@ package com.android.internal.telephony; import android.app.PendingIntent; -import android.net.NetworkProperties; +import android.net.LinkProperties; import android.os.AsyncResult; import android.os.Handler; import android.os.Message; @@ -192,8 +192,8 @@ public abstract class DataConnectionTracker extends Handler { /** indication of our availability (preconditions to trysetupData are met) **/ protected boolean mAvailability = false; - /** all our network properties (dns, gateway, ip, etc) */ - protected NetworkProperties mNetworkProperties; + /** all our link properties (dns, gateway, ip, etc) */ + protected LinkProperties mLinkProperties; /** * Default constructor @@ -420,10 +420,10 @@ public abstract class DataConnectionTracker extends Handler { protected abstract void setState(State s); - protected NetworkProperties getNetworkProperties(String apnType) { + protected LinkProperties getLinkProperties(String apnType) { int id = apnTypeToId(apnType); if (isApnIdEnabled(id)) { - return mNetworkProperties; + return new LinkProperties(mLinkProperties); } else { return null; } @@ -673,7 +673,7 @@ public abstract class DataConnectionTracker extends Handler { } } - protected NetworkProperties getNetworkProperties(DataConnection connection) { - return connection.getNetworkProperties(); + protected LinkProperties getLinkProperties(DataConnection connection) { + return connection.getLinkProperties(); } } diff --git a/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java b/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java index 382c19fcd98d..bf3c4d1e8fea 100644 --- a/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java +++ b/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java @@ -16,7 +16,7 @@ package com.android.internal.telephony; -import android.net.NetworkProperties; +import android.net.LinkProperties; import android.os.Bundle; import android.os.RemoteException; import android.os.ServiceManager; @@ -108,9 +108,9 @@ public class DefaultPhoneNotifier implements PhoneNotifier { // use apnType as the key to which connection we're talking about. // pass apnType back up to fetch particular for this one. TelephonyManager telephony = TelephonyManager.getDefault(); - NetworkProperties networkProperties = null; + LinkProperties linkProperties = null; if (state == Phone.DataState.CONNECTED) { - networkProperties = sender.getNetworkProperties(apnType); + linkProperties = sender.getLinkProperties(apnType); } try { mRegistry.notifyDataConnection( @@ -118,7 +118,7 @@ public class DefaultPhoneNotifier implements PhoneNotifier { sender.isDataConnectivityPossible(), reason, sender.getActiveApn(), apnType, - networkProperties, + linkProperties, ((telephony!=null) ? telephony.getNetworkType() : TelephonyManager.NETWORK_TYPE_UNKNOWN)); } catch (RemoteException ex) { diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl index f7b70ee35fd6..eb7e566194f3 100644 --- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl @@ -17,7 +17,7 @@ package com.android.internal.telephony; import android.content.Intent; -import android.net.NetworkProperties; +import android.net.LinkProperties; import android.os.Bundle; import android.telephony.ServiceState; import android.telephony.SignalStrength; @@ -33,7 +33,7 @@ interface ITelephonyRegistry { void notifyCallForwardingChanged(boolean cfi); void notifyDataActivity(int state); void notifyDataConnection(int state, boolean isDataConnectivityPossible, - String reason, String apn, String apnType, in NetworkProperties networkProperties, + String reason, String apn, String apnType, in LinkProperties linkProperties, int networkType); void notifyDataConnectionFailed(String reason, String apnType); void notifyCellLocation(in Bundle cellLocation); diff --git a/telephony/java/com/android/internal/telephony/Phone.java b/telephony/java/com/android/internal/telephony/Phone.java index e752dc6534d5..fffe057fccaa 100644 --- a/telephony/java/com/android/internal/telephony/Phone.java +++ b/telephony/java/com/android/internal/telephony/Phone.java @@ -17,7 +17,7 @@ package com.android.internal.telephony; import android.content.Context; -import android.net.NetworkProperties; +import android.net.LinkProperties; import android.os.Handler; import android.os.Message; import android.telephony.CellLocation; @@ -99,7 +99,7 @@ public interface Phone { static final String STATE_CHANGE_REASON_KEY = "reason"; static final String DATA_APN_TYPE_KEY = "apnType"; static final String DATA_APN_KEY = "apn"; - static final String DATA_NETWORK_PROPERTIES_KEY = "dataProperties"; + static final String DATA_LINK_PROPERTIES_KEY = "linkProperties"; static final String DATA_IFACE_NAME_KEY = "iface"; static final String NETWORK_UNAVAILABLE_KEY = "networkUnvailable"; @@ -319,9 +319,9 @@ public interface Phone { String getActiveApn(); /** - * Return the NetworkProperties for the named apn or null if not available + * Return the LinkProperties for the named apn or null if not available */ - NetworkProperties getNetworkProperties(String apnType); + LinkProperties getLinkProperties(String apnType); /** * Get current signal strength. No change notification available on this diff --git a/telephony/java/com/android/internal/telephony/PhoneBase.java b/telephony/java/com/android/internal/telephony/PhoneBase.java index 05579423f49b..36a2fcff1718 100644 --- a/telephony/java/com/android/internal/telephony/PhoneBase.java +++ b/telephony/java/com/android/internal/telephony/PhoneBase.java @@ -21,7 +21,7 @@ import android.app.IActivityManager; import android.content.Context; import android.content.res.Configuration; import android.content.SharedPreferences; -import android.net.NetworkProperties; +import android.net.LinkProperties; import android.net.wifi.WifiManager; import android.os.AsyncResult; import android.os.Handler; @@ -938,8 +938,8 @@ public abstract class PhoneBase extends Handler implements Phone { return mDataConnection.getActiveApnTypes(); } - public NetworkProperties getNetworkProperties(String apnType) { - return mDataConnection.getNetworkProperties(apnType); + public LinkProperties getLinkProperties(String apnType) { + return mDataConnection.getLinkProperties(apnType); } public String getActiveApn() { diff --git a/telephony/java/com/android/internal/telephony/PhoneProxy.java b/telephony/java/com/android/internal/telephony/PhoneProxy.java index bcf3337bb3ae..b6e4cda24db1 100644 --- a/telephony/java/com/android/internal/telephony/PhoneProxy.java +++ b/telephony/java/com/android/internal/telephony/PhoneProxy.java @@ -20,7 +20,7 @@ package com.android.internal.telephony; import android.app.ActivityManagerNative; import android.content.Context; import android.content.Intent; -import android.net.NetworkProperties; +import android.net.LinkProperties; import android.os.Handler; import android.os.Message; import android.os.SystemProperties; @@ -208,8 +208,8 @@ public class PhoneProxy extends Handler implements Phone { return mActivePhone.getActiveApnTypes(); } - public NetworkProperties getNetworkProperties(String apnType) { - return mActivePhone.getNetworkProperties(apnType); + public LinkProperties getLinkProperties(String apnType) { + return mActivePhone.getLinkProperties(apnType); } public String getActiveApn() { diff --git a/telephony/java/com/android/internal/telephony/SipPhoneNotifier.java b/telephony/java/com/android/internal/telephony/SipPhoneNotifier.java index 1229d14df943..30d06d85512d 100644 --- a/telephony/java/com/android/internal/telephony/SipPhoneNotifier.java +++ b/telephony/java/com/android/internal/telephony/SipPhoneNotifier.java @@ -16,7 +16,7 @@ package com.android.internal.telephony; -import android.net.NetworkProperties; +import android.net.LinkProperties; import android.os.Bundle; import android.os.RemoteException; import android.os.ServiceManager; @@ -110,9 +110,9 @@ public class SipPhoneNotifier implements PhoneNotifier { // use apnType as the key to which connection we're talking about. // pass apnType back up to fetch particular for this one. TelephonyManager telephony = TelephonyManager.getDefault(); - NetworkProperties networkProperties = null; + LinkProperties linkProperties = null; if (state == Phone.DataState.CONNECTED) { - networkProperties = sender.getNetworkProperties(apnType); + linkProperties = sender.getLinkProperties(apnType); } try { mRegistry.notifyDataConnection( @@ -120,7 +120,7 @@ public class SipPhoneNotifier implements PhoneNotifier { sender.isDataConnectivityPossible(), reason, sender.getActiveApn(), apnType, - networkProperties, + linkProperties, ((telephony!=null) ? telephony.getNetworkType() : TelephonyManager.NETWORK_TYPE_UNKNOWN)); } catch (RemoteException ex) { diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java index c94cfa448564..59182457038e 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java @@ -732,7 +732,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { } if (ar.exception == null) { - mNetworkProperties = getNetworkProperties(mActiveDataConnection); + mLinkProperties = getLinkProperties(mActiveDataConnection); // everything is setup notifyDefaultData(reason); diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java index face581b41d7..441446061f55 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java @@ -1098,7 +1098,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } if (ar.exception == null) { - mNetworkProperties = getNetworkProperties(mActivePdp); + mLinkProperties = getLinkProperties(mActivePdp); ApnSetting apn = mActivePdp.getApn(); if (apn.proxy != null && apn.proxy.length() != 0) { @@ -1106,7 +1106,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { ProxyProperties proxy = new ProxyProperties(); proxy.setAddress(InetAddress.getByName(apn.proxy)); proxy.setPort(Integer.parseInt(apn.port)); - mNetworkProperties.setHttpProxy(proxy); + mLinkProperties.setHttpProxy(proxy); } catch (UnknownHostException e) { Log.e(LOG_TAG, "UnknownHostException making ProxyProperties: " + e); } catch (SecurityException e) { diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java b/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java index 1d33be9e90a0..e7428877d4cc 100755 --- a/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java +++ b/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java @@ -19,7 +19,7 @@ package com.android.internal.telephony.sip; import android.content.ContentValues; import android.content.Context; import android.content.SharedPreferences; -import android.net.NetworkProperties; +import android.net.LinkProperties; import android.net.Uri; import android.os.AsyncResult; import android.os.Handler; @@ -540,7 +540,7 @@ abstract class SipPhoneBase extends PhoneBase { } //@Override - public NetworkProperties getNetworkProperties(String apnType) { + public LinkProperties getLinkProperties(String apnType) { // FIXME: what's this for SIP? return null; } diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java index 88aa78ef3dab..c4a6f53dc34a 100644 --- a/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java +++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java @@ -20,10 +20,6 @@ import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.SmallTest; import android.text.SpannableStringBuilder; import android.telephony.PhoneNumberUtils; -import android.telephony.TelephonyManager; -import android.content.Context; - -import junit.framework.TestCase; public class PhoneNumberUtilsTest extends AndroidTestCase { @@ -527,4 +523,16 @@ public class PhoneNumberUtilsTest extends AndroidTestCase { assertEquals("+16502910000", PhoneNumberUtils.normalizeNumber("+1 650 2910000")); } + @SmallTest + public void testFormatDailabeNumber() { + // Using the phoneNumberE164's country code + assertEquals("(650) 291-0000", + PhoneNumberUtils.formatNumber("6502910000", "+16502910000", "CN")); + // The phoneNumberE164 is null + assertEquals("(650) 291-0000", PhoneNumberUtils.formatNumber("6502910000", null, "US")); + // The given number has a country code. + assertEquals("+1 650-291-0000", PhoneNumberUtils.formatNumber("+16502910000", null, "CN")); + // The given number was formatted. + assertEquals("650-291-0000", PhoneNumberUtils.formatNumber("650-291-0000", null, "US")); + } } diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index 21671f1da1a1..8c3ec5ff4f1c 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -307,19 +307,19 @@ public class WifiManager { @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String CONFIG_CHANGED_ACTION = "android.net.wifi.CONFIG_CHANGED"; /** - * The lookup key for a {@link android.net.NetworkProperties} object associated with the + * The lookup key for a {@link android.net.LinkProperties} object associated with the * Wi-Fi network. Retrieve with * {@link android.content.Intent#getParcelableExtra(String)}. * @hide */ - public static final String EXTRA_NETWORK_PROPERTIES = "networkProperties"; + public static final String EXTRA_LINK_PROPERTIES = "linkProperties"; /** * The network IDs of the configured networks could have changed. */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String NETWORK_IDS_CHANGED_ACTION = "android.net.wifi.NETWORK_IDS_CHANGED"; - + /** * Activity Action: Pick a Wi-Fi network to connect to. * <p>Input: Nothing. diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java index 69e8f2ebe148..7554bd1e61a5 100644 --- a/wifi/java/android/net/wifi/WifiStateMachine.java +++ b/wifi/java/android/net/wifi/WifiStateMachine.java @@ -43,7 +43,7 @@ import android.net.DhcpInfo; import android.net.NetworkUtils; import android.net.ConnectivityManager; import android.net.NetworkInfo.DetailedState; -import android.net.NetworkProperties; +import android.net.LinkProperties; import android.net.wifi.WifiConfiguration.Status; import android.os.Binder; import android.os.Message; @@ -143,7 +143,7 @@ public class WifiStateMachine extends HierarchicalStateMachine { * Observes the static IP address settings. */ private SettingsObserver mSettingsObserver; - private NetworkProperties mNetworkProperties; + private LinkProperties mLinkProperties; // Held during driver load and unload private static PowerManager.WakeLock sWakeLock; @@ -421,10 +421,10 @@ public class WifiStateMachine extends HierarchicalStateMachine { mSupplicantStateTracker = new SupplicantStateTracker(context, getHandler()); mBluetoothHeadset = new BluetoothHeadset(mContext, null); - mNetworkProperties = new NetworkProperties(); + mLinkProperties = new LinkProperties(); mNetworkInfo.setIsAvailable(false); - mNetworkProperties.clear(); + mLinkProperties.clear(); mLastBssid = null; mLastNetworkId = -1; mLastSignalLevel = -1; @@ -899,7 +899,7 @@ public class WifiStateMachine extends HierarchicalStateMachine { StringBuffer sb = new StringBuffer(); String LS = System.getProperty("line.separator"); sb.append("current HSM state: ").append(getCurrentState().getName()).append(LS); - sb.append("mNetworkProperties ").append(mNetworkProperties).append(LS); + sb.append("mLinkProperties ").append(mLinkProperties).append(LS); sb.append("mWifiInfo ").append(mWifiInfo).append(LS); sb.append("mDhcpInfo ").append(mDhcpInfo).append(LS); sb.append("mNetworkInfo ").append(mNetworkInfo).append(LS); @@ -1189,9 +1189,9 @@ public class WifiStateMachine extends HierarchicalStateMachine { return null; } - private void configureNetworkProperties() { + private void configureLinkProperties() { try { - mNetworkProperties.setInterface(NetworkInterface.getByName(mInterfaceName)); + mLinkProperties.setInterface(NetworkInterface.getByName(mInterfaceName)); } catch (SocketException e) { Log.e(TAG, "SocketException creating NetworkInterface from " + mInterfaceName + ". e=" + e); @@ -1201,10 +1201,10 @@ public class WifiStateMachine extends HierarchicalStateMachine { return; } // TODO - fix this for v6 - mNetworkProperties.addAddress(NetworkUtils.intToInetAddress(mDhcpInfo.ipAddress)); - mNetworkProperties.setGateway(NetworkUtils.intToInetAddress(mDhcpInfo.gateway)); - mNetworkProperties.addDns(NetworkUtils.intToInetAddress(mDhcpInfo.dns1)); - mNetworkProperties.addDns(NetworkUtils.intToInetAddress(mDhcpInfo.dns2)); + mLinkProperties.addAddress(NetworkUtils.intToInetAddress(mDhcpInfo.ipAddress)); + mLinkProperties.setGateway(NetworkUtils.intToInetAddress(mDhcpInfo.gateway)); + mLinkProperties.addDns(NetworkUtils.intToInetAddress(mDhcpInfo.dns1)); + mLinkProperties.addDns(NetworkUtils.intToInetAddress(mDhcpInfo.dns2)); // TODO - add proxy info } @@ -1381,7 +1381,7 @@ public class WifiStateMachine extends HierarchicalStateMachine { intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT | Intent.FLAG_RECEIVER_REPLACE_PENDING); intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, mNetworkInfo); - intent.putExtra(WifiManager.EXTRA_NETWORK_PROPERTIES, mNetworkProperties); + intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, mLinkProperties); if (bssid != null) intent.putExtra(WifiManager.EXTRA_BSSID, bssid); mContext.sendStickyBroadcast(intent); @@ -1390,7 +1390,7 @@ public class WifiStateMachine extends HierarchicalStateMachine { private void sendConfigChangeBroadcast() { if (!ActivityManagerNative.isSystemReady()) return; Intent intent = new Intent(WifiManager.CONFIG_CHANGED_ACTION); - intent.putExtra(WifiManager.EXTRA_NETWORK_PROPERTIES, mNetworkProperties); + intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, mLinkProperties); mContext.sendBroadcast(intent); } @@ -1945,7 +1945,7 @@ public class WifiStateMachine extends HierarchicalStateMachine { mWifiInfo.setNetworkId(-1); /* Clear network properties */ - mNetworkProperties.clear(); + mLinkProperties.clear(); mLastBssid= null; mLastNetworkId = -1; @@ -3036,7 +3036,7 @@ public class WifiStateMachine extends HierarchicalStateMachine { mLastSignalLevel = -1; // force update of signal strength mWifiInfo.setIpAddress(mDhcpInfo.ipAddress); Log.d(TAG, "IP configuration: " + mDhcpInfo); - configureNetworkProperties(); + configureLinkProperties(); setDetailedState(DetailedState.CONNECTED); sendNetworkStateChangeBroadcast(mLastBssid); //TODO: we could also detect an IP config change diff --git a/wifi/java/android/net/wifi/WifiStateTracker.java b/wifi/java/android/net/wifi/WifiStateTracker.java index 147e2dcdffaf..5a20736a7b75 100644 --- a/wifi/java/android/net/wifi/WifiStateTracker.java +++ b/wifi/java/android/net/wifi/WifiStateTracker.java @@ -24,7 +24,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.net.ConnectivityManager; import android.net.NetworkInfo; -import android.net.NetworkProperties; +import android.net.LinkProperties; import android.net.NetworkStateTracker; import android.os.Handler; import android.os.Message; @@ -47,7 +47,7 @@ public class WifiStateTracker implements NetworkStateTracker { private AtomicInteger mDefaultGatewayAddr = new AtomicInteger(0); private AtomicBoolean mDefaultRouteSet = new AtomicBoolean(false); - private NetworkProperties mNetworkProperties; + private LinkProperties mLinkProperties; private NetworkInfo mNetworkInfo; /* For sending events to connectivity service handler */ @@ -58,10 +58,10 @@ public class WifiStateTracker implements NetworkStateTracker { public WifiStateTracker() { mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, NETWORKTYPE, ""); - mNetworkProperties = new NetworkProperties(); + mLinkProperties = new LinkProperties(); mNetworkInfo.setIsAvailable(false); - mNetworkProperties.clear(); + mLinkProperties.clear(); setTeardownRequested(false); } @@ -191,10 +191,10 @@ public class WifiStateTracker implements NetworkStateTracker { } /** - * Fetch NetworkProperties for the network + * Fetch LinkProperties for the network */ - public NetworkProperties getNetworkProperties() { - return mNetworkProperties; + public LinkProperties getLinkProperties() { + return new LinkProperties(mLinkProperties); } /** @@ -232,13 +232,13 @@ public class WifiStateTracker implements NetworkStateTracker { if (intent.getAction().equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) { mNetworkInfo = (NetworkInfo) intent.getParcelableExtra( WifiManager.EXTRA_NETWORK_INFO); - mNetworkProperties = (NetworkProperties) intent.getParcelableExtra( - WifiManager.EXTRA_NETWORK_PROPERTIES); + mLinkProperties = (LinkProperties) intent.getParcelableExtra( + WifiManager.EXTRA_LINK_PROPERTIES); Message msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo); msg.sendToTarget(); } else if (intent.getAction().equals(WifiManager.CONFIG_CHANGED_ACTION)) { - mNetworkProperties = (NetworkProperties) intent.getParcelableExtra( - WifiManager.EXTRA_NETWORK_PROPERTIES); + mLinkProperties = (LinkProperties) intent.getParcelableExtra( + WifiManager.EXTRA_LINK_PROPERTIES); Message msg = mCsHandler.obtainMessage(EVENT_CONFIGURATION_CHANGED, mNetworkInfo); msg.sendToTarget(); } |