Merge "Add reason field to DEACTIVATE_DATA_CALL request."
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 4ea4a16..ed71da2 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2576,12 +2576,13 @@
public static final String PARENTAL_CONTROL_REDIRECT_URL = "parental_control_redirect_url";
/**
- * A positive value indicates the frequency of SamplingProfiler
- * taking snapshots in hertz. Zero value means SamplingProfiler is disabled.
+ * A positive value indicates how often the SamplingProfiler
+ * should take snapshots. Zero value means SamplingProfiler
+ * is disabled.
*
* @hide
*/
- public static final String SAMPLING_PROFILER_HZ = "sampling_profiler_hz";
+ public static final String SAMPLING_PROFILER_MS = "sampling_profiler_ms";
/**
* Settings classname to launch when Settings is clicked from All
diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java
index 2f7482c..a6fd2f1 100644
--- a/core/java/android/text/TextLine.java
+++ b/core/java/android/text/TextLine.java
@@ -663,6 +663,25 @@
}
/**
+ * @param wp
+ */
+ private static void expandMetricsFromPaint(FontMetricsInt fmi, TextPaint wp) {
+ final int previousTop = fmi.top;
+ final int previousAscent = fmi.ascent;
+ final int previousDescent = fmi.descent;
+ final int previousBottom = fmi.bottom;
+ final int previousLeading = fmi.leading;
+
+ wp.getFontMetricsInt(fmi);
+
+ fmi.top = Math.min(fmi.top, previousTop);
+ fmi.ascent = Math.min(fmi.ascent, previousAscent);
+ fmi.descent = Math.max(fmi.descent, previousDescent);
+ fmi.bottom = Math.max(fmi.bottom, previousBottom);
+ fmi.leading = Math.max(fmi.leading, previousLeading);
+ }
+
+ /**
* Utility function for measuring and rendering text. The text must
* not include a tab or emoji.
*
@@ -703,7 +722,7 @@
}
if (fmi != null) {
- wp.getFontMetricsInt(fmi);
+ expandMetricsFromPaint(fmi, wp);
}
if (c != null) {
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index 5f3184d..dcde6ef 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -2611,6 +2611,10 @@
captureKeyLog("captureDispatchKeyEvent", event);
}
+ // Make sure the fallback event policy sees all keys that will be delivered to the
+ // view hierarchy.
+ mFallbackEventHandler.preDispatchKeyEvent(event);
+
// Deliver the key to the view hierarchy.
if (mView.dispatchKeyEvent(event)) {
finishKeyEvent(event, sendDone, true);
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index dd71b3f..7340486 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -85,6 +85,16 @@
* @param thumb Drawable representing the thumb
*/
public void setThumb(Drawable thumb) {
+ boolean needUpdate;
+ // This way, calling setThumb again with the same bitmap will result in
+ // it recalcuating mThumbOffset (if for example it the bounds of the
+ // drawable changed)
+ if (mThumb != null && thumb != mThumb) {
+ mThumb.setCallback(null);
+ needUpdate = true;
+ } else {
+ needUpdate = false;
+ }
if (thumb != null) {
thumb.setCallback(this);
@@ -92,9 +102,25 @@
// such that the thumb will hang halfway off either edge of the
// progress bar.
mThumbOffset = thumb.getIntrinsicWidth() / 2;
+
+ // If we're updating get the new states
+ if (needUpdate &&
+ (thumb.getIntrinsicWidth() != mThumb.getIntrinsicWidth()
+ || thumb.getIntrinsicHeight() != mThumb.getIntrinsicHeight())) {
+ requestLayout();
+ }
}
mThumb = thumb;
invalidate();
+ if (needUpdate) {
+ updateThumbPos(getWidth(), getHeight());
+ if (thumb.isStateful()) {
+ // Note that if the states are different this won't work.
+ // For now, let's consider that an app bug.
+ int[] state = getDrawableState();
+ thumb.setState(state);
+ }
+ }
}
/**
@@ -191,6 +217,10 @@
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+ updateThumbPos(w, h);
+ }
+
+ private void updateThumbPos(int w, int h) {
Drawable d = getCurrentDrawable();
Drawable thumb = mThumb;
int thumbHeight = thumb == null ? 0 : thumb.getIntrinsicHeight();
diff --git a/core/res/res/drawable-mdpi/scrubber_control_holo.png b/core/res/res/drawable-mdpi/scrubber_control_holo.png
index 135b2aa..8457833 100644
--- a/core/res/res/drawable-mdpi/scrubber_control_holo.png
+++ b/core/res/res/drawable-mdpi/scrubber_control_holo.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/scrubber_primary_holo.9.png b/core/res/res/drawable-mdpi/scrubber_primary_holo.9.png
new file mode 100644
index 0000000..8582b13
--- /dev/null
+++ b/core/res/res/drawable-mdpi/scrubber_primary_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/scrubber_secondary_holo.9.png b/core/res/res/drawable-mdpi/scrubber_secondary_holo.9.png
new file mode 100644
index 0000000..6ad876e
--- /dev/null
+++ b/core/res/res/drawable-mdpi/scrubber_secondary_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/scrubber_track_holo_dark.9.png b/core/res/res/drawable-mdpi/scrubber_track_holo_dark.9.png
index 7b48cf9..baf70cd 100644
--- a/core/res/res/drawable-mdpi/scrubber_track_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/scrubber_track_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/scrubber_track_holo_light.9.png b/core/res/res/drawable-mdpi/scrubber_track_holo_light.9.png
index 7c84ac9..6f31497 100644
--- a/core/res/res/drawable-mdpi/scrubber_track_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/scrubber_track_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable/scrubber_progress_horizontal_holo_dark.xml b/core/res/res/drawable/scrubber_progress_horizontal_holo_dark.xml
index 90172a5..b117bb8 100644
--- a/core/res/res/drawable/scrubber_progress_horizontal_holo_dark.xml
+++ b/core/res/res/drawable/scrubber_progress_horizontal_holo_dark.xml
@@ -15,11 +15,14 @@
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
-
<item android:id="@android:id/background"
- android:drawable="@android:drawable/scrubber_track_holo_dark" />
- <item android:id="@android:id/secondaryProgress"
- android:drawable="@android:drawable/scrubber_track_holo_dark" />
- <item android:id="@android:id/progress"
- android:drawable="@android:drawable/scrubber_track_holo_dark" />
+ android:drawable="@android:drawable/scrubber_track_holo_dark" />
+ <item android:id="@android:id/secondaryProgress">
+ <scale android:scaleWidth="100%"
+ android:drawable="@android:drawable/scrubber_secondary_holo" />
+ </item>
+ <item android:id="@android:id/progress">
+ <scale android:scaleWidth="100%"
+ android:drawable="@android:drawable/scrubber_primary_holo" />
+ </item>
</layer-list>
diff --git a/core/res/res/drawable/scrubber_progress_horizontal_holo_light.xml b/core/res/res/drawable/scrubber_progress_horizontal_holo_light.xml
index 5fc9697..6cd08ea 100644
--- a/core/res/res/drawable/scrubber_progress_horizontal_holo_light.xml
+++ b/core/res/res/drawable/scrubber_progress_horizontal_holo_light.xml
@@ -15,11 +15,14 @@
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
-
<item android:id="@android:id/background"
- android:drawable="@android:drawable/scrubber_track_holo_light" />
- <item android:id="@android:id/secondaryProgress"
- android:drawable="@android:drawable/scrubber_track_holo_light" />
- <item android:id="@android:id/progress"
- android:drawable="@android:drawable/scrubber_track_holo_light" />
+ android:drawable="@android:drawable/scrubber_track_holo_light" />
+ <item android:id="@android:id/secondaryProgress">
+ <scale android:scaleWidth="100%"
+ android:drawable="@android:drawable/scrubber_secondary_holo" />
+ </item>
+ <item android:id="@android:id/progress">
+ <scale android:scaleWidth="100%"
+ android:drawable="@android:drawable/scrubber_primary_holo" />
+ </item>
</layer-list>
diff --git a/core/tests/ConnectivityManagerTest/assets/accesspoints.xml b/core/tests/ConnectivityManagerTest/assets/accesspoints.xml
index 2b0e4af..5e3252c 100755
--- a/core/tests/ConnectivityManagerTest/assets/accesspoints.xml
+++ b/core/tests/ConnectivityManagerTest/assets/accesspoints.xml
@@ -4,7 +4,7 @@
<ssid>opennet</ssid>
<security>NONE</security>
</accesspoint>
- <accesspoint>
+ <accesspoint>
<ssid>GoogleGuest</ssid>
<security>NONE</security>
</accesspoint>
@@ -14,6 +14,16 @@
<password>androidwifi</password>
</accesspoint>
<accesspoint>
+ <ssid>securenetstatic</ssid>
+ <security>PSK</security>
+ <password>androidwifi</password>
+ <ip>192.168.14.2</ip>
+ <gateway>192.168.14.1</gateway>
+ <networkprefixlength>24</networkprefixlength>
+ <dns1>192.168.14.1</dns1>
+ <dns2>192.168.1.9</dns2>
+ </accesspoint>
+ <accesspoint>
<ssid>botnet</ssid>
<security>EAP</security>
<eap>PEAP</eap>
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
index 863fbe6..21f1bfc 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
@@ -25,11 +25,18 @@
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiConfiguration.AuthAlgorithm;
+import android.net.wifi.WifiConfiguration.IpAssignment;
import android.net.wifi.WifiConfiguration.KeyMgmt;
-
+import android.net.wifi.WifiConfiguration.ProxySettings;
+import android.net.LinkAddress;
+import android.net.LinkProperties;
import android.util.Log;
+
import java.io.InputStream;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
@@ -38,7 +45,8 @@
* The configurations of an access point is included in tag
* <accesspoint></accesspoint>. The supported configuration includes: ssid,
* security, eap, phase2, identity, password, anonymousidentity, cacert, usercert,
- * in which each is included in the corresponding tags. All access points have to be
+ * in which each is included in the corresponding tags. Static IP setting is also supported.
+ * Tags that can be used include: ip, gateway, netmask, dns1, dns2. All access points have to be
* enclosed in tags of <resources></resources>.
*
* The following is a sample configuration file for an access point using EAP-PEAP with MSCHAP2.
@@ -52,6 +60,9 @@
* <password>abcdefgh</password>
* </accesspoint>
* </resources>
+ *
+ * Note:ssid and security have to be the first two tags
+ * for static ip setting, tag "ip" should be listed before other fields: dns, gateway, netmask.
*/
public class AccessPointParserHelper {
private static final String KEYSTORE_SPACE = "keystore://";
@@ -93,9 +104,11 @@
boolean security = false;
boolean password = false;
boolean ip = false;
- boolean subnetmask = false;
boolean gateway = false;
- boolean dns = false;
+ boolean networkprefix = false;
+ boolean netmask = false;
+ boolean dns1 = false;
+ boolean dns2 = false;
boolean eap = false;
boolean phase2 = false;
boolean identity = false;
@@ -104,6 +117,8 @@
boolean usercert = false;
WifiConfiguration config = null;
int securityType = NONE;
+ LinkProperties mLinkProperties = null;
+ InetAddress mInetAddr = null;
@Override
public void startElement(String uri, String localName, String tagName,
@@ -138,12 +153,37 @@
if (tagName.equalsIgnoreCase("usercert")) {
usercert = true;
}
+ if (tagName.equalsIgnoreCase("ip")) {
+ mLinkProperties = new LinkProperties();
+ ip = true;
+ }
+ if (tagName.equalsIgnoreCase("gateway")) {
+ gateway = true;
+ }
+ if (tagName.equalsIgnoreCase("networkprefixlength")) {
+ networkprefix = true;
+ }
+ if (tagName.equalsIgnoreCase("netmask")) {
+ netmask = true;
+ }
+ if (tagName.equalsIgnoreCase("dns1")) {
+ dns1 = true;
+ }
+ if (tagName.equalsIgnoreCase("dns2")) {
+ dns2 = true;
+ }
}
@Override
public void endElement(String uri, String localName, String tagName) throws SAXException {
- Log.v(TAG, "endElement: " + tagName);
if (tagName.equalsIgnoreCase("accesspoint")) {
+ if (mLinkProperties != null) {
+ config.ipAssignment = IpAssignment.STATIC;
+ config.linkProperties = mLinkProperties;
+ } else {
+ config.ipAssignment = IpAssignment.DHCP;
+ }
+ config.proxySettings = ProxySettings.NONE;
networks.add(config);
}
}
@@ -152,14 +192,11 @@
public void characters(char ch[], int start, int length) throws SAXException {
if (ssid) {
config.SSID = new String(ch, start, length);
- Log.v(TAG, "ssid: " + config.SSID);
ssid = false;
}
if (security) {
String securityStr = (new String(ch, start, length)).toUpperCase();
- Log.v(TAG, "security: " + securityStr);
securityType = getSecurityType(securityStr);
- Log.v(TAG, "securityType = " + securityType);
switch (securityType) {
case NONE:
config.allowedKeyManagement.set(KeyMgmt.NONE);
@@ -175,6 +212,13 @@
case EAP:
config.allowedKeyManagement.set(KeyMgmt.WPA_EAP);
config.allowedKeyManagement.set(KeyMgmt.IEEE8021X);
+ // Initialize other fields.
+ config.phase2.setValue("");
+ config.ca_cert.setValue("");
+ config.client_cert.setValue("");
+ config.private_key.setValue("");
+ config.identity.setValue("");
+ config.anonymous_identity.setValue("");
break;
default:
throw new SAXException();
@@ -187,7 +231,6 @@
if (len == 0) {
throw new SAXException();
}
- Log.v(TAG, "passwordStr:" + passwordStr);
if (securityType == WEP) {
if ((len == 10 || len == 26 || len == 58) &&
passwordStr.matches("[0-9A-Fa-f]*")) {
@@ -242,21 +285,94 @@
config.client_cert.setValue(KEYSTORE_SPACE);
usercert = false;
}
+ if (ip) {
+ try {
+ String ipAddr = new String(ch, start, length);
+ if (!InetAddress.isNumeric(ipAddr)) {
+ throw new SAXException();
+ }
+ mInetAddr = InetAddress.getByName(ipAddr);
+ } catch (UnknownHostException e) {
+ throw new SAXException();
+ }
+ ip = false;
+ }
+ if (gateway) {
+ try {
+ String gwAddr = new String(ch, start, length);
+ if (!InetAddress.isNumeric(gwAddr)) {
+ throw new SAXException();
+ }
+ mLinkProperties.setGateway(InetAddress.getByName(gwAddr));
+ } catch (UnknownHostException e) {
+ throw new SAXException();
+ }
+ gateway = false;
+ }
+ if (networkprefix) {
+ try {
+ int nwPrefixLength = Integer.parseInt(new String(ch, start, length));
+ if ((nwPrefixLength < 0) || (nwPrefixLength > 32)) {
+ throw new SAXException();
+ }
+ mLinkProperties.addLinkAddress(new LinkAddress(mInetAddr, nwPrefixLength));
+ } catch (NumberFormatException e) {
+ throw new SAXException();
+ }
+ networkprefix = false;
+ }
+ if (netmask) {
+ try {
+ String netMaskStr = new String(ch, start, length);
+ if (!InetAddress.isNumeric(netMaskStr)) {
+ throw new SAXException();
+ }
+ InetAddress netMaskAddr = InetAddress.getByName(netMaskStr);
+ mLinkProperties.addLinkAddress(new LinkAddress(mInetAddr, netMaskAddr));
+ } catch (UnknownHostException e) {
+ throw new SAXException();
+ }
+ netmask = false;
+ }
+ if (dns1) {
+ try {
+ String dnsAddr = new String(ch, start, length);
+ if (!InetAddress.isNumeric(dnsAddr)) {
+ throw new SAXException();
+ }
+ mLinkProperties.addDns(InetAddress.getByName(dnsAddr));
+ } catch (UnknownHostException e) {
+ throw new SAXException();
+ }
+ dns1 = false;
+ }
+ if (dns2) {
+ try {
+ String dnsAddr = new String(ch, start, length);
+ if (!InetAddress.isNumeric(dnsAddr)) {
+ throw new SAXException();
+ }
+ mLinkProperties.addDns(InetAddress.getByName(dnsAddr));
+ } catch (UnknownHostException e) {
+ throw new SAXException();
+ }
+ dns2 = false;
+ }
}
};
- public AccessPointParserHelper() {
- }
-
/**
- * Process the accesspoint.xml file
- * @return List of WifiConfiguration
- * @throws Exception when parsing the XML file
+ * Process the InputStream in
+ * @param in is the InputStream that can be used for XML parsing
+ * @throws Exception
*/
- public List<WifiConfiguration> processAccessPoint(InputStream in) throws Exception {
+ public AccessPointParserHelper(InputStream in) throws Exception {
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser saxParser = factory.newSAXParser();
saxParser.parse(in, mHandler);
+ }
+
+ public List<WifiConfiguration> getNetworkConfigurations() throws Exception {
return networks;
}
}
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java
index 37b9f52..2888696 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java
@@ -16,10 +16,8 @@
package com.android.connectivitymanagertest;
-import com.android.connectivitymanagertest.R;
import android.app.Activity;
import android.content.Context;
-import android.content.res.Resources;
import android.content.BroadcastReceiver;
import android.content.Intent;
import android.content.IntentFilter;
@@ -36,7 +34,6 @@
import android.net.NetworkInfo;
import android.net.NetworkInfo.State;
-import android.net.wifi.SupplicantState;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiInfo;
@@ -52,7 +49,7 @@
public static final String LOG_TAG = "ConnectivityManagerTestActivity";
public static final int WAIT_FOR_SCAN_RESULT = 10 * 1000; //10 seconds
- public static final int WIFI_SCAN_TIMEOUT = 20 * 1000;
+ public static final int WIFI_SCAN_TIMEOUT = 50 * 1000;
public static final int SHORT_TIMEOUT = 5 * 1000;
public static final long LONG_TIMEOUT = 50 * 1000;
public static final int SUCCESS = 0; // for Wifi tethering state change
@@ -61,6 +58,7 @@
private static final String ACCESS_POINT_FILE = "accesspoints.xml";
public ConnectivityReceiver mConnectivityReceiver = null;
public WifiReceiver mWifiReceiver = null;
+ private AccessPointParserHelper mParseHelper = null;
/*
* Track network connectivity information
*/
@@ -101,7 +99,7 @@
private class ConnectivityReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
- Log.v(LOG_TAG, "ConnectivityReceiver: onReceive() is called with " + intent);
+ log("ConnectivityReceiver: onReceive() is called with " + intent);
String action = intent.getAction();
if (!action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
Log.v("ConnectivityReceiver", "onReceive() called with " + intent);
@@ -126,9 +124,9 @@
mReason = intent.getStringExtra(ConnectivityManager.EXTRA_REASON);
mIsFailOver = intent.getBooleanExtra(ConnectivityManager.EXTRA_IS_FAILOVER, false);
- Log.v(LOG_TAG, "mNetworkInfo: " + mNetworkInfo.toString());
+ log("mNetworkInfo: " + mNetworkInfo.toString());
if (mOtherNetworkInfo != null) {
- Log.v(LOG_TAG, "mOtherNetworkInfo: " + mOtherNetworkInfo.toString());
+ log("mOtherNetworkInfo: " + mOtherNetworkInfo.toString());
}
recordNetworkState(mNetworkInfo.getType(), mNetworkInfo.getState());
if (mOtherNetworkInfo != null) {
@@ -148,7 +146,7 @@
} else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
mWifiNetworkInfo =
(NetworkInfo) intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
- Log.v(LOG_TAG, "mWifiNetworkInfo: " + mWifiNetworkInfo.toString());
+ log("mWifiNetworkInfo: " + mWifiNetworkInfo.toString());
if (mWifiNetworkInfo.getState() == State.CONNECTED) {
mBssid = intent.getStringExtra(WifiManager.EXTRA_BSSID);
}
@@ -181,7 +179,7 @@
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- Log.v(LOG_TAG, "onCreate, inst=" + Integer.toHexString(hashCode()));
+ log("onCreate, inst=" + Integer.toHexString(hashCode()));
// Create a simple layout
LinearLayout contentView = new LinearLayout(this);
@@ -212,7 +210,7 @@
initializeNetworkStates();
if (mWifiManager.isWifiEnabled()) {
- Log.v(LOG_TAG, "Clear Wifi before we start the test.");
+ log("Clear Wifi before we start the test.");
removeConfiguredNetworksAndDisableWifi();
}
mWifiRegexs = mCM.getTetherableWifiRegexs();
@@ -220,32 +218,22 @@
public List<WifiConfiguration> loadNetworkConfigurations() throws Exception {
InputStream in = getAssets().open(ACCESS_POINT_FILE);
- AccessPointParserHelper parseHelper = new AccessPointParserHelper();
- return parseHelper.processAccessPoint(in);
- }
-
- private void printNetConfig(String[] configuration) {
- for (int i = 0; i < configuration.length; i++) {
- if (i == 0) {
- Log.v(LOG_TAG, "SSID: " + configuration[0]);
- } else {
- Log.v(LOG_TAG, " " + configuration[i]);
- }
- }
+ mParseHelper = new AccessPointParserHelper(in);
+ return mParseHelper.getNetworkConfigurations();
}
// for each network type, initialize network states to UNKNOWN, and no verification flag is set
public void initializeNetworkStates() {
for (int networkType = NUM_NETWORK_TYPES - 1; networkType >=0; networkType--) {
connectivityState[networkType] = new NetworkState();
- Log.v(LOG_TAG, "Initialize network state for " + networkType + ": " +
+ log("Initialize network state for " + networkType + ": " +
connectivityState[networkType].toString());
}
}
// deposit a network state
public void recordNetworkState(int networkType, State networkState) {
- Log.v(LOG_TAG, "record network state for network " + networkType +
+ log("record network state for network " + networkType +
", state is " + networkState);
connectivityState[networkType].recordState(networkState);
}
@@ -259,40 +247,40 @@
// Validate the states recorded
public boolean validateNetworkStates(int networkType) {
- Log.v(LOG_TAG, "validate network state for " + networkType + ": ");
+ log("validate network state for " + networkType + ": ");
return connectivityState[networkType].validateStateTransition();
}
// return result from network state validation
public String getTransitionFailureReason(int networkType) {
- Log.v(LOG_TAG, "get network state transition failure reason for " + networkType + ": " +
+ log("get network state transition failure reason for " + networkType + ": " +
connectivityState[networkType].toString());
return connectivityState[networkType].getReason();
}
private void notifyNetworkConnectivityChange() {
synchronized(connectivityObject) {
- Log.v(LOG_TAG, "notify network connectivity changed");
+ log("notify network connectivity changed");
connectivityObject.notifyAll();
}
}
private void notifyScanResult() {
synchronized (this) {
- Log.v(LOG_TAG, "notify that scan results are available");
+ log("notify that scan results are available");
this.notify();
}
}
private void notifyWifiState() {
synchronized (wifiObject) {
- Log.v(LOG_TAG, "notify wifi state changed");
+ log("notify wifi state changed");
wifiObject.notify();
}
}
private void notifyWifiAPState() {
synchronized (this) {
- Log.v(LOG_TAG, "notify wifi AP state changed");
+ log("notify wifi AP state changed");
this.notify();
}
}
@@ -306,7 +294,7 @@
for (Object obj: tethered) {
String str = (String)obj;
for (String tethRex: mWifiRegexs) {
- Log.v(LOG_TAG, "str: " + str +"tethRex: " + tethRex);
+ log("str: " + str +"tethRex: " + tethRex);
if (str.matches(tethRex)) {
wifiTethered = true;
}
@@ -316,7 +304,7 @@
for (Object obj: errored) {
String str = (String)obj;
for (String tethRex: mWifiRegexs) {
- Log.v(LOG_TAG, "error: str: " + str +"tethRex: " + tethRex);
+ log("error: str: " + str +"tethRex: " + tethRex);
if (str.matches(tethRex)) {
wifiErrored = true;
}
@@ -328,7 +316,7 @@
} else if (wifiErrored) {
mWifiTetherResult = FAILURE; // wifi tethering failed
}
- Log.v(LOG_TAG, "mWifiTetherResult: " + mWifiTetherResult);
+ log("mWifiTetherResult: " + mWifiTetherResult);
this.notify();
}
}
@@ -344,12 +332,12 @@
return false;
} else {
// the broadcast has been sent out. the state has been changed.
- Log.v(LOG_TAG, "networktype: " + networkType + " state: " +
+ log("networktype: " + networkType + " state: " +
mCM.getNetworkInfo(networkType));
return true;
}
}
- Log.v(LOG_TAG, "Wait for the connectivity state for network: " + networkType +
+ log("Wait for the connectivity state for network: " + networkType +
" to be " + expectedState.toString());
synchronized (connectivityObject) {
try {
@@ -359,7 +347,7 @@
}
if ((mNetworkInfo.getType() != networkType) ||
(mNetworkInfo.getState() != expectedState)) {
- Log.v(LOG_TAG, "network state for " + mNetworkInfo.getType() +
+ log("network state for " + mNetworkInfo.getType() +
"is: " + mNetworkInfo.getState());
continue;
}
@@ -380,7 +368,7 @@
return true;
}
}
- Log.v(LOG_TAG, "Wait for wifi state to be: " + expectedState);
+ log("Wait for wifi state to be: " + expectedState);
synchronized (wifiObject) {
try {
wifiObject.wait(SHORT_TIMEOUT);
@@ -388,7 +376,7 @@
e.printStackTrace();
}
if (mWifiState != expectedState) {
- Log.v(LOG_TAG, "Wifi state is: " + mWifiNetworkInfo.getState());
+ log("Wifi state is: " + mWifiState);
continue;
}
return true;
@@ -408,7 +396,7 @@
return true;
}
}
- Log.v(LOG_TAG, "Wait for wifi AP state to be: " + expectedState);
+ log("Wait for wifi AP state to be: " + expectedState);
synchronized (wifiObject) {
try {
wifiObject.wait(SHORT_TIMEOUT);
@@ -416,7 +404,7 @@
e.printStackTrace();
}
if (mWifiManager.getWifiApState() != expectedState) {
- Log.v(LOG_TAG, "Wifi state is: " + mWifiManager.getWifiApState());
+ log("Wifi state is: " + mWifiManager.getWifiApState());
continue;
}
return true;
@@ -436,7 +424,7 @@
if ((System.currentTimeMillis() - startTime) > timeout) {
return mWifiTetherResult;
}
- Log.v(LOG_TAG, "Wait for wifi tethering result.");
+ log("Wait for wifi tethering result.");
synchronized (this) {
try {
this.wait(SHORT_TIMEOUT);
@@ -490,64 +478,61 @@
//If Wifi is not enabled, enable it
if (!mWifiManager.isWifiEnabled()) {
- Log.v(LOG_TAG, "Wifi is not enabled, enable it");
+ log("Wifi is not enabled, enable it");
mWifiManager.setWifiEnabled(true);
- }
-
- List<ScanResult> netList = mWifiManager.getScanResults();
- if (netList == null) {
- Log.v(LOG_TAG, "scan results are null");
- // if no scan results are available, start active scan
- mWifiManager.startScanActive();
- mScanResultIsAvailable = false;
- long startTime = System.currentTimeMillis();
- while (!mScanResultIsAvailable) {
- if ((System.currentTimeMillis() - startTime) > WIFI_SCAN_TIMEOUT) {
- return false;
- }
- // wait for the scan results to be available
- synchronized (this) {
- // wait for the scan result to be available
- try {
- this.wait(WAIT_FOR_SCAN_RESULT);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- if ((mWifiManager.getScanResults() == null) ||
- (mWifiManager.getScanResults().size() <= 0)) {
- continue;
- }
- mScanResultIsAvailable = true;
- }
+ // wait for the wifi state change before start scanning.
+ if (!waitForWifiState(WifiManager.WIFI_STATE_ENABLED, 2*SHORT_TIMEOUT)) {
+ log("wait for WIFI_STATE_ENABLED failed");
+ return false;
}
}
- netList = mWifiManager.getScanResults();
-
- for (int i = 0; i < netList.size(); i++) {
- ScanResult sr= netList.get(i);
- if (sr.SSID.equals(ssid)) {
- Log.v(LOG_TAG, "found " + ssid + " in the scan result list");
- int networkId = mWifiManager.addNetwork(config);
- // Connect to network by disabling others.
- mWifiManager.enableNetwork(networkId, true);
- mWifiManager.saveConfiguration();
- List<WifiConfiguration> wifiNetworks = mWifiManager.getConfiguredNetworks();
- for (WifiConfiguration netConfig : wifiNetworks) {
- Log.v(LOG_TAG, netConfig.toString());
+ boolean foundApInScanResults = false;
+ for (int retry = 0; retry < 5; retry++) {
+ List<ScanResult> netList = mWifiManager.getScanResults();
+ if (netList != null) {
+ log("size of scan result list: " + netList.size());
+ for (int i = 0; i < netList.size(); i++) {
+ ScanResult sr= netList.get(i);
+ if (sr.SSID.equals(ssid)) {
+ log("found " + ssid + " in the scan result list");
+ log("retry: " + retry);
+ foundApInScanResults = true;
+ mWifiManager.connectNetwork(config);
+ break;
+ }
}
-
- mWifiManager.reconnect();
- break;
- }
+ }
+ if (foundApInScanResults) {
+ return true;
+ } else {
+ // Start an active scan
+ mWifiManager.startScanActive();
+ mScanResultIsAvailable = false;
+ long startTime = System.currentTimeMillis();
+ while (!mScanResultIsAvailable) {
+ if ((System.currentTimeMillis() - startTime) > WIFI_SCAN_TIMEOUT) {
+ log("wait for scan results timeout");
+ return false;
+ }
+ // wait for the scan results to be available
+ synchronized (this) {
+ // wait for the scan result to be available
+ try {
+ this.wait(WAIT_FOR_SCAN_RESULT);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ if ((mWifiManager.getScanResults() == null) ||
+ (mWifiManager.getScanResults().size() <= 0)) {
+ continue;
+ }
+ mScanResultIsAvailable = true;
+ }
+ }
+ }
}
-
- List<WifiConfiguration> netConfList = mWifiManager.getConfiguredNetworks();
- if (netConfList.size() <= 0) {
- Log.v(LOG_TAG, ssid + " is not available");
- return false;
- }
- return true;
+ return false;
}
/*
@@ -555,27 +540,13 @@
*/
public boolean disconnectAP() {
if (mWifiManager.isWifiEnabled()) {
- //remove the current network Id
- WifiInfo curWifi = mWifiManager.getConnectionInfo();
- if (curWifi == null) {
- return false;
- }
- int curNetworkId = curWifi.getNetworkId();
- mWifiManager.removeNetwork(curNetworkId);
- mWifiManager.saveConfiguration();
-
- // remove other saved networks
- List<WifiConfiguration> netConfList = mWifiManager.getConfiguredNetworks();
- if (netConfList != null) {
- Log.v(LOG_TAG, "remove configured network ids");
- for (int i = 0; i < netConfList.size(); i++) {
- WifiConfiguration conf = new WifiConfiguration();
- conf = netConfList.get(i);
- mWifiManager.removeNetwork(conf.networkId);
- }
+ // remove saved networks
+ List<WifiConfiguration> wifiConfigList = mWifiManager.getConfiguredNetworks();
+ for (WifiConfiguration wifiConfig: wifiConfigList) {
+ log("remove wifi configuration: " + wifiConfig.toString());
+ mWifiManager.forgetNetwork(wifiConfig.networkId);
}
}
- mWifiManager.saveConfiguration();
return true;
}
/**
@@ -599,7 +570,7 @@
}
// Wait for the actions to be completed
try {
- Thread.sleep(5*1000);
+ Thread.sleep(SHORT_TIMEOUT);
} catch (InterruptedException e) {}
return true;
}
@@ -632,7 +603,7 @@
if (mWifiReceiver != null) {
unregisterReceiver(mWifiReceiver);
}
- Log.v(LOG_TAG, "onDestroy, inst=" + Integer.toHexString(hashCode()));
+ log("onDestroy, inst=" + Integer.toHexString(hashCode()));
}
@Override
@@ -674,4 +645,8 @@
}
return super.onKeyDown(keyCode, event);
}
+
+ private void log(String message) {
+ Log.v(LOG_TAG, message);
+ }
}
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java
index 69eb5db..9c72102 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java
@@ -17,26 +17,33 @@
package com.android.connectivitymanagertest.functional;
import com.android.connectivitymanagertest.ConnectivityManagerTestActivity;
-import com.android.connectivitymanagertest.NetworkState;
+import com.android.connectivitymanagertest.ConnectivityManagerTestRunner;
import android.R;
import android.app.Activity;
+import android.content.ContentResolver;
import android.content.Intent;
import android.content.Context;
import android.content.res.Resources;
import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiConfiguration.KeyMgmt;
+import android.net.wifi.WifiConfiguration.Status;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.net.ConnectivityManager;
+import android.net.DhcpInfo;
import android.net.NetworkInfo;
import android.net.NetworkInfo.State;
+import android.provider.Settings;
import android.test.suitebuilder.annotation.LargeTest;
import android.test.ActivityInstrumentationTestCase2;
import android.util.Log;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
/**
* Test Wi-Fi connection with different configuration
@@ -48,18 +55,25 @@
public class WifiConnectionTest
extends ActivityInstrumentationTestCase2<ConnectivityManagerTestActivity> {
private static final String TAG = "WifiConnectionTest";
- private static final boolean DEBUG = true;
- private static final String PKG_NAME = "com.android.connectivitymanagertests";
+ private static final boolean DEBUG = false;
private List<WifiConfiguration> networks = new ArrayList<WifiConfiguration>();
private ConnectivityManagerTestActivity mAct;
+ private ConnectivityManagerTestRunner mRunner;
+ private WifiManager mWifiManager = null;
+ private Set<WifiConfiguration> enabledNetworks = null;
public WifiConnectionTest() {
- super(PKG_NAME, ConnectivityManagerTestActivity.class);
+ super(ConnectivityManagerTestActivity.class);
}
@Override
public void setUp() throws Exception {
super.setUp();
+ log("before we launch the test activity, we preserve all the configured networks.");
+ mRunner = ((ConnectivityManagerTestRunner)getInstrumentation());
+ mWifiManager = (WifiManager) mRunner.getContext().getSystemService(Context.WIFI_SERVICE);
+ enabledNetworks = getEnabledNetworks(mWifiManager.getConfiguredNetworks());
+
mAct = getActivity();
networks = mAct.loadNetworkConfigurations();
if (DEBUG) {
@@ -68,30 +82,61 @@
// enable Wifi and verify wpa_supplicant is started
assertTrue("enable Wifi failed", mAct.enableWifi());
- try {
- Thread.sleep( 2 * ConnectivityManagerTestActivity.SHORT_TIMEOUT);
- } catch (Exception e) {
- fail("interrupted while waiting for WPA_SUPPLICANT to start");
- }
+ sleep(2 * ConnectivityManagerTestActivity.SHORT_TIMEOUT,
+ "interrupted while waiting for WPA_SUPPLICANT to start");
WifiInfo mConnection = mAct.mWifiManager.getConnectionInfo();
assertNotNull(mConnection);
assertTrue("wpa_supplicant is not started ", mAct.mWifiManager.pingSupplicant());
}
private void printNetworkConfigurations() {
- Log.v(TAG, "==== print network configurations parsed from XML file ====");
- Log.v(TAG, "number of access points: " + networks.size());
+ log("==== print network configurations parsed from XML file ====");
+ log("number of access points: " + networks.size());
for (WifiConfiguration config : networks) {
- Log.v(TAG, config.toString());
+ log(config.toString());
}
}
@Override
public void tearDown() throws Exception {
+ log("tearDown()");
mAct.removeConfiguredNetworksAndDisableWifi();
+ reEnableNetworks(enabledNetworks);
super.tearDown();
}
+ private Set<WifiConfiguration> getEnabledNetworks(List<WifiConfiguration> configuredNetworks) {
+ Set<WifiConfiguration> networks = new HashSet<WifiConfiguration>();
+ for (WifiConfiguration wifiConfig : configuredNetworks) {
+ if (wifiConfig.status == Status.ENABLED || wifiConfig.status == Status.CURRENT) {
+ networks.add(wifiConfig);
+ log("remembering enabled network " + wifiConfig.SSID +
+ " status is " + wifiConfig.status);
+ }
+ }
+ return networks;
+ }
+
+ private void reEnableNetworks(Set<WifiConfiguration> enabledNetworks) {
+ if (!mWifiManager.isWifiEnabled()) {
+ log("reEnableNetworks: enable Wifi");
+ mWifiManager.setWifiEnabled(true);
+ sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT,
+ "interruped while waiting for wifi to be enabled");
+ }
+
+ for (WifiConfiguration config : enabledNetworks) {
+ if (DEBUG) {
+ log("recover wifi configuration: " + config.toString());
+ }
+ config.SSID = "\"" + config.SSID + "\"";
+ config.networkId = -1;
+ mWifiManager.connectNetwork(config);
+ sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT,
+ "interruped while connecting to " + config.SSID);
+ }
+ }
+
/**
* Connect to the provided Wi-Fi network
* @param config is the network configuration
@@ -103,32 +148,40 @@
mAct.connectToWifiWithConfiguration(config));
// step 2: verify Wifi state and network state;
- assertTrue(mAct.waitForWifiState(WifiManager.WIFI_STATE_ENABLED,
- ConnectivityManagerTestActivity.SHORT_TIMEOUT));
assertTrue(mAct.waitForNetworkState(ConnectivityManager.TYPE_WIFI,
- State.CONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
+ State.CONNECTED, 2 * ConnectivityManagerTestActivity.LONG_TIMEOUT));
// step 3: verify the current connected network is the given SSID
+ assertNotNull("Wifi connection returns null", mAct.mWifiManager.getConnectionInfo());
if (DEBUG) {
- Log.v(TAG, "config.SSID = " + config.SSID);
- Log.v(TAG, "mAct.mWifiManager.getConnectionInfo.getSSID()" +
+ log("config.SSID = " + config.SSID);
+ log("mAct.mWifiManager.getConnectionInfo.getSSID()" +
mAct.mWifiManager.getConnectionInfo().getSSID());
}
assertTrue(config.SSID.contains(mAct.mWifiManager.getConnectionInfo().getSSID()));
+ }
- // Maintain the connection for 50 seconds before switching
+ private void sleep(long sometime, String errorMsg) {
try {
- Thread.sleep(50*1000);
- } catch (Exception e) {
- fail("interrupted while waiting for WPA_SUPPLICANT to start");
+ Thread.sleep(sometime);
+ } catch (InterruptedException e) {
+ fail(errorMsg);
}
}
+ private void log(String message) {
+ Log.v(TAG, message);
+ }
+
@LargeTest
public void testWifiConnections() {
for (int i = 0; i < networks.size(); i++) {
+ String ssid = networks.get(i).SSID;
+ log("-- START Wi-Fi connection test to : " + ssid + " --");
connectToWifi(networks.get(i));
- mAct.removeConfiguredNetworksAndDisableWifi();
+ sleep(2 * ConnectivityManagerTestActivity.SHORT_TIMEOUT,
+ "interruped while waiting for wifi disabled.");
+ log("-- END Wi-Fi connection test to " + ssid + " -- ");
}
}
}
diff --git a/data/keyboards/Logitech_USB_Receiver.kl b/data/keyboards/Vendor_046d_Product_c532.kl
similarity index 98%
rename from data/keyboards/Logitech_USB_Receiver.kl
rename to data/keyboards/Vendor_046d_Product_c532.kl
index aa7c0ee..741c2e1 100644
--- a/data/keyboards/Logitech_USB_Receiver.kl
+++ b/data/keyboards/Vendor_046d_Product_c532.kl
@@ -13,7 +13,7 @@
# limitations under the License.
#
-# Logitech Revue keyboard
+# Logitech Revue Wireless keyboard
#
# Notes:
# - The GRAVE key is emulated by the keyboard.
diff --git a/data/keyboards/Apple_Wireless_Keyboard.kl b/data/keyboards/Vendor_05ac_Product_0239.kl
similarity index 100%
rename from data/keyboards/Apple_Wireless_Keyboard.kl
rename to data/keyboards/Vendor_05ac_Product_0239.kl
diff --git a/data/keyboards/Motorola_Bluetooth_Wireless_Keyboard.kl b/data/keyboards/Vendor_22b8_Product_093d.kl
similarity index 100%
rename from data/keyboards/Motorola_Bluetooth_Wireless_Keyboard.kl
rename to data/keyboards/Vendor_22b8_Product_093d.kl
diff --git a/data/keyboards/common.mk b/data/keyboards/common.mk
index 5c2a75d..56c287a 100644
--- a/data/keyboards/common.mk
+++ b/data/keyboards/common.mk
@@ -16,16 +16,20 @@
# Used by Android.mk and keyboards.mk.
keylayouts := \
- Apple_Wireless_Keyboard.kl \
- AVRCP.kl \
Generic.kl \
- Logitech_USB_Receiver.kl \
- Motorola_Bluetooth_Wireless_Keyboard.kl \
+ AVRCP.kl \
qwerty.kl \
- qwerty2.kl
+ Vendor_046d_Product_c532.kl \
+ Vendor_05ac_Product_0239.kl \
+ Vendor_22b8_Product_093d.kl
keycharmaps := \
Generic.kcm \
+ Virtual.kcm \
qwerty.kcm \
- qwerty2.kcm \
- Virtual.kcm
+ qwerty2.kcm
+
+keyconfigs := \
+ qwerty.idc \
+ qwerty2.idc
+
diff --git a/data/keyboards/keyboards.mk b/data/keyboards/keyboards.mk
index b32e436..564f41c 100644
--- a/data/keyboards/keyboards.mk
+++ b/data/keyboards/keyboards.mk
@@ -22,4 +22,8 @@
PRODUCT_COPY_FILES += $(foreach file,$(keycharmaps),\
frameworks/base/data/keyboards/$(file):system/usr/keychars/$(file))
-PRODUCT_PACKAGES := $(keylayouts) $(keycharmaps)
+PRODUCT_COPY_FILES += $(foreach file,$(keyconfigs),\
+ frameworks/base/data/keyboards/$(file):system/usr/idc/$(file))
+
+PRODUCT_PACKAGES := $(keylayouts) $(keycharmaps) $(keyconfigs)
+
diff --git a/data/keyboards/qwerty.idc b/data/keyboards/qwerty.idc
new file mode 100644
index 0000000..129b0bc
--- /dev/null
+++ b/data/keyboards/qwerty.idc
@@ -0,0 +1,23 @@
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Emulator keyboard configuration file #1.
+#
+
+keyboard.layout = qwerty
+keyboard.characterMap = qwerty
+keyboard.orientationAware = 1
+keyboard.builtIn = 1
+
diff --git a/data/keyboards/qwerty2.idc b/data/keyboards/qwerty2.idc
new file mode 100644
index 0000000..1a795c6
--- /dev/null
+++ b/data/keyboards/qwerty2.idc
@@ -0,0 +1,23 @@
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Emulator keyboard configuration file #2.
+#
+
+keyboard.layout = qwerty
+keyboard.characterMap = qwerty2
+keyboard.orientationAware = 1
+keyboard.builtIn = 1
+
diff --git a/data/keyboards/qwerty2.kl b/data/keyboards/qwerty2.kl
deleted file mode 100644
index 863a258..0000000
--- a/data/keyboards/qwerty2.kl
+++ /dev/null
@@ -1,109 +0,0 @@
-# Copyright (C) 2010 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-#
-# Emulator keyboard layout #2.
-#
-
-key 399 GRAVE
-key 2 1
-key 3 2
-key 4 3
-key 5 4
-key 6 5
-key 7 6
-key 8 7
-key 9 8
-key 10 9
-key 11 0
-key 158 BACK WAKE_DROPPED
-key 230 SOFT_RIGHT WAKE
-key 60 SOFT_RIGHT WAKE
-key 107 ENDCALL WAKE_DROPPED
-key 62 ENDCALL WAKE_DROPPED
-key 229 MENU WAKE_DROPPED
-key 139 MENU WAKE_DROPPED
-key 59 MENU WAKE_DROPPED
-key 127 SEARCH WAKE_DROPPED
-key 217 SEARCH WAKE_DROPPED
-key 228 POUND
-key 227 STAR
-key 231 CALL WAKE_DROPPED
-key 61 CALL WAKE_DROPPED
-key 232 DPAD_CENTER WAKE_DROPPED
-key 108 DPAD_DOWN WAKE_DROPPED
-key 103 DPAD_UP WAKE_DROPPED
-key 102 HOME WAKE
-key 105 DPAD_LEFT WAKE_DROPPED
-key 106 DPAD_RIGHT WAKE_DROPPED
-key 115 VOLUME_UP WAKE
-key 114 VOLUME_DOWN WAKE
-key 116 POWER WAKE
-key 212 CAMERA
-
-key 16 Q
-key 17 W
-key 18 E
-key 19 R
-key 20 T
-key 21 Y
-key 22 U
-key 23 I
-key 24 O
-key 25 P
-key 26 LEFT_BRACKET
-key 27 RIGHT_BRACKET
-key 43 BACKSLASH
-
-key 30 A
-key 31 S
-key 32 D
-key 33 F
-key 34 G
-key 35 H
-key 36 J
-key 37 K
-key 38 L
-key 39 SEMICOLON
-key 40 APOSTROPHE
-key 14 DEL
-
-key 44 Z
-key 45 X
-key 46 C
-key 47 V
-key 48 B
-key 49 N
-key 50 M
-key 51 COMMA
-key 52 PERIOD
-key 53 SLASH
-key 28 ENTER
-
-key 56 ALT_LEFT
-key 100 ALT_RIGHT
-key 42 SHIFT_LEFT
-key 54 SHIFT_RIGHT
-key 15 TAB
-key 57 SPACE
-key 150 EXPLORER
-key 155 ENVELOPE
-
-key 12 MINUS
-key 13 EQUALS
-key 215 AT
-
-# On an AT keyboard: ESC, F10
-key 1 BACK WAKE_DROPPED
-key 68 MENU WAKE_DROPPED
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 62fbfb4..e3bb6eb 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -1818,6 +1818,7 @@
nativeGetCharArrayBounds(mNativePaint, text, index, count, bounds);
}
+ @Override
protected void finalize() throws Throwable {
finalizer(mNativePaint);
}
diff --git a/include/ui/EventHub.h b/include/ui/EventHub.h
index 6c798a6..6c6c297 100644
--- a/include/ui/EventHub.h
+++ b/include/ui/EventHub.h
@@ -18,8 +18,11 @@
#ifndef _RUNTIME_EVENT_HUB_H
#define _RUNTIME_EVENT_HUB_H
-#include <android/input.h>
+#include <ui/Input.h>
#include <ui/Keyboard.h>
+#include <ui/KeyLayoutMap.h>
+#include <ui/KeyCharacterMap.h>
+#include <ui/VirtualKeyMap.h>
#include <utils/String8.h>
#include <utils/threads.h>
#include <utils/Log.h>
@@ -27,6 +30,7 @@
#include <utils/List.h>
#include <utils/Errors.h>
#include <utils/PropertyMap.h>
+#include <utils/Vector.h>
#include <linux/input.h>
@@ -59,8 +63,6 @@
namespace android {
-class KeyLayoutMap;
-
/*
* A raw event as retrieved from the EventHub.
*/
@@ -194,6 +196,9 @@
virtual bool hasLed(int32_t deviceId, int32_t led) const = 0;
virtual void setLedState(int32_t deviceId, int32_t led, bool on) = 0;
+ virtual void getVirtualKeyDefinitions(int32_t deviceId,
+ Vector<VirtualKeyDefinition>& outVirtualKeys) const = 0;
+
virtual void dump(String8& dump) = 0;
};
@@ -230,6 +235,9 @@
virtual bool hasLed(int32_t deviceId, int32_t led) const;
virtual void setLedState(int32_t deviceId, int32_t led, bool on);
+ virtual void getVirtualKeyDefinitions(int32_t deviceId,
+ Vector<VirtualKeyDefinition>& outVirtualKeys) const;
+
virtual void dump(String8& dump);
protected:
@@ -238,78 +246,80 @@
private:
bool openPlatformInput(void);
- int openDevice(const char *device);
- int closeDevice(const char *device);
+ int openDevice(const char *devicePath);
+ int closeDevice(const char *devicePath);
int scanDir(const char *dirname);
int readNotify(int nfd);
status_t mError;
- struct device_t {
- const int32_t id;
- const String8 path;
- String8 name;
- uint32_t classes;
- uint8_t* keyBitmask;
- KeyLayoutMap* layoutMap;
- String8 configurationFile;
- PropertyMap* configuration;
- KeyMapInfo keyMapInfo;
- int fd;
- device_t* next;
-
- device_t(int32_t _id, const char* _path, const char* name);
- ~device_t();
+ struct Device {
+ Device* next;
+
+ int fd;
+ const int32_t id;
+ const String8 path;
+ const InputDeviceIdentifier identifier;
+
+ uint32_t classes;
+ uint8_t* keyBitmask;
+ String8 configurationFile;
+ PropertyMap* configuration;
+ VirtualKeyMap* virtualKeyMap;
+ KeyMap keyMap;
+
+ Device(int fd, int32_t id, const String8& path, const InputDeviceIdentifier& identifier);
+ ~Device();
+
+ void close();
};
- device_t* getDeviceLocked(int32_t deviceId) const;
- bool hasKeycodeLocked(device_t* device, int keycode) const;
+ Device* getDeviceLocked(int32_t deviceId) const;
+ bool hasKeycodeLocked(Device* device, int keycode) const;
- int32_t getScanCodeStateLocked(device_t* device, int32_t scanCode) const;
- int32_t getKeyCodeStateLocked(device_t* device, int32_t keyCode) const;
- int32_t getSwitchStateLocked(device_t* device, int32_t sw) const;
- bool markSupportedKeyCodesLocked(device_t* device, size_t numCodes,
+ int32_t getScanCodeStateLocked(Device* device, int32_t scanCode) const;
+ int32_t getKeyCodeStateLocked(Device* device, int32_t keyCode) const;
+ int32_t getSwitchStateLocked(Device* device, int32_t sw) const;
+ bool markSupportedKeyCodesLocked(Device* device, size_t numCodes,
const int32_t* keyCodes, uint8_t* outFlags) const;
- void loadConfiguration(device_t* device);
- void configureKeyMap(device_t* device);
- void setKeyboardProperties(device_t* device, bool firstKeyboard);
- void clearKeyboardProperties(device_t* device, bool firstKeyboard);
+ void loadConfiguration(Device* device);
+ status_t loadVirtualKeyMap(Device* device);
+ status_t loadKeyMap(Device* device);
+ void setKeyboardProperties(Device* device, bool builtInKeyboard);
+ void clearKeyboardProperties(Device* device, bool builtInKeyboard);
// Protect all internal state.
- mutable Mutex mLock;
-
- bool mHaveFirstKeyboard;
- int32_t mFirstKeyboardId; // the API is that the built-in keyboard is id 0, so map it
-
- struct device_ent {
- device_t* device;
- uint32_t seq;
- };
- device_ent *mDevicesById;
- int mNumDevicesById;
-
- device_t *mOpeningDevices;
- device_t *mClosingDevices;
-
- device_t **mDevices;
- struct pollfd *mFDs;
- int mFDCount;
+ mutable Mutex mLock;
- bool mOpened;
- bool mNeedToSendFinishedDeviceScan;
- List<String8> mExcludedDevices;
+ // The actual id of the built-in keyboard, or -1 if none.
+ // EventHub remaps the built-in keyboard to id 0 externally as required by the API.
+ int32_t mBuiltInKeyboardId;
+
+ int32_t mNextDeviceId;
+
+ // Parallel arrays of fds and devices.
+ // First index is reserved for inotify.
+ Vector<struct pollfd> mFds;
+ Vector<Device*> mDevices;
+
+ Device *mOpeningDevices;
+ Device *mClosingDevices;
+
+ bool mOpened;
+ bool mNeedToSendFinishedDeviceScan;
+ List<String8> mExcludedDevices;
// device ids that report particular switches.
#ifdef EV_SW
- int32_t mSwitches[SW_MAX + 1];
+ int32_t mSwitches[SW_MAX + 1];
#endif
static const int INPUT_BUFFER_SIZE = 64;
struct input_event mInputBufferData[INPUT_BUFFER_SIZE];
- int32_t mInputBufferIndex;
- int32_t mInputBufferCount;
- int32_t mInputDeviceIndex;
+ size_t mInputBufferIndex;
+ size_t mInputBufferCount;
+ size_t mInputFdIndex;
};
}; // namespace android
diff --git a/include/ui/Input.h b/include/ui/Input.h
index 4dc8f2a..27f65bc 100644
--- a/include/ui/Input.h
+++ b/include/ui/Input.h
@@ -497,6 +497,23 @@
KeyedVector<int32_t, MotionRange> mMotionRanges;
};
+/*
+ * Identifies a device.
+ */
+struct InputDeviceIdentifier {
+ inline InputDeviceIdentifier() :
+ bus(0), vendor(0), product(0), version(0) {
+ }
+
+ String8 name;
+ String8 location;
+ String8 uniqueId;
+ uint16_t bus;
+ uint16_t vendor;
+ uint16_t product;
+ uint16_t version;
+};
+
/* Types of input device configuration files. */
enum InputDeviceConfigurationFileType {
INPUT_DEVICE_CONFIGURATION_FILE_TYPE_CONFIGURATION = 0, /* .idc file */
@@ -505,13 +522,28 @@
};
/*
- * Get the path of an input device configuration file, if one is available.
- * Spaces in the name are replaced with underscores.
+ * Gets the path of an input device configuration file, if one is available.
* Considers both system provided and user installed configuration files.
*
+ * The device identifier is used to construct several default configuration file
+ * names to try based on the device name, vendor, product, and version.
+ *
* Returns an empty string if not found.
*/
-extern String8 getInputDeviceConfigurationFilePath(
+extern String8 getInputDeviceConfigurationFilePathByDeviceIdentifier(
+ const InputDeviceIdentifier& deviceIdentifier,
+ InputDeviceConfigurationFileType type);
+
+/*
+ * Gets the path of an input device configuration file, if one is available.
+ * Considers both system provided and user installed configuration files.
+ *
+ * The name is case-sensitive and is used to construct the filename to resolve.
+ * All characters except 'a'-'z', 'A'-'Z', '0'-'9', '-', and '_' are replaced by underscores.
+ *
+ * Returns an empty string if not found.
+ */
+extern String8 getInputDeviceConfigurationFilePathByName(
const String8& name, InputDeviceConfigurationFileType type);
} // namespace android
diff --git a/include/ui/InputReader.h b/include/ui/InputReader.h
index cfceaab..8ec5421 100644
--- a/include/ui/InputReader.h
+++ b/include/ui/InputReader.h
@@ -35,17 +35,6 @@
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;
-};
-
/*
* Input reader policy interface.
@@ -86,10 +75,6 @@
*/
virtual bool filterJumpyTouchEvents() = 0;
- /* Gets the configured virtual key definitions for an input device. */
- virtual void getVirtualKeyDefinitions(const String8& deviceName,
- Vector<VirtualKeyDefinition>& outVirtualKeyDefinitions) = 0;
-
/* Gets the excluded device names for the platform. */
virtual void getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames) = 0;
};
diff --git a/include/ui/Keyboard.h b/include/ui/Keyboard.h
index 689607d..50296e2 100644
--- a/include/ui/Keyboard.h
+++ b/include/ui/Keyboard.h
@@ -33,30 +33,58 @@
DEVICE_ID_VIRTUAL_KEYBOARD = -1,
};
-struct KeyMapInfo {
+class KeyLayoutMap;
+class KeyCharacterMap;
+
+/**
+ * Loads the key layout map and key character map for a keyboard device.
+ */
+class KeyMap {
+public:
String8 keyLayoutFile;
+ KeyLayoutMap* keyLayoutMap;
+
String8 keyCharacterMapFile;
- bool isDefaultKeyMap;
+ KeyCharacterMap* keyCharacterMap;
- KeyMapInfo() : isDefaultKeyMap(false) {
+ KeyMap();
+ ~KeyMap();
+
+ status_t load(const InputDeviceIdentifier& deviceIdenfier,
+ const PropertyMap* deviceConfiguration);
+
+ inline bool haveKeyLayout() const {
+ return !keyLayoutFile.isEmpty();
}
- bool isComplete() {
- return !keyLayoutFile.isEmpty() && !keyCharacterMapFile.isEmpty();
+ inline bool haveKeyCharacterMap() const {
+ return !keyCharacterMapFile.isEmpty();
}
+
+ inline bool isComplete() const {
+ return haveKeyLayout() && haveKeyCharacterMap();
+ }
+
+private:
+ bool probeKeyMap(const InputDeviceIdentifier& deviceIdentifier, const String8& name);
+ status_t loadKeyLayout(const InputDeviceIdentifier& deviceIdentifier, const String8& name);
+ status_t loadKeyCharacterMap(const InputDeviceIdentifier& deviceIdentifier,
+ const String8& name);
+ String8 getPath(const InputDeviceIdentifier& deviceIdentifier,
+ const String8& name, InputDeviceConfigurationFileType type);
};
/**
- * Resolves the key map to use for a particular keyboard device.
+ * Returns true if the keyboard is eligible for use as a built-in keyboard.
*/
-extern status_t resolveKeyMap(const String8& deviceName,
- const PropertyMap* deviceConfiguration, KeyMapInfo& outKeyMapInfo);
+extern bool isEligibleBuiltInKeyboard(const InputDeviceIdentifier& deviceIdentifier,
+ const PropertyMap* deviceConfiguration, const KeyMap* keyMap);
/**
* Sets keyboard system properties.
*/
-extern void setKeyboardProperties(int32_t deviceId, const String8& deviceName,
- const KeyMapInfo& keyMapInfo);
+extern void setKeyboardProperties(int32_t deviceId, const InputDeviceIdentifier& deviceIdentifier,
+ const String8& keyLayoutFile, const String8& keyCharacterMapFile);
/**
* Clears keyboard system properties.
diff --git a/include/ui/VirtualKeyMap.h b/include/ui/VirtualKeyMap.h
new file mode 100644
index 0000000..7813d9d
--- /dev/null
+++ b/include/ui/VirtualKeyMap.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _UI_VIRTUAL_KEY_MAP_H
+#define _UI_VIRTUAL_KEY_MAP_H
+
+#include <stdint.h>
+
+#include <ui/Input.h>
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <utils/Tokenizer.h>
+#include <utils/String8.h>
+#include <utils/Unicode.h>
+
+namespace android {
+
+/* 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;
+};
+
+
+/**
+ * Describes a collection of virtual keys on a touch screen in terms of
+ * virtual scan codes and hit rectangles.
+ */
+class VirtualKeyMap {
+public:
+ ~VirtualKeyMap();
+
+ static status_t load(const String8& filename, VirtualKeyMap** outMap);
+
+ inline const Vector<VirtualKeyDefinition>& getVirtualKeys() const {
+ return mVirtualKeys;
+ }
+
+private:
+ class Parser {
+ VirtualKeyMap* mMap;
+ Tokenizer* mTokenizer;
+
+ public:
+ Parser(VirtualKeyMap* map, Tokenizer* tokenizer);
+ ~Parser();
+ status_t parse();
+
+ private:
+ bool consumeFieldDelimiterAndSkipWhitespace();
+ bool parseNextIntField(int32_t* outValue);
+ };
+
+ Vector<VirtualKeyDefinition> mVirtualKeys;
+
+ VirtualKeyMap();
+};
+
+} // namespace android
+
+#endif // _UI_KEY_CHARACTER_MAP_H
diff --git a/include/utils/String8.h b/include/utils/String8.h
index 6abfb06..6b49ff5 100644
--- a/include/utils/String8.h
+++ b/include/utils/String8.h
@@ -47,7 +47,12 @@
explicit String8(const char32_t* o);
explicit String8(const char32_t* o, size_t numChars);
~String8();
-
+
+ static inline const String8 empty();
+
+ static String8 format(const char* fmt, ...) __attribute__((format (printf, 1, 2)));
+ static String8 formatV(const char* fmt, va_list args);
+
inline const char* string() const;
inline size_t size() const;
inline size_t length() const;
@@ -229,6 +234,10 @@
return compare_type(lhs, rhs) < 0;
}
+inline const String8 String8::empty() {
+ return String8();
+}
+
inline const char* String8::string() const
{
return mString;
diff --git a/include/utils/Tokenizer.h b/include/utils/Tokenizer.h
index 21e58e6..c7db5fb 100644
--- a/include/utils/Tokenizer.h
+++ b/include/utils/Tokenizer.h
@@ -28,7 +28,7 @@
* A simple tokenizer for loading and parsing ASCII text files line by line.
*/
class Tokenizer {
- Tokenizer(const String8& filename, FileMap* fileMap, const char* buffer, size_t length);
+ Tokenizer(const String8& filename, FileMap* fileMap, char* buffer, size_t length);
public:
~Tokenizer();
@@ -110,7 +110,7 @@
String8 mFilename;
FileMap* mFileMap;
- const char* mBuffer;
+ char* mBuffer;
size_t mLength;
const char* mCurrent;
diff --git a/libs/hwui/Patch.cpp b/libs/hwui/Patch.cpp
index 7ca289d..ebffd34 100644
--- a/libs/hwui/Patch.cpp
+++ b/libs/hwui/Patch.cpp
@@ -42,6 +42,9 @@
mXDivs = new int32_t[mXCount];
mYDivs = new int32_t[mYCount];
+ PATCH_LOGD(" patch: xCount = %d, yCount = %d, emptyQuads = %d, vertices = %d",
+ xCount, yCount, emptyQuads, verticesCount);
+
glGenBuffers(1, &meshBuffer);
}
@@ -208,7 +211,15 @@
void Patch::generateQuad(TextureVertex*& vertex, float x1, float y1, float x2, float y2,
float u1, float v1, float u2, float v2, uint32_t& quadCount) {
- if (((mColorKey >> quadCount++) & 0x1) == 1) {
+ uint32_t oldQuadCount = quadCount;
+
+ // Degenerate quads are an artifact of our implementation and should not
+ // be taken into account when checking for transparent quads
+ if (x2 - x1 > 0.999f && y2 - y1 > 0.999f) {
+ quadCount++;
+ }
+
+ if (((mColorKey >> oldQuadCount) & 0x1) == 1) {
return;
}
diff --git a/libs/ui/Android.mk b/libs/ui/Android.mk
index 5948e04..d0e041a 100644
--- a/libs/ui/Android.mk
+++ b/libs/ui/Android.mk
@@ -21,6 +21,7 @@
Keyboard.cpp \
KeyLayoutMap.cpp \
KeyCharacterMap.cpp \
+ VirtualKeyMap.cpp
# For the host
# =====================================================
diff --git a/libs/ui/EventHub.cpp b/libs/ui/EventHub.cpp
index b312cda..8f4bac6 100644
--- a/libs/ui/EventHub.cpp
+++ b/libs/ui/EventHub.cpp
@@ -33,6 +33,8 @@
#include <assert.h>
#include <ui/KeyLayoutMap.h>
+#include <ui/KeyCharacterMap.h>
+#include <ui/VirtualKeyMap.h>
#include <string.h>
#include <stdint.h>
@@ -56,10 +58,6 @@
/* this macro computes the number of bytes needed to represent a bit array of the specified size */
#define sizeof_bit_array(bits) ((bits + 7) / 8)
-#define ID_MASK 0x0000ffff
-#define SEQ_MASK 0x7fff0000
-#define SEQ_SHIFT 16
-
#ifndef ABS_MT_TOUCH_MAJOR
#define ABS_MT_TOUCH_MAJOR 0x30 /* Major axis of touching ellipse */
#endif
@@ -72,6 +70,9 @@
#define ABS_MT_POSITION_Y 0x36 /* Center Y ellipse position */
#endif
+// Fd at index 0 is always reserved for inotify
+#define FIRST_ACTUAL_DEVICE_INDEX 1
+
#define INDENT " "
#define INDENT2 " "
#define INDENT3 " "
@@ -79,7 +80,7 @@
namespace android {
static const char *WAKE_LOCK_ID = "KeyEvents";
-static const char *device_path = "/dev/input";
+static const char *DEVICE_PATH = "/dev/input";
/* return the larger integer */
static inline int max(int v1, int v2)
@@ -91,63 +92,69 @@
return value ? "true" : "false";
}
-EventHub::device_t::device_t(int32_t _id, const char* _path, const char* name)
- : id(_id), path(_path), name(name), classes(0)
- , keyBitmask(NULL), layoutMap(NULL), configuration(NULL), fd(-1), next(NULL) {
+// --- EventHub::Device ---
+
+EventHub::Device::Device(int fd, int32_t id, const String8& path,
+ const InputDeviceIdentifier& identifier) :
+ next(NULL),
+ fd(fd), id(id), path(path), identifier(identifier),
+ classes(0), keyBitmask(NULL), configuration(NULL), virtualKeyMap(NULL) {
}
-EventHub::device_t::~device_t() {
- delete [] keyBitmask;
- delete layoutMap;
+EventHub::Device::~Device() {
+ close();
+ delete[] keyBitmask;
delete configuration;
+ delete virtualKeyMap;
}
-EventHub::EventHub(void)
- : mError(NO_INIT), mHaveFirstKeyboard(false), mFirstKeyboardId(-1)
- , mDevicesById(0), mNumDevicesById(0)
- , mOpeningDevices(0), mClosingDevices(0)
- , mDevices(0), mFDs(0), mFDCount(0), mOpened(false), mNeedToSendFinishedDeviceScan(false)
- , mInputBufferIndex(0), mInputBufferCount(0), mInputDeviceIndex(0)
-{
+void EventHub::Device::close() {
+ if (fd >= 0) {
+ ::close(fd);
+ fd = -1;
+ }
+}
+
+
+// --- EventHub ---
+
+EventHub::EventHub(void) :
+ mError(NO_INIT), mBuiltInKeyboardId(-1), mNextDeviceId(1),
+ mOpeningDevices(0), mClosingDevices(0),
+ mOpened(false), mNeedToSendFinishedDeviceScan(false),
+ mInputBufferIndex(0), mInputBufferCount(0), mInputFdIndex(0) {
acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
#ifdef EV_SW
memset(mSwitches, 0, sizeof(mSwitches));
#endif
}
-/*
- * Clean up.
- */
-EventHub::~EventHub(void)
-{
+EventHub::~EventHub(void) {
release_wake_lock(WAKE_LOCK_ID);
// we should free stuff here...
}
-status_t EventHub::errorCheck() const
-{
+status_t EventHub::errorCheck() const {
return mError;
}
-String8 EventHub::getDeviceName(int32_t deviceId) const
-{
+String8 EventHub::getDeviceName(int32_t deviceId) const {
AutoMutex _l(mLock);
- device_t* device = getDeviceLocked(deviceId);
+ Device* device = getDeviceLocked(deviceId);
if (device == NULL) return String8();
- return device->name;
+ return device->identifier.name;
}
-uint32_t EventHub::getDeviceClasses(int32_t deviceId) const
-{
+uint32_t EventHub::getDeviceClasses(int32_t deviceId) const {
AutoMutex _l(mLock);
- device_t* device = getDeviceLocked(deviceId);
+ Device* device = getDeviceLocked(deviceId);
if (device == NULL) return 0;
return device->classes;
}
void EventHub::getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const {
AutoMutex _l(mLock);
- device_t* device = getDeviceLocked(deviceId);
+ Device* device = getDeviceLocked(deviceId);
if (device && device->configuration) {
*outConfiguration = *device->configuration;
} else {
@@ -160,14 +167,14 @@
outAxisInfo->clear();
AutoMutex _l(mLock);
- device_t* device = getDeviceLocked(deviceId);
+ Device* device = getDeviceLocked(deviceId);
if (device == NULL) return -1;
struct input_absinfo info;
if(ioctl(device->fd, EVIOCGABS(axis), &info)) {
LOGW("Error reading absolute controller %d for device %s fd %d\n",
- axis, device->name.string(), device->fd);
+ axis, device->identifier.name.string(), device->fd);
return -errno;
}
@@ -185,7 +192,7 @@
if (scanCode >= 0 && scanCode <= KEY_MAX) {
AutoMutex _l(mLock);
- device_t* device = getDeviceLocked(deviceId);
+ Device* device = getDeviceLocked(deviceId);
if (device != NULL) {
return getScanCodeStateLocked(device, scanCode);
}
@@ -193,7 +200,7 @@
return AKEY_STATE_UNKNOWN;
}
-int32_t EventHub::getScanCodeStateLocked(device_t* device, int32_t scanCode) const {
+int32_t EventHub::getScanCodeStateLocked(Device* device, int32_t scanCode) const {
uint8_t key_bitmask[sizeof_bit_array(KEY_MAX + 1)];
memset(key_bitmask, 0, sizeof(key_bitmask));
if (ioctl(device->fd,
@@ -206,20 +213,20 @@
int32_t EventHub::getKeyCodeState(int32_t deviceId, int32_t keyCode) const {
AutoMutex _l(mLock);
- device_t* device = getDeviceLocked(deviceId);
+ Device* device = getDeviceLocked(deviceId);
if (device != NULL) {
return getKeyCodeStateLocked(device, keyCode);
}
return AKEY_STATE_UNKNOWN;
}
-int32_t EventHub::getKeyCodeStateLocked(device_t* device, int32_t keyCode) const {
- if (!device->layoutMap) {
+int32_t EventHub::getKeyCodeStateLocked(Device* device, int32_t keyCode) const {
+ if (!device->keyMap.haveKeyLayout()) {
return AKEY_STATE_UNKNOWN;
}
Vector<int32_t> scanCodes;
- device->layoutMap->findScanCodes(keyCode, &scanCodes);
+ device->keyMap.keyLayoutMap->findScanCodes(keyCode, &scanCodes);
uint8_t key_bitmask[sizeof_bit_array(KEY_MAX + 1)];
memset(key_bitmask, 0, sizeof(key_bitmask));
@@ -247,7 +254,7 @@
if (sw >= 0 && sw <= SW_MAX) {
AutoMutex _l(mLock);
- device_t* device = getDeviceLocked(deviceId);
+ Device* device = getDeviceLocked(deviceId);
if (device != NULL) {
return getSwitchStateLocked(device, sw);
}
@@ -256,7 +263,7 @@
return AKEY_STATE_UNKNOWN;
}
-int32_t EventHub::getSwitchStateLocked(device_t* device, int32_t sw) const {
+int32_t EventHub::getSwitchStateLocked(Device* device, int32_t sw) const {
uint8_t sw_bitmask[sizeof_bit_array(SW_MAX + 1)];
memset(sw_bitmask, 0, sizeof(sw_bitmask));
if (ioctl(device->fd,
@@ -270,16 +277,16 @@
const int32_t* keyCodes, uint8_t* outFlags) const {
AutoMutex _l(mLock);
- device_t* device = getDeviceLocked(deviceId);
+ Device* device = getDeviceLocked(deviceId);
if (device != NULL) {
return markSupportedKeyCodesLocked(device, numCodes, keyCodes, outFlags);
}
return false;
}
-bool EventHub::markSupportedKeyCodesLocked(device_t* device, size_t numCodes,
+bool EventHub::markSupportedKeyCodesLocked(Device* device, size_t numCodes,
const int32_t* keyCodes, uint8_t* outFlags) const {
- if (device->layoutMap == NULL || device->keyBitmask == NULL) {
+ if (!device->keyMap.haveKeyLayout() || !device->keyBitmask) {
return false;
}
@@ -287,7 +294,7 @@
for (size_t codeIndex = 0; codeIndex < numCodes; codeIndex++) {
scanCodes.clear();
- status_t err = device->layoutMap->findScanCodes(keyCodes[codeIndex], &scanCodes);
+ status_t err = device->keyMap.keyLayoutMap->findScanCodes(keyCodes[codeIndex], &scanCodes);
if (! err) {
// check the possible scan codes identified by the layout map against the
// map of codes actually emitted by the driver
@@ -306,20 +313,20 @@
int32_t* outKeycode, uint32_t* outFlags) const
{
AutoMutex _l(mLock);
- device_t* device = getDeviceLocked(deviceId);
+ Device* device = getDeviceLocked(deviceId);
- if (device != NULL && device->layoutMap != NULL) {
- status_t err = device->layoutMap->map(scancode, outKeycode, outFlags);
+ if (device && device->keyMap.haveKeyLayout()) {
+ status_t err = device->keyMap.keyLayoutMap->map(scancode, outKeycode, outFlags);
if (err == NO_ERROR) {
return NO_ERROR;
}
}
- if (mHaveFirstKeyboard) {
- device = getDeviceLocked(mFirstKeyboardId);
+ if (mBuiltInKeyboardId != -1) {
+ device = getDeviceLocked(mBuiltInKeyboardId);
- if (device != NULL && device->layoutMap != NULL) {
- status_t err = device->layoutMap->map(scancode, outKeycode, outFlags);
+ if (device && device->keyMap.haveKeyLayout()) {
+ status_t err = device->keyMap.keyLayoutMap->map(scancode, outKeycode, outFlags);
if (err == NO_ERROR) {
return NO_ERROR;
}
@@ -341,7 +348,7 @@
bool EventHub::hasLed(int32_t deviceId, int32_t led) const {
AutoMutex _l(mLock);
- device_t* device = getDeviceLocked(deviceId);
+ Device* device = getDeviceLocked(deviceId);
if (device) {
uint8_t bitmask[sizeof_bit_array(LED_MAX + 1)];
memset(bitmask, 0, sizeof(bitmask));
@@ -356,7 +363,7 @@
void EventHub::setLedState(int32_t deviceId, int32_t led, bool on) {
AutoMutex _l(mLock);
- device_t* device = getDeviceLocked(deviceId);
+ Device* device = getDeviceLocked(deviceId);
if (device) {
struct input_event ev;
ev.time.tv_sec = 0;
@@ -372,21 +379,33 @@
}
}
-EventHub::device_t* EventHub::getDeviceLocked(int32_t deviceId) const
-{
- if (deviceId == 0) deviceId = mFirstKeyboardId;
- int32_t id = deviceId & ID_MASK;
- if (id >= mNumDevicesById || id < 0) return NULL;
- device_t* dev = mDevicesById[id].device;
- if (dev == NULL) return NULL;
- if (dev->id == deviceId) {
- return dev;
+void EventHub::getVirtualKeyDefinitions(int32_t deviceId,
+ Vector<VirtualKeyDefinition>& outVirtualKeys) const {
+ outVirtualKeys.clear();
+
+ AutoMutex _l(mLock);
+ Device* device = getDeviceLocked(deviceId);
+ if (device && device->virtualKeyMap) {
+ outVirtualKeys.appendVector(device->virtualKeyMap->getVirtualKeys());
+ }
+}
+
+EventHub::Device* EventHub::getDeviceLocked(int32_t deviceId) const {
+ if (deviceId == 0) {
+ deviceId = mBuiltInKeyboardId;
+ }
+
+ size_t numDevices = mDevices.size();
+ for (size_t i = FIRST_ACTUAL_DEVICE_INDEX; i < numDevices; i++) {
+ Device* device = mDevices[i];
+ if (device->id == deviceId) {
+ return device;
+ }
}
return NULL;
}
-bool EventHub::getEvent(RawEvent* outEvent)
-{
+bool EventHub::getEvent(RawEvent* outEvent) {
outEvent->deviceId = 0;
outEvent->type = 0;
outEvent->scanCode = 0;
@@ -407,11 +426,11 @@
for (;;) {
// Report any devices that had last been added/removed.
if (mClosingDevices != NULL) {
- device_t* device = mClosingDevices;
- LOGV("Reporting device closed: id=0x%x, name=%s\n",
+ Device* device = mClosingDevices;
+ LOGV("Reporting device closed: id=%d, name=%s\n",
device->id, device->path.string());
mClosingDevices = device->next;
- if (device->id == mFirstKeyboardId) {
+ if (device->id == mBuiltInKeyboardId) {
outEvent->deviceId = 0;
} else {
outEvent->deviceId = device->id;
@@ -424,11 +443,11 @@
}
if (mOpeningDevices != NULL) {
- device_t* device = mOpeningDevices;
- LOGV("Reporting device opened: id=0x%x, name=%s\n",
+ Device* device = mOpeningDevices;
+ LOGV("Reporting device opened: id=%d, name=%s\n",
device->id, device->path.string());
mOpeningDevices = device->next;
- if (device->id == mFirstKeyboardId) {
+ if (device->id == mBuiltInKeyboardId) {
outEvent->deviceId = 0;
} else {
outEvent->deviceId = device->id;
@@ -451,11 +470,11 @@
// Consume buffered input events, if any.
if (mInputBufferIndex < mInputBufferCount) {
const struct input_event& iev = mInputBufferData[mInputBufferIndex++];
- const device_t* device = mDevices[mInputDeviceIndex];
+ const Device* device = mDevices[mInputFdIndex];
LOGV("%s got: t0=%d, t1=%d, type=%d, code=%d, v=%d", device->path.string(),
(int) iev.time.tv_sec, (int) iev.time.tv_usec, iev.type, iev.code, iev.value);
- if (device->id == mFirstKeyboardId) {
+ if (device->id == mBuiltInKeyboardId) {
outEvent->deviceId = 0;
} else {
outEvent->deviceId = device->id;
@@ -465,8 +484,8 @@
outEvent->flags = 0;
if (iev.type == EV_KEY) {
outEvent->keyCode = AKEYCODE_UNKNOWN;
- if (device->layoutMap) {
- status_t err = device->layoutMap->map(iev.code,
+ if (device->keyMap.haveKeyLayout()) {
+ status_t err = device->keyMap.keyLayoutMap->map(iev.code,
&outEvent->keyCode, &outEvent->flags);
LOGV("iev.code=%d keyCode=%d flags=0x%08x err=%d\n",
iev.code, outEvent->keyCode, outEvent->flags, err);
@@ -486,13 +505,13 @@
// Finish reading all events from devices identified in previous poll().
// This code assumes that mInputDeviceIndex is initially 0 and that the
// revents member of pollfd is initialized to 0 when the device is first added.
- // Since mFDs[0] is used for inotify, we process regular events starting at index 1.
- mInputDeviceIndex += 1;
- if (mInputDeviceIndex >= mFDCount) {
+ // Since mFds[0] is used for inotify, we process regular events starting at index 1.
+ mInputFdIndex += 1;
+ if (mInputFdIndex >= mFds.size()) {
break;
}
- const struct pollfd& pfd = mFDs[mInputDeviceIndex];
+ const struct pollfd& pfd = mFds[mInputFdIndex];
if (pfd.revents & POLLIN) {
int32_t readSize = read(pfd.fd, mInputBufferData,
sizeof(struct input_event) * INPUT_BUFFER_SIZE);
@@ -503,7 +522,7 @@
} else if ((readSize % sizeof(struct input_event)) != 0) {
LOGE("could not get event (wrong size: %d)", readSize);
} else {
- mInputBufferCount = readSize / sizeof(struct input_event);
+ mInputBufferCount = size_t(readSize) / sizeof(struct input_event);
mInputBufferIndex = 0;
}
}
@@ -512,14 +531,14 @@
#if HAVE_INOTIFY
// readNotify() will modify mFDs and mFDCount, so this must be done after
// processing all other events.
- if(mFDs[0].revents & POLLIN) {
- readNotify(mFDs[0].fd);
- mFDs[0].revents = 0;
+ if(mFds[0].revents & POLLIN) {
+ readNotify(mFds[0].fd);
+ mFds.editItemAt(0).revents = 0;
continue; // report added or removed devices immediately
}
#endif
- mInputDeviceIndex = 0;
+ mInputFdIndex = 0;
// Poll for events. Mind the wake lock dance!
// We hold a wake lock at all times except during poll(). This works due to some
@@ -531,7 +550,7 @@
// pending or currently being processed.
release_wake_lock(WAKE_LOCK_ID);
- int pollResult = poll(mFDs, mFDCount, -1);
+ int pollResult = poll(mFds.editArray(), mFds.size(), -1);
acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
@@ -547,36 +566,37 @@
/*
* Open the platform-specific input device.
*/
-bool EventHub::openPlatformInput(void)
-{
+bool EventHub::openPlatformInput(void) {
/*
* Open platform-specific input device(s).
*/
- int res;
+ int res, fd;
- mFDCount = 1;
- mFDs = (pollfd *)calloc(1, sizeof(mFDs[0]));
- mDevices = (device_t **)calloc(1, sizeof(mDevices[0]));
- mFDs[0].events = POLLIN;
- mFDs[0].revents = 0;
- mDevices[0] = NULL;
#ifdef HAVE_INOTIFY
- mFDs[0].fd = inotify_init();
- res = inotify_add_watch(mFDs[0].fd, device_path, IN_DELETE | IN_CREATE);
+ fd = inotify_init();
+ res = inotify_add_watch(fd, DEVICE_PATH, IN_DELETE | IN_CREATE);
if(res < 0) {
- LOGE("could not add watch for %s, %s\n", device_path, strerror(errno));
+ LOGE("could not add watch for %s, %s\n", DEVICE_PATH, strerror(errno));
}
#else
/*
* The code in EventHub::getEvent assumes that mFDs[0] is an inotify fd.
* We allocate space for it and set it to something invalid.
*/
- mFDs[0].fd = -1;
+ fd = -1;
#endif
- res = scanDir(device_path);
+ // Reserve fd index 0 for inotify.
+ struct pollfd pollfd;
+ pollfd.fd = fd;
+ pollfd.events = POLLIN;
+ pollfd.revents = 0;
+ mFds.push(pollfd);
+ mDevices.push(NULL);
+
+ res = scanDir(DEVICE_PATH);
if(res < 0) {
- LOGE("scan dir failed for %s\n", device_path);
+ LOGE("scan dir failed for %s\n", DEVICE_PATH);
}
return true;
@@ -604,129 +624,102 @@
AKEYCODE_BUTTON_START, AKEYCODE_BUTTON_SELECT, AKEYCODE_BUTTON_MODE
};
-int EventHub::openDevice(const char *deviceName) {
- int version;
- int fd;
- struct pollfd *new_mFDs;
- device_t **new_devices;
- char **new_device_names;
- char name[80];
- char location[80];
- char idstr[80];
- struct input_id id;
+int EventHub::openDevice(const char *devicePath) {
+ char buffer[80];
- LOGV("Opening device: %s", deviceName);
+ LOGV("Opening device: %s", devicePath);
AutoMutex _l(mLock);
- fd = open(deviceName, O_RDWR);
+ int fd = open(devicePath, O_RDWR);
if(fd < 0) {
- LOGE("could not open %s, %s\n", deviceName, strerror(errno));
+ LOGE("could not open %s, %s\n", devicePath, strerror(errno));
return -1;
}
- if(ioctl(fd, EVIOCGVERSION, &version)) {
- LOGE("could not get driver version for %s, %s\n", deviceName, strerror(errno));
- return -1;
- }
- if(ioctl(fd, EVIOCGID, &id)) {
- LOGE("could not get driver id for %s, %s\n", deviceName, strerror(errno));
- return -1;
- }
- name[sizeof(name) - 1] = '\0';
- location[sizeof(location) - 1] = '\0';
- idstr[sizeof(idstr) - 1] = '\0';
- if(ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) {
- //fprintf(stderr, "could not get device name for %s, %s\n", deviceName, strerror(errno));
- name[0] = '\0';
+ InputDeviceIdentifier identifier;
+
+ // Get device name.
+ if(ioctl(fd, EVIOCGNAME(sizeof(buffer) - 1), &buffer) < 1) {
+ //fprintf(stderr, "could not get device name for %s, %s\n", devicePath, strerror(errno));
+ } else {
+ buffer[sizeof(buffer) - 1] = '\0';
+ identifier.name.setTo(buffer);
}
- // check to see if the device is on our excluded list
+ // Check to see if the device is on our excluded list
List<String8>::iterator iter = mExcludedDevices.begin();
List<String8>::iterator end = mExcludedDevices.end();
for ( ; iter != end; iter++) {
const char* test = *iter;
- if (strcmp(name, test) == 0) {
- LOGI("ignoring event id %s driver %s\n", deviceName, test);
+ if (identifier.name == test) {
+ LOGI("ignoring event id %s driver %s\n", devicePath, test);
close(fd);
return -1;
}
}
- if(ioctl(fd, EVIOCGPHYS(sizeof(location) - 1), &location) < 1) {
- //fprintf(stderr, "could not get location for %s, %s\n", deviceName, strerror(errno));
- location[0] = '\0';
- }
- if(ioctl(fd, EVIOCGUNIQ(sizeof(idstr) - 1), &idstr) < 1) {
- //fprintf(stderr, "could not get idstring for %s, %s\n", deviceName, strerror(errno));
- idstr[0] = '\0';
+ // Get device driver version.
+ int driverVersion;
+ if(ioctl(fd, EVIOCGVERSION, &driverVersion)) {
+ LOGE("could not get driver version for %s, %s\n", devicePath, strerror(errno));
+ close(fd);
+ return -1;
}
+ // Get device identifier.
+ struct input_id inputId;
+ if(ioctl(fd, EVIOCGID, &inputId)) {
+ LOGE("could not get device input id for %s, %s\n", devicePath, strerror(errno));
+ close(fd);
+ return -1;
+ }
+ identifier.bus = inputId.bustype;
+ identifier.product = inputId.product;
+ identifier.vendor = inputId.vendor;
+ identifier.version = inputId.version;
+
+ // Get device physical location.
+ if(ioctl(fd, EVIOCGPHYS(sizeof(buffer) - 1), &buffer) < 1) {
+ //fprintf(stderr, "could not get location for %s, %s\n", devicePath, strerror(errno));
+ } else {
+ buffer[sizeof(buffer) - 1] = '\0';
+ identifier.location.setTo(buffer);
+ }
+
+ // Get device unique id.
+ if(ioctl(fd, EVIOCGUNIQ(sizeof(buffer) - 1), &buffer) < 1) {
+ //fprintf(stderr, "could not get idstring for %s, %s\n", devicePath, strerror(errno));
+ } else {
+ buffer[sizeof(buffer) - 1] = '\0';
+ identifier.uniqueId.setTo(buffer);
+ }
+
+ // Make file descriptor non-blocking for use with poll().
if (fcntl(fd, F_SETFL, O_NONBLOCK)) {
LOGE("Error %d making device file descriptor non-blocking.", errno);
close(fd);
return -1;
}
- int devid = 0;
- while (devid < mNumDevicesById) {
- if (mDevicesById[devid].device == NULL) {
- break;
- }
- devid++;
- }
- if (devid >= mNumDevicesById) {
- device_ent* new_devids = (device_ent*)realloc(mDevicesById,
- sizeof(mDevicesById[0]) * (devid + 1));
- if (new_devids == NULL) {
- LOGE("out of memory");
- return -1;
- }
- mDevicesById = new_devids;
- mNumDevicesById = devid+1;
- mDevicesById[devid].device = NULL;
- mDevicesById[devid].seq = 0;
- }
-
- mDevicesById[devid].seq = (mDevicesById[devid].seq+(1<<SEQ_SHIFT))&SEQ_MASK;
- if (mDevicesById[devid].seq == 0) {
- mDevicesById[devid].seq = 1<<SEQ_SHIFT;
- }
-
- new_mFDs = (pollfd*)realloc(mFDs, sizeof(mFDs[0]) * (mFDCount + 1));
- new_devices = (device_t**)realloc(mDevices, sizeof(mDevices[0]) * (mFDCount + 1));
- if (new_mFDs == NULL || new_devices == NULL) {
- LOGE("out of memory");
- return -1;
- }
- mFDs = new_mFDs;
- mDevices = new_devices;
+ // Allocate device. (The device object takes ownership of the fd at this point.)
+ int32_t deviceId = mNextDeviceId++;
+ Device* device = new Device(fd, deviceId, String8(devicePath), identifier);
#if 0
- LOGI("add device %d: %s\n", mFDCount, deviceName);
- LOGI(" bus: %04x\n"
- " vendor %04x\n"
- " product %04x\n"
- " version %04x\n",
- id.bustype, id.vendor, id.product, id.version);
- LOGI(" name: \"%s\"\n", name);
- LOGI(" location: \"%s\"\n"
- " id: \"%s\"\n", location, idstr);
- LOGI(" version: %d.%d.%d\n",
- version >> 16, (version >> 8) & 0xff, version & 0xff);
+ LOGI("add device %d: %s\n", deviceId, devicePath);
+ LOGI(" bus: %04x\n"
+ " vendor %04x\n"
+ " product %04x\n"
+ " version %04x\n",
+ identifier.bus, identifier.vendor, identifier.product, identifier.version);
+ LOGI(" name: \"%s\"\n", identifier.name.string());
+ LOGI(" location: \"%s\"\n", identifier.location.string());
+ LOGI(" unique id: \"%s\"\n", identifier.uniqueId.string());
+ LOGI(" driver: v%d.%d.%d\n",
+ driverVersion >> 16, (driverVersion >> 8) & 0xff, driverVersion & 0xff);
#endif
- device_t* device = new device_t(devid|mDevicesById[devid].seq, deviceName, name);
- if (device == NULL) {
- LOGE("out of memory");
- return -1;
- }
-
- device->fd = fd;
- mFDs[mFDCount].fd = fd;
- mFDs[mFDCount].events = POLLIN;
- mFDs[mFDCount].revents = 0;
-
// Load the configuration file for the device.
loadConfiguration(device);
@@ -798,7 +791,7 @@
bool hasSwitches = false;
if (ioctl(fd, EVIOCGBIT(EV_SW, sizeof(sw_bitmask)), sw_bitmask) >= 0) {
for (int i=0; i<EV_SW; i++) {
- //LOGI("Device 0x%x sw %d: has=%d", device->id, i, test_bit(i, sw_bitmask));
+ //LOGI("Device %d sw %d: has=%d", device->id, i, test_bit(i, sw_bitmask));
if (test_bit(i, sw_bitmask)) {
hasSwitches = true;
if (mSwitches[i] == 0) {
@@ -812,37 +805,29 @@
}
#endif
- if ((device->classes & INPUT_DEVICE_CLASS_KEYBOARD) != 0) {
- // a more descriptive name
- device->name = name;
-
- // Configure the keymap for the device.
- configureKeyMap(device);
-
- // Tell the world about the devname (the descriptive name)
- if (!mHaveFirstKeyboard && !device->keyMapInfo.isDefaultKeyMap && strstr(name, "-keypad")) {
- // the built-in keyboard has a well-known device ID of 0,
- // this device better not go away.
- mHaveFirstKeyboard = true;
- mFirstKeyboardId = device->id;
- setKeyboardProperties(device, true);
- } else {
- // ensure mFirstKeyboardId is set to -something-.
- if (mFirstKeyboardId == -1) {
- mFirstKeyboardId = device->id;
- setKeyboardProperties(device, true);
- }
+ if ((device->classes & INPUT_DEVICE_CLASS_TOUCHSCREEN)) {
+ // Load the virtual keys for the touch screen, if any.
+ // We do this now so that we can make sure to load the keymap if necessary.
+ status_t status = loadVirtualKeyMap(device);
+ if (!status) {
+ device->classes |= INPUT_DEVICE_CLASS_KEYBOARD;
}
+ }
+
+ if ((device->classes & INPUT_DEVICE_CLASS_KEYBOARD) != 0) {
+ // Load the keymap for the device.
+ status_t status = loadKeyMap(device);
+
+ // Set system properties for the keyboard.
setKeyboardProperties(device, false);
- // Load the keylayout.
- if (!device->keyMapInfo.keyLayoutFile.isEmpty()) {
- status_t status = KeyLayoutMap::load(device->keyMapInfo.keyLayoutFile,
- &device->layoutMap);
- if (status) {
- LOGE("Error %d loading key layout file '%s'.", status,
- device->keyMapInfo.keyLayoutFile.string());
- }
+ // Register the keyboard as a built-in keyboard if it is eligible.
+ if (!status
+ && mBuiltInKeyboardId == -1
+ && isEligibleBuiltInKeyboard(device->identifier,
+ device->configuration, &device->keyMap)) {
+ mBuiltInKeyboardId = device->id;
+ setKeyboardProperties(device, true);
}
// 'Q' key support = cheap test of whether this is an alpha-capable kbd
@@ -866,76 +851,87 @@
break;
}
}
-
- LOGI("New keyboard: device->id=0x%x devname='%s' keylayout='%s' keycharactermap='%s'\n",
- device->id, name,
- device->keyMapInfo.keyLayoutFile.string(),
- device->keyMapInfo.keyCharacterMapFile.string());
}
// If the device isn't recognized as something we handle, don't monitor it.
if (device->classes == 0) {
- LOGV("Dropping device %s %p, id = %d\n", deviceName, device, devid);
- close(fd);
+ LOGV("Dropping device: id=%d, path='%s', name='%s'",
+ deviceId, devicePath, device->identifier.name.string());
delete device;
return -1;
}
- LOGI("New device: path=%s name=%s id=0x%x (of 0x%x) index=%d fd=%d classes=0x%x "
- "configuration='%s'\n",
- deviceName, name, device->id, mNumDevicesById, mFDCount, fd, device->classes,
- device->configurationFile.string());
+ LOGI("New device: id=%d, fd=%d, path='%s', name='%s', classes=0x%x, "
+ "configuration='%s', keyLayout='%s', keyCharacterMap='%s', builtinKeyboard=%s",
+ deviceId, fd, devicePath, device->identifier.name.string(),
+ device->classes,
+ device->configurationFile.string(),
+ device->keyMap.keyLayoutFile.string(),
+ device->keyMap.keyCharacterMapFile.string(),
+ toString(mBuiltInKeyboardId == deviceId));
- LOGV("Adding device %s %p at %d, id = %d, classes = 0x%x\n",
- deviceName, device, mFDCount, devid, device->classes);
+ struct pollfd pollfd;
+ pollfd.fd = fd;
+ pollfd.events = POLLIN;
+ pollfd.revents = 0;
+ mFds.push(pollfd);
+ mDevices.push(device);
- mDevicesById[devid].device = device;
device->next = mOpeningDevices;
mOpeningDevices = device;
- mDevices[mFDCount] = device;
-
- mFDCount++;
return 0;
}
-void EventHub::loadConfiguration(device_t* device) {
- device->configurationFile = getInputDeviceConfigurationFilePath(device->name,
- INPUT_DEVICE_CONFIGURATION_FILE_TYPE_CONFIGURATION);
+void EventHub::loadConfiguration(Device* device) {
+ device->configurationFile = getInputDeviceConfigurationFilePathByDeviceIdentifier(
+ device->identifier, INPUT_DEVICE_CONFIGURATION_FILE_TYPE_CONFIGURATION);
if (device->configurationFile.isEmpty()) {
- LOGI("No input device configuration file found for device '%s'.",
- device->name.string());
+ LOGD("No input device configuration file found for device '%s'.",
+ device->identifier.name.string());
} else {
status_t status = PropertyMap::load(device->configurationFile,
&device->configuration);
if (status) {
- LOGE("Error loading input device configuration file for device '%s'.",
- device->name.string());
+ LOGE("Error loading input device configuration file for device '%s'. "
+ "Using default configuration.",
+ device->identifier.name.string());
}
}
}
-void EventHub::configureKeyMap(device_t* device) {
- android::resolveKeyMap(device->name, device->configuration, device->keyMapInfo);
+status_t EventHub::loadVirtualKeyMap(Device* device) {
+ // The virtual key map is supplied by the kernel as a system board property file.
+ String8 path;
+ path.append("/sys/board_properties/virtualkeys.");
+ path.append(device->identifier.name);
+ if (access(path.string(), R_OK)) {
+ return NAME_NOT_FOUND;
+ }
+ return VirtualKeyMap::load(path, &device->virtualKeyMap);
}
-void EventHub::setKeyboardProperties(device_t* device, bool firstKeyboard) {
- int32_t id = firstKeyboard ? 0 : device->id;
- android::setKeyboardProperties(id, device->name, device->keyMapInfo);
+status_t EventHub::loadKeyMap(Device* device) {
+ return device->keyMap.load(device->identifier, device->configuration);
}
-void EventHub::clearKeyboardProperties(device_t* device, bool firstKeyboard) {
- int32_t id = firstKeyboard ? 0 : device->id;
+void EventHub::setKeyboardProperties(Device* device, bool builtInKeyboard) {
+ int32_t id = builtInKeyboard ? 0 : device->id;
+ android::setKeyboardProperties(id, device->identifier,
+ device->keyMap.keyLayoutFile, device->keyMap.keyCharacterMapFile);
+}
+
+void EventHub::clearKeyboardProperties(Device* device, bool builtInKeyboard) {
+ int32_t id = builtInKeyboard ? 0 : device->id;
android::clearKeyboardProperties(id);
}
-bool EventHub::hasKeycodeLocked(device_t* device, int keycode) const
-{
- if (device->keyBitmask == NULL || device->layoutMap == NULL) {
+bool EventHub::hasKeycodeLocked(Device* device, int keycode) const {
+ if (!device->keyMap.haveKeyLayout() || !device->keyBitmask) {
return false;
}
Vector<int32_t> scanCodes;
- device->layoutMap->findScanCodes(keycode, &scanCodes);
+ device->keyMap.keyLayoutMap->findScanCodes(keycode, &scanCodes);
const size_t N = scanCodes.size();
for (size_t i=0; i<N && i<=KEY_MAX; i++) {
int32_t sc = scanCodes.itemAt(i);
@@ -947,29 +943,15 @@
return false;
}
-int EventHub::closeDevice(const char *deviceName) {
+int EventHub::closeDevice(const char *devicePath) {
AutoMutex _l(mLock);
- int i;
- for(i = 1; i < mFDCount; i++) {
- if(strcmp(mDevices[i]->path.string(), deviceName) == 0) {
- //LOGD("remove device %d: %s\n", i, deviceName);
- device_t* device = mDevices[i];
-
- LOGI("Removed device: path=%s name=%s id=0x%x (of 0x%x) index=%d fd=%d classes=0x%x\n",
- device->path.string(), device->name.string(), device->id,
- mNumDevicesById, mFDCount, mFDs[i].fd, device->classes);
-
- // Clear this device's entry.
- int index = (device->id&ID_MASK);
- mDevicesById[index].device = NULL;
-
- // Close the file descriptor and compact the fd array.
- close(mFDs[i].fd);
- int count = mFDCount - i - 1;
- memmove(mDevices + i, mDevices + i + 1, sizeof(mDevices[0]) * count);
- memmove(mFDs + i, mFDs + i + 1, sizeof(mFDs[0]) * count);
- mFDCount--;
+ for (size_t i = FIRST_ACTUAL_DEVICE_INDEX; i < mDevices.size(); i++) {
+ Device* device = mDevices[i];
+ if (device->path == devicePath) {
+ LOGI("Removed device: path=%s name=%s id=%d fd=%d classes=0x%x\n",
+ device->path.string(), device->identifier.name.string(), device->id,
+ device->fd, device->classes);
#ifdef EV_SW
for (int j=0; j<EV_SW; j++) {
@@ -978,21 +960,25 @@
}
}
#endif
-
- device->next = mClosingDevices;
- mClosingDevices = device;
- if (device->id == mFirstKeyboardId) {
+ if (device->id == mBuiltInKeyboardId) {
LOGW("built-in keyboard device %s (id=%d) is closing! the apps will not like this",
- device->path.string(), mFirstKeyboardId);
- mFirstKeyboardId = -1;
+ device->path.string(), mBuiltInKeyboardId);
+ mBuiltInKeyboardId = -1;
clearKeyboardProperties(device, true);
}
clearKeyboardProperties(device, false);
+
+ mFds.removeAt(i);
+ mDevices.removeAt(i);
+ device->close();
+
+ device->next = mClosingDevices;
+ mClosingDevices = device;
return 0;
}
}
- LOGE("remove device: %s not found\n", deviceName);
+ LOGE("remove device: %s not found\n", devicePath);
return -1;
}
@@ -1016,7 +1002,7 @@
}
//printf("got %d bytes of event information\n", res);
- strcpy(devname, device_path);
+ strcpy(devname, DEVICE_PATH);
filename = devname + strlen(devname);
*filename++ = '/';
@@ -1040,7 +1026,6 @@
return 0;
}
-
int EventHub::scanDir(const char *dirname)
{
char devname[PATH_MAX];
@@ -1071,28 +1056,32 @@
{ // acquire lock
AutoMutex _l(mLock);
- dump.appendFormat(INDENT "HaveFirstKeyboard: %s\n", toString(mHaveFirstKeyboard));
- dump.appendFormat(INDENT "FirstKeyboardId: 0x%x\n", mFirstKeyboardId);
+ dump.appendFormat(INDENT "BuiltInKeyboardId: %d\n", mBuiltInKeyboardId);
dump.append(INDENT "Devices:\n");
- for (int i = 0; i < mNumDevicesById; i++) {
- const device_t* device = mDevicesById[i].device;
+ for (size_t i = FIRST_ACTUAL_DEVICE_INDEX; i < mDevices.size(); i++) {
+ const Device* device = mDevices[i];
if (device) {
- if (mFirstKeyboardId == device->id) {
- dump.appendFormat(INDENT2 "0x%x: %s (aka device 0 - first keyboard)\n",
- device->id, device->name.string());
+ if (mBuiltInKeyboardId == device->id) {
+ dump.appendFormat(INDENT2 "%d: %s (aka device 0 - built-in keyboard)\n",
+ device->id, device->identifier.name.string());
} else {
- dump.appendFormat(INDENT2 "0x%x: %s\n", device->id, device->name.string());
+ dump.appendFormat(INDENT2 "%d: %s\n", device->id,
+ device->identifier.name.string());
}
dump.appendFormat(INDENT3 "Classes: 0x%08x\n", device->classes);
dump.appendFormat(INDENT3 "Path: %s\n", device->path.string());
- dump.appendFormat(INDENT3 "IsDefaultKeyMap: %s\n",
- toString(device->keyMapInfo.isDefaultKeyMap));
+ dump.appendFormat(INDENT3 "Location: %s\n", device->identifier.location.string());
+ dump.appendFormat(INDENT3 "UniqueId: %s\n", device->identifier.uniqueId.string());
+ dump.appendFormat(INDENT3 "Identifier: bus=0x%04x, vendor=0x%04x, "
+ "product=0x%04x, version=0x%04x\n",
+ device->identifier.bus, device->identifier.vendor,
+ device->identifier.product, device->identifier.version);
dump.appendFormat(INDENT3 "KeyLayoutFile: %s\n",
- device->keyMapInfo.keyLayoutFile.string());
+ device->keyMap.keyLayoutFile.string());
dump.appendFormat(INDENT3 "KeyCharacterMapFile: %s\n",
- device->keyMapInfo.keyCharacterMapFile.string());
+ device->keyMap.keyCharacterMapFile.string());
dump.appendFormat(INDENT3 "ConfigurationFile: %s\n",
device->configurationFile.string());
}
diff --git a/libs/ui/Input.cpp b/libs/ui/Input.cpp
index 9e697db..b8d59e6 100644
--- a/libs/ui/Input.cpp
+++ b/libs/ui/Input.cpp
@@ -11,6 +11,7 @@
#include <stdlib.h>
#include <unistd.h>
+#include <ctype.h>
#include <ui/Input.h>
@@ -28,12 +29,16 @@
".kcm",
};
+static bool isValidNameChar(char ch) {
+ return isascii(ch) && (isdigit(ch) || isalpha(ch) || ch == '-' || ch == '_');
+}
+
static void appendInputDeviceConfigurationFileRelativePath(String8& path,
const String8& name, InputDeviceConfigurationFileType type) {
path.append(CONFIGURATION_FILE_DIR[type]);
for (size_t i = 0; i < name.length(); i++) {
char ch = name[i];
- if (ch == ' ') {
+ if (!isValidNameChar(ch)) {
ch = '_';
}
path.append(&ch, 1);
@@ -41,7 +46,37 @@
path.append(CONFIGURATION_FILE_EXTENSION[type]);
}
-extern String8 getInputDeviceConfigurationFilePath(
+String8 getInputDeviceConfigurationFilePathByDeviceIdentifier(
+ const InputDeviceIdentifier& deviceIdentifier,
+ InputDeviceConfigurationFileType type) {
+ if (deviceIdentifier.vendor !=0 && deviceIdentifier.product != 0) {
+ if (deviceIdentifier.version != 0) {
+ // Try vendor product version.
+ String8 versionPath(getInputDeviceConfigurationFilePathByName(
+ String8::format("Vendor_%04x_Product_%04x_Version_%04x",
+ deviceIdentifier.vendor, deviceIdentifier.product,
+ deviceIdentifier.version),
+ type));
+ if (!versionPath.isEmpty()) {
+ return versionPath;
+ }
+ }
+
+ // Try vendor product.
+ String8 productPath(getInputDeviceConfigurationFilePathByName(
+ String8::format("Vendor_%04x_Product_%04x",
+ deviceIdentifier.vendor, deviceIdentifier.product),
+ type));
+ if (!productPath.isEmpty()) {
+ return productPath;
+ }
+ }
+
+ // Try device name.
+ return getInputDeviceConfigurationFilePathByName(deviceIdentifier.name, type);
+}
+
+String8 getInputDeviceConfigurationFilePathByName(
const String8& name, InputDeviceConfigurationFileType type) {
// Search system repository.
String8 path;
diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp
index 0708223..f1223f1 100644
--- a/libs/ui/InputDispatcher.cpp
+++ b/libs/ui/InputDispatcher.cpp
@@ -315,7 +315,7 @@
// Throttle it!
#if DEBUG_THROTTLING
LOGD("Throttling - Delaying motion event for "
- "device 0x%x, source 0x%08x by up to %0.3fms.",
+ "device %d, source 0x%08x by up to %0.3fms.",
deviceId, source, (nextTime - currentTime) * 0.000001);
#endif
if (nextTime < *nextWakeupTime) {
@@ -704,7 +704,7 @@
void InputDispatcher::logOutboundKeyDetailsLocked(const char* prefix, const KeyEntry* entry) {
#if DEBUG_OUTBOUND_EVENT_DETAILS
- LOGD("%seventTime=%lld, deviceId=0x%x, source=0x%x, policyFlags=0x%x, "
+ LOGD("%seventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, "
"action=0x%x, flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, "
"repeatCount=%d, downTime=%lld",
prefix,
@@ -767,7 +767,7 @@
void InputDispatcher::logOutboundMotionDetailsLocked(const char* prefix, const MotionEntry* entry) {
#if DEBUG_OUTBOUND_EVENT_DETAILS
- LOGD("%seventTime=%lld, deviceId=0x%x, source=0x%x, policyFlags=0x%x, "
+ LOGD("%seventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, "
"action=0x%x, flags=0x%x, "
"metaState=0x%x, edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%lld",
prefix,
@@ -2072,7 +2072,7 @@
uint32_t policyFlags, int32_t action, int32_t flags,
int32_t keyCode, int32_t scanCode, int32_t metaState, nsecs_t downTime) {
#if DEBUG_INBOUND_EVENT_DETAILS
- LOGD("notifyKey - eventTime=%lld, deviceId=0x%x, source=0x%x, policyFlags=0x%x, action=0x%x, "
+ LOGD("notifyKey - eventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, action=0x%x, "
"flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, downTime=%lld",
eventTime, deviceId, source, policyFlags, action, flags,
keyCode, scanCode, metaState, downTime);
@@ -2120,7 +2120,7 @@
uint32_t pointerCount, const int32_t* pointerIds, const PointerCoords* pointerCoords,
float xPrecision, float yPrecision, nsecs_t downTime) {
#if DEBUG_INBOUND_EVENT_DETAILS
- LOGD("notifyMotion - eventTime=%lld, deviceId=0x%x, source=0x%x, policyFlags=0x%x, "
+ LOGD("notifyMotion - eventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, "
"action=0x%x, flags=0x%x, metaState=0x%x, edgeFlags=0x%x, "
"xPrecision=%f, yPrecision=%f, downTime=%lld",
eventTime, deviceId, source, policyFlags, action, flags, metaState, edgeFlags,
diff --git a/libs/ui/InputReader.cpp b/libs/ui/InputReader.cpp
index aa690e5..9cc96ad 100644
--- a/libs/ui/InputReader.cpp
+++ b/libs/ui/InputReader.cpp
@@ -25,6 +25,7 @@
#include <cutils/log.h>
#include <ui/InputReader.h>
#include <ui/Keyboard.h>
+#include <ui/VirtualKeyMap.h>
#include <stddef.h>
#include <stdlib.h>
@@ -121,7 +122,7 @@
mEventHub->getEvent(& rawEvent);
#if DEBUG_RAW_EVENTS
- LOGD("Input event: device=0x%x type=0x%x scancode=%d keycode=%d value=%d",
+ LOGD("Input event: device=%d type=0x%x scancode=%d keycode=%d value=%d",
rawEvent.deviceId, rawEvent.type, rawEvent.scanCode, rawEvent.keyCode,
rawEvent.value);
#endif
@@ -157,9 +158,9 @@
device->configure();
if (device->isIgnored()) {
- LOGI("Device added: id=0x%x, name=%s (ignored non-input device)", deviceId, name.string());
+ LOGI("Device added: id=%d, name='%s' (ignored non-input device)", deviceId, name.string());
} else {
- LOGI("Device added: id=0x%x, name=%s, sources=%08x", deviceId, name.string(),
+ LOGI("Device added: id=%d, name='%s', sources=0x%08x", deviceId, name.string(),
device->getSources());
}
@@ -201,10 +202,10 @@
}
if (device->isIgnored()) {
- LOGI("Device removed: id=0x%x, name=%s (ignored non-input device)",
+ LOGI("Device removed: id=%d, name='%s' (ignored non-input device)",
device->getId(), device->getName().string());
} else {
- LOGI("Device removed: id=0x%x, name=%s, sources=%08x",
+ LOGI("Device removed: id=%d, name='%s', sources=0x%08x",
device->getId(), device->getName().string(), device->getSources());
}
@@ -535,7 +536,7 @@
InputDeviceInfo deviceInfo;
getDeviceInfo(& deviceInfo);
- dump.appendFormat(INDENT "Device 0x%x: %s\n", deviceInfo.getId(),
+ dump.appendFormat(INDENT "Device %d: %s\n", deviceInfo.getId(),
deviceInfo.getName().string());
dump.appendFormat(INDENT2 "Sources: 0x%08x\n", deviceInfo.getSources());
dump.appendFormat(INDENT2 "KeyboardType: %d\n", deviceInfo.getKeyboardType());
@@ -1439,7 +1440,7 @@
bool sizeChanged = mLocked.surfaceWidth != width || mLocked.surfaceHeight != height;
if (sizeChanged) {
- LOGI("Device reconfigured: id=0x%x, name=%s, display size is now %dx%d",
+ LOGI("Device reconfigured: id=%d, name='%s', display size is now %dx%d",
getDeviceId(), getDeviceName().string(), width, height);
mLocked.surfaceWidth = width;
@@ -1651,9 +1652,8 @@
void TouchInputMapper::configureVirtualKeysLocked() {
assert(mRawAxes.x.valid && mRawAxes.y.valid);
- // Note: getVirtualKeyDefinitions is non-reentrant so we can continue holding the lock.
Vector<VirtualKeyDefinition> virtualKeyDefinitions;
- getPolicy()->getVirtualKeyDefinitions(getDeviceName(), virtualKeyDefinitions);
+ getEventHub()->getVirtualKeyDefinitions(getDeviceId(), virtualKeyDefinitions);
mLocked.virtualKeys.clear();
diff --git a/libs/ui/Keyboard.cpp b/libs/ui/Keyboard.cpp
index a4cc22d..6faa600 100644
--- a/libs/ui/Keyboard.cpp
+++ b/libs/ui/Keyboard.cpp
@@ -22,97 +22,167 @@
#include <ui/Keyboard.h>
#include <ui/KeycodeLabels.h>
+#include <ui/KeyLayoutMap.h>
+#include <ui/KeyCharacterMap.h>
#include <utils/Errors.h>
#include <utils/Log.h>
#include <cutils/properties.h>
namespace android {
-static bool probeKeyMap(KeyMapInfo& keyMapInfo, const String8& keyMapName, bool defaultKeyMap) {
- bool foundOne = false;
- if (keyMapInfo.keyLayoutFile.isEmpty()) {
- keyMapInfo.keyLayoutFile.setTo(getInputDeviceConfigurationFilePath(keyMapName,
- INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_LAYOUT));
- if (!keyMapInfo.keyLayoutFile.isEmpty()) {
- foundOne = true;
- }
- }
+// --- KeyMap ---
- if (keyMapInfo.keyCharacterMapFile.isEmpty()) {
- keyMapInfo.keyCharacterMapFile.setTo(getInputDeviceConfigurationFilePath(keyMapName,
- INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_CHARACTER_MAP));
- if (!keyMapInfo.keyCharacterMapFile.isEmpty()) {
- foundOne = true;
- }
- }
-
- if (foundOne && defaultKeyMap) {
- keyMapInfo.isDefaultKeyMap = true;
- }
- return keyMapInfo.isComplete();
+KeyMap::KeyMap() :
+ keyLayoutMap(NULL), keyCharacterMap(NULL) {
}
-status_t resolveKeyMap(const String8& deviceName,
- const PropertyMap* deviceConfiguration, KeyMapInfo& outKeyMapInfo) {
+KeyMap::~KeyMap() {
+ delete keyLayoutMap;
+ delete keyCharacterMap;
+}
+
+status_t KeyMap::load(const InputDeviceIdentifier& deviceIdenfifier,
+ const PropertyMap* deviceConfiguration) {
// Use the configured key layout if available.
if (deviceConfiguration) {
String8 keyLayoutName;
if (deviceConfiguration->tryGetProperty(String8("keyboard.layout"),
keyLayoutName)) {
- outKeyMapInfo.keyLayoutFile.setTo(getInputDeviceConfigurationFilePath(
- keyLayoutName, INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_LAYOUT));
- if (outKeyMapInfo.keyLayoutFile.isEmpty()) {
- LOGW("Configuration for keyboard device '%s' requested keyboard layout '%s' but "
+ status_t status = loadKeyLayout(deviceIdenfifier, keyLayoutName);
+ if (status == NAME_NOT_FOUND) {
+ LOGE("Configuration for keyboard device '%s' requested keyboard layout '%s' but "
"it was not found.",
- deviceName.string(), keyLayoutName.string());
+ deviceIdenfifier.name.string(), keyLayoutName.string());
}
}
String8 keyCharacterMapName;
if (deviceConfiguration->tryGetProperty(String8("keyboard.characterMap"),
keyCharacterMapName)) {
- outKeyMapInfo.keyCharacterMapFile.setTo(getInputDeviceConfigurationFilePath(
- keyCharacterMapName, INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_CHARACTER_MAP));
- if (outKeyMapInfo.keyCharacterMapFile.isEmpty()) {
- LOGW("Configuration for keyboard device '%s' requested keyboard character "
+ status_t status = loadKeyCharacterMap(deviceIdenfifier, keyCharacterMapName);
+ if (status == NAME_NOT_FOUND) {
+ LOGE("Configuration for keyboard device '%s' requested keyboard character "
"map '%s' but it was not found.",
- deviceName.string(), keyCharacterMapName.string());
+ deviceIdenfifier.name.string(), keyLayoutName.string());
}
}
- if (outKeyMapInfo.isComplete()) {
+ if (isComplete()) {
return OK;
}
}
- // Try searching by device name.
- if (probeKeyMap(outKeyMapInfo, deviceName, false)) {
+ // Try searching by device identifier.
+ if (probeKeyMap(deviceIdenfifier, String8::empty())) {
return OK;
}
// Fall back on the Generic key map.
// TODO Apply some additional heuristics here to figure out what kind of
- // generic key map to use (US English, etc.).
- if (probeKeyMap(outKeyMapInfo, String8("Generic"), true)) {
+ // generic key map to use (US English, etc.) for typical external keyboards.
+ if (probeKeyMap(deviceIdenfifier, String8("Generic"))) {
+ return OK;
+ }
+
+ // Try the Virtual key map as a last resort.
+ if (probeKeyMap(deviceIdenfifier, String8("Virtual"))) {
return OK;
}
// Give up!
- LOGE("Could not determine key map for device '%s' and the Generic key map was not found!",
- deviceName.string());
- outKeyMapInfo.isDefaultKeyMap = true;
+ LOGE("Could not determine key map for device '%s' and no default key maps were found!",
+ deviceIdenfifier.name.string());
return NAME_NOT_FOUND;
}
-void setKeyboardProperties(int32_t deviceId, const String8& deviceName,
- const KeyMapInfo& keyMapInfo) {
+bool KeyMap::probeKeyMap(const InputDeviceIdentifier& deviceIdentifier,
+ const String8& keyMapName) {
+ if (!haveKeyLayout()) {
+ loadKeyLayout(deviceIdentifier, keyMapName);
+ }
+ if (!haveKeyCharacterMap()) {
+ loadKeyCharacterMap(deviceIdentifier, keyMapName);
+ }
+ return isComplete();
+}
+
+status_t KeyMap::loadKeyLayout(const InputDeviceIdentifier& deviceIdentifier,
+ const String8& name) {
+ String8 path(getPath(deviceIdentifier, name,
+ INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_LAYOUT));
+ if (path.isEmpty()) {
+ return NAME_NOT_FOUND;
+ }
+
+ KeyLayoutMap* map;
+ status_t status = KeyLayoutMap::load(path, &map);
+ if (status) {
+ return status;
+ }
+
+ keyLayoutFile.setTo(path);
+ keyLayoutMap = map;
+ return OK;
+}
+
+status_t KeyMap::loadKeyCharacterMap(const InputDeviceIdentifier& deviceIdentifier,
+ const String8& name) {
+ String8 path(getPath(deviceIdentifier, name,
+ INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_CHARACTER_MAP));
+ if (path.isEmpty()) {
+ return NAME_NOT_FOUND;
+ }
+
+ KeyCharacterMap* map;
+ status_t status = KeyCharacterMap::load(path, &map);
+ if (status) {
+ return status;
+ }
+
+ keyCharacterMapFile.setTo(path);
+ keyCharacterMap = map;
+ return OK;
+}
+
+String8 KeyMap::getPath(const InputDeviceIdentifier& deviceIdentifier,
+ const String8& name, InputDeviceConfigurationFileType type) {
+ return name.isEmpty()
+ ? getInputDeviceConfigurationFilePathByDeviceIdentifier(deviceIdentifier, type)
+ : getInputDeviceConfigurationFilePathByName(name, type);
+}
+
+
+// --- Global functions ---
+
+bool isEligibleBuiltInKeyboard(const InputDeviceIdentifier& deviceIdentifier,
+ const PropertyMap* deviceConfiguration, const KeyMap* keyMap) {
+ if (!keyMap->haveKeyCharacterMap()
+ || keyMap->keyCharacterMap->getKeyboardType()
+ == KeyCharacterMap::KEYBOARD_TYPE_SPECIAL_FUNCTION) {
+ return false;
+ }
+
+ if (deviceConfiguration) {
+ bool builtIn = false;
+ if (deviceConfiguration->tryGetProperty(String8("keyboard.builtIn"), builtIn)
+ && builtIn) {
+ return true;
+ }
+ }
+
+ return strstr(deviceIdentifier.name.string(), "-keypad");
+}
+
+void setKeyboardProperties(int32_t deviceId,
+ const InputDeviceIdentifier& deviceIdentifier,
+ const String8& keyLayoutFile, const String8& keyCharacterMapFile) {
char propName[PROPERTY_KEY_MAX];
snprintf(propName, sizeof(propName), "hw.keyboards.%u.devname", deviceId);
- property_set(propName, deviceName.string());
+ property_set(propName, deviceIdentifier.name.string());
snprintf(propName, sizeof(propName), "hw.keyboards.%u.klfile", deviceId);
- property_set(propName, keyMapInfo.keyLayoutFile.string());
+ property_set(propName, keyLayoutFile.string());
snprintf(propName, sizeof(propName), "hw.keyboards.%u.kcmfile", deviceId);
- property_set(propName, keyMapInfo.keyCharacterMapFile.string());
+ property_set(propName, keyCharacterMapFile.string());
}
void clearKeyboardProperties(int32_t deviceId) {
@@ -126,29 +196,24 @@
}
status_t getKeyCharacterMapFile(int32_t deviceId, String8& outKeyCharacterMapFile) {
- if (deviceId == DEVICE_ID_VIRTUAL_KEYBOARD) {
- outKeyCharacterMapFile.setTo(getInputDeviceConfigurationFilePath(String8("Virtual"),
- INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_CHARACTER_MAP));
- if (!outKeyCharacterMapFile.isEmpty()) {
+ if (deviceId != DEVICE_ID_VIRTUAL_KEYBOARD) {
+ char propName[PROPERTY_KEY_MAX];
+ char fn[PROPERTY_VALUE_MAX];
+ snprintf(propName, sizeof(propName), "hw.keyboards.%u.kcmfile", deviceId);
+ if (property_get(propName, fn, "") > 0) {
+ outKeyCharacterMapFile.setTo(fn);
return OK;
}
}
- char propName[PROPERTY_KEY_MAX];
- char fn[PROPERTY_VALUE_MAX];
- snprintf(propName, sizeof(propName), "hw.keyboards.%u.kcmfile", deviceId);
- if (property_get(propName, fn, "") > 0) {
- outKeyCharacterMapFile.setTo(fn);
- return OK;
- }
-
- outKeyCharacterMapFile.setTo(getInputDeviceConfigurationFilePath(String8("Generic"),
+ // Default to Virtual since the keyboard does not appear to be installed.
+ outKeyCharacterMapFile.setTo(getInputDeviceConfigurationFilePathByName(String8("Virtual"),
INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_CHARACTER_MAP));
if (!outKeyCharacterMapFile.isEmpty()) {
return OK;
}
- LOGE("Can't find any key character map files (also tried Virtual and Generic key maps)");
+ LOGE("Can't find any key character map files including the Virtual key map!");
return NAME_NOT_FOUND;
}
diff --git a/libs/ui/VirtualKeyMap.cpp b/libs/ui/VirtualKeyMap.cpp
new file mode 100644
index 0000000..e756cdd
--- /dev/null
+++ b/libs/ui/VirtualKeyMap.cpp
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "VirtualKeyMap"
+
+#include <stdlib.h>
+#include <string.h>
+#include <ui/VirtualKeyMap.h>
+#include <utils/Log.h>
+#include <utils/Errors.h>
+#include <utils/Tokenizer.h>
+#include <utils/Timers.h>
+
+// Enables debug output for the parser.
+#define DEBUG_PARSER 0
+
+// Enables debug output for parser performance.
+#define DEBUG_PARSER_PERFORMANCE 0
+
+
+namespace android {
+
+static const char* WHITESPACE = " \t\r";
+static const char* WHITESPACE_OR_FIELD_DELIMITER = " \t\r:";
+
+
+// --- VirtualKeyMap ---
+
+VirtualKeyMap::VirtualKeyMap() {
+}
+
+VirtualKeyMap::~VirtualKeyMap() {
+}
+
+status_t VirtualKeyMap::load(const String8& filename, VirtualKeyMap** outMap) {
+ *outMap = NULL;
+
+ Tokenizer* tokenizer;
+ status_t status = Tokenizer::open(filename, &tokenizer);
+ if (status) {
+ LOGE("Error %d opening virtual key map file %s.", status, filename.string());
+ } else {
+ VirtualKeyMap* map = new VirtualKeyMap();
+ if (!map) {
+ LOGE("Error allocating virtual key map.");
+ status = NO_MEMORY;
+ } else {
+#if DEBUG_PARSER_PERFORMANCE
+ nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
+#endif
+ Parser parser(map, tokenizer);
+ status = parser.parse();
+#if DEBUG_PARSER_PERFORMANCE
+ nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
+ LOGD("Parsed key character map file '%s' %d lines in %0.3fms.",
+ tokenizer->getFilename().string(), tokenizer->getLineNumber(),
+ elapsedTime / 1000000.0);
+#endif
+ if (status) {
+ delete map;
+ } else {
+ *outMap = map;
+ }
+ }
+ delete tokenizer;
+ }
+ return status;
+}
+
+
+// --- VirtualKeyMap::Parser ---
+
+VirtualKeyMap::Parser::Parser(VirtualKeyMap* map, Tokenizer* tokenizer) :
+ mMap(map), mTokenizer(tokenizer) {
+}
+
+VirtualKeyMap::Parser::~Parser() {
+}
+
+status_t VirtualKeyMap::Parser::parse() {
+ while (!mTokenizer->isEof()) {
+#if DEBUG_PARSER
+ LOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(),
+ mTokenizer->peekRemainderOfLine().string());
+#endif
+
+ mTokenizer->skipDelimiters(WHITESPACE);
+
+ if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
+ // Multiple keys can appear on one line or they can be broken up across multiple lines.
+ do {
+ String8 token = mTokenizer->nextToken(WHITESPACE_OR_FIELD_DELIMITER);
+ if (token != "0x01") {
+ LOGE("%s: Unknown virtual key type, expected 0x01.",
+ mTokenizer->getLocation().string());
+ return BAD_VALUE;
+ }
+
+ VirtualKeyDefinition defn;
+ bool success = parseNextIntField(&defn.scanCode)
+ && parseNextIntField(&defn.centerX)
+ && parseNextIntField(&defn.centerY)
+ && parseNextIntField(&defn.width)
+ && parseNextIntField(&defn.height);
+ if (!success) {
+ LOGE("%s: Expected 5 colon-delimited integers in virtual key definition.",
+ mTokenizer->getLocation().string());
+ return BAD_VALUE;
+ }
+
+#if DEBUG_PARSER
+ LOGD("Parsed virtual key: scanCode=%d, centerX=%d, centerY=%d, "
+ "width=%d, height=%d",
+ defn.scanCode, defn.centerX, defn.centerY, defn.width, defn.height);
+#endif
+ mMap->mVirtualKeys.push(defn);
+ } while (consumeFieldDelimiterAndSkipWhitespace());
+
+ if (!mTokenizer->isEol()) {
+ LOGE("%s: Expected end of line, got '%s'.",
+ mTokenizer->getLocation().string(),
+ mTokenizer->peekRemainderOfLine().string());
+ return BAD_VALUE;
+ }
+ }
+
+ mTokenizer->nextLine();
+ }
+
+ return NO_ERROR;
+}
+
+bool VirtualKeyMap::Parser::consumeFieldDelimiterAndSkipWhitespace() {
+ mTokenizer->skipDelimiters(WHITESPACE);
+ if (mTokenizer->peekChar() == ':') {
+ mTokenizer->nextChar();
+ mTokenizer->skipDelimiters(WHITESPACE);
+ return true;
+ }
+ return false;
+}
+
+bool VirtualKeyMap::Parser::parseNextIntField(int32_t* outValue) {
+ if (!consumeFieldDelimiterAndSkipWhitespace()) {
+ return false;
+ }
+
+ String8 token = mTokenizer->nextToken(WHITESPACE_OR_FIELD_DELIMITER);
+ char* end;
+ *outValue = strtol(token.string(), &end, 0);
+ if (token.isEmpty() || *end != '\0') {
+ LOGE("Expected an integer, got '%s'.", token.string());
+ return false;
+ }
+ return true;
+}
+
+} // namespace android
diff --git a/libs/ui/tests/InputReader_test.cpp b/libs/ui/tests/InputReader_test.cpp
index 05bebc5..d6c2cbd 100644
--- a/libs/ui/tests/InputReader_test.cpp
+++ b/libs/ui/tests/InputReader_test.cpp
@@ -42,7 +42,6 @@
KeyedVector<int32_t, DisplayInfo> mDisplayInfos;
bool mFilterTouchEvents;
bool mFilterJumpyTouchEvents;
- KeyedVector<String8, Vector<VirtualKeyDefinition> > mVirtualKeyDefinitions;
Vector<String8> mExcludedDeviceNames;
protected:
@@ -75,15 +74,6 @@
mFilterJumpyTouchEvents = enabled;
}
- void addVirtualKeyDefinition(const String8& deviceName,
- const VirtualKeyDefinition& definition) {
- if (mVirtualKeyDefinitions.indexOfKey(deviceName) < 0) {
- mVirtualKeyDefinitions.add(deviceName, Vector<VirtualKeyDefinition>());
- }
-
- mVirtualKeyDefinitions.editValueFor(deviceName).push(definition);
- }
-
void addExcludedDeviceName(const String8& deviceName) {
mExcludedDeviceNames.push(deviceName);
}
@@ -116,14 +106,6 @@
return mFilterJumpyTouchEvents;
}
- virtual void getVirtualKeyDefinitions(const String8& deviceName,
- Vector<VirtualKeyDefinition>& outVirtualKeyDefinitions) {
- ssize_t index = mVirtualKeyDefinitions.indexOfKey(deviceName);
- if (index >= 0) {
- outVirtualKeyDefinitions.appendVector(mVirtualKeyDefinitions.valueAt(index));
- }
- }
-
virtual void getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames) {
outExcludedDeviceNames.appendVector(mExcludedDeviceNames);
}
@@ -355,6 +337,7 @@
KeyedVector<int32_t, int32_t> switchStates;
KeyedVector<int32_t, KeyInfo> keys;
KeyedVector<int32_t, bool> leds;
+ Vector<VirtualKeyDefinition> virtualKeys;
Device(const String8& name, uint32_t classes) :
name(name), classes(classes) {
@@ -448,6 +431,11 @@
return mExcludedDevices;
}
+ void addVirtualKeyDefinition(int32_t deviceId, const VirtualKeyDefinition& definition) {
+ Device* device = getDevice(deviceId);
+ device->virtualKeys.push(definition);
+ }
+
void enqueueEvent(nsecs_t when, int32_t deviceId, int32_t type,
int32_t scanCode, int32_t keyCode, int32_t value, uint32_t flags) {
RawEvent event;
@@ -603,6 +591,16 @@
}
}
+ virtual void getVirtualKeyDefinitions(int32_t deviceId,
+ Vector<VirtualKeyDefinition>& outVirtualKeys) const {
+ outVirtualKeys.clear();
+
+ Device* device = getDevice(deviceId);
+ if (device) {
+ outVirtualKeys.appendVector(device->virtualKeys);
+ }
+ }
+
virtual void dump(String8& dump) {
}
};
@@ -2147,8 +2145,8 @@
}
void TouchInputMapperTest::prepareVirtualKeys() {
- mFakePolicy->addVirtualKeyDefinition(String8(DEVICE_NAME), VIRTUAL_KEYS[0]);
- mFakePolicy->addVirtualKeyDefinition(String8(DEVICE_NAME), VIRTUAL_KEYS[1]);
+ mFakeEventHub->addVirtualKeyDefinition(DEVICE_ID, VIRTUAL_KEYS[0]);
+ mFakeEventHub->addVirtualKeyDefinition(DEVICE_ID, VIRTUAL_KEYS[1]);
mFakeEventHub->addKey(DEVICE_ID, KEY_HOME, AKEYCODE_HOME, POLICY_FLAG_WAKE);
mFakeEventHub->addKey(DEVICE_ID, KEY_MENU, AKEYCODE_MENU, POLICY_FLAG_WAKE);
}
diff --git a/libs/utils/FileMap.cpp b/libs/utils/FileMap.cpp
index e1ba9b2..f1f8bda 100644
--- a/libs/utils/FileMap.cpp
+++ b/libs/utils/FileMap.cpp
@@ -63,16 +63,18 @@
free(mFileName);
}
#ifdef HAVE_POSIX_FILEMAP
- if (munmap(mBasePtr, mBaseLength) != 0) {
+ if (mBasePtr && munmap(mBasePtr, mBaseLength) != 0) {
LOGD("munmap(%p, %d) failed\n", mBasePtr, (int) mBaseLength);
}
#endif
#ifdef HAVE_WIN32_FILEMAP
- if ( UnmapViewOfFile(mBasePtr) == 0) {
+ if (mBasePtr && UnmapViewOfFile(mBasePtr) == 0) {
LOGD("UnmapViewOfFile(%p) failed, error = %ld\n", mBasePtr,
GetLastError() );
}
- CloseHandle(mFileMapping);
+ if (mFileMapping != INVALID_HANDLE_VALUE) {
+ CloseHandle(mFileMapping);
+ }
CloseHandle(mFileHandle);
#endif
}
diff --git a/libs/utils/String8.cpp b/libs/utils/String8.cpp
index e531a2a..0bc5aff 100644
--- a/libs/utils/String8.cpp
+++ b/libs/utils/String8.cpp
@@ -195,6 +195,24 @@
SharedBuffer::bufferFromData(mString)->release();
}
+String8 String8::format(const char* fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+
+ String8 result(formatV(fmt, args));
+
+ va_end(args);
+ return result;
+}
+
+String8 String8::formatV(const char* fmt, va_list args)
+{
+ String8 result;
+ result.appendFormatV(fmt, args);
+ return result;
+}
+
void String8::clear() {
SharedBuffer::bufferFromData(mString)->release();
mString = getEmptyString();
diff --git a/libs/utils/Tokenizer.cpp b/libs/utils/Tokenizer.cpp
index 9251973..b3445b7 100644
--- a/libs/utils/Tokenizer.cpp
+++ b/libs/utils/Tokenizer.cpp
@@ -35,16 +35,16 @@
return strchr(delimiters, ch) != NULL;
}
-
-Tokenizer::Tokenizer(const String8& filename, FileMap* fileMap,
- const char* buffer, size_t length) :
- mFilename(filename), mFileMap(fileMap), mBuffer(buffer), mLength(length),
- mCurrent(buffer), mLineNumber(1) {
+Tokenizer::Tokenizer(const String8& filename, FileMap* fileMap, char* buffer, size_t length) :
+ mFilename(filename), mFileMap(fileMap),
+ mBuffer(buffer), mLength(length), mCurrent(buffer), mLineNumber(1) {
}
Tokenizer::~Tokenizer() {
if (mFileMap) {
mFileMap->release();
+ } else {
+ delete[] mBuffer;
}
}
@@ -63,22 +63,33 @@
LOGE("Error getting size of file '%s', %s.", filename.string(), strerror(errno));
} else {
size_t length = size_t(stat.st_size);
- FileMap* fileMap = new FileMap();
- if (!fileMap->create(NULL, fd, 0, length, true)) {
- result = NO_MEMORY;
- LOGE("Error mapping file '%s', %s.", filename.string(), strerror(errno));
- } else {
- fileMap->advise(FileMap::SEQUENTIAL);
- *outTokenizer = new Tokenizer(filename, fileMap,
- static_cast<const char*>(fileMap->getDataPtr()), length);
- if (!*outTokenizer) {
- result = NO_MEMORY;
- LOGE("Error allocating tokenizer for file=%s.", filename.string());
+ FileMap* fileMap = new FileMap();
+ char* buffer;
+ if (fileMap->create(NULL, fd, 0, length, true)) {
+ fileMap->advise(FileMap::SEQUENTIAL);
+ buffer = static_cast<char*>(fileMap->getDataPtr());
+ } else {
+ fileMap->release();
+ fileMap = NULL;
+
+ // Fall back to reading into a buffer since we can't mmap files in sysfs.
+ // The length we obtained from stat is wrong too (it will always be 4096)
+ // so we must trust that read will read the entire file.
+ buffer = new char[length];
+ ssize_t nrd = read(fd, buffer, length);
+ if (nrd < 0) {
+ result = -errno;
+ LOGE("Error reading file '%s', %s.", filename.string(), strerror(errno));
+ delete[] buffer;
+ buffer = NULL;
+ } else {
+ length = size_t(nrd);
}
}
- if (result) {
- fileMap->release();
+
+ if (!result) {
+ *outTokenizer = new Tokenizer(filename, fileMap, buffer, length);
}
}
close(fd);
diff --git a/packages/SystemUI/res/drawable-mdpi/scrubber_control_disabled_holo.png b/packages/SystemUI/res/drawable-mdpi/scrubber_control_disabled_holo.png
new file mode 100644
index 0000000..b8adc97
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/scrubber_control_disabled_holo.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/scrubber_control_holo.png b/packages/SystemUI/res/drawable-mdpi/scrubber_control_holo.png
new file mode 100644
index 0000000..621e980
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/scrubber_control_holo.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable/status_bar_toggle_button.xml b/packages/SystemUI/res/drawable/status_bar_toggle_button.xml
new file mode 100644
index 0000000..e17c62f
--- /dev/null
+++ b/packages/SystemUI/res/drawable/status_bar_toggle_button.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_checked="true"
+ android:drawable="@*android:drawable/scrubber_primary_holo" />
+ <item
+ android:drawable="@*android:drawable/scrubber_track_holo_dark" />
+</selector>
+
diff --git a/packages/SystemUI/res/layout-xlarge/status_bar.xml b/packages/SystemUI/res/layout-xlarge/status_bar.xml
index 758377b..666bfdc 100644
--- a/packages/SystemUI/res/layout-xlarge/status_bar.xml
+++ b/packages/SystemUI/res/layout-xlarge/status_bar.xml
@@ -158,10 +158,8 @@
/>
<com.android.systemui.statusbar.tablet.ShirtPocket
android:id="@+id/pocket"
- android:layout_width="96dip"
+ android:layout_width="wrap_content"
android:layout_height="match_parent"
- android:paddingLeft="18dip"
- android:paddingRight="18dip"
android:animateLayoutChanges="true"
android:clickable="true"
android:descendantFocusability="blocksDescendants"
@@ -170,10 +168,12 @@
<ImageView
android:id="@+id/pocket_icon"
android:src="@drawable/ic_sysbar_pocket"
- android:visibility="invisible"
- android:layout_width="match_parent"
+ android:paddingLeft="18dip"
+ android:paddingRight="18dip"
+ android:layout_width="96dip"
android:layout_height="wrap_content"
android:gravity="center"
+ android:visibility="gone"
/>
</com.android.systemui.statusbar.tablet.ShirtPocket>
<com.android.systemui.statusbar.tablet.InputMethodButton
diff --git a/packages/SystemUI/res/layout-xlarge/status_bar_settings_view.xml b/packages/SystemUI/res/layout-xlarge/status_bar_settings_view.xml
index 6dd97c3..5e867e5 100644
--- a/packages/SystemUI/res/layout-xlarge/status_bar_settings_view.xml
+++ b/packages/SystemUI/res/layout-xlarge/status_bar_settings_view.xml
@@ -17,11 +17,13 @@
<com.android.systemui.statusbar.tablet.SettingsView
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="@drawable/status_bar_item_background"
android:paddingLeft="16dp"
+ android:paddingRight="46dp"
>
<!-- Airplane mode -->
@@ -39,11 +41,12 @@
style="@style/StatusBarPanelSettingsContents"
android:text="@string/status_bar_settings_airplane"
/>
- <CheckBox
+ <Switch
android:id="@+id/airplane_checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
+ android:layout_marginRight="5dp"
/>
</LinearLayout>
<View style="@style/StatusBarPanelSettingsPanelSeparator" />
@@ -67,7 +70,7 @@
android:layout_height="wrap_content"
android:layout_gravity="top"
android:layout_marginTop="16dp"
- android:layout_marginRight="8dp"
+ android:layout_marginRight="2dp"
android:src="@drawable/ic_notification_open"
/>
</LinearLayout>
@@ -88,11 +91,12 @@
style="@style/StatusBarPanelSettingsContents"
android:text="@string/status_bar_settings_rotation_lock"
/>
- <CheckBox
+ <Switch
android:id="@+id/rotate_checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
+ android:layout_marginRight="5dp"
/>
</LinearLayout>
<View style="@style/StatusBarPanelSettingsPanelSeparator" />
@@ -104,6 +108,14 @@
style="@style/StatusBarPanelSettingsIcon"
android:src="@drawable/ic_sysbar_brightness"
/>
+ <com.android.systemui.statusbar.policy.ToggleSlider
+ android:id="@+id/brightness"
+ android:layout_width="0dp"
+ android:layout_height="fill_parent"
+ android:layout_weight="1"
+ android:layout_marginRight="2dp"
+ systemui:text="@string/status_bar_settings_auto_brightness_label"
+ />
</LinearLayout>
<View style="@style/StatusBarPanelSettingsPanelSeparator" />
@@ -114,6 +126,14 @@
style="@style/StatusBarPanelSettingsIcon"
android:src="@drawable/ic_sysbar_sound_on"
/>
+ <com.android.systemui.statusbar.policy.ToggleSlider
+ android:id="@+id/volume"
+ android:layout_width="0dp"
+ android:layout_height="fill_parent"
+ android:layout_weight="1"
+ android:layout_marginRight="2dp"
+ systemui:text="@string/status_bar_settings_mute_label"
+ />
</LinearLayout>
<View style="@style/StatusBarPanelSettingsPanelSeparator" />
@@ -131,11 +151,12 @@
style="@style/StatusBarPanelSettingsContents"
android:text="@string/status_bar_settings_notifications"
/>
- <CheckBox
+ <Switch
android:id="@+id/do_not_disturb_checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
+ android:layout_marginRight="5dp"
/>
</LinearLayout>
<View style="@style/StatusBarPanelSettingsPanelSeparator" />
@@ -160,7 +181,7 @@
android:layout_height="wrap_content"
android:layout_gravity="top"
android:layout_marginTop="16dp"
- android:layout_marginRight="8dp"
+ android:layout_marginRight="2dp"
android:src="@drawable/ic_notification_open"
/>
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/status_bar_toggle_slider.xml b/packages/SystemUI/res/layout/status_bar_toggle_slider.xml
new file mode 100644
index 0000000..cdf56c5
--- /dev/null
+++ b/packages/SystemUI/res/layout/status_bar_toggle_slider.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+
+<!-- android:background="@drawable/status_bar_closed_default_background" -->
+<merge
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
+ >
+ <CheckBox
+ android:id="@+id/toggle"
+ android:layout_width="48dp"
+ android:layout_height="0dp"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentBottom="true"
+ android:button="@drawable/status_bar_toggle_button"
+ />
+ <SeekBar
+ android:id="@+id/slider"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@id/toggle"
+ android:layout_centerVertical="true"
+ android:layout_alignParentRight="true"
+ android:paddingLeft="20dp"
+ android:paddingRight="20dp"
+ />
+ <TextView
+ android:id="@+id/label"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_alignLeft="@id/toggle"
+ android:layout_alignRight="@id/toggle"
+ android:layout_centerVertical="true"
+ android:gravity="center"
+ android:paddingTop="26dp"
+ android:textColor="#666666"
+ android:textSize="12sp"
+ />
+</merge>
diff --git a/packages/SystemUI/res/values-xlarge/strings.xml b/packages/SystemUI/res/values-xlarge/strings.xml
index e3e5148..279a135 100644
--- a/packages/SystemUI/res/values-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-xlarge/strings.xml
@@ -26,44 +26,16 @@
<!-- Text to display underneath the graphical signal strength meter when
no connection is available. [CHAR LIMIT=20] -->
<string name="status_bar_settings_signal_meter_disconnected">
- no internet connection
- </string>
-
- <!-- Text to display underneath the graphical signal strength meter when
- it is displaying information about a connected, named Wi-Fi network.
- [CHAR LIMIT=20] -->
- <string name="status_bar_settings_signal_meter_wifi_ssid_format">
- <xliff:g id="ssid">%s</xliff:g>
+ No Internet connection
</string>
<!-- Text to display underneath the graphical signal strength meter when
it is displaying Wi-Fi status and Wi-Fi is connected to a network
whose SSID is not available.
[CHAR LIMIT=20] -->
- <string name="status_bar_settings_signal_meter_wifi_nossid">
- Wi-Fi: connected
- </string>
+ <string name="status_bar_settings_signal_meter_wifi_nossid">Wi-Fi connected</string>
- <!-- Text to display underneath the graphical signal strength meter when
- it is displaying Wi-Fi status and Wi-Fi is in the process of
- connecting to a network. [CHAR LIMIT=20] -->
- <string name="status_bar_settings_signal_meter_wifi_connecting">
- Wi-Fi: connecting…
- </string>
-
- <!-- Text to display underneath the graphical signal strength meter when
- it is displaying mobile data (3G) status and a network connection is
- available.
- [CHAR LIMIT=20] -->
- <string name="status_bar_settings_signal_meter_data_connected">
- Mobile data: connected
- </string>
+ <!-- Separator for PLMN and SPN in network name. -->
+ <string name="status_bar_network_name_separator" translatable="false">" – "</string>
- <!-- Text to display underneath the graphical signal strength meter when
- it is displaying mobile data (3G) status and a network connection is
- unavailable.
- [CHAR LIMIT=20] -->
- <string name="status_bar_settings_signal_meter_data_connecting">
- Mobile data: connecting…
- </string>
</resources>
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index 23bcf20..87395c1 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -18,5 +18,8 @@
<declare-styleable name="KeyButtonView">
<attr name="keyCode" format="integer" />
</declare-styleable>
+ <declare-styleable name="ToggleSlider">
+ <attr name="text" format="string" />
+ </declare-styleable>
</resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index ed31a34..644cca0 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -80,6 +80,12 @@
<!-- Label in system panel saying the device will use the orientation sensor to rotate [CHAR LIMIT=30] -->
<string name="status_bar_settings_rotation_lock">Lock screen orientation</string>
+ <!-- Abbreviation / label for mute brightness mode button. Should be all caps. [CHAR LIMIT=6] -->
+ <string name="status_bar_settings_mute_label">MUTE</string>
+
+ <!-- Abbreviation / label for automatic brightness mode button. Should be all caps. [CHAR LIMIT=6] -->
+ <string name="status_bar_settings_auto_brightness_label">AUTO</string>
+
<!-- Label in system panel saying the device will show notifications [CHAR LIMIT=30] -->
<string name="status_bar_settings_notifications">Notifications</string>
@@ -88,6 +94,9 @@
<xliff:g id="number">%d</xliff:g><xliff:g id="percent">%%</xliff:g>
</string>
+ <!-- Separator for PLMN and SPN in network name. -->
+ <string name="status_bar_network_name_separator" translatable="false">"\n"</string>
+
<!-- Recent Tasks dialog: title [CHAR LIMIT=30] -->
<string name="recent_tasks_title">Recent</string>
<!-- Recent Tasks dialog: message when there are no recent applications [CHAR LIMIT=NONE]-->
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessController.java
new file mode 100644
index 0000000..c11d04e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessController.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.os.IPowerManager;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.provider.Settings;
+import android.provider.Settings.SettingNotFoundException;
+import android.util.Slog;
+import android.view.IWindowManager;
+import android.widget.CompoundButton;
+
+public class BrightnessController implements ToggleSlider.Listener {
+ private static final String TAG = "StatusBar.BrightnessController";
+
+ // Backlight range is from 0 - 255. Need to make sure that user
+ // doesn't set the backlight to 0 and get stuck
+ private static final int MINIMUM_BACKLIGHT = android.os.Power.BRIGHTNESS_DIM + 10;
+ private static final int MAXIMUM_BACKLIGHT = android.os.Power.BRIGHTNESS_ON;
+
+ private Context mContext;
+ private ToggleSlider mControl;
+ private IPowerManager mPower;
+
+ public BrightnessController(Context context, ToggleSlider control) {
+ mContext = context;
+ mControl = control;
+
+ boolean automaticAvailable = context.getResources().getBoolean(
+ com.android.internal.R.bool.config_automatic_brightness_available);
+ mPower = IPowerManager.Stub.asInterface(ServiceManager.getService("power"));
+
+ if (automaticAvailable) {
+ int automatic;
+ try {
+ automatic = Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.SCREEN_BRIGHTNESS_MODE);
+ } catch (SettingNotFoundException snfe) {
+ automatic = 0;
+ }
+ control.setChecked(automatic != 0);
+ } else {
+ control.setChecked(false);
+ //control.hideToggle();
+ }
+
+ int value;
+ try {
+ value = Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.SCREEN_BRIGHTNESS);
+ } catch (SettingNotFoundException ex) {
+ value = MAXIMUM_BACKLIGHT;
+ }
+
+ control.setMax(MAXIMUM_BACKLIGHT - MINIMUM_BACKLIGHT);
+ control.setValue(value - MINIMUM_BACKLIGHT);
+
+ control.setOnChangedListener(this);
+ }
+
+ public void onChanged(ToggleSlider view, boolean tracking, boolean automatic, int value) {
+ setMode(automatic ? Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC
+ : Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL);
+ if (!automatic) {
+ setBrightness(value + MINIMUM_BACKLIGHT);
+ }
+ }
+
+ private void setMode(int mode) {
+ Settings.System.putInt(mContext.getContentResolver(),
+ Settings.System.SCREEN_BRIGHTNESS_MODE, mode);
+ }
+
+ private void setBrightness(int brightness) {
+ try {
+ mPower.setBacklightBrightness(brightness);
+ } catch (RemoteException ex) {
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index ec23a3d..1090463 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -32,6 +32,7 @@
import android.os.Binder;
import android.os.RemoteException;
import android.provider.Settings;
+import android.provider.Telephony;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
@@ -65,6 +66,9 @@
ServiceState mServiceState;
SignalStrength mSignalStrength;
int[] mDataIconList = TelephonyIcons.DATA_G[0];
+ String mNetworkName;
+ String mNetworkNameDefault;
+ String mNetworkNameSeparator;
int mPhoneSignalIconId;
int mDataDirectionIconId;
int mDataSignalIconId;
@@ -116,7 +120,10 @@
| PhoneStateListener.LISTEN_DATA_ACTIVITY);
mHspaDataDistinguishable = mContext.getResources().getBoolean(
R.bool.config_hspa_data_distinguishable);
-
+ mNetworkNameSeparator = mContext.getString(R.string.status_bar_network_name_separator);
+ mNetworkNameDefault = mContext.getString(
+ com.android.internal.R.string.lockscreen_carrier_default);
+ mNetworkName = mNetworkNameDefault;
// wifi
mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
@@ -127,6 +134,9 @@
filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
+ filter.addAction(Telephony.Intents.SPN_STRINGS_UPDATED_ACTION);
+ filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
+ filter.addAction(ConnectivityManager.INET_CONDITION_ACTION);
context.registerReceiver(this, filter);
// yuck
@@ -168,6 +178,12 @@
updateSimState(intent);
updateDataIcon();
refreshViews();
+ } else if (action.equals(Telephony.Intents.SPN_STRINGS_UPDATED_ACTION)) {
+ updateNetworkName(intent.getBooleanExtra(Telephony.Intents.EXTRA_SHOW_SPN, false),
+ intent.getStringExtra(Telephony.Intents.EXTRA_SPN),
+ intent.getBooleanExtra(Telephony.Intents.EXTRA_SHOW_PLMN, false),
+ intent.getStringExtra(Telephony.Intents.EXTRA_PLMN));
+ refreshViews();
} else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION) ||
action.equals(ConnectivityManager.INET_CONDITION_ACTION)) {
updateConnectivity(intent);
@@ -516,6 +532,31 @@
mDataConnected = visible;
}
+ void updateNetworkName(boolean showSpn, String spn, boolean showPlmn, String plmn) {
+ if (false) {
+ Slog.d("CarrierLabel", "updateNetworkName showSpn=" + showSpn + " spn=" + spn
+ + " showPlmn=" + showPlmn + " plmn=" + plmn);
+ }
+ StringBuilder str = new StringBuilder();
+ boolean something = false;
+ if (showPlmn && plmn != null) {
+ str.append(plmn);
+ something = true;
+ }
+ if (showSpn && spn != null) {
+ if (something) {
+ str.append(mNetworkNameSeparator);
+ }
+ str.append(spn);
+ something = true;
+ }
+ if (something) {
+ mNetworkName = str.toString();
+ } else {
+ mNetworkName = mNetworkNameDefault;
+ }
+ }
+
// ===== Wifi ===================================================================
private void updateWifiState(Intent intent) {
@@ -618,14 +659,13 @@
if (mWifiSsid == null) {
label = context.getString(R.string.status_bar_settings_signal_meter_wifi_nossid);
} else {
- label = context.getString(R.string.status_bar_settings_signal_meter_wifi_ssid_format,
- mWifiSsid);
+ label = mWifiSsid;
}
combinedSignalIconId = mWifiIconId;
dataTypeIconId = 0;
} else {
if (mDataConnected) {
- label = context.getString(R.string.status_bar_settings_signal_meter_data_connected);
+ label = mNetworkName;
} else {
label = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ToggleSlider.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ToggleSlider.java
new file mode 100644
index 0000000..46207ee
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ToggleSlider.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.util.Slog;
+import android.view.View;
+import android.widget.CompoundButton;
+import android.widget.RelativeLayout;
+import android.widget.SeekBar;
+import android.widget.TextView;
+import android.widget.CompoundButton;
+
+import com.android.systemui.R;
+
+public class ToggleSlider extends RelativeLayout
+ implements CompoundButton.OnCheckedChangeListener, SeekBar.OnSeekBarChangeListener {
+ private static final String TAG = "StatusBar.ToggleSlider";
+
+ public interface Listener {
+ public void onChanged(ToggleSlider v, boolean tracking, boolean checked, int value);
+ }
+
+ private Listener mListener;
+ private boolean mTracking;
+
+ private CompoundButton mToggle;
+ private SeekBar mSlider;
+ private TextView mLabel;
+
+ public ToggleSlider(Context context) {
+ this(context, null);
+ }
+
+ public ToggleSlider(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public ToggleSlider(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ View.inflate(context, R.layout.status_bar_toggle_slider, this);
+
+ final Resources res = context.getResources();
+ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ToggleSlider,
+ defStyle, 0);
+
+ mToggle = (CompoundButton)findViewById(R.id.toggle);
+ mToggle.setOnCheckedChangeListener(this);
+ mToggle.setBackgroundDrawable(res.getDrawable(R.drawable.status_bar_toggle_button));
+
+ mSlider = (SeekBar)findViewById(R.id.slider);
+ mSlider.setOnSeekBarChangeListener(this);
+
+ mLabel = (TextView)findViewById(R.id.label);
+ mLabel.setText(a.getString(R.styleable.ToggleSlider_text));
+
+ a.recycle();
+ }
+
+ public void onCheckedChanged(CompoundButton toggle, boolean checked) {
+ Drawable thumb;
+ final Resources res = getContext().getResources();
+ if (checked) {
+ thumb = res.getDrawable(R.drawable.scrubber_control_disabled_holo);
+ } else {
+ thumb = res.getDrawable(R.drawable.scrubber_control_holo);
+ }
+ mSlider.setThumb(thumb);
+
+ if (mListener != null) {
+ mListener.onChanged(this, mTracking, checked, mSlider.getProgress());
+ }
+ }
+
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ if (mListener != null) {
+ mListener.onChanged(this, mTracking, mToggle.isChecked(), progress);
+ }
+ }
+
+ public void onStartTrackingTouch(SeekBar seekBar) {
+ mTracking = true;
+ if (mListener != null) {
+ mListener.onChanged(this, mTracking, mToggle.isChecked(), mSlider.getProgress());
+ }
+ mToggle.setChecked(false);
+ }
+
+ public void onStopTrackingTouch(SeekBar seekBar) {
+ mTracking = false;
+ if (mListener != null) {
+ mListener.onChanged(this, mTracking, mToggle.isChecked(), mSlider.getProgress());
+ }
+ }
+
+ public void setOnChangedListener(Listener l) {
+ mListener = l;
+ }
+
+ public void setChecked(boolean checked) {
+ mToggle.setChecked(checked);
+ }
+
+ public boolean isChecked() {
+ return mToggle.isChecked();
+ }
+
+ public void setMax(int max) {
+ mSlider.setMax(max);
+ }
+
+ public void setValue(int value) {
+ mSlider.setProgress(value);
+ }
+}
+
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/VolumeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/VolumeController.java
new file mode 100644
index 0000000..c9da01a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/VolumeController.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.media.AudioManager;
+import android.provider.Settings;
+import android.util.Slog;
+import android.view.IWindowManager;
+import android.widget.CompoundButton;
+
+public class VolumeController implements ToggleSlider.Listener {
+ private static final String TAG = "StatusBar.VolumeController";
+ private static final int STREAM = AudioManager.STREAM_NOTIFICATION;
+
+ private Context mContext;
+ private ToggleSlider mControl;
+ private AudioManager mAudioManager;
+
+ private boolean mMute;
+ private int mVolume;
+
+ public VolumeController(Context context, ToggleSlider control) {
+ mContext = context;
+ mControl = control;
+ mAudioManager = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
+
+ mMute = mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL;
+ mVolume = mAudioManager.getStreamVolume(STREAM);
+ control.setMax(mAudioManager.getStreamMaxVolume(STREAM));
+ control.setValue(mVolume);
+ control.setChecked(mMute);
+
+ control.setOnChangedListener(this);
+ }
+
+ public void onChanged(ToggleSlider view, boolean tracking, boolean mute, int level) {
+ if (!tracking) {
+ if (mute) {
+ boolean vibeInSilent = (1 == Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.VIBRATE_IN_SILENT, 1));
+ mAudioManager.setRingerMode(
+ vibeInSilent ? AudioManager.RINGER_MODE_VIBRATE
+ : AudioManager.RINGER_MODE_SILENT);
+ } else {
+ mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
+ mAudioManager.setStreamVolume(STREAM, level, AudioManager.FLAG_PLAY_SOUND);
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SettingsView.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SettingsView.java
index d1f8dd0..0491baa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SettingsView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SettingsView.java
@@ -31,13 +31,18 @@
import com.android.systemui.R;
import com.android.systemui.statusbar.policy.AirplaneModeController;
import com.android.systemui.statusbar.policy.AutoRotateController;
+import com.android.systemui.statusbar.policy.BrightnessController;
import com.android.systemui.statusbar.policy.DoNotDisturbController;
+import com.android.systemui.statusbar.policy.ToggleSlider;
+import com.android.systemui.statusbar.policy.VolumeController;
public class SettingsView extends LinearLayout implements View.OnClickListener {
static final String TAG = "SettingsView";
AirplaneModeController mAirplane;
AutoRotateController mRotate;
+ VolumeController mVolume;
+ BrightnessController mBrightness;
DoNotDisturbController mDoNotDisturb;
public SettingsView(Context context, AttributeSet attrs) {
@@ -59,6 +64,10 @@
findViewById(R.id.network).setOnClickListener(this);
mRotate = new AutoRotateController(context,
(CompoundButton)findViewById(R.id.rotate_checkbox));
+ mVolume = new VolumeController(context,
+ (ToggleSlider)findViewById(R.id.volume));
+ mBrightness = new BrightnessController(context,
+ (ToggleSlider)findViewById(R.id.brightness));
mDoNotDisturb = new DoNotDisturbController(context,
(CompoundButton)findViewById(R.id.do_not_disturb_checkbox));
findViewById(R.id.settings).setOnClickListener(this);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/ShirtPocket.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/ShirtPocket.java
index 4d0835f..698f5af 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/ShirtPocket.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/ShirtPocket.java
@@ -81,7 +81,7 @@
mIcon.setImageResource(mClipping == null
? R.drawable.ic_sysbar_pocket_hidden
: R.drawable.ic_sysbar_pocket_holding);
- mIcon.setVisibility(mClipping == null ? View.INVISIBLE : View.VISIBLE);
+ mIcon.setVisibility(mClipping == null ? View.GONE : View.VISIBLE);
}
private void showWindow() {
diff --git a/services/java/com/android/server/InputManager.java b/services/java/com/android/server/InputManager.java
index 9078811..8634eec 100644
--- a/services/java/com/android/server/InputManager.java
+++ b/services/java/com/android/server/InputManager.java
@@ -358,16 +358,6 @@
}
}
- private static final class VirtualKeyDefinition {
- public int scanCode;
-
- // configured position data, specified in display coords
- public int centerX;
- public int centerY;
- public int width;
- public int height;
- }
-
/*
* Callbacks from native.
*/
@@ -438,54 +428,6 @@
}
@SuppressWarnings("unused")
- public VirtualKeyDefinition[] getVirtualKeyDefinitions(String deviceName) {
- ArrayList<VirtualKeyDefinition> keys = new ArrayList<VirtualKeyDefinition>();
-
- try {
- FileInputStream fis = new FileInputStream(
- "/sys/board_properties/virtualkeys." + deviceName);
- InputStreamReader isr = new InputStreamReader(fis);
- BufferedReader br = new BufferedReader(isr, 2048);
- String str = br.readLine();
- if (str != null) {
- String[] it = str.split(":");
- if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "***** VIRTUAL KEYS: " + it);
- 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] + " for device " + deviceName);
- continue;
- }
- try {
- VirtualKeyDefinition key = new VirtualKeyDefinition();
- key.scanCode = Integer.parseInt(it[i+1]);
- key.centerX = Integer.parseInt(it[i+2]);
- key.centerY = Integer.parseInt(it[i+3]);
- key.width = Integer.parseInt(it[i+4]);
- key.height = Integer.parseInt(it[i+5]);
- if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "Virtual key "
- + key.scanCode + ": center=" + key.centerX + ","
- + key.centerY + " size=" + key.width + "x"
- + key.height);
- keys.add(key);
- } catch (NumberFormatException 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 for device " + deviceName + ".");
- } catch (IOException e) {
- Slog.w(TAG, "Error reading virtual keys for device " + deviceName + ".", e);
- }
-
- return keys.toArray(new VirtualKeyDefinition[keys.size()]);
- }
-
- @SuppressWarnings("unused")
public String[] getExcludedDeviceNames() {
ArrayList<String> names = new ArrayList<String>();
diff --git a/services/java/com/android/server/SamplingProfilerService.java b/services/java/com/android/server/SamplingProfilerService.java
index 26af7f7..61267d0 100644
--- a/services/java/com/android/server/SamplingProfilerService.java
+++ b/services/java/com/android/server/SamplingProfilerService.java
@@ -88,7 +88,7 @@
private void registerSettingObserver(Context context) {
ContentResolver contentResolver = context.getContentResolver();
contentResolver.registerContentObserver(
- Settings.Secure.getUriFor(Settings.Secure.SAMPLING_PROFILER_HZ),
+ Settings.Secure.getUriFor(Settings.Secure.SAMPLING_PROFILER_MS),
false, new SamplingProfilerSettingsObserver(contentResolver));
}
@@ -107,12 +107,11 @@
}
@Override
public void onChange(boolean selfChange) {
- Integer samplingProfilerHz = Settings.Secure.getInt(
- mContentResolver, Settings.Secure.SAMPLING_PROFILER_HZ, 0);
+ Integer samplingProfilerMs = Settings.Secure.getInt(
+ mContentResolver, Settings.Secure.SAMPLING_PROFILER_MS, 0);
// setting this secure property will start or stop sampling profiler,
- // as well as adjust the frequency of taking snapshots.
- SystemProperties.set("persist.sys.profiler_hz", samplingProfilerHz.toString());
+ // as well as adjust the the time between taking snapshots.
+ SystemProperties.set("persist.sys.profiler_ms", samplingProfilerMs.toString());
}
}
}
-
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index d7a6a0e..7504bb4 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -6005,6 +6005,7 @@
int deviceId = ev.getDeviceId();
int scancode = ev.getScanCode();
int source = ev.getSource();
+ int flags = ev.getFlags();
if (source == InputDevice.SOURCE_UNKNOWN) {
source = InputDevice.SOURCE_KEYBOARD;
@@ -6014,7 +6015,7 @@
if (downTime == 0) downTime = eventTime;
KeyEvent newEvent = new KeyEvent(downTime, eventTime, action, code, repeatCount, metaState,
- deviceId, scancode, KeyEvent.FLAG_FROM_SYSTEM, source);
+ deviceId, scancode, flags | KeyEvent.FLAG_FROM_SYSTEM, source);
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp
index aa84db5..1996dd0 100644
--- a/services/jni/com_android_server_InputManager.cpp
+++ b/services/jni/com_android_server_InputManager.cpp
@@ -56,7 +56,6 @@
jmethodID checkInjectEventsPermission;
jmethodID filterTouchEvents;
jmethodID filterJumpyTouchEvents;
- jmethodID getVirtualKeyDefinitions;
jmethodID getExcludedDeviceNames;
jmethodID getMaxEventsPerSecond;
} gCallbacksClassInfo;
@@ -64,16 +63,6 @@
static struct {
jclass clazz;
- jfieldID scanCode;
- jfieldID centerX;
- jfieldID centerY;
- jfieldID width;
- jfieldID height;
-} gVirtualKeyDefinitionClassInfo;
-
-static struct {
- jclass clazz;
-
jfieldID inputChannel;
jfieldID name;
jfieldID layoutParamsFlags;
@@ -176,8 +165,6 @@
int32_t* width, int32_t* height, int32_t* orientation);
virtual bool filterTouchEvents();
virtual bool filterJumpyTouchEvents();
- virtual void getVirtualKeyDefinitions(const String8& deviceName,
- Vector<VirtualKeyDefinition>& outVirtualKeyDefinitions);
virtual void getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames);
/* --- InputDispatcherPolicyInterface implementation --- */
@@ -442,41 +429,6 @@
return mFilterJumpyTouchEvents;
}
-void NativeInputManager::getVirtualKeyDefinitions(const String8& deviceName,
- Vector<VirtualKeyDefinition>& outVirtualKeyDefinitions) {
- outVirtualKeyDefinitions.clear();
-
- JNIEnv* env = jniEnv();
-
- jstring deviceNameStr = env->NewStringUTF(deviceName.string());
- if (! checkAndClearExceptionFromCallback(env, "getVirtualKeyDefinitions")) {
- jobjectArray result = jobjectArray(env->CallObjectMethod(mCallbacksObj,
- gCallbacksClassInfo.getVirtualKeyDefinitions, deviceNameStr));
- if (! checkAndClearExceptionFromCallback(env, "getVirtualKeyDefinitions") && result) {
- jsize length = env->GetArrayLength(result);
- for (jsize i = 0; i < length; i++) {
- jobject item = env->GetObjectArrayElement(result, i);
-
- outVirtualKeyDefinitions.add();
- outVirtualKeyDefinitions.editTop().scanCode =
- int32_t(env->GetIntField(item, gVirtualKeyDefinitionClassInfo.scanCode));
- outVirtualKeyDefinitions.editTop().centerX =
- int32_t(env->GetIntField(item, gVirtualKeyDefinitionClassInfo.centerX));
- outVirtualKeyDefinitions.editTop().centerY =
- int32_t(env->GetIntField(item, gVirtualKeyDefinitionClassInfo.centerY));
- outVirtualKeyDefinitions.editTop().width =
- int32_t(env->GetIntField(item, gVirtualKeyDefinitionClassInfo.width));
- outVirtualKeyDefinitions.editTop().height =
- int32_t(env->GetIntField(item, gVirtualKeyDefinitionClassInfo.height));
-
- env->DeleteLocalRef(item);
- }
- env->DeleteLocalRef(result);
- }
- env->DeleteLocalRef(deviceNameStr);
- }
-}
-
void NativeInputManager::getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames) {
outExcludedDeviceNames.clear();
@@ -1366,36 +1318,12 @@
GET_METHOD_ID(gCallbacksClassInfo.filterJumpyTouchEvents, gCallbacksClassInfo.clazz,
"filterJumpyTouchEvents", "()Z");
- GET_METHOD_ID(gCallbacksClassInfo.getVirtualKeyDefinitions, gCallbacksClassInfo.clazz,
- "getVirtualKeyDefinitions",
- "(Ljava/lang/String;)[Lcom/android/server/InputManager$VirtualKeyDefinition;");
-
GET_METHOD_ID(gCallbacksClassInfo.getExcludedDeviceNames, gCallbacksClassInfo.clazz,
"getExcludedDeviceNames", "()[Ljava/lang/String;");
GET_METHOD_ID(gCallbacksClassInfo.getMaxEventsPerSecond, gCallbacksClassInfo.clazz,
"getMaxEventsPerSecond", "()I");
- // VirtualKeyDefinition
-
- FIND_CLASS(gVirtualKeyDefinitionClassInfo.clazz,
- "com/android/server/InputManager$VirtualKeyDefinition");
-
- GET_FIELD_ID(gVirtualKeyDefinitionClassInfo.scanCode, gVirtualKeyDefinitionClassInfo.clazz,
- "scanCode", "I");
-
- GET_FIELD_ID(gVirtualKeyDefinitionClassInfo.centerX, gVirtualKeyDefinitionClassInfo.clazz,
- "centerX", "I");
-
- GET_FIELD_ID(gVirtualKeyDefinitionClassInfo.centerY, gVirtualKeyDefinitionClassInfo.clazz,
- "centerY", "I");
-
- GET_FIELD_ID(gVirtualKeyDefinitionClassInfo.width, gVirtualKeyDefinitionClassInfo.clazz,
- "width", "I");
-
- GET_FIELD_ID(gVirtualKeyDefinitionClassInfo.height, gVirtualKeyDefinitionClassInfo.clazz,
- "height", "I");
-
// InputWindow
FIND_CLASS(gInputWindowClassInfo.clazz, "com/android/server/InputWindow");
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
index 59fcc52..392717e 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -16,6 +16,7 @@
package com.android.layoutlib.bridge;
+import com.android.layoutlib.api.Capabilities;
import com.android.layoutlib.api.ILayoutLog;
import com.android.layoutlib.api.IProjectCallback;
import com.android.layoutlib.api.IResourceValue;
@@ -40,6 +41,7 @@
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Arrays;
+import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;
@@ -152,11 +154,19 @@
}
};
+ private EnumSet<Capabilities> mCapabilities;
+
+
@Override
public int getApiLevel() {
return LayoutBridge.API_CURRENT;
}
+ @Override
+ public EnumSet<Capabilities> getCapabilities() {
+ return mCapabilities;
+ }
+
/*
* (non-Javadoc)
* @see com.android.layoutlib.api.ILayoutLibBridge#init(java.lang.String, java.util.Map)
@@ -165,6 +175,15 @@
public boolean init(String fontOsLocation, Map<String, Map<String, Integer>> enumValueMap) {
sEnumValueMap = enumValueMap;
+ // don't use EnumSet.allOf(), because the bridge doesn't come with it's specific version
+ // of layoutlib_api. It is provided by the client which could have a more recent version
+ // with newer, unsupported capabilities.
+ mCapabilities = EnumSet.of(
+ Capabilities.RENDER,
+ Capabilities.VIEW_MANIPULATION,
+ Capabilities.ANIMATE);
+
+
Finalizers.init();
BridgeAssetManager.initSystem();
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeLayoutScene.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeLayoutScene.java
index 2f7ef48..a491901 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeLayoutScene.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeLayoutScene.java
@@ -119,7 +119,7 @@
@Override
public SceneResult moveChild(Object parentView, Object childView, int index,
- IAnimationListener listener) {
+ Map<String, String> layoutParams, IAnimationListener listener) {
if (parentView instanceof ViewGroup == false) {
throw new IllegalArgumentException("parentView is not a ViewGroup");
}
diff --git a/tools/validatekeymaps/Main.cpp b/tools/validatekeymaps/Main.cpp
index 6ec223b..097b109 100644
--- a/tools/validatekeymaps/Main.cpp
+++ b/tools/validatekeymaps/Main.cpp
@@ -16,6 +16,7 @@
#include <ui/KeyCharacterMap.h>
#include <ui/KeyLayoutMap.h>
+#include <ui/VirtualKeyMap.h>
#include <utils/String8.h>
#include <stdio.h>
@@ -30,6 +31,7 @@
FILETYPE_UNKNOWN,
FILETYPE_KEYLAYOUT,
FILETYPE_KEYCHARACTERMAP,
+ FILETYPE_VIRTUALKEYDEFINITION,
};
@@ -37,8 +39,10 @@
fprintf(stderr, "Keymap Validation Tool\n\n");
fprintf(stderr, "Usage:\n");
fprintf(stderr,
- " %s [FILENAME.kl] [FILENAME.kcm] [...]\n"
- " Validates the specified key layout and/or key character map files.\n\n", gProgName);
+ " %s [*.kl] [*.kcm] [virtualkeys.*] [...]\n"
+ " Validates the specified key layouts, key character maps \n"
+ " or virtual key definitions.\n\n",
+ gProgName);
}
static FileType getFileType(const char* filename) {
@@ -51,6 +55,11 @@
return FILETYPE_KEYCHARACTERMAP;
}
}
+
+ if (strstr(filename, "virtualkeys.")) {
+ return FILETYPE_VIRTUALKEYDEFINITION;
+ }
+
return FILETYPE_UNKNOWN;
}
@@ -60,7 +69,7 @@
FileType fileType = getFileType(filename);
switch (fileType) {
case FILETYPE_UNKNOWN:
- fprintf(stderr, "File extension must be .kl or .kcm.\n\n");
+ fprintf(stderr, "Supported file types: *.kl, *.kcm, virtualkeys.*\n\n");
return false;
case FILETYPE_KEYLAYOUT: {
@@ -82,6 +91,16 @@
}
break;
}
+
+ case FILETYPE_VIRTUALKEYDEFINITION: {
+ VirtualKeyMap* map;
+ status_t status = VirtualKeyMap::load(String8(filename), &map);
+ if (status) {
+ fprintf(stderr, "Error %d parsing virtual key definition file.\n\n", status);
+ return false;
+ }
+ break;
+ }
}
fputs("No errors.\n\n", stdout);
diff --git a/voip/java/android/net/sip/SipAudioCall.java b/voip/java/android/net/sip/SipAudioCall.java
index f275e39..51236fe 100644
--- a/voip/java/android/net/sip/SipAudioCall.java
+++ b/voip/java/android/net/sip/SipAudioCall.java
@@ -594,12 +594,10 @@
*/
public void holdCall(int timeout) throws SipException {
synchronized (this) {
- if (mHold) return;
+ if (mHold) return;
mSipSession.changeCall(createHoldOffer().encode(), timeout);
mHold = true;
-
- AudioGroup audioGroup = getAudioGroup();
- if (audioGroup != null) audioGroup.setMode(AudioGroup.MODE_ON_HOLD);
+ setAudioGroupMode();
}
}
@@ -643,8 +641,7 @@
if (!mHold) return;
mSipSession.changeCall(createContinueOffer().encode(), timeout);
mHold = false;
- AudioGroup audioGroup = getAudioGroup();
- if (audioGroup != null) audioGroup.setMode(AudioGroup.MODE_NORMAL);
+ setAudioGroupMode();
}
}
@@ -767,13 +764,8 @@
/** Toggles mute. */
public void toggleMute() {
synchronized (this) {
- AudioGroup audioGroup = getAudioGroup();
- if (audioGroup != null) {
- audioGroup.setMode(mMuted
- ? AudioGroup.MODE_NORMAL
- : AudioGroup.MODE_MUTED);
- mMuted = !mMuted;
- }
+ mMuted = !mMuted;
+ setAudioGroupMode();
}
}
@@ -792,14 +784,22 @@
* Puts the device to speaker mode.
* <p class="note"><strong>Note:</strong> Requires the
* {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS} permission.</p>
+ *
+ * @param speakerMode set true to enable speaker mode; false to disable
*/
public void setSpeakerMode(boolean speakerMode) {
synchronized (this) {
((AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE))
.setSpeakerphoneOn(speakerMode);
+ setAudioGroupMode();
}
}
+ private boolean isSpeakerOn() {
+ return ((AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE))
+ .isSpeakerphoneOn();
+ }
+
/**
* Sends a DTMF code. According to <a href="http://tools.ietf.org/html/rfc2833">RFC 2883</a>,
* event 0--9 maps to decimal
@@ -876,7 +876,11 @@
/**
* Sets the {@link AudioGroup} object which the {@link AudioStream} object
* joins. If {@code audioGroup} is null, then the {@code AudioGroup} object
- * will be dynamically created when needed.
+ * will be dynamically created when needed. Note that the mode of the
+ * {@code AudioGroup} is not changed according to the audio settings (i.e.,
+ * hold, mute, speaker phone) of this object. This is mainly used to merge
+ * multiple {@code SipAudioCall} objects to form a conference call. The
+ * settings of the first object (that merges others) override others'.
*
* @see #getAudioStream
* @hide
@@ -992,16 +996,25 @@
// AudioGroup logic:
AudioGroup audioGroup = getAudioGroup();
if (mHold) {
- if (audioGroup != null) {
- audioGroup.setMode(AudioGroup.MODE_ON_HOLD);
- }
// don't create an AudioGroup here; doing so will fail if
// there's another AudioGroup out there that's active
} else {
if (audioGroup == null) audioGroup = new AudioGroup();
stream.join(audioGroup);
- if (mMuted) {
+ }
+ setAudioGroupMode();
+ }
+
+ // set audio group mode based on current audio configuration
+ private void setAudioGroupMode() {
+ AudioGroup audioGroup = getAudioGroup();
+ if (audioGroup != null) {
+ if (mHold) {
+ audioGroup.setMode(AudioGroup.MODE_ON_HOLD);
+ } else if (mMuted) {
audioGroup.setMode(AudioGroup.MODE_MUTED);
+ } else if (isSpeakerOn()) {
+ audioGroup.setMode(AudioGroup.MODE_ECHO_SUPPRESSION);
} else {
audioGroup.setMode(AudioGroup.MODE_NORMAL);
}