Merge "Minor fixes to SurfaceTexture transform matrix."
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_ime.png b/core/res/res/drawable-hdpi/ic_lockscreen_ime.png
new file mode 100644
index 0000000..29a7989
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_ime.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_ime.png b/core/res/res/drawable-mdpi/ic_lockscreen_ime.png
new file mode 100644
index 0000000..b27e059
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_ime.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_ime.png b/core/res/res/drawable-xhdpi/ic_lockscreen_ime.png
new file mode 100644
index 0000000..a40ddeb
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_ime.png
Binary files differ
diff --git a/core/res/res/layout/keyguard_screen_password_landscape.xml b/core/res/res/layout/keyguard_screen_password_landscape.xml
index 4c44049..bc86ab7 100644
--- a/core/res/res/layout/keyguard_screen_password_landscape.xml
+++ b/core/res/res/layout/keyguard_screen_password_landscape.xml
@@ -133,13 +133,14 @@
<!-- Column 2 - password entry field and PIN keyboard -->
<LinearLayout
- android:orientation="vertical"
+ android:orientation="horizontal"
android:layout_width="270dip"
android:layout_gravity="center_vertical">
<EditText android:id="@+id/passwordEntry"
android:layout_height="wrap_content"
- android:layout_width="match_parent"
+ android:layout_width="0dip"
+ android:layout_weight="1"
android:gravity="center"
android:singleLine="true"
android:textStyle="normal"
@@ -153,6 +154,17 @@
android:suggestionsEnabled="false"
/>
+ <ImageView android:id="@+id/switch_ime_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_lockscreen_ime"
+ android:clickable="true"
+ android:padding="8dip"
+ android:layout_gravity="center"
+ android:background="?android:attr/selectableItemBackground"
+ android:visibility="gone"
+ />
+
</LinearLayout>
<!-- Numeric keyboard -->
diff --git a/core/res/res/layout/keyguard_screen_password_portrait.xml b/core/res/res/layout/keyguard_screen_password_portrait.xml
index 1d0ea54..994c439 100644
--- a/core/res/res/layout/keyguard_screen_password_portrait.xml
+++ b/core/res/res/layout/keyguard_screen_password_portrait.xml
@@ -95,22 +95,39 @@
/>
<!-- Password entry field -->
- <EditText android:id="@+id/passwordEntry"
- android:layout_height="wrap_content"
- android:layout_width="match_parent"
+ <LinearLayout
android:layout_gravity="center_vertical|fill_horizontal"
- android:gravity="center_horizontal"
- android:singleLine="true"
- android:textStyle="normal"
- android:inputType="textPassword"
- android:textSize="36sp"
+ android:orientation="horizontal"
android:layout_marginLeft="16dip"
- android:layout_marginRight="16dip"
- android:background="@drawable/lockscreen_password_field_dark"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textColor="#ffffffff"
- android:imeOptions="actionDone"
- android:suggestionsEnabled="false"/>
+ android:layout_marginRight="16dip">
+
+ <EditText android:id="@+id/passwordEntry"
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:gravity="center_horizontal"
+ android:singleLine="true"
+ android:textStyle="normal"
+ android:inputType="textPassword"
+ android:textSize="36sp"
+ android:background="@drawable/lockscreen_password_field_dark"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="#ffffffff"
+ android:imeOptions="actionDone"
+ android:suggestionsEnabled="false"/>
+
+ <ImageView android:id="@+id/switch_ime_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_lockscreen_ime"
+ android:clickable="true"
+ android:padding="8dip"
+ android:layout_gravity="center"
+ android:background="?android:attr/selectableItemBackground"
+ android:visibility="gone"
+ />
+
+ </LinearLayout>
<!-- Numeric keyboard -->
<com.android.internal.widget.PasswordEntryKeyboardView android:id="@+id/keyboard"
diff --git a/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java b/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java
index 7c1f93a..d70b3bb 100644
--- a/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java
+++ b/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java
@@ -16,6 +16,8 @@
package com.android.internal.policy.impl;
+import java.util.List;
+
import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.content.res.Configuration;
@@ -27,18 +29,18 @@
import android.os.CountDownTimer;
import android.os.SystemClock;
import android.security.KeyStore;
-import android.telephony.TelephonyManager;
import android.text.Editable;
import android.text.InputType;
import android.text.TextWatcher;
import android.text.method.DigitsKeyListener;
import android.text.method.TextKeyListener;
-import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
-import android.view.View.OnClickListener;
import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodInfo;
+import android.view.inputmethod.InputMethodManager;
+import android.view.inputmethod.InputMethodSubtype;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
@@ -159,6 +161,68 @@
}
}
});
+
+ // If there's more than one IME, enable the IME switcher button
+ View switchImeButton = findViewById(R.id.switch_ime_button);
+ final InputMethodManager imm = (InputMethodManager) getContext().getSystemService(
+ Context.INPUT_METHOD_SERVICE);
+ if (switchImeButton != null && hasMultipleEnabledIMEsOrSubtypes(imm, false)) {
+ switchImeButton.setVisibility(View.VISIBLE);
+ switchImeButton.setOnClickListener(new OnClickListener() {
+ public void onClick(View v) {
+ mCallback.pokeWakelock(); // Leave the screen on a bit longer
+ imm.showInputMethodPicker();
+ }
+ });
+ }
+ }
+
+ /**
+ * Method adapted from com.android.inputmethod.latin.Utils
+ *
+ * @param imm The input method manager
+ * @param shouldIncludeAuxiliarySubtypes
+ * @return true if we have multiple IMEs to choose from
+ */
+ private boolean hasMultipleEnabledIMEsOrSubtypes(InputMethodManager imm,
+ final boolean shouldIncludeAuxiliarySubtypes) {
+ final List<InputMethodInfo> enabledImis = imm.getEnabledInputMethodList();
+
+ // Number of the filtered IMEs
+ int filteredImisCount = 0;
+
+ for (InputMethodInfo imi : enabledImis) {
+ // We can return true immediately after we find two or more filtered IMEs.
+ if (filteredImisCount > 1) return true;
+ final List<InputMethodSubtype> subtypes =
+ imm.getEnabledInputMethodSubtypeList(imi, true);
+ // IMEs that have no subtypes should be counted.
+ if (subtypes.isEmpty()) {
+ ++filteredImisCount;
+ continue;
+ }
+
+ int auxCount = 0;
+ for (InputMethodSubtype subtype : subtypes) {
+ if (subtype.isAuxiliary()) {
+ ++auxCount;
+ }
+ }
+ final int nonAuxCount = subtypes.size() - auxCount;
+
+ // IMEs that have one or more non-auxiliary subtypes should be counted.
+ // If shouldIncludeAuxiliarySubtypes is true, IMEs that have two or more auxiliary
+ // subtypes should be counted as well.
+ if (nonAuxCount > 0 || (shouldIncludeAuxiliarySubtypes && auxCount > 1)) {
+ ++filteredImisCount;
+ continue;
+ }
+ }
+
+ return filteredImisCount > 1
+ // imm.getEnabledInputMethodSubtypeList(null, false) will return the current IME's enabled
+ // input method subtype (The current IME should be LatinIME.)
+ || imm.getEnabledInputMethodSubtypeList(null, false).size() > 1;
}
@Override
diff --git a/services/sensorservice/Fusion.cpp b/services/sensorservice/Fusion.cpp
index d706af5..ff4786b 100644
--- a/services/sensorservice/Fusion.cpp
+++ b/services/sensorservice/Fusion.cpp
@@ -48,6 +48,7 @@
static const float magSTDEV = 0.5f; // uT (measured 0.7 / CDD 0.5)
static const float FREE_FALL_THRESHOLD = 0.981f;
+static const float SYMMETRY_TOLERANCE = 1e-10f;
// -----------------------------------------------------------------------
@@ -134,10 +135,13 @@
void Fusion::init() {
mInitState = 0;
+
mGyroRate = 0;
+
mCount[0] = 0;
mCount[1] = 0;
mCount[2] = 0;
+
mData = 0;
}
@@ -267,19 +271,16 @@
return NO_ERROR;
}
-bool Fusion::checkState(const vec3_t& v) {
- if (isnanf(length(v))) {
- LOGW("9-axis fusion diverged. reseting state.");
+void Fusion::checkState() {
+ // P needs to stay positive semidefinite or the fusion diverges. When we
+ // detect divergence, we reset the fusion.
+ // TODO(braun): Instead, find the reason for the divergence and fix it.
+
+ if (!isPositiveSemidefinite(P[0][0], SYMMETRY_TOLERANCE) ||
+ !isPositiveSemidefinite(P[1][1], SYMMETRY_TOLERANCE)) {
+ LOGW("Sensor fusion diverged; resetting state.");
P = 0;
- x1 = 0;
- mInitState = 0;
- mCount[0] = 0;
- mCount[1] = 0;
- mCount[2] = 0;
- mData = 0;
- return false;
}
- return true;
}
vec4_t Fusion::getAttitude() const {
@@ -327,6 +328,8 @@
Phi[1][0] = wx*k0 - I33dT - wx2*(ilwe*ilwe*ilwe)*(lwedT-k1);
P = Phi*P*transpose(Phi) + GQGt;
+
+ checkState();
}
void Fusion::update(const vec3_t& z, const vec3_t& Bi, float sigma) {
@@ -365,6 +368,8 @@
q += getF(q)*(0.5f*dq);
x0 = normalize_quat(q);
x1 += db;
+
+ checkState();
}
// -----------------------------------------------------------------------
diff --git a/services/sensorservice/Fusion.h b/services/sensorservice/Fusion.h
index 556944b..7062999 100644
--- a/services/sensorservice/Fusion.h
+++ b/services/sensorservice/Fusion.h
@@ -37,7 +37,7 @@
vec3_t x1;
/*
- * the predicated covariance matrix is made of 4 3x3 sub-matrices and it
+ * the predicated covariance matrix is made of 4 3x3 sub-matrices and it is
* semi-definite positive.
*
* P = | P00 P10 | = | P00 P10 |
@@ -74,7 +74,7 @@
enum { ACC=0x1, MAG=0x2, GYRO=0x4 };
bool checkInitComplete(int, const vec3_t& w, float d = 0);
void initFusion(const vec4_t& q0, float dT);
- bool checkState(const vec3_t& v);
+ void checkState();
void predict(const vec3_t& w, float dT);
void update(const vec3_t& z, const vec3_t& Bi, float sigma);
static mat34_t getF(const vec4_t& p);
diff --git a/services/sensorservice/mat.h b/services/sensorservice/mat.h
index 1302ca3..a76fc91 100644
--- a/services/sensorservice/mat.h
+++ b/services/sensorservice/mat.h
@@ -295,6 +295,29 @@
return r;
}
+// Calculate the trace of a matrix
+template <typename TYPE, size_t C> static TYPE trace(const mat<TYPE, C, C>& m) {
+ TYPE t;
+ for (size_t i=0 ; i<C ; i++)
+ t += m[i][i];
+ return t;
+}
+
+// Test positive-semidefiniteness of a matrix
+template <typename TYPE, size_t C>
+static bool isPositiveSemidefinite(const mat<TYPE, C, C>& m, TYPE tolerance) {
+ for (size_t i=0 ; i<C ; i++)
+ if (m[i][i] < 0)
+ return false;
+
+ for (size_t i=0 ; i<C ; i++)
+ for (size_t j=i+1 ; j<C ; j++)
+ if (fabs(m[i][j] - m[j][i]) > tolerance)
+ return false;
+
+ return true;
+}
+
// Transpose a vector
template <
template<typename T, size_t S> class VEC,
diff --git a/wifi/java/android/net/wifi/WifiNative.java b/wifi/java/android/net/wifi/WifiNative.java
index bfc4d5e..6c6f149 100644
--- a/wifi/java/android/net/wifi/WifiNative.java
+++ b/wifi/java/android/net/wifi/WifiNative.java
@@ -304,4 +304,28 @@
return doBooleanCommand("P2P_INVITE group=" + group.getInterface()
+ " peer=" + deviceAddress + " go_dev_addr=" + group.getOwner().deviceAddress);
}
+
+ public static String p2pGetInterfaceAddress(String deviceAddress) {
+ if (deviceAddress == null) return null;
+
+ // "p2p_peer deviceAddress" returns a multi-line result containing
+ // intended_addr=fa:7b:7a:42:82:13
+ String peerInfo = p2pPeer(deviceAddress);
+ if (peerInfo == null) return null;
+ String[] tokens= peerInfo.split("\n");
+
+ for (String token : tokens) {
+ //TODO: update from interface_addr when wpa_supplicant implementation is fixed
+ if (token.startsWith("intended_addr=")) {
+ String[] nameValue = token.split("=");
+ if (nameValue.length != 2) break;
+ return nameValue[1];
+ }
+ }
+ return null;
+ }
+
+ public static String p2pPeer(String deviceAddress) {
+ return doStringCommand("P2P_PEER " + deviceAddress);
+ }
}
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java b/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java
index 83dc285..7908726 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java
@@ -158,9 +158,6 @@
return;
}
- Pattern p = Pattern.compile("(?:[0-9a-f]{2}:){5}[0-9a-f]{2}", Pattern.CASE_INSENSITIVE);
- if (p.matcher(tokens[1]).matches()) interfaceAddress = tokens[1];
-
for (String token : tokens) {
String[] nameValue = token.split("=");
if (nameValue.length != 2) continue;
@@ -177,6 +174,7 @@
if (nameValue[0].equals("name")) {
deviceName = trimQuotes(nameValue[1]);
+ continue;
}
if (nameValue[0].equals("config_methods")) {
@@ -213,9 +211,7 @@
if (other == null || other.deviceAddress == null) {
return (deviceAddress == null);
}
- //STOPSHIP: fix later
- //return other.deviceAddress.equals(deviceAddress);
- return other.deviceAddress.startsWith(deviceAddress.substring(0,8));
+ return other.deviceAddress.equals(deviceAddress);
}
public String toString() {
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pService.java b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
index 49ce124..4447971 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pService.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
@@ -663,17 +663,20 @@
if (DBG) Slog.d(TAG, getName() + message.toString());
switch (message.what) {
case WifiMonitor.AP_STA_CONNECTED_EVENT:
- String address = (String) message.obj;
- mGroup.addClient(address);
- updateDeviceStatus(address, Status.CONNECTED);
+ //After a GO setup, STA connected event comes with interface address
+ String interfaceAddress = (String) message.obj;
+ String deviceAddress = getDeviceAddress(interfaceAddress);
+ mGroup.addClient(deviceAddress);
+ updateDeviceStatus(deviceAddress, Status.CONNECTED);
if (DBG) Slog.d(TAG, getName() + " ap sta connected");
sendP2pPeersChangedBroadcast();
break;
case WifiMonitor.AP_STA_DISCONNECTED_EVENT:
- address = (String) message.obj;
- updateDeviceStatus(address, Status.AVAILABLE);
- if (mGroup.removeClient(address)) {
- if (DBG) Slog.d(TAG, "Removed client " + address);
+ interfaceAddress = (String) message.obj;
+ deviceAddress = getDeviceAddress(interfaceAddress);
+ updateDeviceStatus(deviceAddress, Status.AVAILABLE);
+ if (mGroup.removeClient(deviceAddress)) {
+ if (DBG) Slog.d(TAG, "Removed client " + deviceAddress);
if (mGroup.isClientListEmpty()) {
Slog.d(TAG, "Client list empty, killing p2p connection");
sendMessage(WifiP2pManager.REMOVE_GROUP);
@@ -682,7 +685,7 @@
sendP2pPeersChangedBroadcast();
}
} else {
- if (DBG) Slog.d(TAG, "Failed to remove client " + address);
+ if (DBG) Slog.d(TAG, "Failed to remove client " + deviceAddress);
for (WifiP2pDevice c : mGroup.getClientList()) {
if (DBG) Slog.d(TAG,"client " + c.deviceAddress);
}
@@ -1005,12 +1008,20 @@
private void updateDeviceStatus(String deviceAddress, Status status) {
for (WifiP2pDevice d : mPeers.getDeviceList()) {
- // TODO: fix later
- // if (d.deviceAddress.equals(deviceAddress)) {
- if (d.deviceAddress.startsWith(deviceAddress.substring(0, 8))) {
+ if (d.deviceAddress.equals(deviceAddress)) {
d.status = status;
}
}
}
+
+ private String getDeviceAddress(String interfaceAddress) {
+ for (WifiP2pDevice d : mPeers.getDeviceList()) {
+ if (interfaceAddress.equals(WifiNative.p2pGetInterfaceAddress(d.deviceAddress))) {
+ return d.deviceAddress;
+ }
+ }
+ return null;
+ }
+
}
}