am 9dfca201: Merge "Print newly generated userId." into jb-mr1-dev
* commit '9dfca20105aa998f5767b1b330bf9307ec479906':
Print newly generated userId.
diff --git a/api/current.txt b/api/current.txt
index 7b2f161..0e3d7a2 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -23460,6 +23460,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);
@@ -23608,6 +23619,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;
@@ -27993,10 +28012,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 {
@@ -28169,14 +28190,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 {
@@ -29202,11 +29225,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 5f65f08..c9a2f91 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -112,7 +112,6 @@
import java.util.regex.Pattern;
import libcore.io.DropBox;
-import libcore.io.EventLogger;
import libcore.io.IoUtils;
import dalvik.system.CloseGuard;
@@ -4959,13 +4958,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;
@@ -4995,9 +4987,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 0475283..df4bb99 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -144,6 +144,8 @@
final TrackballAxis mTrackballAxisX = new TrackballAxis();
final TrackballAxis mTrackballAxisY = new TrackballAxis();
+ final SimulatedTrackball mSimulatedTrackball = new SimulatedTrackball();
+
int mLastJoystickXDirection;
int mLastJoystickYDirection;
int mLastJoystickXKeyCode;
@@ -3387,7 +3389,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);
@@ -3414,12 +3415,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;
@@ -3429,6 +3435,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;
@@ -3439,6 +3448,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);
}