am 9bef3294: Merge changes Ie3c8ca8d,Ia175b36d into jb-mr1-dev

* commit '9bef3294d3660a85442829a25c9777e25d3c3cc8':
  Try to free cache before giving up on install
  Robustly add symlink and add for non-primary users
diff --git a/api/current.txt b/api/current.txt
index 5462aee..bac280ae 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -23462,6 +23462,17 @@
     method public void set(T, V);
   }
 
+  public class PropertyValueModel extends android.util.ValueModel {
+    method public T get();
+    method public H getHost();
+    method public android.util.Property<H, T> getProperty();
+    method public java.lang.Class<T> getType();
+    method public static android.util.PropertyValueModel<H, T> of(H, android.util.Property<H, T>);
+    method public static android.util.PropertyValueModel<H, T> of(H, java.lang.Class<T>, java.lang.String);
+    method public static android.util.PropertyValueModel of(java.lang.Object, java.lang.String);
+    method public void set(T);
+  }
+
   public class SparseArray implements java.lang.Cloneable {
     ctor public SparseArray();
     ctor public SparseArray(int);
@@ -23610,6 +23621,14 @@
     field public int type;
   }
 
+  public abstract class ValueModel {
+    ctor protected ValueModel();
+    method public abstract T get();
+    method public abstract java.lang.Class<T> getType();
+    method public abstract void set(T);
+    field public static final android.util.ValueModel EMPTY;
+  }
+
   public class Xml {
     method public static android.util.AttributeSet asAttributeSet(org.xmlpull.v1.XmlPullParser);
     method public static android.util.Xml.Encoding findEncodingByName(java.lang.String) throws java.io.UnsupportedEncodingException;
@@ -27995,10 +28014,12 @@
     method public abstract void onSelectedDayChange(android.widget.CalendarView, int, int, int);
   }
 
-  public class CheckBox extends android.widget.CompoundButton {
+  public class CheckBox extends android.widget.CompoundButton implements android.widget.ValueEditor {
     ctor public CheckBox(android.content.Context);
     ctor public CheckBox(android.content.Context, android.util.AttributeSet);
     ctor public CheckBox(android.content.Context, android.util.AttributeSet, int);
+    method public android.util.ValueModel<java.lang.Boolean> getValueModel();
+    method public void setValueModel(android.util.ValueModel<java.lang.Boolean>);
   }
 
   public abstract interface Checkable {
@@ -28171,14 +28192,16 @@
     method public void setSize(int, int);
   }
 
-  public class EditText extends android.widget.TextView {
+  public class EditText extends android.widget.TextView implements android.widget.ValueEditor {
     ctor public EditText(android.content.Context);
     ctor public EditText(android.content.Context, android.util.AttributeSet);
     ctor public EditText(android.content.Context, android.util.AttributeSet, int);
     method public void extendSelection(int);
+    method public android.util.ValueModel<java.lang.CharSequence> getValueModel();
     method public void selectAll();
     method public void setSelection(int, int);
     method public void setSelection(int);
+    method public void setValueModel(android.util.ValueModel<java.lang.CharSequence>);
   }
 
   public abstract interface ExpandableListAdapter {
@@ -29203,11 +29226,13 @@
     method public abstract java.lang.Object[] getSections();
   }
 
-  public class SeekBar extends android.widget.AbsSeekBar {
+  public class SeekBar extends android.widget.AbsSeekBar implements android.widget.ValueEditor {
     ctor public SeekBar(android.content.Context);
     ctor public SeekBar(android.content.Context, android.util.AttributeSet);
     ctor public SeekBar(android.content.Context, android.util.AttributeSet, int);
+    method public android.util.ValueModel<java.lang.Integer> getValueModel();
     method public void setOnSeekBarChangeListener(android.widget.SeekBar.OnSeekBarChangeListener);
+    method public void setValueModel(android.util.ValueModel<java.lang.Integer>);
   }
 
   public static abstract interface SeekBar.OnSeekBarChangeListener {
@@ -29780,6 +29805,11 @@
     method public android.widget.TextView getText2();
   }
 
+  public abstract interface ValueEditor {
+    method public abstract android.util.ValueModel<T> getValueModel();
+    method public abstract void setValueModel(android.util.ValueModel<T>);
+  }
+
   public class VideoView extends android.view.SurfaceView implements android.widget.MediaController.MediaPlayerControl {
     ctor public VideoView(android.content.Context);
     ctor public VideoView(android.content.Context, android.util.AttributeSet);
diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c
index 3314dc3..71e840e 100644
--- a/cmds/servicemanager/service_manager.c
+++ b/cmds/servicemanager/service_manager.c
@@ -31,6 +31,7 @@
     { AID_MEDIA, "media.player" },
     { AID_MEDIA, "media.camera" },
     { AID_MEDIA, "media.audio_policy" },
+    { AID_MEDIA, "android.media.IAAHMetaDataService" },
     { AID_DRM,   "drm.drmManager" },
     { AID_NFC,   "nfc" },
     { AID_BLUETOOTH, "bluetooth" },
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 456d757..c136a4d 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -113,7 +113,6 @@
 import java.util.regex.Pattern;
 
 import libcore.io.DropBox;
-import libcore.io.EventLogger;
 import libcore.io.IoUtils;
 
 import dalvik.system.CloseGuard;
@@ -4979,13 +4978,6 @@
         }
     }
 
-    private static class EventLoggingReporter implements EventLogger.Reporter {
-        @Override
-        public void report (int code, Object... list) {
-            EventLog.writeEvent(code, list);
-        }
-    }
-
     private class DropBoxReporter implements DropBox.Reporter {
 
         private DropBoxManager dropBox;
@@ -5015,9 +5007,6 @@
 
         Environment.initForCurrentUser();
 
-        // Set the reporter for event logging in libcore
-        EventLogger.setReporter(new EventLoggingReporter());
-
         Process.setArgV0("<pre-initialized>");
 
         Looper.prepareMainLooper();
diff --git a/core/java/android/text/format/Time.java b/core/java/android/text/format/Time.java
index 5ef86b1..200b57b 100644
--- a/core/java/android/text/format/Time.java
+++ b/core/java/android/text/format/Time.java
@@ -411,9 +411,6 @@
      * @throws android.util.TimeFormatException if s cannot be parsed.
      */
     public boolean parse(String s) {
-        if (s == null) {
-            throw new NullPointerException("time string is null");
-        }
         if (nativeParse(s)) {
             timezone = TIMEZONE_UTC;
             return true;
diff --git a/core/java/android/util/PropertyValueModel.java b/core/java/android/util/PropertyValueModel.java
new file mode 100755
index 0000000..eb9c47d
--- /dev/null
+++ b/core/java/android/util/PropertyValueModel.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util;
+
+/**
+ * A value model for a {@link Property property} of a host object. This class can be used for
+ * both reflective and non-reflective property implementations.
+ *
+ * @param <H> the host type, where the host is the object that holds this property
+ * @param <T> the value type
+ *
+ * @see Property
+ * @see ValueModel
+ */
+public class PropertyValueModel<H, T> extends ValueModel<T> {
+    private final H mHost;
+    private final Property<H, T> mProperty;
+
+    private PropertyValueModel(H host, Property<H, T> property) {
+        mProperty = property;
+        mHost = host;
+    }
+
+    /**
+     * Returns the host.
+     *
+     * @return the host
+     */
+    public H getHost() {
+        return mHost;
+    }
+
+    /**
+     * Returns the property.
+     *
+     * @return the property
+     */
+    public Property<H, T> getProperty() {
+        return mProperty;
+    }
+
+    @Override
+    public Class<T> getType() {
+        return mProperty.getType();
+    }
+
+    @Override
+    public T get() {
+        return mProperty.get(mHost);
+    }
+
+    @Override
+    public void set(T value) {
+        mProperty.set(mHost, value);
+    }
+
+    /**
+     * Return an appropriate PropertyValueModel for this host and property.
+     *
+     * @param host the host
+     * @param property the property
+     * @return the value model
+     */
+    public static <H, T> PropertyValueModel<H, T> of(H host, Property<H, T> property) {
+        return new PropertyValueModel<H, T>(host, property);
+    }
+
+    /**
+     * Return a PropertyValueModel for this {@code host} and a
+     * reflective property, constructed from this {@code propertyType} and {@code propertyName}.
+     *
+     * @param host
+     * @param propertyType the property type
+     * @param propertyName the property name
+     * @return a value model with this host and a reflective property with this type and name
+     *
+     * @see Property#of
+     */
+    public static <H, T> PropertyValueModel<H, T> of(H host, Class<T> propertyType,
+            String propertyName) {
+        return of(host, Property.of((Class<H>) host.getClass(), propertyType, propertyName));
+    }
+
+    private static Class getNullaryMethodReturnType(Class c, String name) {
+        try {
+            return c.getMethod(name).getReturnType();
+        } catch (NoSuchMethodException e) {
+            return null;
+        }
+    }
+
+    private static Class getFieldType(Class c, String name) {
+        try {
+            return c.getField(name).getType();
+        } catch (NoSuchFieldException e) {
+            return null;
+        }
+    }
+
+    private static String capitalize(String name) {
+        if (name.isEmpty()) {
+            return name;
+        }
+        return Character.toUpperCase(name.charAt(0)) + name.substring(1);
+    }
+
+    /**
+     * Return a PropertyValueModel for this {@code host} and and {@code propertyName}.
+     *
+     * @param host the host
+     * @param propertyName the property name
+     * @return a value model with this host and a reflective property with this name
+     */
+    public static PropertyValueModel of(Object host, String propertyName) {
+        Class clazz = host.getClass();
+        String suffix = capitalize(propertyName);
+        Class propertyType = getNullaryMethodReturnType(clazz, "get" + suffix);
+        if (propertyType == null) {
+            propertyType = getNullaryMethodReturnType(clazz, "is" + suffix);
+        } 
+        if (propertyType == null) {
+            propertyType = getFieldType(clazz, propertyName); 
+        }         
+        if (propertyType == null) {
+            throw new NoSuchPropertyException(propertyName); 
+        }
+        return of(host, propertyType, propertyName);
+    }
+}
diff --git a/core/java/android/util/ValueModel.java b/core/java/android/util/ValueModel.java
new file mode 100755
index 0000000..4789682
--- /dev/null
+++ b/core/java/android/util/ValueModel.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util;
+
+/**
+ * A ValueModel is an abstraction for a 'slot' or place in memory in which a value
+ * may be stored and retrieved. A common implementation of ValueModel is a regular property of
+ * an object, whose value may be retrieved by calling the appropriate <em>getter</em>
+ * method and set by calling the corresponding <em>setter</em> method.
+ *
+ * @param <T> the value type
+ *
+ * @see PropertyValueModel
+ */
+public abstract class ValueModel<T> {
+    /**
+     * The empty model should be used in place of {@code null} to indicate that a
+     * model has not been set. The empty model has no value and does nothing when it is set.
+     */
+    public static final ValueModel EMPTY = new ValueModel() {
+        @Override
+        public Class getType() {
+            return Object.class;
+        }
+
+        @Override
+        public Object get() {
+            return null;
+        }
+
+        @Override
+        public void set(Object value) {
+
+        }
+    };
+
+    protected ValueModel() {
+    }
+
+    /**
+     * Returns the type of this property.
+     *
+     * @return the property type
+     */
+    public abstract Class<T> getType();
+
+    /**
+     * Returns the value of this property.
+     *
+     * @return the property value
+     */
+    public abstract T get();
+
+    /**
+     * Sets the value of this property.
+     *
+     * @param value the new value for this property
+     */
+    public abstract void set(T value);
+}
\ No newline at end of file
diff --git a/core/java/android/view/SimulatedTrackball.java b/core/java/android/view/SimulatedTrackball.java
new file mode 100644
index 0000000..1878e28
--- /dev/null
+++ b/core/java/android/view/SimulatedTrackball.java
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import android.os.Handler;
+import android.os.Handler.Callback;
+import android.os.Message;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+
+/**
+ * This class creates trackball events from touchpad events.
+ * 
+ * @see ViewRootImpl
+ */
+class SimulatedTrackball {
+
+    // Maximum difference in milliseconds between the down and up of a touch
+    // event for it to be considered a tap
+    // TODO:Read this value from a configuration file
+    private static final int MAX_TAP_TIME = 250;
+    private static final int FLICK_MSG_ID = 313;
+
+    // The position of the previous touchpad event
+    private float mLastTouchpadXPosition;
+    private float mLastTouchpadYPosition;
+    // Where the touchpad was initially pressed
+    private float mTouchpadEnterXPosition;
+    private float mTouchpadEnterYPosition;
+    // When the most recent ACTION_HOVER_ENTER occurred
+    private long mLastTouchPadStartTimeMs = 0;
+    // When the most recent direction key was sent
+    private long mLastTouchPadKeySendTimeMs = 0;
+    // When the most recent touch event of any type occurred
+    private long mLastTouchPadEventTimeMs = 0;
+
+    // How quickly keys were sent;
+    private int mKeySendRateMs = 0;
+    private int mLastKeySent;
+    // Last movement in device screen pixels
+    private float mLastMoveX = 0;
+    private float mLastMoveY = 0;
+    // Offset from the initial touch. Gets reset as direction keys are sent.
+    private float mAccumulatedX;
+    private float mAccumulatedY;
+
+    // Change in position allowed during tap events
+    private float mTouchSlop;
+    private float mTouchSlopSquared;
+    // Has the TouchSlop constraint been invalidated
+    private boolean mAlwaysInTapRegion = true;
+
+    // Most recent event. Used to determine what device sent the event.
+    private MotionEvent mRecentEvent;
+
+    // TODO: Currently using screen dimensions tuned to a Galaxy Nexus, need to
+    // read this from a config file instead
+    private int mDistancePerTick;
+    private int mDistancePerTickSquared;
+    // Highest rate that the flinged events can occur at before dying out
+    private int mMaxRepeatDelay;
+    // The square of the minimum distance needed for a flick to register
+    private int mMinFlickDistanceSquared;
+    // How quickly the repeated events die off
+    private float mFlickDecay;
+
+    public SimulatedTrackball() {
+        mDistancePerTick = SystemProperties.getInt("persist.vr_dist_tick", 64);
+        mDistancePerTickSquared = mDistancePerTick * mDistancePerTick;
+        mMaxRepeatDelay = SystemProperties.getInt("persist.vr_repeat_delay", 300);
+        mMinFlickDistanceSquared = SystemProperties.getInt("persist.vr_min_flick", 20);
+        mMinFlickDistanceSquared *= mMinFlickDistanceSquared;
+        mFlickDecay = Float.parseFloat(SystemProperties.get(
+                "persist.sys.vr_flick_decay", "1.3"));
+        mTouchSlop = ViewConfiguration.getTouchSlop();
+        mTouchSlopSquared = mTouchSlop * mTouchSlop;
+    }
+
+    private final Handler mHandler = new Handler(new Callback() {
+            @Override
+        public boolean handleMessage(Message msg) {
+            if (msg.what != FLICK_MSG_ID)
+                return false;
+
+            final long time = SystemClock.uptimeMillis();
+            ViewRootImpl viewroot = (ViewRootImpl) msg.obj;
+            // Send the key
+            viewroot.enqueueInputEvent(new KeyEvent(time, time,
+                    KeyEvent.ACTION_DOWN, msg.arg2, 0, mRecentEvent.getMetaState(),
+                    mRecentEvent.getDeviceId(), 0,
+                    KeyEvent.FLAG_FALLBACK, mRecentEvent.getSource()));
+            viewroot.enqueueInputEvent(new KeyEvent(time, time,
+                    KeyEvent.ACTION_UP, msg.arg2, 0, mRecentEvent.getMetaState(),
+                    mRecentEvent.getDeviceId(), 0,
+                    KeyEvent.FLAG_FALLBACK, mRecentEvent.getSource()));
+            Message msgCopy = Message.obtain(msg);
+            // Increase the delay by the decay factor
+            msgCopy.arg1 = (int) Math.ceil(mFlickDecay * msgCopy.arg1);
+            if (msgCopy.arg1 <= mMaxRepeatDelay) {
+                // Send the key again in arg1 milliseconds
+                mHandler.sendMessageDelayed(msgCopy, msgCopy.arg1);
+            }
+            return false;
+        }
+    });
+
+    public void updateTrackballDirection(ViewRootImpl viewroot, MotionEvent event) {
+        // Store what time the touchpad event occurred
+        final long time = SystemClock.uptimeMillis();
+        switch (event.getAction()) {
+            case MotionEvent.ACTION_HOVER_ENTER:
+                mLastTouchPadStartTimeMs = time;
+                mAlwaysInTapRegion = true;
+                mTouchpadEnterXPosition = event.getX();
+                mTouchpadEnterYPosition = event.getY();
+                mAccumulatedX = 0;
+                mAccumulatedY = 0;
+                mLastMoveX = 0;
+                mLastMoveY = 0;
+                // Clear any flings
+                mHandler.removeMessages(FLICK_MSG_ID);
+                break;
+            case MotionEvent.ACTION_HOVER_MOVE:
+                // Determine whether the move is slop or an intentional move
+                float deltaX = event.getX() - mTouchpadEnterXPosition;
+                float deltaY = event.getY() - mTouchpadEnterYPosition;
+                if (mTouchSlopSquared < deltaX * deltaX + deltaY * deltaY) {
+                    mAlwaysInTapRegion = false;
+                }
+
+                // Find the difference in position between the two most recent
+                // touchpad events
+                mLastMoveX = event.getX() - mLastTouchpadXPosition;
+                mLastMoveY = event.getY() - mLastTouchpadYPosition;
+                mAccumulatedX += mLastMoveX;
+                mAccumulatedY += mLastMoveY;
+                float mAccumulatedXSquared = mAccumulatedX * mAccumulatedX;
+                float mAccumulatedYSquared = mAccumulatedY * mAccumulatedY;
+                // Determine if we've moved far enough to send a key press
+                if (mAccumulatedXSquared > mDistancePerTickSquared ||
+                        mAccumulatedYSquared > mDistancePerTickSquared) {
+                    float dominantAxis;
+                    float sign;
+                    boolean isXAxis;
+                    int key;
+                    int repeatCount = 0;
+                    // Determine dominant axis
+                    if (mAccumulatedXSquared > mAccumulatedYSquared) {
+                        dominantAxis = mAccumulatedX;
+                        isXAxis = true;
+                    } else {
+                        dominantAxis = mAccumulatedY;
+                        isXAxis = false;
+                    }
+                    // Determine sign of axis
+                    sign = (dominantAxis > 0) ? 1 : -1;
+                    // Determine key to send
+                    if (isXAxis) {
+                        key = (sign == 1) ? KeyEvent.KEYCODE_DPAD_RIGHT :
+                                KeyEvent.KEYCODE_DPAD_LEFT;
+                    } else {
+                        key = (sign == 1) ? KeyEvent.KEYCODE_DPAD_DOWN : KeyEvent.KEYCODE_DPAD_UP;
+                    }
+                    // Send key until maximum distance constraint is satisfied
+                    while (dominantAxis * dominantAxis > mDistancePerTickSquared) {
+                        repeatCount++;
+                        dominantAxis -= sign * mDistancePerTick;
+                        viewroot.enqueueInputEvent(new KeyEvent(time, time,
+                                KeyEvent.ACTION_DOWN, key, 0, event.getMetaState(),
+                                event.getDeviceId(), 0, KeyEvent.FLAG_FALLBACK, event.getSource()));
+                        viewroot.enqueueInputEvent(new KeyEvent(time, time,
+                                KeyEvent.ACTION_UP, key, 0, event.getMetaState(),
+                                event.getDeviceId(), 0, KeyEvent.FLAG_FALLBACK, event.getSource()));
+                    }
+                    // Save new axis values
+                    mAccumulatedX = isXAxis ? dominantAxis : 0;
+                    mAccumulatedY = isXAxis ? 0 : dominantAxis;
+
+                    mLastKeySent = key;
+                    mKeySendRateMs = (int) ((time - mLastTouchPadKeySendTimeMs) / repeatCount);
+                    mLastTouchPadKeySendTimeMs = time;
+                }
+                break;
+            case MotionEvent.ACTION_HOVER_EXIT:
+                if (time - mLastTouchPadStartTimeMs < MAX_TAP_TIME && mAlwaysInTapRegion) {
+                    // Trackball Down
+                    MotionEvent trackballEvent = MotionEvent.obtain(mLastTouchPadStartTimeMs, time,
+                            MotionEvent.ACTION_DOWN, 0, 0, 0, 0, event.getMetaState(),
+                            10f, 10f, event.getDeviceId(), 0);
+                    trackballEvent.setSource(InputDevice.SOURCE_CLASS_TRACKBALL);
+                    viewroot.enqueueInputEvent(trackballEvent);
+                    // Trackball Release
+                    trackballEvent = MotionEvent.obtain(mLastTouchPadStartTimeMs, time,
+                            MotionEvent.ACTION_UP, 0, 0, 0, 0, event.getMetaState(),
+                            10f, 10f, event.getDeviceId(), 0);
+                    trackballEvent.setSource(InputDevice.SOURCE_CLASS_TRACKBALL);
+                    viewroot.enqueueInputEvent(trackballEvent);
+                } else {
+                    float xMoveSquared = mLastMoveX * mLastMoveX;
+                    float yMoveSquared = mLastMoveY * mLastMoveY;
+                    // Determine whether the last gesture was a fling.
+                    if (mMinFlickDistanceSquared <= xMoveSquared + yMoveSquared &&
+                            time - mLastTouchPadEventTimeMs <= MAX_TAP_TIME &&
+                            mKeySendRateMs <= mMaxRepeatDelay && mKeySendRateMs > 0) {
+                        Message message = Message.obtain(mHandler, FLICK_MSG_ID,
+                                mKeySendRateMs, mLastKeySent, viewroot);
+                        mRecentEvent = event;
+                        mHandler.sendMessageDelayed(message, mKeySendRateMs);
+                    }
+                }
+                break;
+        }
+        // Store touch event position and time
+        mLastTouchPadEventTimeMs = time;
+        mLastTouchpadXPosition = event.getX();
+        mLastTouchpadYPosition = event.getY();
+    }
+}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 8a82a54..3e2cdba 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -146,6 +146,8 @@
     final TrackballAxis mTrackballAxisX = new TrackballAxis();
     final TrackballAxis mTrackballAxisY = new TrackballAxis();
 
+    final SimulatedTrackball mSimulatedTrackball = new SimulatedTrackball();
+
     int mLastJoystickXDirection;
     int mLastJoystickYDirection;
     int mLastJoystickXKeyCode;
@@ -3394,7 +3396,6 @@
         if (mInputEventConsistencyVerifier != null) {
             mInputEventConsistencyVerifier.onGenericMotionEvent(event, 0);
         }
-
         if (mView != null && mAdded && (q.mFlags & QueuedInputEvent.FLAG_DELIVER_POST_IME) == 0) {
             if (LOCAL_LOGV)
                 Log.v(TAG, "Dispatching generic motion " + event + " to " + mView);
@@ -3421,12 +3422,17 @@
 
     private void deliverGenericMotionEventPostIme(QueuedInputEvent q) {
         final MotionEvent event = (MotionEvent) q.mEvent;
-        final boolean isJoystick = (event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0;
+        final int source = event.getSource();
+        final boolean isJoystick = (source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0;
+        final boolean isTouchPad = (source & InputDevice.SOURCE_CLASS_POSITION) != 0;
 
         // If there is no view, then the event will not be handled.
         if (mView == null || !mAdded) {
             if (isJoystick) {
                 updateJoystickDirection(event, false);
+            } else if (isTouchPad) {
+              //Convert TouchPad motion into a TrackBall event
+              mSimulatedTrackball.updateTrackballDirection(this, event);
             }
             finishInputEvent(q, false);
             return;
@@ -3436,6 +3442,9 @@
         if (mView.dispatchGenericMotionEvent(event)) {
             if (isJoystick) {
                 updateJoystickDirection(event, false);
+            } else if (isTouchPad) {
+              //Convert TouchPad motion into a TrackBall event
+              mSimulatedTrackball.updateTrackballDirection(this, event);
             }
             finishInputEvent(q, true);
             return;
@@ -3446,6 +3455,10 @@
             // those.
             updateJoystickDirection(event, true);
             finishInputEvent(q, true);
+        } else if (isTouchPad) {
+            //Convert TouchPad motion into a TrackBall event
+            mSimulatedTrackball.updateTrackballDirection(this, event);
+            finishInputEvent(q, true);
         } else {
             finishInputEvent(q, false);
         }
diff --git a/core/java/android/widget/CheckBox.java b/core/java/android/widget/CheckBox.java
index f1804f8..41ab5f2 100644
--- a/core/java/android/widget/CheckBox.java
+++ b/core/java/android/widget/CheckBox.java
@@ -20,6 +20,7 @@
 import android.util.AttributeSet;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
+import android.util.ValueModel;
 
 
 /**
@@ -55,7 +56,9 @@
  * {@link android.R.styleable#View View Attributes}
  * </p>
  */
-public class CheckBox extends CompoundButton {
+public class CheckBox extends CompoundButton implements ValueEditor<Boolean> {
+    private ValueModel<Boolean> mValueModel = ValueModel.EMPTY;
+
     public CheckBox(Context context) {
         this(context, null);
     }
@@ -79,4 +82,22 @@
         super.onInitializeAccessibilityNodeInfo(info);
         info.setClassName(CheckBox.class.getName());
     }
+
+    @Override
+    public ValueModel<Boolean> getValueModel() {
+        return mValueModel;
+    }
+
+    @Override
+    public void setValueModel(ValueModel<Boolean> valueModel) {
+        mValueModel = valueModel;
+        setChecked(mValueModel.get());
+    }
+
+    @Override
+    public boolean performClick() {
+        boolean handled = super.performClick();
+        mValueModel.set(isChecked());
+        return handled;
+    }
 }
diff --git a/core/java/android/widget/EditText.java b/core/java/android/widget/EditText.java
index 57e51c2..ec81214 100644
--- a/core/java/android/widget/EditText.java
+++ b/core/java/android/widget/EditText.java
@@ -17,6 +17,7 @@
 package android.widget;
 
 import android.content.Context;
+import android.graphics.Rect;
 import android.text.Editable;
 import android.text.Selection;
 import android.text.Spannable;
@@ -24,6 +25,7 @@
 import android.text.method.ArrowKeyMovementMethod;
 import android.text.method.MovementMethod;
 import android.util.AttributeSet;
+import android.util.ValueModel;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
 
@@ -47,7 +49,9 @@
  * {@link android.R.styleable#TextView TextView Attributes},
  * {@link android.R.styleable#View View Attributes}
  */
-public class EditText extends TextView {
+public class EditText extends TextView implements ValueEditor<CharSequence> {
+    private ValueModel<CharSequence> mValueModel = ValueModel.EMPTY;
+
     public EditText(Context context) {
         this(context, null);
     }
@@ -128,4 +132,21 @@
         super.onInitializeAccessibilityNodeInfo(info);
         info.setClassName(EditText.class.getName());
     }
+
+    @Override
+    public ValueModel<CharSequence> getValueModel() {
+        return mValueModel;
+    }
+
+    @Override
+    public void setValueModel(ValueModel<CharSequence> valueModel) {
+        mValueModel = valueModel;
+        setText(mValueModel.get());
+    }
+
+    @Override
+    void sendAfterTextChanged(Editable text) {
+        super.sendAfterTextChanged(text);
+        mValueModel.set(text);
+    }
 }
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index 4918e48..6cfeb15 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -470,6 +470,11 @@
     private final PressedStateHelper mPressedStateHelper;
 
     /**
+     * The keycode of the last handled DPAD down event.
+     */
+    private int mLastHandledDownDpadKeyCode = -1;
+
+    /**
      * Interface to listen for changes of the current value.
      */
     public interface OnValueChangeListener {
@@ -936,6 +941,31 @@
             case KeyEvent.KEYCODE_ENTER:
                 removeAllCallbacks();
                 break;
+            case KeyEvent.KEYCODE_DPAD_DOWN:
+            case KeyEvent.KEYCODE_DPAD_UP:
+                if (!mHasSelectorWheel) {
+                    break;
+                }
+                switch (event.getAction()) {
+                    case KeyEvent.ACTION_DOWN:
+                        if (mWrapSelectorWheel || (keyCode == KeyEvent.KEYCODE_DPAD_DOWN)
+                                ? getValue() < getMaxValue() : getValue() > getMinValue()) {
+                            requestFocus();
+                            mLastHandledDownDpadKeyCode = keyCode;
+                            removeAllCallbacks();
+                            if (mFlingScroller.isFinished()) {
+                                changeValueByOne(keyCode == KeyEvent.KEYCODE_DPAD_DOWN);
+                            }
+                            return true;
+                        }
+                        break;
+                    case KeyEvent.ACTION_UP:
+                        if (mLastHandledDownDpadKeyCode == keyCode) {
+                            mLastHandledDownDpadKeyCode = -1;
+                            return true;
+                        }
+                        break;
+                }
         }
         return super.dispatchKeyEvent(event);
     }
diff --git a/core/java/android/widget/SeekBar.java b/core/java/android/widget/SeekBar.java
index 2737f94..a6486a8 100644
--- a/core/java/android/widget/SeekBar.java
+++ b/core/java/android/widget/SeekBar.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.util.AttributeSet;
+import android.util.ValueModel;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
 
@@ -33,7 +34,7 @@
  *
  * @attr ref android.R.styleable#SeekBar_thumb
  */
-public class SeekBar extends AbsSeekBar {
+public class SeekBar extends AbsSeekBar implements ValueEditor<Integer> {
 
     /**
      * A callback that notifies clients when the progress level has been
@@ -69,8 +70,9 @@
         void onStopTrackingTouch(SeekBar seekBar);
     }
 
+    private ValueModel<Integer> mValueModel = ValueModel.EMPTY;
     private OnSeekBarChangeListener mOnSeekBarChangeListener;
-    
+
     public SeekBar(Context context) {
         this(context, null);
     }
@@ -89,9 +91,23 @@
 
         if (mOnSeekBarChangeListener != null) {
             mOnSeekBarChangeListener.onProgressChanged(this, getProgress(), fromUser);
+            if (fromUser) {
+                mValueModel.set(getProgress());
+            }
         }
     }
 
+    @Override
+    public ValueModel<Integer> getValueModel() {
+        return mValueModel;
+    }
+
+    @Override
+    public void setValueModel(ValueModel<Integer> valueModel) {
+        mValueModel = valueModel;
+        setProgress(mValueModel.get());
+    }
+
     /**
      * Sets a listener to receive notifications of changes to the SeekBar's progress level. Also
      * provides notifications of when the user starts and stops a touch gesture within the SeekBar.
diff --git a/core/java/android/widget/ValueEditor.java b/core/java/android/widget/ValueEditor.java
new file mode 100755
index 0000000..2b91abf
--- /dev/null
+++ b/core/java/android/widget/ValueEditor.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.widget;
+
+import android.util.ValueModel;
+
+/**
+ * An interface for editors of simple values. Classes implementing this interface are normally
+ * UI controls (subclasses of {@link android.view.View View}) that can provide a suitable
+ * user interface to display and edit values of the specified type. This interface is
+ * intended to describe editors for simple types, like {@code boolean}, {@code int} or
+ * {@code String}, where the values themselves are immutable.
+ * <p>
+ * For example, {@link android.widget.CheckBox CheckBox} implements
+ * this interface for the Boolean type as it is capable of providing an appropriate
+ * mechanism for displaying and changing the value of a Boolean property.
+ *
+ * @param <T> the value type that this editor supports
+ */
+public interface ValueEditor<T> {
+    /**
+     * Return the last value model that was set. If no value model has been set, the editor
+     * should return the value {@link android.util.ValueModel#EMPTY}.
+     *
+     * @return the value model
+     */
+    public ValueModel<T> getValueModel();
+
+    /**
+     * Sets the value model for this editor. When the value model is set, the editor should
+     * retrieve the value from the value model, using {@link android.util.ValueModel#get()},
+     * and set its internal state accordingly. Likewise, when the editor's internal state changes
+     * it should update the value model by calling  {@link android.util.ValueModel#set(T)}
+     * with the appropriate value.
+     *
+     * @param valueModel the new value model for this editor.
+     */
+    public void setValueModel(ValueModel<T> valueModel);
+}
diff --git a/core/jni/android_text_format_Time.cpp b/core/jni/android_text_format_Time.cpp
index aa2c5f39..0a59ae7 100644
--- a/core/jni/android_text_format_Time.cpp
+++ b/core/jni/android_text_format_Time.cpp
@@ -23,7 +23,6 @@
 #include "jni.h"
 #include "utils/misc.h"
 #include "android_runtime/AndroidRuntime.h"
-#include "ScopedStringChars.h"
 #include "TimeUtils.h"
 #include <nativehelper/JNIHelp.h>
 #include <cutils/tztime.h>
@@ -72,10 +71,11 @@
     t->t.tm_gmtoff = env->GetLongField(o, g_gmtoffField);
     bool allDay = env->GetBooleanField(o, g_allDayField);
     if (allDay &&
-       ((t->t.tm_sec !=0) || (t->t.tm_min != 0) || (t->t.tm_hour != 0))) {
-        jniThrowException(env, "java/lang/IllegalArgumentException",
-                          "allDay is true but sec, min, hour are not 0.");
-        return false;
+	((t->t.tm_sec !=0) || (t->t.tm_min != 0) || (t->t.tm_hour != 0))) {
+        char msg[100];
+	sprintf(msg, "allDay is true but sec, min, hour are not 0.");
+	jniThrowException(env, "java/lang/IllegalArgumentException", msg);
+	return false;
     }
     return true;
 }
@@ -313,7 +313,7 @@
 static jstring android_text_format_Time_toString(JNIEnv* env, jobject This)
 {
     Time t;
-    if (!java2time(env, &t, This)) return env->NewStringUTF("");
+    if (!java2time(env, &t, This)) return env->NewStringUTF("");;
     ACQUIRE_TIMEZONE(This, t)
 
     String8 r = t.toString();
@@ -365,30 +365,32 @@
 // ============================================================================
 // Just do this here because it's not worth recreating the strings
 
-static int get_char(JNIEnv* env, const ScopedStringChars& s, int spos, int mul,
-                    bool* thrown)
+static int get_char(JNIEnv* env, const jchar *s, int spos, int mul,
+                    bool *thrown)
 {
     jchar c = s[spos];
     if (c >= '0' && c <= '9') {
         return (c - '0') * mul;
     } else {
         if (!*thrown) {
-            jniThrowExceptionFmt(env, "android/util/TimeFormatException",
-                                 "Parse error at pos=%d", spos);
+            char msg[100];
+            sprintf(msg, "Parse error at pos=%d", spos);
+            jniThrowException(env, "android/util/TimeFormatException", msg);
             *thrown = true;
         }
         return 0;
     }
 }
 
-static bool check_char(JNIEnv* env, const ScopedStringChars& s, int spos, jchar expected)
+static bool check_char(JNIEnv* env, const jchar *s, int spos, jchar expected)
 {
     jchar c = s[spos];
     if (c != expected) {
-        jniThrowExceptionFmt(env, "android/util/TimeFormatException",
-                             "Unexpected character 0x%02x at pos=%d.  Expected %c.",
-                             c, spos, expected);
-        return false;
+        char msg[100];
+	sprintf(msg, "Unexpected character 0x%02x at pos=%d.  Expected %c.", c, spos,
+		expected);
+	jniThrowException(env, "android/util/TimeFormatException", msg);
+	return false;
     }
     return true;
 }
@@ -397,19 +399,20 @@
 static jboolean android_text_format_Time_parse(JNIEnv* env, jobject This, jstring strObj)
 {
     jsize len = env->GetStringLength(strObj);
-    if (len < 8) {
-        jniThrowException(env, "android/util/TimeFormatException",
-                          "String too short -- expected at least 8 characters.");
-        return false;
-    }
+    const jchar *s = env->GetStringChars(strObj, NULL);
 
+    bool thrown = false;
+    int n;
     jboolean inUtc = false;
 
-    ScopedStringChars s(env, strObj);
+    if (len < 8) {
+        char msg[100];
+        sprintf(msg, "String too short -- expected at least 8 characters.");
+	jniThrowException(env, "android/util/TimeFormatException", msg);
+	return false;
+    }
 
     // year
-    int n;
-    bool thrown = false;
     n = get_char(env, s, 0, 1000, &thrown);
     n += get_char(env, s, 1, 100, &thrown);
     n += get_char(env, s, 2, 10, &thrown);
@@ -456,7 +459,7 @@
         if (len > 15) {
             // Z
             if (!check_char(env, s, 15, 'Z')) return false;
-            inUtc = true;
+	    inUtc = true;
         }
     } else {
         env->SetBooleanField(This, g_allDayField, JNI_TRUE);
@@ -469,7 +472,8 @@
     env->SetIntField(This, g_ydayField, 0);
     env->SetIntField(This, g_isdstField, -1);
     env->SetLongField(This, g_gmtoffField, 0);
-
+    
+    env->ReleaseStringChars(strObj, s);
     return inUtc;
 }
 
@@ -478,19 +482,19 @@
                                            jstring strObj)
 {
     jsize len = env->GetStringLength(strObj);
+    const jchar *s = env->GetStringChars(strObj, NULL);
+
+    bool thrown = false;
+    int n;
+    jboolean inUtc = false;
+
     if (len < 10) {
         jniThrowException(env, "android/util/TimeFormatException",
-                          "String too short --- expected at least 10 characters.");
+                "Time input is too short; must be at least 10 characters");
         return false;
     }
 
-    jboolean inUtc = false;
-
-    ScopedStringChars s(env, strObj);
-
     // year
-    int n;
-    bool thrown = false;
     n = get_char(env, s, 0, 1000, &thrown);    
     n += get_char(env, s, 1, 100, &thrown);
     n += get_char(env, s, 2, 10, &thrown);
@@ -521,28 +525,28 @@
         // T
         if (!check_char(env, s, 10, 'T')) return false;
 
-        env->SetBooleanField(This, g_allDayField, JNI_FALSE);
+	env->SetBooleanField(This, g_allDayField, JNI_FALSE);
         // hour
         n = get_char(env, s, 11, 10, &thrown);
         n += get_char(env, s, 12, 1, &thrown);
         if (thrown) return false;
-        int hour = n;
+	int hour = n;
         // env->SetIntField(This, g_hourField, n);
+	
+	// :
+	if (!check_char(env, s, 13, ':')) return false;
 
-        // :
-        if (!check_char(env, s, 13, ':')) return false;
-
-        // minute
+	// minute
         n = get_char(env, s, 14, 10, &thrown);
         n += get_char(env, s, 15, 1, &thrown);
         if (thrown) return false;
-        int minute = n;
+	int minute = n;
         // env->SetIntField(This, g_minField, n);
 
-        // :
-        if (!check_char(env, s, 16, ':')) return false;
+	// :
+	if (!check_char(env, s, 16, ':')) return false;
 
-        // second
+	// second
         n = get_char(env, s, 17, 10, &thrown);
         n += get_char(env, s, 18, 1, &thrown);
         if (thrown) return false;
@@ -562,63 +566,64 @@
         if (len > tz_index) {
             char c = s[tz_index];
 
-            // NOTE: the offset is meant to be subtracted to get from local time
-            // to UTC.  we therefore use 1 for '-' and -1 for '+'.
-            switch (c) {
-            case 'Z':
-                // Zulu time -- UTC
-                offset = 0;
-                break;
-            case '-': 
+	    // NOTE: the offset is meant to be subtracted to get from local time
+	    // to UTC.  we therefore use 1 for '-' and -1 for '+'.
+	    switch (c) {
+	    case 'Z':
+	        // Zulu time -- UTC
+	        offset = 0;
+		break;
+	    case '-': 
                 offset = 1;
-                break;
-            case '+': 
+	        break;
+	    case '+': 
                 offset = -1;
-                break;
-            default:
-                jniThrowExceptionFmt(env, "android/util/TimeFormatException",
-                                     "Unexpected character 0x%02x at position %d.  Expected + or -",
-                                     c, tz_index);
-                return false;
-            }
+	        break;
+	    default:
+	        char msg[100];
+	        sprintf(msg, "Unexpected character 0x%02x at position %d.  Expected + or -",
+			c, tz_index);
+	        jniThrowException(env, "android/util/TimeFormatException", msg);
+	        return false;
+	    }
             inUtc = true;
 
-            if (offset != 0) {
-                if (len < tz_index + 6) {
-                    jniThrowExceptionFmt(env, "android/util/TimeFormatException",
-                                         "Unexpected length; should be %d characters",
-                                         tz_index + 6);
-                    return false;
-                }
+	    if (offset != 0) {
+	        if (len < tz_index + 6) {
+	            char msg[100];
+	            sprintf(msg, "Unexpected length; should be %d characters", tz_index + 6);
+	            jniThrowException(env, "android/util/TimeFormatException", msg);
+	            return false;
+	        }
 
-                // hour
-                n = get_char(env, s, tz_index + 1, 10, &thrown);
-                n += get_char(env, s, tz_index + 2, 1, &thrown);
-                if (thrown) return false;
-                n *= offset;
-                hour += n;
+	        // hour
+	        n = get_char(env, s, tz_index + 1, 10, &thrown);
+		n += get_char(env, s, tz_index + 2, 1, &thrown);
+		if (thrown) return false;
+		n *= offset;
+		hour += n;
 
-                // :
-                if (!check_char(env, s, tz_index + 3, ':')) return false;
-            
-                // minute
-                n = get_char(env, s, tz_index + 4, 10, &thrown);
-                n += get_char(env, s, tz_index + 5, 1, &thrown);
-                if (thrown) return false;
-                n *= offset;
-                minute += n;
-            }
-        }
-        env->SetIntField(This, g_hourField, hour);
+		// :
+		if (!check_char(env, s, tz_index + 3, ':')) return false;
+	    
+		// minute
+		n = get_char(env, s, tz_index + 4, 10, &thrown);
+		n += get_char(env, s, tz_index + 5, 1, &thrown);
+		if (thrown) return false;
+		n *= offset;
+		minute += n;
+	    }
+	}
+	env->SetIntField(This, g_hourField, hour);
         env->SetIntField(This, g_minField, minute);
 
-        if (offset != 0) {
-            // we need to normalize after applying the hour and minute offsets
-            android_text_format_Time_normalize(env, This, false /* use isdst */);
-            // The timezone is set to UTC in the calling Java code.
-        }
+	if (offset != 0) {
+	    // we need to normalize after applying the hour and minute offsets
+	    android_text_format_Time_normalize(env, This, false /* use isdst */);
+	    // The timezone is set to UTC in the calling Java code.
+	}
     } else {
-        env->SetBooleanField(This, g_allDayField, JNI_TRUE);
+	env->SetBooleanField(This, g_allDayField, JNI_TRUE);
         env->SetIntField(This, g_hourField, 0);
         env->SetIntField(This, g_minField, 0);
         env->SetIntField(This, g_secField, 0);
@@ -628,7 +633,8 @@
     env->SetIntField(This, g_ydayField, 0);
     env->SetIntField(This, g_isdstField, -1);
     env->SetLongField(This, g_gmtoffField, 0);
-
+    
+    env->ReleaseStringChars(strObj, s);
     return inUtc;
 }
 
diff --git a/services/java/com/android/server/updates/ConfigUpdateInstallReceiver.java b/services/java/com/android/server/updatable/ConfigUpdateInstallReceiver.java
similarity index 100%
rename from services/java/com/android/server/updates/ConfigUpdateInstallReceiver.java
rename to services/java/com/android/server/updatable/ConfigUpdateInstallReceiver.java
diff --git a/services/java/com/android/server/updates/CertPinInstallReceiver.java b/services/java/com/android/server/updates/CertPinInstallReceiver.java
deleted file mode 100644
index c03fbc3..0000000
--- a/services/java/com/android/server/updates/CertPinInstallReceiver.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2012 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.server.updates;
-
-public class CertPinInstallReceiver extends ConfigUpdateInstallReceiver {
-
-    public CertPinInstallReceiver() {
-        super("/data/misc/keychain/", "pins", "metadata/", "version");
-    }
-}
diff --git a/services/tests/servicestests/src/com/android/server/updates/CertPinInstallReceiverTest.java b/services/tests/servicestests/src/com/android/server/updates/CertPinInstallReceiverTest.java
deleted file mode 100644
index b6742a1..0000000
--- a/services/tests/servicestests/src/com/android/server/updates/CertPinInstallReceiverTest.java
+++ /dev/null
@@ -1,243 +0,0 @@
-/*
- * Copyright (C) 2012 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.server.updates;
-
-import android.content.Context;
-import android.content.Intent;
-import android.test.AndroidTestCase;
-import android.provider.Settings;
-import android.util.Base64;
-import android.util.Log;
-
-import java.io.ByteArrayInputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.InputStream;
-import java.security.cert.CertificateFactory;
-import java.security.cert.Certificate;
-import java.security.cert.X509Certificate;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.security.PrivateKey;
-import java.security.Signature;
-import java.security.spec.PKCS8EncodedKeySpec;
-import java.security.KeyFactory;
-import java.util.HashSet;
-import java.io.*;
-import libcore.io.IoUtils;
-
-/**
- * Tests for {@link com.android.server.CertPinInstallReceiver}
- */
-public class CertPinInstallReceiverTest extends AndroidTestCase {
-
-    private static final String TAG = "CertPinInstallReceiverTest";
-
-    private static final String PINLIST_ROOT = System.getenv("ANDROID_DATA") + "/misc/keychain/";
-
-    public static final String PINLIST_CONTENT_PATH = PINLIST_ROOT + "pins";
-    public static final String PINLIST_METADATA_PATH = PINLIST_CONTENT_PATH + "metadata";
-
-    public static final String PINLIST_CONTENT_URL_KEY = "pinlist_content_url";
-    public static final String PINLIST_METADATA_URL_KEY = "pinlist_metadata_url";
-    public static final String PINLIST_CERTIFICATE_KEY = "config_update_certificate";
-    public static final String PINLIST_VERSION_KEY = "pinlist_version";
-
-    private static final String EXTRA_CONTENT_PATH = "CONTENT_PATH";
-    private static final String EXTRA_REQUIRED_HASH = "REQUIRED_HASH";
-    private static final String EXTRA_SIGNATURE = "SIGNATURE";
-    private static final String EXTRA_VERSION_NUMBER = "VERSION";
-
-    public static final String TEST_CERT = "" +
-                    "MIIDsjCCAxugAwIBAgIJAPLf2gS0zYGUMA0GCSqGSIb3DQEBBQUAMIGYMQswCQYDVQQGEwJVUzET" +
-                    "MBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEPMA0GA1UEChMGR29v" +
-                    "Z2xlMRAwDgYDVQQLEwd0ZXN0aW5nMRYwFAYDVQQDEw1HZXJlbXkgQ29uZHJhMSEwHwYJKoZIhvcN" +
-                    "AQkBFhJnY29uZHJhQGdvb2dsZS5jb20wHhcNMTIwNzE0MTc1MjIxWhcNMTIwODEzMTc1MjIxWjCB" +
-                    "mDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDU1vdW50YWluIFZp" +
-                    "ZXcxDzANBgNVBAoTBkdvb2dsZTEQMA4GA1UECxMHdGVzdGluZzEWMBQGA1UEAxMNR2VyZW15IENv" +
-                    "bmRyYTEhMB8GCSqGSIb3DQEJARYSZ2NvbmRyYUBnb29nbGUuY29tMIGfMA0GCSqGSIb3DQEBAQUA" +
-                    "A4GNADCBiQKBgQCjGGHATBYlmas+0sEECkno8LZ1KPglb/mfe6VpCT3GhSr+7br7NG/ZwGZnEhLq" +
-                    "E7YIH4fxltHmQC3Tz+jM1YN+kMaQgRRjo/LBCJdOKaMwUbkVynAH6OYsKevjrOPk8lfM5SFQzJMG" +
-                    "sA9+Tfopr5xg0BwZ1vA/+E3mE7Tr3M2UvwIDAQABo4IBADCB/TAdBgNVHQ4EFgQUhzkS9E6G+x8W" +
-                    "L4EsmRjDxu28tHUwgc0GA1UdIwSBxTCBwoAUhzkS9E6G+x8WL4EsmRjDxu28tHWhgZ6kgZswgZgx" +
-                    "CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3" +
-                    "MQ8wDQYDVQQKEwZHb29nbGUxEDAOBgNVBAsTB3Rlc3RpbmcxFjAUBgNVBAMTDUdlcmVteSBDb25k" +
-                    "cmExITAfBgkqhkiG9w0BCQEWEmdjb25kcmFAZ29vZ2xlLmNvbYIJAPLf2gS0zYGUMAwGA1UdEwQF" +
-                    "MAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAYiugFDmbDOQ2U/+mqNt7o8ftlEo9SJrns6O8uTtK6AvR" +
-                    "orDrR1AXTXkuxwLSbmVfedMGOZy7Awh7iZa8hw5x9XmUudfNxvmrKVEwGQY2DZ9PXbrnta/dwbhK" +
-                    "mWfoepESVbo7CKIhJp8gRW0h1Z55ETXD57aGJRvQS4pxkP8ANhM=";
-
-
-    public static final String TEST_KEY = "" +
-                    "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKMYYcBMFiWZqz7SwQQKSejwtnUo" +
-                    "+CVv+Z97pWkJPcaFKv7tuvs0b9nAZmcSEuoTtggfh/GW0eZALdPP6MzVg36QxpCBFGOj8sEIl04p" +
-                    "ozBRuRXKcAfo5iwp6+Os4+TyV8zlIVDMkwawD35N+imvnGDQHBnW8D/4TeYTtOvczZS/AgMBAAEC" +
-                    "gYBxwFalNSwZK3WJipq+g6KLCiBn1JxGGDQlLKrweFaSuFyFky9fd3IvkIabirqQchD612sMb+GT" +
-                    "0t1jptW6z4w2w6++IW0A3apDOCwoD+uvDBXrbFqI0VbyAWUNqHVdaFFIRk2IHGEE6463mGRdmILX" +
-                    "IlCd/85RTHReg4rl/GFqWQJBANgLAIR4pWbl5Gm+DtY18wp6Q3pJAAMkmP/lISCBIidu1zcqYIKt" +
-                    "PoDW4Knq9xnhxPbXrXKv4YzZWHBK8GkKhQ0CQQDBQnXufQcMew+PwiS0oJvS+eQ6YJwynuqG2ejg" +
-                    "WE+T7489jKtscRATpUXpZUYmDLGg9bLt7L62hFvFSj2LO2X7AkBcdrD9AWnBFWlh/G77LVHczSEu" +
-                    "KCoyLiqxcs5vy/TjLaQ8vw1ZQG580/qJnr+tOxyCjSJ18GK3VppsTRaBznfNAkB3nuCKNp9HTWCL" +
-                    "dfrsRsFMrFpk++mSt6SoxXaMbn0LL2u1CD4PCEiQMGt+lK3/3TmRTKNs+23sYS7Ahjxj0udDAkEA" +
-                    "p57Nj65WNaWeYiOfTwKXkLj8l29H5NbaGWxPT0XkWr4PvBOFZVH/wj0/qc3CMVGnv11+DyO+QUCN" +
-                    "SqBB5aRe8g==";
-
-    private void overrideSettings(String key, String value) throws Exception {
-        assertTrue(Settings.Secure.putString(mContext.getContentResolver(), key, value));
-        Thread.sleep(1000);
-    }
-
-    private void overrideCert(String value) throws Exception {
-        overrideSettings(PINLIST_CERTIFICATE_KEY, value);
-    }
-
-    private String readPins() throws Exception {
-        return IoUtils.readFileAsString(PINLIST_CONTENT_PATH);
-    }
-
-    private String readCurrentVersion() throws Exception {
-        return IoUtils.readFileAsString("/data/misc/keychain/metadata/version");
-    }
-
-    private String getNextVersion() throws Exception {
-        int currentVersion = Integer.parseInt(readCurrentVersion());
-        return Integer.toString(currentVersion + 1);
-    }
-
-    private static String getCurrentHash(String content) throws Exception {
-        if (content == null) {
-            return "0";
-        }
-        MessageDigest dgst = MessageDigest.getInstance("SHA512");
-        byte[] encoded = content.getBytes();
-        byte[] fingerprint = dgst.digest(encoded);
-        return IntegralToString.bytesToHexString(fingerprint, false);
-    }
-
-    private static String getHashOfCurrentContent() throws Exception {
-        String content = IoUtils.readFileAsString("/data/misc/keychain/pins");
-        return getCurrentHash(content);
-    }
-
-    private PrivateKey createKey() throws Exception {
-        byte[] derKey = Base64.decode(TEST_KEY.getBytes(), Base64.DEFAULT);
-        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(derKey);
-        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
-        return (PrivateKey) keyFactory.generatePrivate(keySpec);
-    }
-
-    private X509Certificate createCertificate() throws Exception {
-        byte[] derCert = Base64.decode(TEST_CERT.getBytes(), Base64.DEFAULT);
-        InputStream istream = new ByteArrayInputStream(derCert);
-        CertificateFactory cf = CertificateFactory.getInstance("X.509");
-        return (X509Certificate) cf.generateCertificate(istream);
-    }
-
-    private String makeTemporaryContentFile(String content) throws Exception {
-        FileOutputStream fw = mContext.openFileOutput("content.txt", mContext.MODE_WORLD_READABLE);
-        fw.write(content.getBytes(), 0, content.length());
-        fw.close();
-        return mContext.getFilesDir() + "/content.txt";
-    }
-
-    private String createSignature(String content, String version, String requiredHash)
-                                   throws Exception {
-        Signature signer = Signature.getInstance("SHA512withRSA");
-        signer.initSign(createKey());
-        signer.update(content.trim().getBytes());
-        signer.update(version.trim().getBytes());
-        signer.update(requiredHash.getBytes());
-        String sig = new String(Base64.encode(signer.sign(), Base64.DEFAULT));
-        assertEquals(true,
-                     verifySignature(content, version, requiredHash, sig, createCertificate()));
-        return sig;
-    }
-
-    public boolean verifySignature(String content, String version, String requiredPrevious,
-                                   String signature, X509Certificate cert) throws Exception {
-        Signature signer = Signature.getInstance("SHA512withRSA");
-        signer.initVerify(cert);
-        signer.update(content.trim().getBytes());
-        signer.update(version.trim().getBytes());
-        signer.update(requiredPrevious.trim().getBytes());
-        return signer.verify(Base64.decode(signature.getBytes(), Base64.DEFAULT));
-    }
-
-    private void sendIntent(String contentPath, String version, String required, String sig) {
-        Intent i = new Intent();
-        i.setAction("android.intent.action.UPDATE_PINS");
-        i.putExtra(EXTRA_CONTENT_PATH, contentPath);
-        i.putExtra(EXTRA_VERSION_NUMBER, version);
-        i.putExtra(EXTRA_REQUIRED_HASH, required);
-        i.putExtra(EXTRA_SIGNATURE, sig);
-        mContext.sendBroadcast(i);
-    }
-
-    private String runTest(String cert, String content, String version, String required, String sig)
-                           throws Exception {
-        Log.e(TAG, "started test");
-        overrideCert(cert);
-        String contentPath = makeTemporaryContentFile(content);
-        sendIntent(contentPath, version, required, sig);
-        Thread.sleep(1000);
-        return readPins();
-    }
-
-    private String runTestWithoutSig(String cert, String content, String version, String required)
-                                     throws Exception {
-        String sig = createSignature(content, version, required);
-        return runTest(cert, content, version, required, sig);
-    }
-
-    public void testOverwritePinlist() throws Exception {
-        Log.e(TAG, "started testOverwritePinList");
-        assertEquals("abcde", runTestWithoutSig(TEST_CERT, "abcde", getNextVersion(), getHashOfCurrentContent()));
-        Log.e(TAG, "started testOverwritePinList");
-    }
-
-   public void testBadSignatureFails() throws Exception {
-        Log.e(TAG, "started testOverwritePinList");
-        String text = "blahblah";
-        runTestWithoutSig(TEST_CERT, text, getNextVersion(), getHashOfCurrentContent());
-        assertEquals(text, runTest(TEST_CERT, "bcdef", getNextVersion(), getCurrentHash(text), ""));
-        Log.e(TAG, "started testOverwritePinList");
-    }
-
-    public void testBadRequiredHashFails() throws Exception {
-        runTestWithoutSig(TEST_CERT, "blahblahblah", getNextVersion(), getHashOfCurrentContent());
-        assertEquals("blahblahblah", runTestWithoutSig(TEST_CERT, "cdefg", getNextVersion(), "0"));
-        Log.e(TAG, "started testOverwritePinList");
-    }
-
-    public void testBadVersionFails() throws Exception {
-        String text = "blahblahblahblah";
-        String version = getNextVersion();
-        runTestWithoutSig(TEST_CERT, text, version, getHashOfCurrentContent());
-        assertEquals(text, runTestWithoutSig(TEST_CERT, "defgh", version, getCurrentHash(text)));
-        Log.e(TAG, "started testOverwritePinList");
-    }
-
-    public void testOverrideRequiredHash() throws Exception {
-        runTestWithoutSig(TEST_CERT, "blahblahblah", getNextVersion(), getHashOfCurrentContent());
-        assertEquals("blahblahblah", runTestWithoutSig(TEST_CERT, "cdefg", "NONE", "0"));
-        Log.e(TAG, "started testOverwritePinList");
-    }
-
-}
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index 77168f9..9c2e1b9 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -1946,7 +1946,7 @@
                 const bool pub = (typeSpecFlags&ResTable_typeSpec::SPEC_PUBLIC) != 0;
 
                 fprintf(fp,
-                        "int styleable %s_%s %d\n",
+                        "int styleable.%s_%s %d\n",
                         nclassName.string(),
                         String8(name).string(), (int)pos);
             }
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pService.java b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
index f0aef92..ba8ffec 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pService.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
@@ -30,6 +30,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
+import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.net.IConnectivityManager;
 import android.net.ConnectivityManager;
@@ -68,6 +69,7 @@
 import android.text.TextUtils;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -1927,6 +1929,26 @@
                 break;
         }
 
+        if ((r.getConfiguration().uiMode & Configuration.UI_MODE_TYPE_APPLIANCE) ==
+                Configuration.UI_MODE_TYPE_APPLIANCE) {
+            // For appliance devices, add a key listener which accepts.
+            dialog.setOnKeyListener(new DialogInterface.OnKeyListener() {
+
+                @Override
+                public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
+                    // TODO: make the actual key come from a config value.
+                    if (keyCode == KeyEvent.KEYCODE_VOLUME_MUTE) {
+                        sendMessage(PEER_CONNECTION_USER_ACCEPT);
+                        dialog.dismiss();
+                        return true;
+                    }
+                    return false;
+                }
+            });
+            // TODO: add timeout for this dialog.
+            // TODO: update UI in appliance mode to tell user what to do.
+        }
+
         dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
         dialog.show();
     }