Merge "Update WebView.addJavascriptInterface() to ignore null instances"
diff --git a/api/current.xml b/api/current.xml
index 290eff0..7d7bec1 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -161134,6 +161134,468 @@
>
</field>
</interface>
+<class name="Ptp"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Ptp"
+ type="android.provider.Ptp"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<field name="AUTHORITY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""ptp""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="Ptp.Device"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.provider.BaseColumns">
+</implements>
+<constructor name="Ptp.Device"
+ type="android.provider.Ptp.Device"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="getContentUri"
+ return="android.net.Uri"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="deviceID" type="int">
+</parameter>
+</method>
+<field name="CONTENT_URI"
+ type="android.net.Uri"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="MANUFACTURER"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""manufacturer""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="MODEL"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""model""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="Ptp.Object"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.provider.BaseColumns">
+</implements>
+<constructor name="Ptp.Object"
+ type="android.provider.Ptp.Object"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="getContentUri"
+ return="android.net.Uri"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="deviceID" type="int">
+</parameter>
+<parameter name="objectID" type="long">
+</parameter>
+</method>
+<method name="getContentUriForImport"
+ return="android.net.Uri"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="deviceID" type="int">
+</parameter>
+<parameter name="objectID" type="long">
+</parameter>
+<parameter name="destPath" type="java.lang.String">
+</parameter>
+</method>
+<method name="getContentUriForObjectChildren"
+ return="android.net.Uri"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="deviceID" type="int">
+</parameter>
+<parameter name="objectID" type="long">
+</parameter>
+</method>
+<method name="getContentUriForStorageChildren"
+ return="android.net.Uri"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="deviceID" type="int">
+</parameter>
+<parameter name="storageID" type="long">
+</parameter>
+</method>
+<field name="ASSOCIATION_DESC"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""association_desc""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ASSOCIATION_TYPE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""association_type""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="DATE_CREATED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""date_created""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="DATE_MODIFIED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""date_modified""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""format""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="IMAGE_DEPTH"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""image_depth""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="IMAGE_HEIGHT"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""image_height""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="IMAGE_WIDTH"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""image_width""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="KEYWORDS"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""keywords""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="NAME"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""name""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="PARENT"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""parent""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="PROTECTION_STATUS"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""protection_status""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="SEQUENCE_NUMBER"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""sequence_number""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="SIZE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""size""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="STORAGE_ID"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""storage_id""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="THUMB"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""thumb""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="THUMB_FORMAT"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""thumb_format""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="THUMB_HEIGHT"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""thumb_height""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="THUMB_SIZE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""thumb_size""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="THUMB_WIDTH"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""thumb_width""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="Ptp.Storage"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.provider.BaseColumns">
+</implements>
+<constructor name="Ptp.Storage"
+ type="android.provider.Ptp.Storage"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="getContentUri"
+ return="android.net.Uri"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="deviceID" type="int">
+</parameter>
+</method>
+<method name="getContentUri"
+ return="android.net.Uri"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="deviceID" type="int">
+</parameter>
+<parameter name="storageID" type="long">
+</parameter>
+</method>
+<field name="DESCRIPTION"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""description""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="IDENTIFIER"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""identifier""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
<class name="SearchRecentSuggestions"
extends="java.lang.Object"
abstract="false"
@@ -246160,6 +246622,17 @@
visibility="public"
>
</method>
+<method name="getCustomSelectionActionModeCallback"
+ return="android.view.ActionMode.Callback"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getDefaultEditable"
return="boolean"
abstract="false"
@@ -246958,6 +247431,19 @@
<parameter name="visible" type="boolean">
</parameter>
</method>
+<method name="setCustomSelectionActionModeCallback"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="actionModeCallback" type="android.view.ActionMode.Callback">
+</parameter>
+</method>
<method name="setEditableFactory"
return="void"
abstract="false"
@@ -249605,7 +250091,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="arg0" type="T">
+<parameter name="t" type="T">
</parameter>
</method>
</interface>
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 0a2e031..a0a6b42 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -2363,7 +2363,11 @@
*/
public boolean onMenuOpened(int featureId, Menu menu) {
if (featureId == Window.FEATURE_ACTION_BAR) {
- mActionBar.dispatchMenuVisibilityChanged(true);
+ if (mActionBar != null) {
+ mActionBar.dispatchMenuVisibilityChanged(true);
+ } else {
+ Log.e(TAG, "Tried to open action bar menu with no action bar");
+ }
}
return true;
}
diff --git a/core/java/android/content/ContentProviderNative.java b/core/java/android/content/ContentProviderNative.java
index d1ab8d5..abeeb74 100644
--- a/core/java/android/content/ContentProviderNative.java
+++ b/core/java/android/content/ContentProviderNative.java
@@ -110,16 +110,23 @@
IBulkCursor bulkCursor = bulkQuery(url, projection, selection,
selectionArgs, sortOrder, observer, window);
- reply.writeNoException();
if (bulkCursor != null) {
- reply.writeStrongBinder(bulkCursor.asBinder());
-
+ final IBinder binder = bulkCursor.asBinder();
if (wantsCursorMetadata) {
- reply.writeInt(bulkCursor.count());
- reply.writeInt(BulkCursorToCursorAdaptor.findRowIdColumnIndex(
- bulkCursor.getColumnNames()));
+ final int count = bulkCursor.count();
+ final int index = BulkCursorToCursorAdaptor.findRowIdColumnIndex(
+ bulkCursor.getColumnNames());
+
+ reply.writeNoException();
+ reply.writeStrongBinder(binder);
+ reply.writeInt(count);
+ reply.writeInt(index);
+ } else {
+ reply.writeNoException();
+ reply.writeStrongBinder(binder);
}
} else {
+ reply.writeNoException();
reply.writeStrongBinder(null);
}
diff --git a/core/java/android/content/res/AssetFileDescriptor.java b/core/java/android/content/res/AssetFileDescriptor.java
index 01ae1da..9893133 100644
--- a/core/java/android/content/res/AssetFileDescriptor.java
+++ b/core/java/android/content/res/AssetFileDescriptor.java
@@ -16,7 +16,6 @@
package android.content.res;
-import android.os.MemoryFile;
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
@@ -184,14 +183,9 @@
@Override
public int read() throws IOException {
- if (mRemaining >= 0) {
- if (mRemaining == 0) return -1;
- int res = super.read();
- if (res >= 0) mRemaining--;
- return res;
- }
-
- return super.read();
+ byte[] buffer = new byte[1];
+ int result = read(buffer, 0, 1);
+ return result == -1 ? -1 : buffer[0] & 0xff;
}
@Override
@@ -209,16 +203,7 @@
@Override
public int read(byte[] buffer) throws IOException {
- if (mRemaining >= 0) {
- if (mRemaining == 0) return -1;
- int count = buffer.length;
- if (count > mRemaining) count = (int)mRemaining;
- int res = super.read(buffer, 0, count);
- if (res >= 0) mRemaining -= res;
- return res;
- }
-
- return super.read(buffer);
+ return read(buffer, 0, buffer.length);
}
@Override
@@ -231,7 +216,6 @@
return res;
}
- // TODO Auto-generated method stub
return super.skip(count);
}
diff --git a/core/java/android/provider/Ptp.java b/core/java/android/provider/Ptp.java
index 2c54370..0f0919e 100644
--- a/core/java/android/provider/Ptp.java
+++ b/core/java/android/provider/Ptp.java
@@ -20,10 +20,13 @@
import android.net.Uri;
import android.util.Log;
-
/**
* The PTP provider supports accessing content on PTP devices.
- * @hide
+ * Currently the provider supports:
+ * - enumerating the storage units, files and directories on PTP devices
+ * - deleting files and directories on PTP devices
+ * - importing a file from PTP device into the host device's storage
+ * and adding it to the media provider
*/
public final class Ptp
{
@@ -36,6 +39,8 @@
/**
* Contains list of all PTP devices
+ * The BaseColumns._ID column contains a hardware specific identifier for the attached
+ * USB device, and is not guaranteed to be persistent across USB disconnects.
*/
public static final class Device implements BaseColumns {
@@ -59,7 +64,8 @@
}
/**
- * Contains list of storage units for an PTP device
+ * Contains list of storage units for an PTP device.
+ * The BaseColumns._ID column contains the PTP StorageID for the storage unit.
*/
public static final class Storage implements BaseColumns {
@@ -85,7 +91,10 @@
}
/**
- * Contains list of objects on an PTP device
+ * Contains list of objects on a PTP device.
+ * The columns in this table correspond directly to the ObjectInfo dataset
+ * described in the PTP specification (PIMA 15740:2000).
+ * The BaseColumns._ID column contains the object's PTP ObjectHandle.
*/
public static final class Object implements BaseColumns {
@@ -135,14 +144,14 @@
public static final String STORAGE_ID = "storage_id";
/**
- * The object's format. Can be one of the FORMAT_* symbols below,
- * or any of the valid PTP object formats as defined in the PTP specification.
+ * The object's format. Can be any of the valid PTP object formats
+ * as defined in the PTP specification.
* <P>Type: INTEGER</P>
*/
public static final String FORMAT = "format";
/**
- * The protection status of the object. See the PROTECTION_STATUS_*symbols below.
+ * The protection status of the object.
* <P>Type: INTEGER</P>
*/
public static final String PROTECTION_STATUS = "protection_status";
@@ -154,8 +163,8 @@
public static final String SIZE = "size";
/**
- * The object's thumbnail format. Can be one of the FORMAT_* symbols below,
- * or any of the valid PTP object formats as defined in the PTP specification.
+ * The object's thumbnail format. Can be any of the valid PTP object formats
+ * as defined in the PTP specification.
* <P>Type: INTEGER</P>
*/
public static final String THUMB_FORMAT = "thumb_format";
@@ -211,7 +220,6 @@
/**
* The association type for a container object.
- * For folders this is typically {@link #ASSOCIATION_TYPE_GENERIC_FOLDER}
* <P>Type: INTEGER</P>
*/
public static final String ASSOCIATION_TYPE = "association_type";
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/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 43434d3..ced8e9b 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -89,6 +89,7 @@
import android.util.Log;
import android.util.TypedValue;
import android.view.ActionMode;
+import android.view.ActionMode.Callback;
import android.view.ContextMenu;
import android.view.DragEvent;
import android.view.Gravity;
@@ -314,6 +315,7 @@
Drawable mSelectHandleCenter;
private int mLastDownPositionX, mLastDownPositionY;
+ private Callback mCustomSelectionActionModeCallback;
/*
* Kick-start the font cache for the zygote process (to pay the cost of
@@ -6869,7 +6871,7 @@
}
if (mSelectAllOnFocus) {
- Selection.setSelection((Spannable) mText, 0, mText.length());
+ selectAll();
}
mTouchFocusSelected = true;
@@ -7401,10 +7403,8 @@
return false;
}
- if (mText.length() > 0 && hasSelection()) {
- if (mText instanceof Editable && mInput != null) {
- return true;
- }
+ if (mText.length() > 0 && hasSelection() && mText instanceof Editable && mInput != null) {
+ return true;
}
return false;
@@ -7524,13 +7524,17 @@
return (int) (range & 0x00000000FFFFFFFFL);
}
+ private void selectAll() {
+ Selection.setSelection((Spannable) mText, 0, mText.length());
+ }
+
private void selectCurrentWord() {
if (hasPasswordTransformationMethod()) {
// selectCurrentWord is not available on a password field and would return an
// arbitrary 10-charater selection around pressed position. Select all instead.
// Note that cut/copy menu entries are not available for passwords.
// This is however useful to delete or paste to replace the entire content.
- Selection.setSelection((Spannable) mText, 0, mText.length());
+ selectAll();
return;
}
@@ -7862,16 +7866,36 @@
}
/**
- * Provides the callback used to start a selection action mode.
+ * If provided, this ActionMode.Callback will be used to create the ActionMode when text
+ * selection is initiated in this View.
*
- * @return A callback instance that will be used to start selection mode, or null if selection
- * mode is not available.
+ * The standard implementation populates the menu with a subset of Select All, Cut, Copy and
+ * Paste actions, depending on what this View supports.
+ *
+ * A custom implementation can add new entries in the default menu in its
+ * {@link ActionMode.Callback#onPrepareActionMode(ActionMode, Menu)} method. The default actions
+ * can also be removed from the menu using {@link Menu#removeItem(int)} and passing
+ * {@link android.R.id#selectAll}, {@link android.R.id#cut}, {@link android.R.id#copy} or
+ * {@link android.R.id#paste} ids as parameters.
+ *
+ * Action click events should be handled by the custom implementation of
+ * {@link ActionMode.Callback#onActionItemClicked(ActionMode, MenuItem)}.
+ *
+ * Note that text selection mode is not started when a TextView receives focus and the
+ * {@link android.R.attr#selectAllOnFocus} flag has been set. The content is highlighted in
+ * that case, to allow for quick replacement.
*/
- private ActionMode.Callback getActionModeCallback() {
- if (canSelectText()) {
- return new SelectionActionModeCallback();
- }
- return null;
+ public void setCustomSelectionActionModeCallback(ActionMode.Callback actionModeCallback) {
+ mCustomSelectionActionModeCallback = actionModeCallback;
+ }
+
+ /**
+ * Retrieves the value set in {@link #setCustomSelectionActionModeCallback}. Default is null.
+ *
+ * @return The current custom selection callback.
+ */
+ public ActionMode.Callback getCustomSelectionActionModeCallback() {
+ return mCustomSelectionActionModeCallback;
}
/**
@@ -7884,7 +7908,8 @@
return false;
}
- ActionMode.Callback actionModeCallback = getActionModeCallback();
+ selectCurrentWord();
+ ActionMode.Callback actionModeCallback = new SelectionActionModeCallback();
if (actionModeCallback != null) {
mSelectionActionMode = startActionMode(actionModeCallback);
return mSelectionActionMode != null;
@@ -7950,6 +7975,12 @@
sLastCutOrCopyTime = SystemClock.uptimeMillis();
}
+ /**
+ * An ActionMode Callback class that is used to provide actions while in text selection mode.
+ *
+ * The default callback provides a subset of Select All, Cut, Copy and Paste actions, depending
+ * on which of these this TextView supports.
+ */
private class SelectionActionModeCallback implements ActionMode.Callback {
@Override
@@ -7968,48 +7999,47 @@
mode.setTitle(mContext.getString(com.android.internal.R.string.textSelectionCABTitle));
mode.setSubtitle(null);
- boolean atLeastOne = false;
-
if (canSelectText()) {
- selectCurrentWord();
-
menu.add(0, ID_SELECT_ALL, 0, com.android.internal.R.string.selectAll).
setAlphabeticShortcut('a').
setShowAsAction(
MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
- atLeastOne = true;
}
if (canCut()) {
menu.add(0, ID_CUT, 0, com.android.internal.R.string.cut).
- setIcon(styledAttributes.getResourceId(R.styleable.Theme_actionModeCutDrawable, 0)).
+ setIcon(styledAttributes.getResourceId(
+ R.styleable.Theme_actionModeCutDrawable, 0)).
setAlphabeticShortcut('x').
setShowAsAction(
MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
- atLeastOne = true;
}
if (canCopy()) {
menu.add(0, ID_COPY, 0, com.android.internal.R.string.copy).
- setIcon(styledAttributes.getResourceId(R.styleable.Theme_actionModeCopyDrawable, 0)).
+ setIcon(styledAttributes.getResourceId(
+ R.styleable.Theme_actionModeCopyDrawable, 0)).
setAlphabeticShortcut('c').
setShowAsAction(
MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
- atLeastOne = true;
}
if (canPaste()) {
menu.add(0, ID_PASTE, 0, com.android.internal.R.string.paste).
- setIcon(styledAttributes.getResourceId(R.styleable.Theme_actionModePasteDrawable, 0)).
+ setIcon(styledAttributes.getResourceId(
+ R.styleable.Theme_actionModePasteDrawable, 0)).
setAlphabeticShortcut('v').
setShowAsAction(
MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
- atLeastOne = true;
}
styledAttributes.recycle();
- if (atLeastOne) {
+ if (mCustomSelectionActionModeCallback != null) {
+ mCustomSelectionActionModeCallback.onCreateActionMode(mode, menu);
+ }
+
+ if (menu.hasVisibleItems() || mode.getCustomView() != null) {
getSelectionController().show();
return true;
} else {
@@ -8019,15 +8049,23 @@
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
+ if (mCustomSelectionActionModeCallback != null) {
+ return mCustomSelectionActionModeCallback.onPrepareActionMode(mode, menu);
+ }
return true;
}
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
+ if (mCustomSelectionActionModeCallback != null &&
+ mCustomSelectionActionModeCallback.onActionItemClicked(mode, item)) {
+ return true;
+ }
+
final int itemId = item.getItemId();
if (itemId == ID_SELECT_ALL) {
- Selection.setSelection((Spannable) mText, 0, mText.length());
+ selectAll();
// Update controller positions after selection change.
if (hasSelectionController()) {
getSelectionController().show();
@@ -8070,6 +8108,9 @@
@Override
public void onDestroyActionMode(ActionMode mode) {
+ if (mCustomSelectionActionModeCallback != null) {
+ mCustomSelectionActionModeCallback.onDestroyActionMode(mode);
+ }
Selection.setSelection((Spannable) mText, getSelectionStart());
hideSelectionModifierCursorController();
mSelectionActionMode = null;
diff --git a/core/java/com/android/internal/util/AsyncChannel.java b/core/java/com/android/internal/util/AsyncChannel.java
index 0891acc..101dd91 100644
--- a/core/java/com/android/internal/util/AsyncChannel.java
+++ b/core/java/com/android/internal/util/AsyncChannel.java
@@ -95,7 +95,7 @@
*
* msg.arg1 == 0 : STATUS_SUCCESSFUL
* 1 : STATUS_BINDING_UNSUCCESSFUL
- * msg.arg2 == token parameter
+ * msg.obj == the AsyncChannel
* msg.replyTo == dstMessenger if successful
*/
public static final int CMD_CHANNEL_HALF_CONNECTED = -1;
@@ -136,7 +136,7 @@
*
* msg.arg1 == 0 : STATUS_SUCCESSFUL
* : All other values signify failure and the channel state is indeterminate
- * msg.arg2 == token parameter
+ * msg.obj == the AsyncChannel
* msg.replyTo = messenger disconnecting or null if it was never connected.
*/
public static final int CMD_CHANNEL_DISCONNECTED = -5;
@@ -179,14 +179,12 @@
* @param dstPackageName is the destination package name
* @param dstClassName is the fully qualified class name (i.e. contains
* package name)
- * @param token unique id for this connection
*/
private void connectSrcHandlerToPackage(
- Context srcContext, Handler srcHandler, String dstPackageName, String dstClassName,
- int token) {
+ Context srcContext, Handler srcHandler, String dstPackageName, String dstClassName) {
if (DBG) log("connect srcHandler to dst Package & class E");
- mConnection = new AsyncChannelConnection(token);
+ mConnection = new AsyncChannelConnection();
/* Initialize the source information */
mSrcContext = srcContext;
@@ -205,7 +203,7 @@
intent.setClassName(dstPackageName, dstClassName);
boolean result = srcContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
if (!result) {
- replyHalfConnected(STATUS_BINDING_UNSUCCESSFUL, token);
+ replyHalfConnected(STATUS_BINDING_UNSUCCESSFUL);
}
if (DBG) log("connect srcHandler to dst Package & class X result=" + result);
@@ -216,7 +214,7 @@
*
* Sends a CMD_CHANNEL_HALF_CONNECTED message to srcHandler when complete.
* msg.arg1 = status
- * msg.arg2 = token
+ * msg.obj = the AsyncChannel
*
* @param srcContext is the context of the source
* @param srcHandler is the hander to receive CONNECTED & DISCONNECTED
@@ -224,10 +222,9 @@
* @param dstPackageName is the destination package name
* @param dstClassName is the fully qualified class name (i.e. contains
* package name)
- * @param token returned in msg.arg2
*/
public void connect(Context srcContext, Handler srcHandler, String dstPackageName,
- String dstClassName, int token) {
+ String dstClassName) {
if (DBG) log("connect srcHandler to dst Package & class E");
final class ConnectAsync implements Runnable {
@@ -235,25 +232,21 @@
Handler mSrcHdlr;
String mDstPackageName;
String mDstClassName;
- int mToken;
ConnectAsync(Context srcContext, Handler srcHandler, String dstPackageName,
- String dstClassName, int token) {
+ String dstClassName) {
mSrcCtx = srcContext;
mSrcHdlr = srcHandler;
mDstPackageName = dstPackageName;
mDstClassName = dstClassName;
- mToken = token;
}
public void run() {
- connectSrcHandlerToPackage(mSrcCtx, mSrcHdlr, mDstPackageName, mDstClassName,
- mToken);
+ connectSrcHandlerToPackage(mSrcCtx, mSrcHdlr, mDstPackageName, mDstClassName);
}
}
- ConnectAsync ca = new ConnectAsync(srcContext, srcHandler, dstPackageName, dstClassName,
- token);
+ ConnectAsync ca = new ConnectAsync(srcContext, srcHandler, dstPackageName, dstClassName);
new Thread(ca).start();
if (DBG) log("connect srcHandler to dst Package & class X");
@@ -264,15 +257,14 @@
*
* Sends a CMD_CHANNEL_HALF_CONNECTED message to srcHandler when complete.
* msg.arg1 = status
- * msg.arg2 = token
+ * msg.obj = the AsyncChannel
*
* @param srcContext
* @param srcHandler
* @param klass is the class to send messages to.
- * @param token returned in msg.arg2
*/
- public void connect(Context srcContext, Handler srcHandler, Class<?> klass, int token) {
- connect(srcContext, srcHandler, klass.getPackage().getName(), klass.getName(), token);
+ public void connect(Context srcContext, Handler srcHandler, Class<?> klass) {
+ connect(srcContext, srcHandler, klass.getPackage().getName(), klass.getName());
}
/**
@@ -280,14 +272,13 @@
*
* Sends a CMD_CHANNEL_HALF_CONNECTED message to srcHandler when complete.
* msg.arg1 = status
- * msg.arg2 = token
+ * msg.obj = the AsyncChannel
*
* @param srcContext
* @param srcHandler
* @param dstMessenger
- * @param token returned in msg.arg2
*/
- public void connect(Context srcContext, Handler srcHandler, Messenger dstMessenger, int token) {
+ public void connect(Context srcContext, Handler srcHandler, Messenger dstMessenger) {
if (DBG) log("connect srcHandler to the dstMessenger E");
// Initialize source fields
@@ -301,7 +292,7 @@
if (DBG) log("tell source we are half connected");
// Tell source we are half connected
- replyHalfConnected(STATUS_SUCCESSFUL, token);
+ replyHalfConnected(STATUS_SUCCESSFUL);
if (DBG) log("connect srcHandler to the dstMessenger X");
}
@@ -311,16 +302,15 @@
*
* Sends a CMD_CHANNEL_HALF_CONNECTED message to srcHandler when complete.
* msg.arg1 = status
- * msg.arg2 = token
+ * msg.obj = the AsyncChannel
*
* @param srcContext is the context of the source
* @param srcHandler is the hander to receive CONNECTED & DISCONNECTED
* messages
* @param dstHandler is the hander to send messages to.
- * @param token returned in msg.arg2
*/
- public void connect(Context srcContext, Handler srcHandler, Handler dstHandler, int token) {
- connect(srcContext, srcHandler, new Messenger(dstHandler), token);
+ public void connect(Context srcContext, Handler srcHandler, Handler dstHandler) {
+ connect(srcContext, srcHandler, new Messenger(dstHandler));
}
/**
@@ -328,14 +318,13 @@
*
* Sends a CMD_CHANNEL_HALF_CONNECTED message to srcAsyncService when complete.
* msg.arg1 = status
- * msg.arg2 = token
+ * msg.obj = the AsyncChannel
*
* @param srcAsyncService
* @param dstMessenger
- * @param token returned in msg.arg2
*/
- public void connect(AsyncService srcAsyncService, Messenger dstMessenger, int token) {
- connect(srcAsyncService, srcAsyncService.getHandler(), dstMessenger, token);
+ public void connect(AsyncService srcAsyncService, Messenger dstMessenger) {
+ connect(srcAsyncService, srcAsyncService.getHandler(), dstMessenger);
}
/**
@@ -351,15 +340,14 @@
/**
* Disconnect
*/
- public void disconnect(int token) {
+ public void disconnect() {
if (mConnection != null) {
- mConnection.setToken(token);
mSrcContext.unbindService(mConnection);
}
if (mSrcHandler != null) {
Message msg = mSrcHandler.obtainMessage(CMD_CHANNEL_DISCONNECTED);
msg.arg1 = STATUS_SUCCESSFUL;
- msg.arg2 = token;
+ msg.obj = this;
msg.replyTo = mDstMessenger;
mSrcHandler.sendMessage(msg);
}
@@ -727,10 +715,10 @@
*
* @param status to be stored in msg.arg1
*/
- private void replyHalfConnected(int status, int token) {
+ private void replyHalfConnected(int status) {
Message msg = mSrcHandler.obtainMessage(CMD_CHANNEL_HALF_CONNECTED);
msg.arg1 = status;
- msg.arg2 = token;
+ msg.obj = this;
msg.replyTo = mDstMessenger;
mSrcHandler.sendMessage(msg);
}
@@ -739,28 +727,18 @@
* ServiceConnection to receive call backs.
*/
class AsyncChannelConnection implements ServiceConnection {
- private int mToken;
-
- AsyncChannelConnection(int token) {
- mToken = token;
- }
-
- /**
- * @param token
- */
- public void setToken(int token) {
- mToken = token;
+ AsyncChannelConnection() {
}
public void onServiceConnected(ComponentName className, IBinder service) {
mDstMessenger = new Messenger(service);
- replyHalfConnected(STATUS_SUCCESSFUL, mToken);
+ replyHalfConnected(STATUS_SUCCESSFUL);
}
public void onServiceDisconnected(ComponentName className) {
Message msg = mSrcHandler.obtainMessage(CMD_CHANNEL_DISCONNECTED);
msg.arg1 = STATUS_SUCCESSFUL;
- msg.arg2 = mToken;
+ msg.obj = AsyncChannel.this;
msg.replyTo = mDstMessenger;
mSrcHandler.sendMessage(msg);
}
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/res/res/values-id-rID/arrays.xml b/core/res/res/values-in-rID/arrays.xml
similarity index 100%
rename from core/res/res/values-id-rID/arrays.xml
rename to core/res/res/values-in-rID/arrays.xml
diff --git a/core/res/res/values-id-rID/donottranslate-cldr.xml b/core/res/res/values-in-rID/donottranslate-cldr.xml
similarity index 100%
rename from core/res/res/values-id-rID/donottranslate-cldr.xml
rename to core/res/res/values-in-rID/donottranslate-cldr.xml
diff --git a/core/res/res/values-id/donottranslate-cldr.xml b/core/res/res/values-in/donottranslate-cldr.xml
similarity index 100%
rename from core/res/res/values-id/donottranslate-cldr.xml
rename to core/res/res/values-in/donottranslate-cldr.xml
diff --git a/core/res/res/values-id/strings.xml b/core/res/res/values-in/strings.xml
similarity index 100%
rename from core/res/res/values-id/strings.xml
rename to core/res/res/values-in/strings.xml
diff --git a/core/res/res/values-he-rIL/arrays.xml b/core/res/res/values-iw-rIL/arrays.xml
similarity index 100%
rename from core/res/res/values-he-rIL/arrays.xml
rename to core/res/res/values-iw-rIL/arrays.xml
diff --git a/core/res/res/values-he/donottranslate-cldr.xml b/core/res/res/values-iw/donottranslate-cldr.xml
similarity index 100%
rename from core/res/res/values-he/donottranslate-cldr.xml
rename to core/res/res/values-iw/donottranslate-cldr.xml
diff --git a/core/res/res/values-he/strings.xml b/core/res/res/values-iw/strings.xml
similarity index 100%
rename from core/res/res/values-he/strings.xml
rename to core/res/res/values-iw/strings.xml
diff --git a/core/res/res/values-xlarge/dimens.xml b/core/res/res/values-xlarge/dimens.xml
index fef3c13..c67bbb7 100644
--- a/core/res/res/values-xlarge/dimens.xml
+++ b/core/res/res/values-xlarge/dimens.xml
@@ -37,4 +37,7 @@
<dimen name="thumbnail_width">160dp</dimen>
<!-- The height that is used when creating thumbnails of applications. -->
<dimen name="thumbnail_height">100dp</dimen>
+ <!-- The standard size (both width and height) of an application icon that
+ will be displayed in the app launcher and elsewhere. -->
+ <dimen name="app_icon_size">64dip</dimen>
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index eafa9b6..0f5ff05 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1806,7 +1806,7 @@
<!-- Do not translate. WebView User Agent string -->
<string name="web_user_agent" translatable="false">Mozilla/5.0 (Linux; U; <xliff:g id="x">Android %s</xliff:g>)
- AppleWebKit/534.12 (KHTML, like Gecko) Version/4.0 <xliff:g id="mobile">%s</xliff:g>Safari/534.12</string>
+ AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 <xliff:g id="mobile">%s</xliff:g>Safari/534.13</string>
<!-- Do not translate. WebView User Agent targeted content -->
<string name="web_user_agent_target_content" translatable="false">"Mobile "</string>
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 cfceaab1..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/hwui/SkiaColorFilter.cpp b/libs/hwui/SkiaColorFilter.cpp
index 91b1c32..b86bbc5 100644
--- a/libs/hwui/SkiaColorFilter.cpp
+++ b/libs/hwui/SkiaColorFilter.cpp
@@ -36,6 +36,11 @@
SkiaColorMatrixFilter::SkiaColorMatrixFilter(SkColorFilter *skFilter, float* matrix, float* vector):
SkiaColorFilter(skFilter, kColorMatrix, true), mMatrix(matrix), mVector(vector) {
+ // Skia uses the range [0..255] for the addition vector, but we need
+ // the [0..1] range to apply the vector in GLSL
+ for (int i = 0; i < 4; i++) {
+ mVector[i] /= 255.0f;
+ }
}
SkiaColorMatrixFilter::~SkiaColorMatrixFilter() {
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/media/java/android/media/MediaFile.java b/media/java/android/media/MediaFile.java
index 0e689e4..beac04c 100644
--- a/media/java/android/media/MediaFile.java
+++ b/media/java/android/media/MediaFile.java
@@ -194,6 +194,7 @@
addFileType("WBMP", FILE_TYPE_WBMP, "image/vnd.wap.wbmp");
addFileType("M3U", FILE_TYPE_M3U, "audio/x-mpegurl", MtpConstants.FORMAT_M3U_PLAYLIST);
+ addFileType("M3U", FILE_TYPE_M3U, "application/x-mpegurl", MtpConstants.FORMAT_M3U_PLAYLIST);
addFileType("PLS", FILE_TYPE_PLS, "audio/x-scpls", MtpConstants.FORMAT_PLS_PLAYLIST);
addFileType("WPL", FILE_TYPE_WPL, "application/vnd.ms-wpl", MtpConstants.FORMAT_WPL_PLAYLIST);
addFileType("M3U8", FILE_TYPE_HTTPLIVE, "application/vnd.apple.mpegurl");
diff --git a/media/java/android/media/videoeditor/VideoEditor.java b/media/java/android/media/videoeditor/VideoEditor.java
index 64d3229..37bb661 100755
--- a/media/java/android/media/videoeditor/VideoEditor.java
+++ b/media/java/android/media/videoeditor/VideoEditor.java
@@ -98,6 +98,31 @@
}
/**
+ * This listener interface is used by the VideoEditor to emit export status
+ * notifications.
+ * {@link #generatePreview(MediaProcessingProgressListener listener)}
+ */
+ public interface MediaProcessingProgressListener {
+ // Values used for the action parameter
+ public static final int ACTION_ENCODE = 1;
+ public static final int ACTION_DECODE = 2;
+
+ /**
+ * This method notifies the listener of the progress status of
+ * processing a media object such as a Transition, AudioTrack or a
+ * media image item (when Ken Burns effect is applied).
+ * This method may be called maximum 100 times for one operation.
+ *
+ * @param object The object that is being processed such as a
+ * Transition or AudioTrack
+ * @param action The type of processing being performed
+ * @param progress The progress in %. At the beginning of the operation,
+ * this value is set to 0; at the end, the value is set to 100.
+ */
+ public void onProgress(Object item, int action, int progress);
+ }
+
+ /**
* @return The path where the VideoEditor stores all files related to the
* project
*/
@@ -496,8 +521,11 @@
* This method must be called after the aspect ratio of the project changes
* and before startPreview is called. Note that this method may block for
* an extensive period of time.
+ *
+ * @param listener The listener interface which will be used to notify
+ * the caller of the progress of each storyboard item being processed.
*/
- public void generatePreview();
+ public void generatePreview(MediaProcessingProgressListener listener);
/**
* Start the preview of all the storyboard items applied on all MediaItems
diff --git a/media/java/android/media/videoeditor/VideoEditorFactory.java b/media/java/android/media/videoeditor/VideoEditorFactory.java
index 41eed16..85b2666 100755
--- a/media/java/android/media/videoeditor/VideoEditorFactory.java
+++ b/media/java/android/media/videoeditor/VideoEditorFactory.java
@@ -19,8 +19,8 @@
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
+
+import android.media.videoeditor.VideoEditor.MediaProcessingProgressListener;
/**
@@ -30,34 +30,19 @@
* {@hide}
*/
public class VideoEditorFactory {
- // VideoEditor implementation classes
- public static final String TEST_CLASS_IMPLEMENTATION
- = "android.media.videoeditor.VideoEditorTestImpl";
- public static final String DEFAULT_CLASS_IMPLEMENTATION
- = "android.media.videoeditor.VideoEditorImpl";
-
/**
* This is the factory method for creating a new VideoEditor instance.
*
* @param projectPath The path where all VideoEditor internal
* files are stored. When a project is deleted the application is
* responsible for deleting the path and its contents.
- * @param className The implementation class name
*
* @return The VideoEditor instance
*
* @throws IOException if path does not exist or if the path can
* not be accessed in read/write mode
- * @throws IllegalStateException if a previous VideoEditor instance has not
- * been released
- * @throws ClassNotFoundException, NoSuchMethodException,
- * InvocationTargetException, IllegalAccessException,
- * InstantiationException if the implementation class cannot
- * be instantiated.
*/
- public static VideoEditor create(String projectPath, String className) throws IOException,
- ClassNotFoundException, NoSuchMethodException, InvocationTargetException,
- IllegalAccessException, InstantiationException {
+ public static VideoEditor create(String projectPath) throws IOException {
// If the project path does not exist create it
final File dir = new File(projectPath);
if (!dir.exists()) {
@@ -72,14 +57,7 @@
}
}
- final Class<?> cls = Class.forName(className);
- final Class<?> partypes[] = new Class[1];
- partypes[0] = String.class;
- final Constructor<?> ct = cls.getConstructor(partypes);
- final Object arglist[] = new Object[1];
- arglist[0] = projectPath;
-
- return (VideoEditor)ct.newInstance(arglist);
+ return new VideoEditorImpl(projectPath);
}
/**
@@ -90,32 +68,21 @@
* @param projectPath The path where all VideoEditor internal files
* are stored. When a project is deleted the application is
* responsible for deleting the path and its contents.
- * @param className The implementation class name
* @param generatePreview if set to true the
- * {@link MediaEditor#generatePreview()} will be called internally to
- * generate any needed transitions.
+ * {@link MediaEditor#generatePreview(MediaProcessingProgressListener listener)}
+ * will be called internally to generate any needed transitions.
*
* @return The VideoEditor instance
*
* @throws IOException if path does not exist or if the path can
* not be accessed in read/write mode or if one of the resource
* media files cannot be retrieved
- * @throws IllegalStateException if a previous VideoEditor instance has not
- * been released
*/
- public static VideoEditor load(String projectPath, String className, boolean generatePreview)
- throws IOException, ClassNotFoundException, NoSuchMethodException,
- InvocationTargetException, IllegalAccessException, InstantiationException {
- final Class<?> cls = Class.forName(className);
- final Class<?> partypes[] = new Class[1];
- partypes[0] = String.class;
- final Constructor<?> ct = cls.getConstructor(partypes);
- final Object arglist[] = new Object[1];
- arglist[0] = projectPath;
-
- final VideoEditor videoEditor = (VideoEditor)ct.newInstance(arglist);
+ public static VideoEditor load(String projectPath, boolean generatePreview)
+ throws IOException {
+ final VideoEditor videoEditor = new VideoEditorImpl(projectPath);
if (generatePreview) {
- videoEditor.generatePreview();
+ videoEditor.generatePreview(null);
}
return videoEditor;
}
diff --git a/media/java/android/media/videoeditor/VideoEditorTestImpl.java b/media/java/android/media/videoeditor/VideoEditorImpl.java
similarity index 98%
rename from media/java/android/media/videoeditor/VideoEditorTestImpl.java
rename to media/java/android/media/videoeditor/VideoEditorImpl.java
index ca896c3..1a145e6 100644
--- a/media/java/android/media/videoeditor/VideoEditorTestImpl.java
+++ b/media/java/android/media/videoeditor/VideoEditorImpl.java
@@ -39,7 +39,7 @@
/**
* The VideoEditor implementation {@hide}
*/
-public class VideoEditorTestImpl implements VideoEditor {
+public class VideoEditorImpl implements VideoEditor {
// Logging
private static final String TAG = "VideoEditorImpl";
@@ -165,7 +165,7 @@
if (mPositionMs >= mToMs) {
if (!mLoop) {
if (mListener != null) {
- mListener.onProgress(VideoEditorTestImpl.this, mPositionMs, true);
+ mListener.onProgress(VideoEditorImpl.this, mPositionMs, true);
}
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "PreviewThread.run playback complete");
@@ -174,13 +174,13 @@
} else {
// Fire a notification for the end of the clip
if (mListener != null) {
- mListener.onProgress(VideoEditorTestImpl.this, mToMs, false);
+ mListener.onProgress(VideoEditorImpl.this, mToMs, false);
}
// Rewind
mPositionMs = mFromMs;
if (mListener != null) {
- mListener.onProgress(VideoEditorTestImpl.this, mPositionMs, false);
+ mListener.onProgress(VideoEditorImpl.this, mPositionMs, false);
}
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "PreviewThread.run playback complete");
@@ -190,7 +190,7 @@
} else {
if (frameCount == mCallbackAfterFrameCount) {
if (mListener != null) {
- mListener.onProgress(VideoEditorTestImpl.this, mPositionMs, false);
+ mListener.onProgress(VideoEditorImpl.this, mPositionMs, false);
}
frameCount = 0;
}
@@ -222,7 +222,7 @@
*
* @param projectPath
*/
- public VideoEditorTestImpl(String projectPath) throws IOException {
+ public VideoEditorImpl(String projectPath) throws IOException {
mProjectPath = projectPath;
final File projectXml = new File(projectPath, PROJECT_FILENAME);
if (projectXml.exists()) {
@@ -1055,7 +1055,7 @@
/*
* {@inheritDoc}
*/
- public void generatePreview() {
+ public void generatePreview(MediaProcessingProgressListener listener) {
// Generate all the needed transitions
for (Transition transition : mTransitions) {
if (!transition.isGenerated()) {
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index ec3b5a2..cee92d2 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -366,6 +366,9 @@
return BAD_VALUE;
}
+ if (timeUs <= 15 * 1000000LL) {
+ LOGW("Target duration (%lld us) too short to be respected", timeUs);
+ }
mMaxFileDurationUs = timeUs;
return OK;
}
@@ -376,6 +379,11 @@
LOGE("Max file size is too small: %lld bytes", bytes);
return BAD_VALUE;
}
+
+ if (bytes <= 100 * 1024) {
+ LOGW("Target file size (%lld bytes) is too small to be respected", bytes);
+ }
+
mMaxFileSizeBytes = bytes;
return OK;
}
@@ -1156,8 +1164,11 @@
CHECK_EQ(client.connect(), OK);
// Use software codec for time lapse
- uint32_t encoder_flags = (mCaptureTimeLapse) ? OMXCodec::kPreferSoftwareCodecs : 0;
- if (mIsMetaDataStoredInVideoBuffers) {
+ uint32_t encoder_flags = 0;
+ if (mCaptureTimeLapse) {
+ encoder_flags |= OMXCodec::kPreferSoftwareCodecs;
+ } else if (mIsMetaDataStoredInVideoBuffers) {
+ encoder_flags |= OMXCodec::kHardwareCodecsOnly;
encoder_flags |= OMXCodec::kStoreMetaDataInVideoBuffers;
}
sp<MediaSource> encoder = OMXCodec::Create(
@@ -1165,6 +1176,11 @@
true /* createEncoder */, cameraSource,
NULL, encoder_flags);
if (encoder == NULL) {
+ LOGW("Failed to create the encoder");
+ // When the encoder fails to be created, we need
+ // release the camera source due to the camera's lock
+ // and unlock mechanism.
+ cameraSource->stop();
return UNKNOWN_ERROR;
}
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index a804866..8ebbe6c 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -426,7 +426,8 @@
// Hack to support http live.
size_t len = strlen(uri);
- if (!strcasecmp(&uri[len - 5], ".m3u8")) {
+ if (!strcasecmp(&uri[len - 5], ".m3u8")
+ || strstr(&uri[7], "m3u8") != NULL) {
mUri = "httplive://";
mUri.append(&uri[7]);
}
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 6760707..602aa9f 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -878,7 +878,10 @@
nTotalBytesEstimate += (*it)->getEstimatedTrackSizeBytes();
}
- return (nTotalBytesEstimate >= mMaxFileSizeLimitBytes);
+ // Be conservative in the estimate: do not exceed 95% of
+ // the target file limit. For small target file size limit, though,
+ // this will not help.
+ return (nTotalBytesEstimate >= (95 * mMaxFileSizeLimitBytes) / 100);
}
bool MPEG4Writer::exceedsFileDurationLimit() {
diff --git a/media/libstagefright/codecs/avc/enc/AVCEncoder.cpp b/media/libstagefright/codecs/avc/enc/AVCEncoder.cpp
index e6a0976..e3292e6 100644
--- a/media/libstagefright/codecs/avc/enc/AVCEncoder.cpp
+++ b/media/libstagefright/codecs/avc/enc/AVCEncoder.cpp
@@ -178,7 +178,7 @@
mInputFrameData(NULL),
mGroup(NULL) {
- LOGV("Construct software AVCEncoder");
+ LOGI("Construct software AVCEncoder");
mHandle = new tagAVCHandle;
memset(mHandle, 0, sizeof(tagAVCHandle));
diff --git a/media/libstagefright/codecs/m4v_h263/enc/M4vH263Encoder.cpp b/media/libstagefright/codecs/m4v_h263/enc/M4vH263Encoder.cpp
index c7a475b..15ed219 100644
--- a/media/libstagefright/codecs/m4v_h263/enc/M4vH263Encoder.cpp
+++ b/media/libstagefright/codecs/m4v_h263/enc/M4vH263Encoder.cpp
@@ -178,7 +178,7 @@
mInputFrameData(NULL),
mGroup(NULL) {
- LOGV("Construct software M4vH263Encoder");
+ LOGI("Construct software M4vH263Encoder");
mHandle = new tagvideoEncControls;
memset(mHandle, 0, sizeof(tagvideoEncControls));
diff --git a/media/libstagefright/httplive/LiveSource.cpp b/media/libstagefright/httplive/LiveSource.cpp
index 4b4c3d2..4451bd5 100644
--- a/media/libstagefright/httplive/LiveSource.cpp
+++ b/media/libstagefright/httplive/LiveSource.cpp
@@ -359,14 +359,6 @@
return false;
}
- if (keyURI.size() >= 2
- && keyURI.c_str()[0] == '"'
- && keyURI.c_str()[keyURI.size() - 1] == '"') {
- // Remove surrounding quotes.
- AString tmp(keyURI, 1, keyURI.size() - 2);
- keyURI = tmp;
- }
-
ssize_t index = mAESKeyForURI.indexOfKey(keyURI);
sp<ABuffer> key;
diff --git a/media/libstagefright/httplive/M3UParser.cpp b/media/libstagefright/httplive/M3UParser.cpp
index b166cc3..d4a29c0 100644
--- a/media/libstagefright/httplive/M3UParser.cpp
+++ b/media/libstagefright/httplive/M3UParser.cpp
@@ -162,7 +162,7 @@
if (mIsVariantPlaylist) {
return ERROR_MALFORMED;
}
- err = parseCipherInfo(line, &itemMeta);
+ err = parseCipherInfo(line, &itemMeta, mBaseURI);
} else if (line.startsWith("#EXT-X-ENDLIST")) {
mIsComplete = true;
} else if (line.startsWith("#EXTINF")) {
@@ -298,7 +298,7 @@
// static
status_t M3UParser::parseCipherInfo(
- const AString &line, sp<AMessage> *meta) {
+ const AString &line, sp<AMessage> *meta, const AString &baseURI) {
ssize_t colonPos = line.find(":");
if (colonPos < 0) {
@@ -338,6 +338,24 @@
*meta = new AMessage;
}
+ if (key == "uri") {
+ if (val.size() >= 2
+ && val.c_str()[0] == '"'
+ && val.c_str()[val.size() - 1] == '"') {
+ // Remove surrounding quotes.
+ AString tmp(val, 1, val.size() - 2);
+ val = tmp;
+ }
+
+ AString absURI;
+ if (MakeURL(baseURI.c_str(), val.c_str(), &absURI)) {
+ val = absURI;
+ } else {
+ LOGE("failed to make absolute url for '%s'.",
+ val.c_str());
+ }
+ }
+
key.insert(AString("cipher-"), 0);
(*meta)->setString(key.c_str(), val.c_str(), val.size());
diff --git a/media/libstagefright/include/M3UParser.h b/media/libstagefright/include/M3UParser.h
index 531d184..63895b4 100644
--- a/media/libstagefright/include/M3UParser.h
+++ b/media/libstagefright/include/M3UParser.h
@@ -67,7 +67,7 @@
const AString &line, sp<AMessage> *meta);
static status_t parseCipherInfo(
- const AString &line, sp<AMessage> *meta);
+ const AString &line, sp<AMessage> *meta, const AString &baseURI);
static status_t ParseInt32(const char *s, int32_t *x);
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index f06a1bb..a559b21d 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -238,10 +238,15 @@
}
sp<MediaSource> ATSParser::Program::getSource(SourceType type) {
+ size_t index = (type == MPEG2ADTS_AUDIO) ? 0 : 0;
+
for (size_t i = 0; i < mStreams.size(); ++i) {
sp<MediaSource> source = mStreams.editValueAt(i)->getSource(type);
if (source != NULL) {
- return source;
+ if (index == 0) {
+ return source;
+ }
+ --index;
}
}
@@ -508,7 +513,10 @@
int64_t timeUs = mProgram->convertPTSToTimestamp(PTS);
status_t err = mQueue.appendData(data, size, timeUs);
- CHECK_EQ(err, (status_t)OK);
+
+ if (err != OK) {
+ return;
+ }
sp<ABuffer> accessUnit;
while ((accessUnit = mQueue.dequeueAccessUnit()) != NULL) {
diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp
index f11b3c3..37bcb23 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.cpp
+++ b/media/libstagefright/mpeg2ts/ESQueue.cpp
@@ -55,9 +55,34 @@
switch (mMode) {
case H264:
{
+#if 0
if (size < 4 || memcmp("\x00\x00\x00\x01", data, 4)) {
return ERROR_MALFORMED;
}
+#else
+ uint8_t *ptr = (uint8_t *)data;
+
+ ssize_t startOffset = -1;
+ for (size_t i = 0; i + 3 < size; ++i) {
+ if (!memcmp("\x00\x00\x00\x01", &ptr[i], 4)) {
+ startOffset = i;
+ break;
+ }
+ }
+
+ if (startOffset < 0) {
+ return ERROR_MALFORMED;
+ }
+
+ if (startOffset > 0) {
+ LOGI("found something resembling an H.264 syncword at "
+ "offset %ld",
+ startOffset);
+ }
+
+ data = &ptr[startOffset];
+ size -= startOffset;
+#endif
break;
}
@@ -65,9 +90,31 @@
{
uint8_t *ptr = (uint8_t *)data;
+#if 0
if (size < 2 || ptr[0] != 0xff || (ptr[1] >> 4) != 0x0f) {
return ERROR_MALFORMED;
}
+#else
+ ssize_t startOffset = -1;
+ for (size_t i = 0; i + 1 < size; ++i) {
+ if (ptr[i] == 0xff && (ptr[i + 1] >> 4) == 0x0f) {
+ startOffset = i;
+ break;
+ }
+ }
+
+ if (startOffset < 0) {
+ return ERROR_MALFORMED;
+ }
+
+ if (startOffset > 0) {
+ LOGI("found something resembling an AAC syncword at offset %ld",
+ startOffset);
+ }
+
+ data = &ptr[startOffset];
+ size -= startOffset;
+#endif
break;
}
diff --git a/packages/DefaultContainerService/res/values-id/strings.xml b/packages/DefaultContainerService/res/values-in/strings.xml
similarity index 100%
rename from packages/DefaultContainerService/res/values-id/strings.xml
rename to packages/DefaultContainerService/res/values-in/strings.xml
diff --git a/packages/DefaultContainerService/res/values-he/strings.xml b/packages/DefaultContainerService/res/values-iw/strings.xml
similarity index 100%
rename from packages/DefaultContainerService/res/values-he/strings.xml
rename to packages/DefaultContainerService/res/values-iw/strings.xml
diff --git a/packages/SettingsProvider/res/values-id/strings.xml b/packages/SettingsProvider/res/values-in/strings.xml
similarity index 100%
rename from packages/SettingsProvider/res/values-id/strings.xml
rename to packages/SettingsProvider/res/values-in/strings.xml
diff --git a/packages/SettingsProvider/res/values-he/strings.xml b/packages/SettingsProvider/res/values-iw/strings.xml
similarity index 100%
rename from packages/SettingsProvider/res/values-he/strings.xml
rename to packages/SettingsProvider/res/values-iw/strings.xml
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_default.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_default.png
index 615c8b6..25fffd6 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_default.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_default.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_default.png
index 0122025..b6e4ebc 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_default.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_pressed.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_pressed.png
index 0786916..189a089 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_pressed.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_pressed.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_pressed.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_pressed.png
index 35f9240..ebade92 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_pressed.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_pressed.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_default.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_default.png
index 3eb22df..6ef71c7 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_default.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_pressed.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_pressed.png
index 1ce9bd1..f6b0a17 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_pressed.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_pressed.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu_default.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu_default.png
index fef2cf9..91bc4ee 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu_default.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu_pressed.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu_pressed.png
index 05593bc..aa64de4 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu_pressed.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu_pressed.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent_default.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent_default.png
index 32c2c79..246c6fe 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent_default.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent_pressed.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent_pressed.png
index 142c413..34515c7 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent_pressed.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent_pressed.png
Binary files differ
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-id/strings.xml b/packages/SystemUI/res/values-in/strings.xml
similarity index 100%
rename from packages/SystemUI/res/values-id/strings.xml
rename to packages/SystemUI/res/values-in/strings.xml
diff --git a/packages/SystemUI/res/values-he/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
similarity index 100%
rename from packages/SystemUI/res/values-he/strings.xml
rename to packages/SystemUI/res/values-iw/strings.xml
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 d1f8dd0b..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/packages/VpnServices/res/values-id/strings.xml b/packages/VpnServices/res/values-in/strings.xml
similarity index 100%
rename from packages/VpnServices/res/values-id/strings.xml
rename to packages/VpnServices/res/values-in/strings.xml
diff --git a/packages/VpnServices/res/values-he/strings.xml b/packages/VpnServices/res/values-iw/strings.xml
similarity index 100%
rename from packages/VpnServices/res/values-he/strings.xml
rename to packages/VpnServices/res/values-iw/strings.xml
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 138dff7..b487d92 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -867,7 +867,7 @@
if (panel.isOpen) {
// The window manager will give us a valid window token
new MenuDialogHelper(subMenu).show(null);
- } else {
+ } else if (hasFeature(FEATURE_ACTION_BAR)) {
mActionButtonPopup = new ActionButtonSubmenu(getContext(), subMenu);
mActionButtonPopup.show();
Callback cb = getCallback();
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 5c67da7..b5e3888 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -430,6 +430,8 @@
mSettingsObserver = new SettingsObserver(mHandler, EVENT_APPLY_GLOBAL_HTTP_PROXY);
mSettingsObserver.observe(mContext);
+
+ loadGlobalProxy();
}
@@ -2089,7 +2091,7 @@
ContentResolver res = mContext.getContentResolver();
Settings.Secure.putString(res, Settings.Secure.GLOBAL_HTTP_PROXY_HOST, host);
Settings.Secure.putInt(res, Settings.Secure.GLOBAL_HTTP_PROXY_PORT, port);
- Settings.Secure.putString(res,Settings.Secure.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
+ Settings.Secure.putString(res, Settings.Secure.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
exclList);
}
@@ -2099,6 +2101,20 @@
sendProxyBroadcast(proxyProperties);
}
+ private void loadGlobalProxy() {
+ ContentResolver res = mContext.getContentResolver();
+ String host = Settings.Secure.getString(res, Settings.Secure.GLOBAL_HTTP_PROXY_HOST);
+ int port = Settings.Secure.getInt(res, Settings.Secure.GLOBAL_HTTP_PROXY_PORT, 0);
+ String exclList = Settings.Secure.getString(res,
+ Settings.Secure.GLOBAL_HTTP_PROXY_EXCLUSION_LIST);
+ if (!TextUtils.isEmpty(host)) {
+ ProxyProperties proxyProperties = new ProxyProperties(host, port, exclList);
+ synchronized (mGlobalProxyLock) {
+ mGlobalProxy = proxyProperties;
+ }
+ }
+ }
+
public ProxyProperties getGlobalProxy() {
synchronized (mGlobalProxyLock) {
return mGlobalProxy;
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/WifiService.java b/services/java/com/android/server/WifiService.java
index d523fa8..7f81a25 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -197,7 +197,7 @@
WifiServiceHandler(android.os.Looper looper, Context context) {
super(looper);
mWshChannel = new AsyncChannel();
- mWshChannel.connect(context, this, mWifiStateMachine.getHandler(), 0);
+ mWshChannel.connect(context, this, mWifiStateMachine.getHandler());
}
@Override
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/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 7be58c6..145618e 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -231,7 +231,7 @@
hwcl->handle = NULL;
return;
}
- hwcl->handle = const_cast<native_handle_t*>(buffer->handle);
+ hwcl->handle = buffer->handle;
// TODO: set the crop value properly
hwcl->sourceCrop.left = 0;
hwcl->sourceCrop.top = 0;
diff --git a/telephony/java/com/android/internal/telephony/CommandsInterface.java b/telephony/java/com/android/internal/telephony/CommandsInterface.java
index 27a4dca..c7da3d4 100644
--- a/telephony/java/com/android/internal/telephony/CommandsInterface.java
+++ b/telephony/java/com/android/internal/telephony/CommandsInterface.java
@@ -951,22 +951,6 @@
void writeSmsToRuim(int status, String pdu, Message response);
- /**
- * @param apn
- * @param user
- * @param password
- * @param response
- */
- @Deprecated
- void setupDefaultPDP(String apn, String user, String password, Message response);
-
- /**
- * @param cid
- * @param response
- */
- @Deprecated
- void deactivateDefaultPDP(int cid, Message response);
-
void setRadioPower(boolean on, Message response);
void acknowledgeLastIncomingGsmSms(boolean success, int cause, Message response);
@@ -1354,10 +1338,12 @@
*
* @param cid
* The connection ID
+ * @param reason
+ * Data disconnect reason.
* @param result
* Callback message is empty on completion
*/
- public void deactivateDataCall(int cid, Message result);
+ public void deactivateDataCall(int cid, int reason, Message result);
/**
* Activate or deactivate cell broadcast SMS for CDMA.
diff --git a/telephony/java/com/android/internal/telephony/DataConnection.java b/telephony/java/com/android/internal/telephony/DataConnection.java
index 2536745..58fb13b 100644
--- a/telephony/java/com/android/internal/telephony/DataConnection.java
+++ b/telephony/java/com/android/internal/telephony/DataConnection.java
@@ -26,6 +26,7 @@
import android.os.AsyncResult;
import android.os.Message;
import android.os.SystemProperties;
+import android.text.TextUtils;
import android.util.EventLog;
import java.net.InetAddress;
@@ -312,9 +313,19 @@
* and is either a DisconnectParams or ConnectionParams.
*/
private void tearDownData(Object o) {
+ int discReason = RILConstants.DEACTIVATE_REASON_NONE;
+ if ((o != null) && (o instanceof DisconnectParams)) {
+ DisconnectParams dp = (DisconnectParams)o;
+ Message m = dp.onCompletedMsg;
+ if ((m != null) && (m.obj != null) && (m.obj instanceof String)) {
+ String reason = (String)m.obj;
+ if (TextUtils.equals(reason, Phone.REASON_RADIO_TURNED_OFF))
+ discReason = RILConstants.DEACTIVATE_REASON_RADIO_OFF;
+ }
+ }
if (phone.mCM.getRadioState().isOn()) {
if (DBG) log("tearDownData radio is on, call deactivateDataCall");
- phone.mCM.deactivateDataCall(cid, obtainMessage(EVENT_DEACTIVATE_DONE, o));
+ phone.mCM.deactivateDataCall(cid, discReason, obtainMessage(EVENT_DEACTIVATE_DONE, o));
} else {
if (DBG) log("tearDownData radio is off sendMessage EVENT_DEACTIVATE_DONE immediately");
AsyncResult ar = new AsyncResult(o, null, null);
diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java
index a77e73e..916602f 100644
--- a/telephony/java/com/android/internal/telephony/RIL.java
+++ b/telephony/java/com/android/internal/telephony/RIL.java
@@ -1265,33 +1265,6 @@
}
/**
- * @deprecated
- */
- public void
- setupDefaultPDP(String apn, String user, String password, Message result) {
- int radioTechnology;
- int authType;
- String profile = ""; //profile number, NULL for GSM/UMTS
-
- radioTechnology = RILConstants.SETUP_DATA_TECH_GSM;
- //TODO(): Add to the APN database, AuthType is set to CHAP/PAP
- authType = (user != null) ? RILConstants.SETUP_DATA_AUTH_PAP_CHAP
- : RILConstants.SETUP_DATA_AUTH_NONE;
-
- setupDataCall(Integer.toString(radioTechnology), profile, apn, user,
- password, Integer.toString(authType), result);
-
- }
-
- /**
- * @deprecated
- */
- public void
- deactivateDefaultPDP(int cid, Message result) {
- deactivateDataCall(cid, result);
- }
-
- /**
* The preferred new alternative to setupDefaultPDP that is
* CDMA-compatible.
*
@@ -1329,15 +1302,16 @@
}
public void
- deactivateDataCall(int cid, Message result) {
+ deactivateDataCall(int cid, int reason, Message result) {
RILRequest rr
= RILRequest.obtain(RIL_REQUEST_DEACTIVATE_DATA_CALL, result);
- rr.mp.writeInt(1);
+ rr.mp.writeInt(2);
rr.mp.writeString(Integer.toString(cid));
+ rr.mp.writeString(Integer.toString(reason));
if (RILJ_LOGD) riljLog(rr.serialString() + "> " +
- requestToString(rr.mRequest) + " " + cid);
+ requestToString(rr.mRequest) + " " + cid + " " + reason);
send(rr);
}
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 888f721..305e15f 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -96,6 +96,10 @@
int SETUP_DATA_AUTH_CHAP = 2;
int SETUP_DATA_AUTH_PAP_CHAP = 3;
+ /* Deactivate data call reasons */
+ int DEACTIVATE_REASON_NONE = 0;
+ int DEACTIVATE_REASON_RADIO_OFF = 1;
+
/*
cat include/telephony/ril.h | \
egrep '^#define' | \
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
index b60be6e..de15408 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
@@ -569,45 +569,24 @@
msg.obj = CDMAPhone.REASON_RADIO_TURNED_OFF;
synchronized (this) {
- if (networkType == ServiceState.RADIO_TECHNOLOGY_1xRTT) {
- /*
- * In 1x CDMA , during radio power off modem will disconnect the
- * data call and sends the power down registration message along
- * with the data call release message to the network
- */
-
- msg.arg1 = 0; // tearDown is false since modem does it anyway for 1X
- dcTracker.sendMessage(msg);
-
- Log.w(LOG_TAG, "Turn off the radio right away");
- hangupAndPowerOff();
- } else {
- if (!mPendingRadioPowerOffAfterDataOff) {
- DataConnectionTracker.State currentState = dcTracker.getState();
- if (currentState != DataConnectionTracker.State.CONNECTED
- && currentState != DataConnectionTracker.State.DISCONNECTING
- && currentState != DataConnectionTracker.State.INITING) {
-
- msg.arg1 = 0; // tearDown is false as it is not needed.
- dcTracker.sendMessage(msg);
-
- if (DBG)
- log("Data disconnected, turn off radio right away.");
- hangupAndPowerOff();
+ if (!mPendingRadioPowerOffAfterDataOff) {
+ DataConnectionTracker.State currentState = dcTracker.getState();
+ if (currentState != DataConnectionTracker.State.CONNECTED
+ && currentState != DataConnectionTracker.State.DISCONNECTING
+ && currentState != DataConnectionTracker.State.INITING) {
+ msg.arg1 = 0; // tearDown is false as it is not needed.
+ dcTracker.sendMessage(msg);
+ if (DBG) log("Data disconnected, turn off radio right away.");
+ hangupAndPowerOff();
+ } else {
+ msg.arg1 = 1; // tearDown is true
+ dcTracker.sendMessage(msg);
+ if (sendEmptyMessageDelayed(EVENT_SET_RADIO_POWER_OFF, 30000)) {
+ if (DBG) log("Wait upto 30s for data to disconnect, then turn off radio.");
+ mPendingRadioPowerOffAfterDataOff = true;
} else {
- // clean data connection
- msg.arg1 = 1; // tearDown is true
- dcTracker.sendMessage(msg);
-
- if (sendEmptyMessageDelayed(EVENT_SET_RADIO_POWER_OFF, 30000)) {
- if (DBG) {
- log("Wait upto 30s for data to disconnect, then turn off radio.");
- }
- mPendingRadioPowerOffAfterDataOff = true;
- } else {
- Log.w(LOG_TAG, "Cannot send delayed Msg, turn off radio right away.");
- hangupAndPowerOff();
- }
+ Log.w(LOG_TAG, "Cannot send delayed Msg, turn off radio right away.");
+ hangupAndPowerOff();
}
}
}
diff --git a/telephony/java/com/android/internal/telephony/sip/SipCommandInterface.java b/telephony/java/com/android/internal/telephony/sip/SipCommandInterface.java
index ed578c8..2e729fe 100644
--- a/telephony/java/com/android/internal/telephony/sip/SipCommandInterface.java
+++ b/telephony/java/com/android/internal/telephony/sip/SipCommandInterface.java
@@ -184,19 +184,12 @@
public void writeSmsToRuim(int status, String pdu, Message response) {
}
- public void setupDefaultPDP(String apn, String user, String password,
- Message result) {
- }
-
- public void deactivateDefaultPDP(int cid, Message result) {
- }
-
public void setupDataCall(String radioTechnology, String profile,
String apn, String user, String password, String authType,
Message result) {
}
- public void deactivateDataCall(int cid, Message result) {
+ public void deactivateDataCall(int cid, int reason, Message result) {
}
public void setRadioPower(boolean on, Message result) {
diff --git a/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java b/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java
index fdcf78d..c2f88e5 100644
--- a/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java
+++ b/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java
@@ -954,20 +954,12 @@
unimplemented(response);
}
- @Deprecated
- public void setupDefaultPDP(String apn, String user, String password, Message result) {
- unimplemented(result);
- }
-
public void setupDataCall(String radioTechnology, String profile, String apn, String user,
String password, String authType, Message result) {
unimplemented(result);
}
- public void deactivateDataCall(int cid, Message result) {unimplemented(result);}
-
- @Deprecated
- public void deactivateDefaultPDP(int cid, Message result) {unimplemented(result);}
+ public void deactivateDataCall(int cid, int reason, Message result) {unimplemented(result);}
public void setPreferredNetworkType(int networkType , Message result) {
mNetworkType = networkType;
diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
index b901e0d..bc6ad64 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
@@ -92,13 +92,6 @@
return mGraphicsStack.peek();
}
- /**
- * Disposes of the {@link Graphics2D} stack.
- */
- public void dispose() {
-
- }
-
// ---- native methods ----
/*package*/ static boolean isOpaque(Canvas thisCanvas) {
@@ -985,6 +978,16 @@
}
/*package*/ static void finalizer(int nativeCanvas) {
+ // get the delegate from the native int so that it can be disposed.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
+ if (canvasDelegate == null) {
+ assert false;
+ return;
+ }
+
+ canvasDelegate.dispose();
+
+ // remove it from the manager.
sManager.removeDelegate(nativeCanvas);
}
@@ -997,6 +1000,15 @@
private Canvas_Delegate() {
}
+ /**
+ * Disposes of the {@link Graphics2D} stack.
+ */
+ private void dispose() {
+ while (mGraphicsStack.size() > 0) {
+ mGraphicsStack.pop().dispose();
+ }
+ }
+
private void setBitmap(BufferedImage image) {
mBufferedImage = image;
mGraphicsStack.push(mBufferedImage.createGraphics());
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 ca87b4e..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;
@@ -33,12 +34,14 @@
import android.graphics.Bitmap;
import android.graphics.Typeface_Delegate;
+import android.os.Looper;
import android.util.Finalizers;
import java.lang.ref.SoftReference;
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;
@@ -151,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)
@@ -164,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();
@@ -291,20 +311,20 @@
@Override
public BridgeLayoutScene createScene(SceneParams params) {
try {
- SceneResult lastResult = SceneResult.SUCCESS;
+ SceneResult lastResult = SceneStatus.SUCCESS.getResult();
LayoutSceneImpl scene = new LayoutSceneImpl(params);
try {
- scene.prepareThread();
+ prepareThread();
lastResult = scene.init(params.getTimeout());
- if (lastResult == SceneResult.SUCCESS) {
+ if (lastResult.isSuccess()) {
lastResult = scene.inflate();
- if (lastResult == SceneResult.SUCCESS) {
+ if (lastResult.isSuccess()) {
lastResult = scene.render();
}
}
} finally {
scene.release();
- scene.cleanupThread();
+ cleanupThread();
}
return new BridgeLayoutScene(scene, lastResult);
@@ -339,6 +359,31 @@
}
/**
+ * Prepares the current thread for rendering.
+ *
+ * Note that while this can be called several time, the first call to {@link #cleanupThread()}
+ * will do the clean-up, and make the thread unable to do further scene actions.
+ */
+ public static void prepareThread() {
+ // we need to make sure the Looper has been initialized for this thread.
+ // this is required for View that creates Handler objects.
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+ }
+
+ /**
+ * Cleans up thread-specific data. After this, the thread cannot be used for scene actions.
+ * <p>
+ * Note that it doesn't matter how many times {@link #prepareThread()} was called, a single
+ * call to this will prevent the thread from doing further scene actions
+ */
+ public static void cleanupThread() {
+ // clean up the looper
+ Looper.sThreadLocal.remove();
+ }
+
+ /**
* Returns details of a framework resource from its integer value.
* @param value the integer value
* @return an array of 2 strings containing the resource name and type, or null if the id
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 f807214..a491901 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeLayoutScene.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeLayoutScene.java
@@ -64,14 +64,14 @@
@Override
public SceneResult render(long timeout) {
try {
- mScene.prepareThread();
+ Bridge.prepareThread();
mLastResult = mScene.acquire(timeout);
- if (mLastResult == SceneResult.SUCCESS) {
+ if (mLastResult.isSuccess()) {
mLastResult = mScene.render();
}
} finally {
mScene.release();
- mScene.cleanupThread();
+ Bridge.cleanupThread();
}
return mLastResult;
@@ -81,40 +81,36 @@
public SceneResult animate(Object targetObject, String animationName,
boolean isFrameworkAnimation, IAnimationListener listener) {
try {
- mScene.prepareThread();
+ Bridge.prepareThread();
mLastResult = mScene.acquire(SceneParams.DEFAULT_TIMEOUT);
- if (mLastResult == SceneResult.SUCCESS) {
+ if (mLastResult.isSuccess()) {
mLastResult = mScene.animate(targetObject, animationName, isFrameworkAnimation,
listener);
}
} finally {
mScene.release();
- mScene.cleanupThread();
+ Bridge.cleanupThread();
}
return mLastResult;
}
@Override
- public SceneResult insertChild(Object parentView, IXmlPullParser childXml, Object beforeSibling,
+ public SceneResult insertChild(Object parentView, IXmlPullParser childXml, int index,
IAnimationListener listener) {
if (parentView instanceof ViewGroup == false) {
throw new IllegalArgumentException("parentView is not a ViewGroup");
}
- if (beforeSibling != null && beforeSibling instanceof View == false) {
- throw new IllegalArgumentException("beforeSibling is not a View");
- }
try {
- mScene.prepareThread();
+ Bridge.prepareThread();
mLastResult = mScene.acquire(SceneParams.DEFAULT_TIMEOUT);
- if (mLastResult == SceneResult.SUCCESS) {
- mLastResult = mScene.insertChild((ViewGroup) parentView, childXml,
- (View) beforeSibling, listener);
+ if (mLastResult.isSuccess()) {
+ mLastResult = mScene.insertChild((ViewGroup) parentView, childXml, index, listener);
}
} finally {
mScene.release();
- mScene.cleanupThread();
+ Bridge.cleanupThread();
}
return mLastResult;
@@ -122,28 +118,25 @@
@Override
- public SceneResult moveChild(Object parentView, Object childView, Object beforeSibling,
- IAnimationListener listener) {
+ public SceneResult moveChild(Object parentView, Object childView, int index,
+ Map<String, String> layoutParams, IAnimationListener listener) {
if (parentView instanceof ViewGroup == false) {
throw new IllegalArgumentException("parentView is not a ViewGroup");
}
if (childView instanceof View == false) {
throw new IllegalArgumentException("childView is not a View");
}
- if (beforeSibling != null && beforeSibling instanceof View == false) {
- throw new IllegalArgumentException("beforeSibling is not a View");
- }
try {
- mScene.prepareThread();
+ Bridge.prepareThread();
mLastResult = mScene.acquire(SceneParams.DEFAULT_TIMEOUT);
- if (mLastResult == SceneResult.SUCCESS) {
- mLastResult = mScene.moveChild((ViewGroup) parentView, (View) childView,
- (View) beforeSibling, listener);
+ if (mLastResult.isSuccess()) {
+ mLastResult = mScene.moveChild((ViewGroup) parentView, (View) childView, index,
+ listener);
}
} finally {
mScene.release();
- mScene.cleanupThread();
+ Bridge.cleanupThread();
}
return mLastResult;
@@ -156,14 +149,14 @@
}
try {
- mScene.prepareThread();
+ Bridge.prepareThread();
mLastResult = mScene.acquire(SceneParams.DEFAULT_TIMEOUT);
- if (mLastResult == SceneResult.SUCCESS) {
+ if (mLastResult.isSuccess()) {
mLastResult = mScene.removeChild((View) childView, listener);
}
} finally {
mScene.release();
- mScene.cleanupThread();
+ Bridge.cleanupThread();
}
return mLastResult;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/AnimationThread.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/AnimationThread.java
index d5766ab..2b9d52f 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/AnimationThread.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/AnimationThread.java
@@ -16,8 +16,11 @@
package com.android.layoutlib.bridge.impl;
+import com.android.layoutlib.api.LayoutScene;
import com.android.layoutlib.api.SceneResult;
import com.android.layoutlib.api.LayoutScene.IAnimationListener;
+import com.android.layoutlib.api.SceneResult.SceneStatus;
+import com.android.layoutlib.bridge.Bridge;
import android.animation.Animator;
import android.animation.ValueAnimator;
@@ -57,7 +60,7 @@
@Override
public void run() {
- mScene.prepareThread();
+ Bridge.prepareThread();
try {
Handler_Delegate.setCallback(new IHandlerCallback() {
public void sendMessageAtTime(Handler handler, Message msg, long uptimeMillis) {
@@ -75,6 +78,7 @@
mAnimator.start();
// loop the animation
+ LayoutScene scene = mScene.getScene();
do {
// get the next message.
MessageBundle bundle = mQueue.poll();
@@ -88,14 +92,14 @@
try {
sleep(bundle.mUptimeMillis - currentTime);
} catch (InterruptedException e) {
- // TODO Auto-generated catch block
+ // FIXME log/do something/sleep again?
e.printStackTrace();
}
}
// ready to do the work, acquire the scene.
SceneResult result = mScene.acquire(250);
- if (result != SceneResult.SUCCESS) {
+ if (result.isSuccess() == false) {
mListener.done(result);
return;
}
@@ -104,18 +108,18 @@
// the next message, so mQueue will have another one.
try {
bundle.mTarget.handleMessage(bundle.mMessage);
- if (mScene.render() == SceneResult.SUCCESS) {
- mListener.onNewFrame(mScene.getScene());
+ if (mScene.render().isSuccess()) {
+ mListener.onNewFrame(scene);
}
} finally {
mScene.release();
}
} while (mQueue.size() > 0);
- mListener.done(SceneResult.SUCCESS);
+ mListener.done(SceneStatus.SUCCESS.getResult());
} finally {
Handler_Delegate.setCallback(null);
- mScene.cleanupThread();
+ Bridge.cleanupThread();
}
}
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/LayoutSceneImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/LayoutSceneImpl.java
index 05d207c..74e7fb2 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/LayoutSceneImpl.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/LayoutSceneImpl.java
@@ -51,7 +51,6 @@
import android.graphics.Canvas_Delegate;
import android.graphics.drawable.Drawable;
import android.os.Handler;
-import android.os.Looper;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.View;
@@ -104,6 +103,9 @@
private int mScreenOffset;
private IResourceValue mWindowBackground;
private FrameLayout mViewRoot;
+ private Canvas mCanvas;
+ private int mMeasuredScreenWidth = -1;
+ private int mMeasuredScreenHeight = -1;
// information being returned through the API
private BufferedImage mImage;
@@ -198,32 +200,7 @@
mBlockParser = new BridgeXmlBlockParser(mParams.getLayoutDescription(),
mContext, false /* platformResourceFlag */);
- return SceneResult.SUCCESS;
- }
-
- /**
- * Prepares the current thread for rendering.
- *
- * Note that while this can be called several time, the first call to {@link #cleanupThread()}
- * will do the clean-up, and make the thread unable to do further scene actions.
- */
- public void prepareThread() {
- // we need to make sure the Looper has been initialized for this thread.
- // this is required for View that creates Handler objects.
- if (Looper.myLooper() == null) {
- Looper.prepare();
- }
- }
-
- /**
- * Cleans up thread-specific data. After this, the thread cannot be used for scene actions.
- * <p>
- * Note that it doesn't matter how many times {@link #prepareThread()} was called, a single
- * call to this will prevent the thread from doing further scene actions
- */
- public void cleanupThread() {
- // clean up the looper
- Looper.sThreadLocal.remove();
+ return SceneStatus.SUCCESS.getResult();
}
/**
@@ -365,7 +342,7 @@
mViewRoot.setBackgroundDrawable(d);
}
- return SceneResult.SUCCESS;
+ return SceneStatus.SUCCESS.getResult();
} catch (PostInflateException e) {
return new SceneResult(SceneStatus.ERROR_INFLATION, e.getMessage(), e);
} catch (Throwable e) {
@@ -389,99 +366,110 @@
*
* @throws IllegalStateException if the current context is different than the one owned by
* the scene, or if {@link #acquire(long)} was not called.
+ *
+ * @see SceneParams#getRenderingMode()
*/
public SceneResult render() {
checkLock();
try {
- long current = System.currentTimeMillis();
if (mViewRoot == null) {
return new SceneResult(SceneStatus.ERROR_NOT_INFLATED);
}
// measure the views
int w_spec, h_spec;
- int renderScreenWidth = mParams.getScreenWidth();
- int renderScreenHeight = mParams.getScreenHeight();
-
RenderingMode renderingMode = mParams.getRenderingMode();
- if (renderingMode != RenderingMode.NORMAL) {
- // measure the full size needed by the layout.
- w_spec = MeasureSpec.makeMeasureSpec(renderScreenWidth,
- renderingMode.isHorizExpand() ?
- MeasureSpec.UNSPECIFIED // this lets us know the actual needed size
- : MeasureSpec.EXACTLY);
- h_spec = MeasureSpec.makeMeasureSpec(renderScreenHeight - mScreenOffset,
- renderingMode.isVertExpand() ?
- MeasureSpec.UNSPECIFIED // this lets us know the actual needed size
- : MeasureSpec.EXACTLY);
- mViewRoot.measure(w_spec, h_spec);
+ // only do the screen measure when needed.
+ boolean newRenderSize = false;
+ if (mMeasuredScreenWidth == -1) {
+ newRenderSize = true;
+ mMeasuredScreenWidth = mParams.getScreenWidth();
+ mMeasuredScreenHeight = mParams.getScreenHeight();
- if (renderingMode.isHorizExpand()) {
- int neededWidth = mViewRoot.getChildAt(0).getMeasuredWidth();
- if (neededWidth > renderScreenWidth) {
- renderScreenWidth = neededWidth;
+ if (renderingMode != RenderingMode.NORMAL) {
+ // measure the full size needed by the layout.
+ w_spec = MeasureSpec.makeMeasureSpec(mMeasuredScreenWidth,
+ renderingMode.isHorizExpand() ?
+ MeasureSpec.UNSPECIFIED // this lets us know the actual needed size
+ : MeasureSpec.EXACTLY);
+ h_spec = MeasureSpec.makeMeasureSpec(mMeasuredScreenHeight - mScreenOffset,
+ renderingMode.isVertExpand() ?
+ MeasureSpec.UNSPECIFIED // this lets us know the actual needed size
+ : MeasureSpec.EXACTLY);
+ mViewRoot.measure(w_spec, h_spec);
+
+ if (renderingMode.isHorizExpand()) {
+ int neededWidth = mViewRoot.getChildAt(0).getMeasuredWidth();
+ if (neededWidth > mMeasuredScreenWidth) {
+ mMeasuredScreenWidth = neededWidth;
+ }
}
- }
- if (renderingMode.isVertExpand()) {
- int neededHeight = mViewRoot.getChildAt(0).getMeasuredHeight();
- if (neededHeight > renderScreenHeight - mScreenOffset) {
- renderScreenHeight = neededHeight + mScreenOffset;
+ if (renderingMode.isVertExpand()) {
+ int neededHeight = mViewRoot.getChildAt(0).getMeasuredHeight();
+ if (neededHeight > mMeasuredScreenHeight - mScreenOffset) {
+ mMeasuredScreenHeight = neededHeight + mScreenOffset;
+ }
}
}
}
// remeasure with the size we need
// This must always be done before the call to layout
- w_spec = MeasureSpec.makeMeasureSpec(renderScreenWidth, MeasureSpec.EXACTLY);
- h_spec = MeasureSpec.makeMeasureSpec(renderScreenHeight - mScreenOffset,
+ w_spec = MeasureSpec.makeMeasureSpec(mMeasuredScreenWidth, MeasureSpec.EXACTLY);
+ h_spec = MeasureSpec.makeMeasureSpec(mMeasuredScreenHeight - mScreenOffset,
MeasureSpec.EXACTLY);
mViewRoot.measure(w_spec, h_spec);
// now do the layout.
- mViewRoot.layout(0, mScreenOffset, renderScreenWidth, renderScreenHeight);
+ mViewRoot.layout(0, mScreenOffset, mMeasuredScreenWidth, mMeasuredScreenHeight);
// draw the views
// create the BufferedImage into which the layout will be rendered.
- if (mParams.getImageFactory() != null) {
- mImage = mParams.getImageFactory().getImage(renderScreenWidth,
- renderScreenHeight - mScreenOffset);
- } else {
- mImage = new BufferedImage(renderScreenWidth, renderScreenHeight - mScreenOffset,
- BufferedImage.TYPE_INT_ARGB);
+ if (newRenderSize || mCanvas == null) {
+ if (mParams.getImageFactory() != null) {
+ mImage = mParams.getImageFactory().getImage(mMeasuredScreenWidth,
+ mMeasuredScreenHeight - mScreenOffset);
+ } else {
+ mImage = new BufferedImage(mMeasuredScreenWidth,
+ mMeasuredScreenHeight - mScreenOffset, BufferedImage.TYPE_INT_ARGB);
+ }
+
+ if (mParams.isCustomBackgroundEnabled()) {
+ Graphics2D gc = mImage.createGraphics();
+ gc.setColor(new Color(mParams.getCustomBackgroundColor(), true));
+ gc.fillRect(0, 0, mMeasuredScreenWidth, mMeasuredScreenHeight - mScreenOffset);
+ gc.dispose();
+ }
+
+ // create an Android bitmap around the BufferedImage
+ Bitmap bitmap = Bitmap_Delegate.createBitmap(mImage,
+ true /*isMutable*/,
+ Density.getEnum(mParams.getDensity()));
+
+ // create a Canvas around the Android bitmap
+ mCanvas = new Canvas(bitmap);
+ mCanvas.setDensity(mParams.getDensity());
}
- if (mParams.isCustomBackgroundEnabled()) {
- Graphics2D gc = mImage.createGraphics();
- gc.setColor(new Color(mParams.getCustomBackgroundColor(), true));
- gc.fillRect(0, 0, renderScreenWidth, renderScreenHeight - mScreenOffset);
- gc.dispose();
- }
-
- // create an Android bitmap around the BufferedImage
- Bitmap bitmap = Bitmap_Delegate.createBitmap(mImage,
- true /*isMutable*/,
- Density.getEnum(mParams.getDensity()));
-
- // create a Canvas around the Android bitmap
- Canvas canvas = new Canvas(bitmap);
- canvas.setDensity(mParams.getDensity());
-
// to set the logger, get the native delegate
- Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(canvas);
+ Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(mCanvas);
canvasDelegate.setLogger(mParams.getLogger());
- mViewRoot.draw(canvas);
- canvasDelegate.dispose();
+ long preDrawTime = System.currentTimeMillis();
+
+ mViewRoot.draw(mCanvas);
+
+ long drawTime = System.currentTimeMillis();
mViewInfo = visit(((ViewGroup)mViewRoot).getChildAt(0), mContext);
- System.out.println("rendering (ms): " + (System.currentTimeMillis() - current));
+ System.out.println(String.format("rendering (ms): %03d", drawTime - preDrawTime));
// success!
- return SceneResult.SUCCESS;
+ return SceneStatus.SUCCESS.getResult();
} catch (Throwable e) {
// get the real cause of the exception.
Throwable t = e;
@@ -532,7 +520,7 @@
new AnimationThread(this, anim, listener).start();
- return SceneResult.SUCCESS;
+ return SceneStatus.SUCCESS.getResult();
}
} catch (Exception e) {
// get the real cause of the exception.
@@ -549,14 +537,9 @@
}
public SceneResult insertChild(ViewGroup parentView, IXmlPullParser childXml,
- View beforeSibling, IAnimationListener listener) {
+ int index, IAnimationListener listener) {
checkLock();
- int index = parentView.indexOfChild(beforeSibling);
- if (beforeSibling != null && index == -1) {
- throw new IllegalArgumentException("beforeSibling not in parentView");
- }
-
// create a block parser for the XML
BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(childXml, mContext,
false /* platformResourceFlag */);
@@ -567,28 +550,42 @@
View child = mInflater.inflate(blockParser, parentView, false /*attachToRoot*/);
// add it to the parentView in the correct location
- parentView.addView(child, index);
+ try {
+ parentView.addView(child, index);
+ } catch (UnsupportedOperationException e) {
+ // looks like this is a view class that doesn't support children manipulation!
+ return new SceneResult(SceneStatus.ERROR_VIEWGROUP_NO_CHILDREN);
+ }
- return render();
+ invalidateRenderingSize();
+
+ SceneResult result = render();
+ if (result.isSuccess()) {
+ result.setData(child);
+ }
+
+ return result;
}
- public SceneResult moveChild(ViewGroup parentView, View childView, View beforeSibling,
+ public SceneResult moveChild(ViewGroup parentView, View childView, int index,
IAnimationListener listener) {
checkLock();
- int index = parentView.indexOfChild(beforeSibling);
- if (beforeSibling != null && index == -1) {
- throw new IllegalArgumentException("beforeSibling not in parentView");
+ try {
+ ViewParent parent = childView.getParent();
+ if (parent instanceof ViewGroup) {
+ ViewGroup parentGroup = (ViewGroup) parent;
+ parentGroup.removeView(childView);
+ }
+
+ // add it to the parentView in the correct location
+ parentView.addView(childView, index);
+ } catch (UnsupportedOperationException e) {
+ // looks like this is a view class that doesn't support children manipulation!
+ return new SceneResult(SceneStatus.ERROR_VIEWGROUP_NO_CHILDREN);
}
- ViewParent parent = childView.getParent();
- if (parent instanceof ViewGroup) {
- ViewGroup parentGroup = (ViewGroup) parent;
- parentGroup.removeView(childView);
- }
-
- // add it to the parentView in the correct location
- parentView.addView(childView, index);
+ invalidateRenderingSize();
return render();
}
@@ -596,12 +593,19 @@
public SceneResult removeChild(View childView, IAnimationListener listener) {
checkLock();
- ViewParent parent = childView.getParent();
- if (parent instanceof ViewGroup) {
- ViewGroup parentGroup = (ViewGroup) parent;
- parentGroup.removeView(childView);
+ try {
+ ViewParent parent = childView.getParent();
+ if (parent instanceof ViewGroup) {
+ ViewGroup parentGroup = (ViewGroup) parent;
+ parentGroup.removeView(childView);
+ }
+ } catch (UnsupportedOperationException e) {
+ // looks like this is a view class that doesn't support children manipulation!
+ return new SceneResult(SceneStatus.ERROR_VIEWGROUP_NO_CHILDREN);
}
+ invalidateRenderingSize();
+
return render();
}
@@ -971,6 +975,10 @@
return result;
}
+ private void invalidateRenderingSize() {
+ mMeasuredScreenWidth = mMeasuredScreenHeight = -1;
+ }
+
public BufferedImage getImage() {
return mImage;
}
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..51236fe9 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);
}