Merge "Properly respect NALLengthSize in the AVC Configuration header to determine how many bits encode the nal unit size."
diff --git a/core/java/android/os/IMountService.aidl b/core/java/android/os/IMountService.aidl
index 1e79030..e73569a 100644
--- a/core/java/android/os/IMountService.aidl
+++ b/core/java/android/os/IMountService.aidl
@@ -42,17 +42,17 @@
/**
* Mount external storage at given mount point.
*/
- void mountMedia(String mountPoint);
+ void mountVolume(String mountPoint);
/**
* Safely unmount external storage at given mount point.
*/
- void unmountMedia(String mountPoint);
+ void unmountVolume(String mountPoint);
/**
* Format external storage given a mount point.
*/
- void formatMedia(String mountPoint);
+ void formatVolume(String mountPoint);
/**
* Returns true if media notification sounds are enabled.
diff --git a/core/java/android/pim/vcard/VCardParser_V21.java b/core/java/android/pim/vcard/VCardParser_V21.java
index e7c19cf..c2928cb 100644
--- a/core/java/android/pim/vcard/VCardParser_V21.java
+++ b/core/java/android/pim/vcard/VCardParser_V21.java
@@ -110,11 +110,11 @@
private long mTimeHandleBase64;
public VCardParser_V21() {
- this(VCardConfig.PARSE_TYPE_UNKNOWN);
+ this(null);
}
public VCardParser_V21(VCardSourceDetector detector) {
- this(detector.getEstimatedType());
+ this(detector != null ? detector.getEstimatedType() : VCardConfig.PARSE_TYPE_UNKNOWN);
}
public VCardParser_V21(int parseType) {
diff --git a/core/java/android/provider/Calendar.java b/core/java/android/provider/Calendar.java
index 7f947e9..509aac5 100644
--- a/core/java/android/provider/Calendar.java
+++ b/core/java/android/provider/Calendar.java
@@ -583,14 +583,14 @@
* {@link #ACCOUNT_TYPE} identifies a specific account.
* <P>Type: TEXT</P>
*/
- public static final String ACCOUNT_NAME = "account_name";
+ public static final String ACCOUNT_NAME = "_sync_account";
/**
* The type of account to which this row belongs, which when paired with
* {@link #ACCOUNT_NAME} identifies a specific account.
* <P>Type: TEXT</P>
*/
- public static final String ACCOUNT_TYPE = "account_type";
+ public static final String ACCOUNT_TYPE = "_sync_account_type";
public static EntityIterator newEntityIterator(Cursor cursor, ContentResolver resolver) {
return new EntityIteratorImpl(cursor, resolver);
diff --git a/core/java/android/view/TransformGestureDetector.java b/core/java/android/view/TransformGestureDetector.java
new file mode 100644
index 0000000..196716a
--- /dev/null
+++ b/core/java/android/view/TransformGestureDetector.java
@@ -0,0 +1,316 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import android.content.Context;
+import android.util.Log;
+import android.view.GestureDetector.SimpleOnGestureListener;
+
+/**
+ * Detects transformation gestures involving more than one pointer ("multitouch")
+ * using the supplied {@link MotionEvent}s. The {@link OnGestureListener} callback
+ * will notify users when a particular gesture event has occurred. This class
+ * should only be used with {@link MotionEvent}s reported via touch.
+ *
+ * To use this class:
+ * <ul>
+ * <li>Create an instance of the {@code TransformGestureDetector} for your
+ * {@link View}
+ * <li>In the {@link View#onTouchEvent(MotionEvent)} method ensure you call
+ * {@link #onTouchEvent(MotionEvent)}. The methods defined in your
+ * callback will be executed when the events occur.
+ * </ul>
+ * @hide Pending API approval
+ */
+public class TransformGestureDetector {
+ /**
+ * The listener for receiving notifications when gestures occur.
+ * If you want to listen for all the different gestures then implement
+ * this interface. If you only want to listen for a subset it might
+ * be easier to extend {@link SimpleOnGestureListener}.
+ *
+ * An application will receive events in the following order:
+ * One onTransformBegin()
+ * Zero or more onTransform()
+ * One onTransformEnd() or onTransformFling()
+ */
+ public interface OnTransformGestureListener {
+ /**
+ * Responds to transformation events for a gesture in progress.
+ * Reported by pointer motion.
+ *
+ * @param detector The detector reporting the event - use this to
+ * retrieve extended info about event state.
+ * @return true if the event was handled, false otherwise.
+ */
+ public boolean onTransform(TransformGestureDetector detector);
+
+ /**
+ * Responds to the beginning of a transformation gesture. Reported by
+ * new pointers going down.
+ *
+ * @param detector The detector reporting the event - use this to
+ * retrieve extended info about event state.
+ * @return true if the event was handled, false otherwise.
+ */
+ public boolean onTransformBegin(TransformGestureDetector detector);
+
+ /**
+ * Responds to the end of a transformation gesture. Reported by existing
+ * pointers going up. If the end of a gesture would result in a fling,
+ * onTransformFling is called instead.
+ *
+ * @param detector The detector reporting the event - use this to
+ * retrieve extended info about event state.
+ * @return true if the event was handled, false otherwise.
+ */
+ public boolean onTransformEnd(TransformGestureDetector detector);
+
+ /**
+ * Responds to the end of a transformation gesture that begins a fling.
+ * Reported by existing pointers going up. If the end of a gesture
+ * would not result in a fling, onTransformEnd is called instead.
+ *
+ * @param detector The detector reporting the event - use this to
+ * retrieve extended info about event state.
+ * @return true if the event was handled, false otherwise.
+ */
+ public boolean onTransformFling(TransformGestureDetector detector);
+ }
+
+ private static final boolean DEBUG = false;
+
+ private static final int INITIAL_EVENT_IGNORES = 2;
+
+ private Context mContext;
+ private float mTouchSizeScale;
+ private OnTransformGestureListener mListener;
+ private int mVelocityTimeUnits;
+ private MotionEvent mInitialEvent;
+
+ private MotionEvent mPrevEvent;
+ private MotionEvent mCurrEvent;
+ private VelocityTracker mVelocityTracker;
+
+ private float mCenterX;
+ private float mCenterY;
+ private float mTransX;
+ private float mTransY;
+ private float mPrevFingerDiffX;
+ private float mPrevFingerDiffY;
+ private float mCurrFingerDiffX;
+ private float mCurrFingerDiffY;
+ private float mRotateDegrees;
+ private float mCurrLen;
+ private float mPrevLen;
+ private float mScaleFactor;
+
+ // Units in pixels. Current value is pulled out of thin air for debugging only.
+ private float mPointerJumpLimit = 30;
+
+ private int mEventIgnoreCount;
+
+ public TransformGestureDetector(Context context, OnTransformGestureListener listener,
+ int velocityTimeUnits) {
+ mContext = context;
+ mListener = listener;
+ mTouchSizeScale = context.getResources().getDisplayMetrics().widthPixels/3;
+ mVelocityTimeUnits = velocityTimeUnits;
+ mEventIgnoreCount = INITIAL_EVENT_IGNORES;
+ }
+
+ public TransformGestureDetector(Context context, OnTransformGestureListener listener) {
+ this(context, listener, 1000);
+ }
+
+ public boolean onTouchEvent(MotionEvent event) {
+ final int action = event.getAction();
+ boolean handled = true;
+
+ if (mInitialEvent == null) {
+ // No transform gesture in progress
+ if ((action == MotionEvent.ACTION_POINTER_1_DOWN ||
+ action == MotionEvent.ACTION_POINTER_2_DOWN) &&
+ event.getPointerCount() >= 2) {
+ // We have a new multi-finger gesture
+ mInitialEvent = MotionEvent.obtain(event);
+ mPrevEvent = MotionEvent.obtain(event);
+ mVelocityTracker = VelocityTracker.obtain();
+ handled = mListener.onTransformBegin(this);
+ }
+ } else {
+ // Transform gesture in progress - attempt to handle it
+ switch (action) {
+ case MotionEvent.ACTION_POINTER_1_UP:
+ case MotionEvent.ACTION_POINTER_2_UP:
+ // Gesture ended
+ handled = mListener.onTransformEnd(this);
+
+ reset();
+ break;
+
+ case MotionEvent.ACTION_CANCEL:
+ handled = mListener.onTransformEnd(this);
+
+ reset();
+ break;
+
+ case MotionEvent.ACTION_MOVE:
+ setContext(event);
+
+ // Our first few events can be crazy from some touchscreens - drop them.
+ if (mEventIgnoreCount == 0) {
+ mVelocityTracker.addMovement(event);
+ handled = mListener.onTransform(this);
+ } else {
+ mEventIgnoreCount--;
+ }
+
+ mPrevEvent.recycle();
+ mPrevEvent = MotionEvent.obtain(event);
+ break;
+ }
+ }
+ return handled;
+ }
+
+ private void setContext(MotionEvent curr) {
+ mCurrEvent = MotionEvent.obtain(curr);
+
+ mRotateDegrees = -1;
+ mCurrLen = -1;
+ mPrevLen = -1;
+ mScaleFactor = -1;
+
+ final MotionEvent prev = mPrevEvent;
+
+ float px0 = prev.getX(0);
+ float py0 = prev.getY(0);
+ float px1 = prev.getX(1);
+ float py1 = prev.getY(1);
+ float cx0 = curr.getX(0);
+ float cy0 = curr.getY(0);
+ float cx1 = curr.getX(1);
+ float cy1 = curr.getY(1);
+
+ // Some touchscreens do weird things with pointer values where points are
+ // too close along one axis. Try to detect this here and smooth things out.
+ // The main indicator is that we get the X or Y value from the other pointer.
+ final float dx0 = cx0 - px0;
+ final float dy0 = cy0 - py0;
+ final float dx1 = cx1 - px1;
+ final float dy1 = cy1 - py1;
+
+ if (cx0 == cx1) {
+ if (Math.abs(dx0) > mPointerJumpLimit) {
+ cx0 = px0;
+ } else if (Math.abs(dx1) > mPointerJumpLimit) {
+ cx1 = px1;
+ }
+ } else if (cy0 == cy1) {
+ if (Math.abs(dy0) > mPointerJumpLimit) {
+ cy0 = py0;
+ } else if (Math.abs(dy1) > mPointerJumpLimit) {
+ cy1 = py1;
+ }
+ }
+
+ final float pvx = px1 - px0;
+ final float pvy = py1 - py0;
+ final float cvx = cx1 - cx0;
+ final float cvy = cy1 - cy0;
+ mPrevFingerDiffX = pvx;
+ mPrevFingerDiffY = pvy;
+ mCurrFingerDiffX = cvx;
+ mCurrFingerDiffY = cvy;
+
+ final float pmidx = px0 + pvx * 0.5f;
+ final float pmidy = py0 + pvy * 0.5f;
+ final float cmidx = cx0 + cvx * 0.5f;
+ final float cmidy = cy0 + cvy * 0.5f;
+
+ mCenterX = cmidx;
+ mCenterY = cmidy;
+ mTransX = cmidx - pmidx;
+ mTransY = cmidy - pmidy;
+ }
+
+ private void reset() {
+ if (mInitialEvent != null) {
+ mInitialEvent.recycle();
+ mInitialEvent = null;
+ }
+ if (mPrevEvent != null) {
+ mPrevEvent.recycle();
+ mPrevEvent = null;
+ }
+ if (mCurrEvent != null) {
+ mCurrEvent.recycle();
+ mCurrEvent = null;
+ }
+ if (mVelocityTracker != null) {
+ mVelocityTracker.recycle();
+ mVelocityTracker = null;
+ }
+ mEventIgnoreCount = INITIAL_EVENT_IGNORES;
+ }
+
+ public float getCenterX() {
+ return mCenterX;
+ }
+
+ public float getCenterY() {
+ return mCenterY;
+ }
+
+ public float getTranslateX() {
+ return mTransX;
+ }
+
+ public float getTranslateY() {
+ return mTransY;
+ }
+
+ public float getCurrentSpan() {
+ if (mCurrLen == -1) {
+ final float cvx = mCurrFingerDiffX;
+ final float cvy = mCurrFingerDiffY;
+ mCurrLen = (float)Math.sqrt(cvx*cvx + cvy*cvy);
+ }
+ return mCurrLen;
+ }
+
+ public float getPreviousSpan() {
+ if (mPrevLen == -1) {
+ final float pvx = mPrevFingerDiffX;
+ final float pvy = mPrevFingerDiffY;
+ mPrevLen = (float)Math.sqrt(pvx*pvx + pvy*pvy);
+ }
+ return mPrevLen;
+ }
+
+ public float getScaleFactor() {
+ if (mScaleFactor == -1) {
+ mScaleFactor = getCurrentSpan() / getPreviousSpan();
+ }
+ return mScaleFactor;
+ }
+
+ public float getRotation() {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/core/java/android/view/VelocityTracker.java b/core/java/android/view/VelocityTracker.java
index 5d89c46..9581080 100644
--- a/core/java/android/view/VelocityTracker.java
+++ b/core/java/android/view/VelocityTracker.java
@@ -55,12 +55,12 @@
}
}, 2));
- final float mPastX[] = new float[NUM_PAST];
- final float mPastY[] = new float[NUM_PAST];
- final long mPastTime[] = new long[NUM_PAST];
+ final float mPastX[][] = new float[MotionEvent.BASE_AVAIL_POINTERS][NUM_PAST];
+ final float mPastY[][] = new float[MotionEvent.BASE_AVAIL_POINTERS][NUM_PAST];
+ final long mPastTime[][] = new long[MotionEvent.BASE_AVAIL_POINTERS][NUM_PAST];
- float mYVelocity;
- float mXVelocity;
+ float mYVelocity[] = new float[MotionEvent.BASE_AVAIL_POINTERS];
+ float mXVelocity[] = new float[MotionEvent.BASE_AVAIL_POINTERS];
private VelocityTracker mNext;
@@ -105,7 +105,9 @@
* Reset the velocity tracker back to its initial state.
*/
public void clear() {
- mPastTime[0] = 0;
+ for (int i = 0; i < MotionEvent.BASE_AVAIL_POINTERS; i++) {
+ mPastTime[i][0] = 0;
+ }
}
/**
@@ -120,18 +122,21 @@
public void addMovement(MotionEvent ev) {
long time = ev.getEventTime();
final int N = ev.getHistorySize();
- for (int i=0; i<N; i++) {
- addPoint(ev.getHistoricalX(i), ev.getHistoricalY(i),
- ev.getHistoricalEventTime(i));
+ final int pointerCount = ev.getPointerCount();
+ for (int p = 0; p < pointerCount; p++) {
+ for (int i=0; i<N; i++) {
+ addPoint(p, ev.getHistoricalX(p, i), ev.getHistoricalY(p, i),
+ ev.getHistoricalEventTime(i));
+ }
+ addPoint(p, ev.getX(p), ev.getY(p), time);
}
- addPoint(ev.getX(), ev.getY(), time);
}
- private void addPoint(float x, float y, long time) {
+ private void addPoint(int pos, float x, float y, long time) {
int drop = -1;
int i;
if (localLOGV) Log.v(TAG, "Adding past y=" + y + " time=" + time);
- final long[] pastTime = mPastTime;
+ final long[] pastTime = mPastTime[pos];
for (i=0; i<NUM_PAST; i++) {
if (pastTime[i] == 0) {
break;
@@ -146,8 +151,8 @@
drop = 0;
}
if (drop == i) drop--;
- final float[] pastX = mPastX;
- final float[] pastY = mPastY;
+ final float[] pastX = mPastX[pos];
+ final float[] pastY = mPastY[pos];
if (drop >= 0) {
if (localLOGV) Log.v(TAG, "Dropping up to #" + drop);
final int start = drop+1;
@@ -190,44 +195,48 @@
* must be positive.
*/
public void computeCurrentVelocity(int units, float maxVelocity) {
- final float[] pastX = mPastX;
- final float[] pastY = mPastY;
- final long[] pastTime = mPastTime;
-
- // Kind-of stupid.
- final float oldestX = pastX[0];
- final float oldestY = pastY[0];
- final long oldestTime = pastTime[0];
- float accumX = 0;
- float accumY = 0;
- int N=0;
- while (N < NUM_PAST) {
- if (pastTime[N] == 0) {
- break;
+ for (int pos = 0; pos < MotionEvent.BASE_AVAIL_POINTERS; pos++) {
+ final float[] pastX = mPastX[pos];
+ final float[] pastY = mPastY[pos];
+ final long[] pastTime = mPastTime[pos];
+
+ // Kind-of stupid.
+ final float oldestX = pastX[0];
+ final float oldestY = pastY[0];
+ final long oldestTime = pastTime[0];
+ float accumX = 0;
+ float accumY = 0;
+ int N=0;
+ while (N < NUM_PAST) {
+ if (pastTime[N] == 0) {
+ break;
+ }
+ N++;
}
- N++;
+ // Skip the last received event, since it is probably pretty noisy.
+ if (N > 3) N--;
+
+ for (int i=1; i < N; i++) {
+ final int dur = (int)(pastTime[i] - oldestTime);
+ if (dur == 0) continue;
+ float dist = pastX[i] - oldestX;
+ float vel = (dist/dur) * units; // pixels/frame.
+ if (accumX == 0) accumX = vel;
+ else accumX = (accumX + vel) * .5f;
+
+ dist = pastY[i] - oldestY;
+ vel = (dist/dur) * units; // pixels/frame.
+ if (accumY == 0) accumY = vel;
+ else accumY = (accumY + vel) * .5f;
+ }
+ mXVelocity[pos] = accumX < 0.0f ? Math.max(accumX, -maxVelocity)
+ : Math.min(accumX, maxVelocity);
+ mYVelocity[pos] = accumY < 0.0f ? Math.max(accumY, -maxVelocity)
+ : Math.min(accumY, maxVelocity);
+
+ if (localLOGV) Log.v(TAG, "Y velocity=" + mYVelocity +" X velocity="
+ + mXVelocity + " N=" + N);
}
- // Skip the last received event, since it is probably pretty noisy.
- if (N > 3) N--;
-
- for (int i=1; i < N; i++) {
- final int dur = (int)(pastTime[i] - oldestTime);
- if (dur == 0) continue;
- float dist = pastX[i] - oldestX;
- float vel = (dist/dur) * units; // pixels/frame.
- if (accumX == 0) accumX = vel;
- else accumX = (accumX + vel) * .5f;
-
- dist = pastY[i] - oldestY;
- vel = (dist/dur) * units; // pixels/frame.
- if (accumY == 0) accumY = vel;
- else accumY = (accumY + vel) * .5f;
- }
- mXVelocity = accumX < 0.0f ? Math.max(accumX, -maxVelocity) : Math.min(accumX, maxVelocity);
- mYVelocity = accumY < 0.0f ? Math.max(accumY, -maxVelocity) : Math.min(accumY, maxVelocity);
-
- if (localLOGV) Log.v(TAG, "Y velocity=" + mYVelocity +" X velocity="
- + mXVelocity + " N=" + N);
}
/**
@@ -237,7 +246,7 @@
* @return The previously computed X velocity.
*/
public float getXVelocity() {
- return mXVelocity;
+ return mXVelocity[0];
}
/**
@@ -247,6 +256,32 @@
* @return The previously computed Y velocity.
*/
public float getYVelocity() {
- return mYVelocity;
+ return mYVelocity[0];
+ }
+
+ /**
+ * Retrieve the last computed X velocity. You must first call
+ * {@link #computeCurrentVelocity(int)} before calling this function.
+ *
+ * @param pos Which pointer's velocity to return.
+ * @return The previously computed X velocity.
+ *
+ * @hide Pending API approval
+ */
+ public float getXVelocity(int pos) {
+ return mXVelocity[pos];
+ }
+
+ /**
+ * Retrieve the last computed Y velocity. You must first call
+ * {@link #computeCurrentVelocity(int)} before calling this function.
+ *
+ * @param pos Which pointer's velocity to return.
+ * @return The previously computed Y velocity.
+ *
+ * @hide Pending API approval
+ */
+ public float getYVelocity(int pos) {
+ return mYVelocity[pos];
}
}
diff --git a/core/java/com/android/internal/app/ExternalMediaFormatActivity.java b/core/java/com/android/internal/app/ExternalMediaFormatActivity.java
index 000f6c4..2b07ae6 100644
--- a/core/java/com/android/internal/app/ExternalMediaFormatActivity.java
+++ b/core/java/com/android/internal/app/ExternalMediaFormatActivity.java
@@ -102,7 +102,7 @@
.getService("mount"));
if (mountService != null) {
try {
- mountService.formatMedia(Environment.getExternalStorageDirectory().toString());
+ mountService.formatVolume(Environment.getExternalStorageDirectory().toString());
} catch (RemoteException e) {
}
}
diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java
index 115dd62..7d100eb 100644
--- a/graphics/java/android/renderscript/Allocation.java
+++ b/graphics/java/android/renderscript/Allocation.java
@@ -39,6 +39,10 @@
mType = t;
}
+ public Type getType() {
+ return mType;
+ }
+
public void uploadToTexture(int baseMipLevel) {
mRS.validate();
mRS.validateSurface();
diff --git a/graphics/java/android/renderscript/Program.java b/graphics/java/android/renderscript/Program.java
index 9d70cb2..1614ec5 100644
--- a/graphics/java/android/renderscript/Program.java
+++ b/graphics/java/android/renderscript/Program.java
@@ -111,12 +111,13 @@
mOutputs[mOutputCount++] = e;
}
- public void addConstant(Type t) throws IllegalStateException {
+ public int addConstant(Type t) throws IllegalStateException {
// Should check for consistant and non-conflicting names...
if(mConstantCount >= MAX_CONSTANT) {
throw new IllegalArgumentException("Max input count exceeded.");
}
- mConstants[mConstantCount++] = t;
+ mConstants[mConstantCount] = t;
+ return mConstantCount++;
}
public void setTextureCount(int count) throws IllegalArgumentException {
diff --git a/libs/rs/rsProgram.cpp b/libs/rs/rsProgram.cpp
index b7639be..b528c46 100644
--- a/libs/rs/rsProgram.cpp
+++ b/libs/rs/rsProgram.cpp
@@ -95,7 +95,9 @@
Program::~Program()
{
- bindAllocation(NULL);
+ for (uint32_t ct=0; ct < MAX_UNIFORMS; ct++) {
+ bindAllocation(NULL, ct);
+ }
delete[] mInputElements;
delete[] mOutputElements;
@@ -106,15 +108,16 @@
}
-void Program::bindAllocation(Allocation *alloc)
+void Program::bindAllocation(Allocation *alloc, uint32_t slot)
{
- if (mConstants.get() == alloc) {
+ LOGE("bind alloc %p %i", alloc, slot);
+ if (mConstants[slot].get() == alloc) {
return;
}
- if (mConstants.get()) {
- mConstants.get()->removeProgramToDirty(this);
+ if (mConstants[slot].get()) {
+ mConstants[slot].get()->removeProgramToDirty(this);
}
- mConstants.set(alloc);
+ mConstants[slot].set(alloc);
if (alloc) {
alloc->addProgramToDirty(this);
}
@@ -239,7 +242,7 @@
void rsi_ProgramBindConstants(Context *rsc, RsProgram vp, uint32_t slot, RsAllocation constants)
{
Program *p = static_cast<Program *>(vp);
- p->bindAllocation(static_cast<Allocation *>(constants));
+ p->bindAllocation(static_cast<Allocation *>(constants), slot);
}
void rsi_ProgramBindTexture(Context *rsc, RsProgram vpf, uint32_t slot, RsAllocation a)
diff --git a/libs/rs/rsProgram.h b/libs/rs/rsProgram.h
index 4bb7802..a34e89f 100644
--- a/libs/rs/rsProgram.h
+++ b/libs/rs/rsProgram.h
@@ -39,7 +39,7 @@
const uint32_t * params, uint32_t paramLength);
virtual ~Program();
- void bindAllocation(Allocation *);
+ void bindAllocation(Allocation *, uint32_t slot);
virtual void createShader();
bool isUserProgram() const {return mUserShader.size() > 0;}
@@ -69,7 +69,7 @@
uint32_t mOutputCount;
uint32_t mConstantCount;
- ObjectBaseRef<Allocation> mConstants;
+ ObjectBaseRef<Allocation> mConstants[MAX_UNIFORMS];
mutable bool mDirty;
String8 mShader;
diff --git a/libs/rs/rsProgramVertex.cpp b/libs/rs/rsProgramVertex.cpp
index 8e59bc2..8849bda 100644
--- a/libs/rs/rsProgramVertex.cpp
+++ b/libs/rs/rsProgramVertex.cpp
@@ -69,7 +69,7 @@
}
state->mLast.set(this);
- const float *f = static_cast<const float *>(mConstants->getPtr());
+ const float *f = static_cast<const float *>(mConstants[0]->getPtr());
glMatrixMode(GL_TEXTURE);
if (mTextureMatrixEnable) {
@@ -116,16 +116,37 @@
{
mShader.setTo("");
- for (uint32_t ct=0; ct < mUniformCount; ct++) {
- mShader.append("uniform mat4 ");
- mShader.append(mUniformNames[ct]);
- mShader.append(";\n");
- }
-
mShader.append("varying vec4 varColor;\n");
mShader.append("varying vec4 varTex0;\n");
if (mUserShader.length() > 1) {
+ mShader.append("uniform mat4 ");
+ mShader.append(mUniformNames[0]);
+ mShader.append(";\n");
+
+ LOGE("constant %i ", mConstantCount);
+ for (uint32_t ct=0; ct < mConstantCount; ct++) {
+ const Element *e = mConstantTypes[ct]->getElement();
+ for (uint32_t field=0; field < e->getFieldCount(); field++) {
+ const Element *f = e->getField(field);
+
+ // Cannot be complex
+ rsAssert(!f->getFieldCount());
+ switch(f->getComponent().getVectorSize()) {
+ case 1: mShader.append("uniform float UNI_"); break;
+ case 2: mShader.append("uniform vec2 UNI_"); break;
+ case 3: mShader.append("uniform vec3 UNI_"); break;
+ case 4: mShader.append("uniform vec4 UNI_"); break;
+ default:
+ rsAssert(0);
+ }
+
+ mShader.append(e->getFieldName(field));
+ mShader.append(";\n");
+ }
+ }
+
+
for (uint32_t ct=0; ct < mInputCount; ct++) {
const Element *e = mInputElements[ct].get();
for (uint32_t field=0; field < e->getFieldCount(); field++) {
@@ -148,6 +169,12 @@
}
mShader.append(mUserShader);
} else {
+ for (uint32_t ct=0; ct < mUniformCount; ct++) {
+ mShader.append("uniform mat4 ");
+ mShader.append(mUniformNames[ct]);
+ mShader.append(";\n");
+ }
+
for (uint32_t ct=VertexArray::POSITION; ct < mAttribCount; ct++) {
mShader.append("attribute vec4 ");
mShader.append(mAttribNames[ct]);
@@ -155,12 +182,12 @@
}
mShader.append("void main() {\n");
- mShader.append(" gl_Position = uni_MVP * ATTRIB_Position;\n");
+ mShader.append(" gl_Position = UNI_MVP * ATTRIB_Position;\n");
mShader.append(" gl_PointSize = ATTRIB_PointSize.x;\n");
mShader.append(" varColor = ATTRIB_Color;\n");
if (mTextureMatrixEnable) {
- mShader.append(" varTex0 = uni_TexMatrix * ATTRIB_Texture;\n");
+ mShader.append(" varTex0 = UNI_TexMatrix * ATTRIB_Texture;\n");
} else {
mShader.append(" varTex0 = ATTRIB_Texture;\n");
}
@@ -180,7 +207,7 @@
glVertexAttrib4f(1, state->color[0], state->color[1], state->color[2], state->color[3]);
- const float *f = static_cast<const float *>(mConstants->getPtr());
+ const float *f = static_cast<const float *>(mConstants[0]->getPtr());
Matrix mvp;
mvp.load(&f[RS_PROGRAM_VERTEX_PROJECTION_OFFSET]);
@@ -194,6 +221,54 @@
&f[RS_PROGRAM_VERTEX_TEXTURE_OFFSET]);
}
+ uint32_t uidx = 1;
+ for (uint32_t ct=0; ct < mConstantCount; ct++) {
+ Allocation *alloc = mConstants[ct+1].get();
+ if (!alloc) {
+ continue;
+ }
+
+ const uint8_t *data = static_cast<const uint8_t *>(alloc->getPtr());
+ const Element *e = mConstantTypes[ct]->getElement();
+ for (uint32_t field=0; field < e->getFieldCount(); field++) {
+ const Element *f = e->getField(field);
+ uint32_t offset = e->getFieldOffsetBytes(field);
+ int32_t slot = sc->vtxUniformSlot(uidx);
+
+ const float *fd = reinterpret_cast<const float *>(&data[offset]);
+
+ //LOGE("Uniform slot=%i, offset=%i, constant=%i, field=%i, uidx=%i", slot, offset, ct, field, uidx);
+ if (slot >= 0) {
+ switch(f->getComponent().getVectorSize()) {
+ case 1:
+ //LOGE("Uniform 1 = %f", fd[0]);
+ glUniform1fv(slot, 1, fd);
+ break;
+ case 2:
+ //LOGE("Uniform 2 = %f %f", fd[0], fd[1]);
+ glUniform2fv(slot, 1, fd);
+ break;
+ case 3:
+ //LOGE("Uniform 3 = %f %f %f", fd[0], fd[1], fd[2]);
+ glUniform3fv(slot, 1, fd);
+ break;
+ case 4:
+ //LOGE("Uniform 4 = %f %f %f %f", fd[0], fd[1], fd[2], fd[3]);
+ glUniform4fv(slot, 1, fd);
+ break;
+ default:
+ rsAssert(0);
+ }
+ }
+ uidx ++;
+ }
+ }
+
+ for (uint32_t ct=0; ct < mConstantCount; ct++) {
+ uint32_t glSlot = sc->vtxUniformSlot(ct + 1);
+
+ }
+
state->mLast.set(this);
rsc->checkError("ProgramVertex::setupGL2");
}
@@ -208,46 +283,46 @@
void ProgramVertex::setProjectionMatrix(const rsc_Matrix *m) const
{
- float *f = static_cast<float *>(mConstants->getPtr());
+ float *f = static_cast<float *>(mConstants[0]->getPtr());
memcpy(&f[RS_PROGRAM_VERTEX_PROJECTION_OFFSET], m, sizeof(rsc_Matrix));
mDirty = true;
}
void ProgramVertex::setModelviewMatrix(const rsc_Matrix *m) const
{
- float *f = static_cast<float *>(mConstants->getPtr());
+ float *f = static_cast<float *>(mConstants[0]->getPtr());
memcpy(&f[RS_PROGRAM_VERTEX_MODELVIEW_OFFSET], m, sizeof(rsc_Matrix));
mDirty = true;
}
void ProgramVertex::setTextureMatrix(const rsc_Matrix *m) const
{
- float *f = static_cast<float *>(mConstants->getPtr());
+ float *f = static_cast<float *>(mConstants[0]->getPtr());
memcpy(&f[RS_PROGRAM_VERTEX_TEXTURE_OFFSET], m, sizeof(rsc_Matrix));
mDirty = true;
}
void ProgramVertex::transformToScreen(const Context *rsc, float *v4out, const float *v3in) const
{
- float *f = static_cast<float *>(mConstants->getPtr());
+ float *f = static_cast<float *>(mConstants[0]->getPtr());
Matrix mvp;
mvp.loadMultiply((Matrix *)&f[RS_PROGRAM_VERTEX_MODELVIEW_OFFSET],
(Matrix *)&f[RS_PROGRAM_VERTEX_PROJECTION_OFFSET]);
mvp.vectorMultiply(v4out, v3in);
}
-void ProgramVertex::initAddUserAttrib(const Element *e)
+void ProgramVertex::initAddUserElement(const Element *e, String8 *names, uint32_t *count, const char *prefix)
{
rsAssert(e->getFieldCount());
for (uint32_t ct=0; ct < e->getFieldCount(); ct++) {
const Element *ce = e->getField(ct);
if (ce->getFieldCount()) {
- initAddUserAttrib(ce);
+ initAddUserElement(ce, names, count, prefix);
} else {
- String8 tmp("ATTRIB_");
+ String8 tmp(prefix);
tmp.append(e->getFieldName(ct));
- mAttribNames[mAttribCount].setTo(tmp.string());
- mAttribCount++;
+ names[*count].setTo(tmp.string());
+ (*count)++;
}
}
}
@@ -257,7 +332,13 @@
if (mUserShader.size() > 0) {
mAttribCount = 0;
for (uint32_t ct=0; ct < mInputCount; ct++) {
- initAddUserAttrib(mInputElements[ct].get());
+ initAddUserElement(mInputElements[ct].get(), mAttribNames, &mAttribCount, "ATTRIB_");
+ }
+
+ mUniformCount = 1;
+ mUniformNames[0].setTo("UNI_MVP");
+ for (uint32_t ct=0; ct < mInputCount; ct++) {
+ initAddUserElement(mConstantTypes[ct]->getElement(), mUniformNames, &mUniformCount, "UNI_");
}
} else {
mAttribCount = 5;
@@ -266,11 +347,11 @@
mAttribNames[2].setTo("ATTRIB_Normal");
mAttribNames[3].setTo("ATTRIB_PointSize");
mAttribNames[4].setTo("ATTRIB_Texture");
- }
- mUniformCount = 2;
- mUniformNames[0].setTo("uni_MVP");
- mUniformNames[1].setTo("uni_TexMatrix");
+ mUniformCount = 2;
+ mUniformNames[0].setTo("UNI_MVP");
+ mUniformNames[1].setTo("UNI_TexMatrix");
+ }
createShader();
}
@@ -299,7 +380,7 @@
mDefaultAlloc.set(alloc);
mDefault.set(pv);
pv->init(rsc);
- pv->bindAllocation(alloc);
+ pv->bindAllocation(alloc, 0);
color[0] = 1.f;
color[1] = 1.f;
diff --git a/libs/rs/rsProgramVertex.h b/libs/rs/rsProgramVertex.h
index dcb988c..28554cc 100644
--- a/libs/rs/rsProgramVertex.h
+++ b/libs/rs/rsProgramVertex.h
@@ -61,7 +61,7 @@
bool mTextureMatrixEnable;
private:
- void initAddUserAttrib(const Element *e);
+ void initAddUserElement(const Element *e, String8 *names, uint32_t *count, const char *prefix);
};
diff --git a/libs/rs/rsScriptC_Lib.cpp b/libs/rs/rsScriptC_Lib.cpp
index 8a0ab71..3ba9cee 100644
--- a/libs/rs/rsScriptC_Lib.cpp
+++ b/libs/rs/rsScriptC_Lib.cpp
@@ -973,6 +973,13 @@
rsi_AllocationUploadToBufferObject(rsc, va);
}
+static void SC_syncToGL(RsAllocation va)
+{
+ GET_TLS();
+ Allocation *a = static_cast<Allocation *>(va);
+
+}
+
static void SC_ClearColor(float r, float g, float b, float a)
{
//LOGE("c %f %f %f %f", r, g, b, a);
@@ -1321,6 +1328,9 @@
{ "uploadToBufferObject", (void *)&SC_uploadToBufferObject,
"void", "(int)" },
+ { "syncToGL", (void *)&SC_syncToGL,
+ "void", "(int)" },
+
{ "colorFloatRGBAtoUNorm8", (void *)&SC_colorFloatRGBAtoUNorm8,
"int", "(float, float, float, float)" },
{ "colorFloatRGBto565", (void *)&SC_colorFloatRGBAto565,
diff --git a/libs/rs/rsShaderCache.cpp b/libs/rs/rsShaderCache.cpp
index 0d9863de..8ac2487 100644
--- a/libs/rs/rsShaderCache.cpp
+++ b/libs/rs/rsShaderCache.cpp
@@ -132,7 +132,7 @@
LOGV("vtx U, %s = %d\n", vtx->getUniformName(ct).string(), e->mVtxUniformSlots[ct]);
}
}
- for (uint32_t ct=0; ct < vtx->getUniformCount(); ct++) {
+ for (uint32_t ct=0; ct < frag->getUniformCount(); ct++) {
e->mFragUniformSlots[ct] = glGetUniformLocation(pgm, frag->getUniformName(ct));
if (rsc->props.mLogShaders) {
LOGV("frag U, %s = %d\n", frag->getUniformName(ct).string(), e->mFragUniformSlots[ct]);
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index af57a4c..6563caa 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -1258,22 +1258,24 @@
static const int NUMVIZBUF = 32;
static const int VIZBUFFRAMES = 1024;
-static const int TOTALBUFTIMEMSEC = NUMVIZBUF * VIZBUFFRAMES * 1000 / 44100;
+static const int BUFTIMEMSEC = NUMVIZBUF * VIZBUFFRAMES * 1000 / 44100;
+static const int TOTALBUFTIMEMSEC = NUMVIZBUF * BUFTIMEMSEC;
static bool gotMem = false;
+static sp<MemoryHeapBase> heap;
static sp<MemoryBase> mem[NUMVIZBUF];
-static uint64_t timeStamp[NUMVIZBUF];
+static uint64_t endTime;
static uint64_t lastReadTime;
static uint64_t lastWriteTime;
static int writeIdx = 0;
static void allocVizBufs() {
if (!gotMem) {
+ heap = new MemoryHeapBase(NUMVIZBUF * VIZBUFFRAMES * 2, 0, "snooper");
for (int i=0;i<NUMVIZBUF;i++) {
- sp<MemoryHeapBase> heap = new MemoryHeapBase(VIZBUFFRAMES*2, 0, "snooper");
- mem[i] = new MemoryBase(heap, 0, heap->getSize());
- timeStamp[i] = 0;
+ mem[i] = new MemoryBase(heap, VIZBUFFRAMES * 2 * i, VIZBUFFRAMES * 2);
}
+ endTime = 0;
gotMem = true;
}
}
@@ -1290,68 +1292,48 @@
allocVizBufs();
- lastReadTime = uptimeMillis() + 100; // account for renderer delay (we shouldn't be doing this here)
+ lastReadTime = uptimeMillis();
// if there is no recent buffer (yet), just return empty handed
if (lastWriteTime + TOTALBUFTIMEMSEC < lastReadTime) {
- //LOGI("@@@@ no audio data to look at yet");
+ //LOGI("@@@@ no audio data to look at yet: %d + %d < %d", (int)lastWriteTime, TOTALBUFTIMEMSEC, (int)lastReadTime);
return NULL;
}
- char buf[200];
-
- int closestIdx = -1;
- uint32_t closestTime = 0x7ffffff;
-
- for (int i = 0; i < NUMVIZBUF; i++) {
- uint64_t tsi = timeStamp[i];
- uint64_t diff = tsi > lastReadTime ? tsi - lastReadTime : lastReadTime - tsi;
- if (diff < closestTime) {
- closestIdx = i;
- closestTime = diff;
- }
+ int timedelta = endTime - lastReadTime;
+ if (timedelta < 0) timedelta = 0;
+ int framedelta = timedelta * 44100 / 1000;
+ int headIdx = (writeIdx - framedelta) / VIZBUFFRAMES - 1;
+ while (headIdx < 0) {
+ headIdx += NUMVIZBUF;
}
-
-
- if (closestIdx >= 0) {
- //LOGI("@@@ return buffer %d, %d/%d", closestIdx, uint32_t(lastReadTime), uint32_t(timeStamp[closestIdx]));
- return mem[closestIdx];
- }
-
- // we won't get here, since we either bailed out early, or got a buffer
- LOGD("Didn't expect to be here");
- return NULL;
+ return mem[headIdx];
}
-static void storeVizBuf(const void *data, int len, uint64_t time) {
- // Copy the data in to the visualizer buffer
- // Assume a 16 bit stereo source for now.
- short *viz = (short*)mem[writeIdx]->pointer();
- short *src = (short*)data;
- for (int i = 0; i < VIZBUFFRAMES; i++) {
- // Degrade quality by mixing to mono and clearing the lowest 3 bits.
- // This should still be good enough for a visualization
- *viz++ = ((int(src[0]) + int(src[1])) >> 1) & ~0x7;
- src += 2;
- }
- timeStamp[writeIdx++] = time;
- if (writeIdx >= NUMVIZBUF) {
- writeIdx = 0;
- }
-}
-
+// Append the data to the vizualization buffer
static void makeVizBuffers(const char *data, int len, uint64_t time) {
allocVizBufs();
uint64_t startTime = time;
const int frameSize = 4; // 16 bit stereo sample is 4 bytes
- while (len >= VIZBUFFRAMES * frameSize) {
- storeVizBuf(data, len, time);
- data += VIZBUFFRAMES * frameSize;
- len -= VIZBUFFRAMES * frameSize;
- time += 1000 * VIZBUFFRAMES / 44100;
+ int offset = writeIdx;
+ int maxoff = heap->getSize() / 2; // in shorts
+ short *base = (short*)heap->getBase();
+ short *src = (short*)data;
+ while (len > 0) {
+
+ // Degrade quality by mixing to mono and clearing the lowest 3 bits.
+ // This should still be good enough for a visualization
+ base[offset++] = ((int(src[0]) + int(src[1])) >> 1) & ~0x7;
+ src += 2;
+ len -= frameSize;
+ if (offset >= maxoff) {
+ offset = 0;
+ }
}
+ writeIdx = offset;
+ endTime = time + (len / frameSize) / 44;
//LOGI("@@@ stored buffers from %d to %d", uint32_t(startTime), uint32_t(time));
}
@@ -1509,30 +1491,35 @@
}
}
+void MediaPlayerService::AudioOutput::snoopWrite(const void* buffer, size_t size) {
+ // Only make visualization buffers if anyone recently requested visualization data
+ uint64_t now = uptimeMillis();
+ if (lastReadTime + TOTALBUFTIMEMSEC >= now) {
+ // Based on the current play counter, the number of frames written and
+ // the current real time we can calculate the approximate real start
+ // time of the buffer we're about to write.
+ uint32_t pos;
+ mTrack->getPosition(&pos);
+
+ // we're writing ahead by this many frames:
+ int ahead = mNumFramesWritten - pos;
+ //LOGI("@@@ written: %d, playpos: %d, latency: %d", mNumFramesWritten, pos, mTrack->latency());
+ // which is this many milliseconds, assuming 44100 Hz:
+ ahead /= 44;
+
+ makeVizBuffers((const char*)buffer, size, now + ahead + mTrack->latency());
+ lastWriteTime = now;
+ }
+}
+
+
ssize_t MediaPlayerService::AudioOutput::write(const void* buffer, size_t size)
{
LOG_FATAL_IF(mCallback != NULL, "Don't call write if supplying a callback.");
//LOGV("write(%p, %u)", buffer, size);
if (mTrack) {
- // Only make visualization buffers if anyone recently requested visualization data
- uint64_t now = uptimeMillis();
- if (lastReadTime + TOTALBUFTIMEMSEC >= now) {
- // Based on the current play counter, the number of frames written and
- // the current real time we can calculate the approximate real start
- // time of the buffer we're about to write.
- uint32_t pos;
- mTrack->getPosition(&pos);
-
- // we're writing ahead by this many frames:
- int ahead = mNumFramesWritten - pos;
- //LOGI("@@@ written: %d, playpos: %d, latency: %d", mNumFramesWritten, pos, mTrack->latency());
- // which is this many milliseconds, assuming 44100 Hz:
- ahead /= 44;
-
- makeVizBuffers((const char*)buffer, size, now + ahead + mTrack->latency());
- lastWriteTime = now;
- }
+ snoopWrite(buffer, size);
ssize_t ret = mTrack->write(buffer, size);
mNumFramesWritten += ret / 4; // assume 16 bit stereo
return ret;
@@ -1580,6 +1567,7 @@
// static
void MediaPlayerService::AudioOutput::CallbackWrapper(
int event, void *cookie, void *info) {
+ //LOGV("callbackwrapper");
if (event != AudioTrack::EVENT_MORE_DATA) {
return;
}
@@ -1589,6 +1577,7 @@
(*me->mCallback)(
me, buffer->raw, buffer->size, me->mCallbackCookie);
+ me->snoopWrite(buffer->raw, buffer->size);
}
#undef LOG_TAG
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index 1c90cf9..d1206b4 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -113,6 +113,7 @@
public: // visualization hack support
uint32_t mNumFramesWritten;
+ void snoopWrite(const void*, size_t);
};
class AudioCache : public MediaPlayerBase::AudioSink
diff --git a/services/java/com/android/server/INativeDaemonConnectorCallbacks.java b/services/java/com/android/server/INativeDaemonConnectorCallbacks.java
new file mode 100644
index 0000000..6fbf713
--- /dev/null
+++ b/services/java/com/android/server/INativeDaemonConnectorCallbacks.java
@@ -0,0 +1,24 @@
+
+/*
+ * Copyright (C) 2007 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;
+
+interface INativeDaemonConnectorCallbacks {
+
+ void onDaemonConnected();
+ boolean onEvent(int code, String raw, String[] cooked);
+}
diff --git a/services/java/com/android/server/MountListener.java b/services/java/com/android/server/MountListener.java
deleted file mode 100644
index 9443ff8..0000000
--- a/services/java/com/android/server/MountListener.java
+++ /dev/null
@@ -1,377 +0,0 @@
-/*
- * Copyright (C) 2007 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;
-
-import android.net.LocalSocketAddress;
-import android.net.LocalSocket;
-import android.os.Environment;
-import android.os.SystemClock;
-import android.os.SystemProperties;
-import android.util.Config;
-import android.util.Log;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.Socket;
-import java.lang.IllegalStateException;
-
-import java.util.List;
-import java.util.ArrayList;
-import java.util.ListIterator;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.LinkedBlockingQueue;
-
-/**
- * Vold Connection class
- */
-final class MountListener implements Runnable {
- private static final String TAG = "MountListener";
- private static final String VOLD_SOCKET = "vold";
- private static final int RESPONSE_QUEUE_SIZE = 10;
-
- private MountService mService;
- private BlockingQueue<String> mResponseQueue;
- private OutputStream mOutputStream;
-
- class ResponseCode {
- public static final int ActionInitiated = 100;
- public static final int VolumeListResult = 110;
- public static final int AsecListResult = 111;
-
- public static final int CommandOkay = 200;
- public static final int ShareAvailabilityResult = 210;
- public static final int AsecPathResult = 211;
-
- public static final int UnsolicitedInformational = 600;
- public static final int VolumeStateChange = 605;
- public static final int VolumeMountFailedBlank = 610;
- public static final int VolumeMountFailedDamaged = 611;
- public static final int VolumeMountFailedNoMedia = 612;
- public static final int ShareAvailabilityChange = 620;
- public static final int VolumeDiskInserted = 630;
- public static final int VolumeDiskRemoved = 631;
- public static final int VolumeBadRemoval = 632;
- }
-
- MountListener(MountService service) {
- mService = service;
- mResponseQueue = new LinkedBlockingQueue<String>(RESPONSE_QUEUE_SIZE);
- }
-
- public void run() {
- // Vold does not run in the simulator, so fake out a mounted event to trigger the Media Scanner
- if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
- mService.notifyMediaMounted(Environment.getExternalStorageDirectory().getPath(), false);
- return;
- }
-
- try {
- while (true) {
- listenToSocket();
- }
- } catch (Throwable t) {
- Log.e(TAG, "Fatal error " + t + " in MountListener thread!");
- }
- }
-
- private void listenToSocket() {
- LocalSocket socket = null;
-
- try {
- socket = new LocalSocket();
- LocalSocketAddress address = new LocalSocketAddress(VOLD_SOCKET,
- LocalSocketAddress.Namespace.RESERVED);
-
- socket.connect(address);
- mService.onVoldConnected();
-
- InputStream inputStream = socket.getInputStream();
- mOutputStream = socket.getOutputStream();
-
- byte[] buffer = new byte[4096];
-
- while (true) {
- int count = inputStream.read(buffer);
- if (count < 0) break;
-
- int start = 0;
- for (int i = 0; i < count; i++) {
- if (buffer[i] == 0) {
- String event = new String(buffer, start, i - start);
-// Log.d(TAG, "Got packet {" + event + "}");
-
- String[] tokens = event.split(" ");
- try {
- int code = Integer.parseInt(tokens[0]);
-
- if (code >= ResponseCode.UnsolicitedInformational) {
- try {
- handleUnsolicitedEvent(code, event, tokens);
- } catch (Exception ex) {
- Log.e(TAG, String.format(
- "Error handling '%s'", event), ex);
- }
- } else {
- try {
- mResponseQueue.put(event);
- } catch (InterruptedException ex) {
- Log.e(TAG, "InterruptedException");
- }
- }
- } catch (NumberFormatException nfe) {
- Log.w(TAG,
- "Unknown msg from Vold '" + event + "'");
- }
- start = i + 1;
- }
- }
- }
- } catch (IOException ex) {
- Log.e(TAG, "IOException in listenToSocket");
- }
-
- synchronized (this) {
- if (mOutputStream != null) {
- try {
- mOutputStream.close();
- } catch (IOException e) {
- Log.w(TAG, "IOException closing output stream");
- }
-
- mOutputStream = null;
- }
- }
-
- try {
- if (socket != null) {
- socket.close();
- }
- } catch (IOException ex) {
- Log.w(TAG, "IOException closing socket");
- }
-
- Log.e(TAG, "Failed to connect to Vold", new IllegalStateException());
- SystemClock.sleep(5000);
- }
-
- private void handleUnsolicitedEvent(int code, String raw,
- String[] cooked) throws IllegalStateException {
-// Log.d(TAG, "unsolicited {" + raw + "}");
- if (code == ResponseCode.VolumeStateChange) {
- // FMT: NNN Volume <label> <mountpoint> state changed from <old_#> (<old_str>) to <new_#> (<new_str>)
- mService.notifyVolumeStateChange(cooked[2], cooked[3],
- Integer.parseInt(cooked[7]),
- Integer.parseInt(cooked[10]));
- } else if (code == ResponseCode.VolumeMountFailedBlank) {
- // FMT: NNN Volume <label> <mountpoint> mount failed - no supported file-systems
- mService.notifyMediaNoFs(cooked[3]);
- // FMT: NNN Volume <label> <mountpoint> mount failed - no media
- } else if (code == ResponseCode.VolumeMountFailedNoMedia) {
- mService.notifyMediaRemoved(cooked[3]);
- } else if (code == ResponseCode.VolumeMountFailedDamaged) {
- // FMT: NNN Volume <label> <mountpoint> mount failed - filesystem check failed
- mService.notifyMediaUnmountable(cooked[3]);
- } else if (code == ResponseCode.ShareAvailabilityChange) {
- // FMT: NNN Share method <method> now <available|unavailable>
- boolean avail = false;
- if (cooked[5].equals("available")) {
- avail = true;
- }
- mService.notifyShareAvailabilityChange(cooked[3], avail);
- } else if (code == ResponseCode.VolumeDiskInserted) {
- // FMT: NNN Volume <label> <mountpoint> disk inserted (<major>:<minor>)
- mService.notifyMediaInserted(cooked[3]);
- } else if (code == ResponseCode.VolumeDiskRemoved) {
- // FMT: NNN Volume <label> <mountpoint> disk removed (<major>:<minor>)
- mService.notifyMediaRemoved(cooked[3]);
- } else if (code == ResponseCode.VolumeBadRemoval) {
- // FMT: NNN Volume <label> <mountpoint> bad removal (<major>:<minor>)
- mService.notifyMediaBadRemoval(cooked[3]);
- } else {
- Log.w(TAG, "Unhandled event {" + raw + "}");
- }
- }
-
-
- private void sendCommand(String command) {
- sendCommand(command, null);
- }
-
- /**
- * Sends a command to Vold with a single argument
- *
- * @param command The command to send to the mount service daemon
- * @param argument The argument to send with the command (or null)
- */
- private void sendCommand(String command, String argument) {
- synchronized (this) {
- // Log.d(TAG, "sendCommand {" + command + "} {" + argument + "}");
- if (mOutputStream == null) {
- Log.e(TAG, "No connection to Vold", new IllegalStateException());
- } else {
- StringBuilder builder = new StringBuilder(command);
- if (argument != null) {
- builder.append(argument);
- }
- builder.append('\0');
-
- try {
- mOutputStream.write(builder.toString().getBytes());
- } catch (IOException ex) {
- Log.e(TAG, "IOException in sendCommand", ex);
- }
- }
- }
- }
-
- private synchronized ArrayList<String> doCommand(String cmd) throws IllegalStateException {
- sendCommand(cmd);
-
- ArrayList<String> response = new ArrayList<String>();
- boolean complete = false;
- int code = -1;
-
- while (!complete) {
- try {
- String line = mResponseQueue.take();
-// Log.d(TAG, "Removed off queue -> " + line);
- String[] tokens = line.split(" ");
- code = Integer.parseInt(tokens[0]);
-
- if ((code >= 200) && (code < 600))
- complete = true;
- response.add(line);
- } catch (InterruptedException ex) {
- Log.e(TAG, "InterruptedException");
- }
- }
-
- if (code >= 400 && code < 600) {
- throw new IllegalStateException(String.format(
- "Command %s failed with code %d",
- cmd, code));
- }
- return response;
- }
-
- boolean getShareAvailable(String method) throws IllegalStateException {
- ArrayList<String> rsp = doCommand("share_available " + method);
-
- for (String line : rsp) {
- String []tok = line.split(" ");
- int code = Integer.parseInt(tok[0]);
- if (code == ResponseCode.ShareAvailabilityResult) {
- if (tok[2].equals("available"))
- return true;
- return false;
- } else {
- throw new IllegalStateException(String.format("Unexpected response code %d", code));
- }
- }
- throw new IllegalStateException("Got an empty response");
- }
-
- /**
- * Enables or disables USB mass storage support.
- *
- * @param enable true to enable USB mass storage support
- */
- void setShareMethodEnabled(String mountPoint, String method,
- boolean enable) throws IllegalStateException {
- doCommand((enable ? "" : "un") + "share " + mountPoint + " " + method);
- }
-
- /**
- * Mount media at given mount point.
- */
- public void mountVolume(String label) throws IllegalStateException {
- doCommand("mount " + label);
- }
-
- /**
- * Unmount media at given mount point.
- */
- public void unmountVolume(String label) throws IllegalStateException {
- doCommand("unmount " + label);
- }
-
- /**
- * Format media at given mount point.
- */
- public void formatVolume(String label) throws IllegalStateException {
- doCommand("format " + label);
- }
-
- public String createAsec(String id, int sizeMb, String fstype, String key,
- int ownerUid) throws IllegalStateException {
- String cmd = String.format("create_asec %s %d %s %s %d",
- id, sizeMb, fstype, key, ownerUid);
- doCommand(cmd);
- return getAsecPath(id);
- }
-
- public void finalizeAsec(String id) throws IllegalStateException {
- doCommand("finalize_asec " + id);
- }
-
- public void destroyAsec(String id) throws IllegalStateException {
- doCommand("destroy_asec " + id);
- }
-
- public String mountAsec(String id, String key, int ownerUid) throws IllegalStateException {
- String cmd = String.format("mount_asec %s %s %d",
- id, key, ownerUid);
- doCommand(cmd);
- return getAsecPath(id);
- }
-
- public String getAsecPath(String id) throws IllegalStateException {
- ArrayList<String> rsp = doCommand("asec_path " + id);
-
- for (String line : rsp) {
- String []tok = line.split(" ");
- int code = Integer.parseInt(tok[0]);
- if (code == ResponseCode.AsecPathResult) {
- return tok[1];
- } else {
- throw new IllegalStateException(String.format("Unexpected response code %d", code));
- }
- }
- throw new IllegalStateException("Got an empty response");
- }
-
- public String[] listAsec() throws IllegalStateException {
- ArrayList<String> rsp = doCommand("list_asec");
-
- String[] rdata = new String[rsp.size()];
- int idx = 0;
-
- for (String line : rsp) {
- String []tok = line.split(" ");
- int code = Integer.parseInt(tok[0]);
- if (code == ResponseCode.AsecListResult) {
- rdata[idx++] = tok[1];
- } else if (code == ResponseCode.CommandOkay) {
- return rdata;
- } else {
- throw new IllegalStateException(String.format("Unexpected response code %d", code));
- }
- }
- throw new IllegalStateException("Got an empty response");
- }
-}
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index 81ebe03..c8a6915 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -33,6 +33,7 @@
import android.os.Handler;
import android.text.TextUtils;
import android.util.Log;
+import java.util.ArrayList;
import android.provider.Settings;
import android.content.ContentResolver;
@@ -46,7 +47,8 @@
* MountService implements an to the mount service daemon
* @hide
*/
-class MountService extends IMountService.Stub {
+class MountService extends IMountService.Stub
+ implements INativeDaemonConnectorCallbacks {
private static final String TAG = "MountService";
@@ -63,15 +65,33 @@
public static final int SharedMnt = 8;
}
+ class VoldResponseCode {
+ public static final int VolumeListResult = 110;
+ public static final int AsecListResult = 111;
+
+ public static final int ShareAvailabilityResult = 210;
+ public static final int AsecPathResult = 211;
+
+ public static final int VolumeStateChange = 605;
+ public static final int VolumeMountFailedBlank = 610;
+ public static final int VolumeMountFailedDamaged = 611;
+ public static final int VolumeMountFailedNoMedia = 612;
+ public static final int ShareAvailabilityChange = 620;
+ public static final int VolumeDiskInserted = 630;
+ public static final int VolumeDiskRemoved = 631;
+ public static final int VolumeBadRemoval = 632;
+ }
+
+
/**
* Binder context for this service
*/
private Context mContext;
/**
- * listener object for communicating with the mount service daemon
+ * connectorr object for communicating with vold
*/
- private MountListener mListener;
+ private NativeDaemonConnector mConnector;
/**
* The notification that is shown when a USB mass storage host
@@ -119,12 +139,12 @@
mContext = context;
// Register a BOOT_COMPLETED handler so that we can start
- // MountListener. We defer the startup so that we don't
+ // our NativeDaemonConnector. We defer the startup so that we don't
// start processing events before we ought-to
mContext.registerReceiver(mBroadcastReceiver,
new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null);
- mListener = new MountListener(this);
+ mConnector = new NativeDaemonConnector(this, "vold", 10, "VoldConnector");
mShowSafeUnmountNotificationWhenUnmounted = false;
mPlaySounds = SystemProperties.get("persist.service.mount.playsnd", "1").equals("1");
@@ -202,7 +222,18 @@
String action = intent.getAction();
if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
- Thread thread = new Thread(mListener, MountListener.class.getName());
+ /*
+ * Vold does not run in the simulator, so fake out a mounted
+ * event to trigger MediaScanner
+ */
+ if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
+ notifyMediaMounted(
+ Environment.getExternalStorageDirectory().getPath(), false);
+ return;
+ }
+
+ Thread thread = new Thread(
+ mConnector, NativeDaemonConnector.class.getName());
thread.start();
}
}
@@ -258,7 +289,7 @@
*/
try {
String m = Environment.getExternalStorageDirectory().toString();
- unmountMedia(m);
+ unmountVolume(m);
int retries = 12;
while (!state.equals(Environment.MEDIA_UNMOUNTED) && (retries-- >=0)) {
@@ -302,17 +333,14 @@
String vs = getVolumeState(vp);
if (enable && vs.equals(Environment.MEDIA_MOUNTED)) {
- mListener.unmountVolume(vp);
+ unmountVolume(vp);
updateUsbMassStorageNotification(true, false);
}
- mListener.setShareMethodEnabled(Environment
- .getExternalStorageDirectory()
- .getPath(),
- "ums", enable);
+ setShareMethodEnabled(vp, "ums", enable);
mUmsEnabled = enable;
if (!enable) {
- mountMedia(vp);
+ mountVolume(vp);
if (mPromptUms) {
updateUsbMassStorageNotification(false, false);
} else {
@@ -352,19 +380,19 @@
/**
* Attempt to mount external media
*/
- public void mountMedia(String mountPath) throws IllegalStateException {
+ public void mountVolume(String mountPath) throws IllegalStateException {
if (mContext.checkCallingOrSelfPermission(
android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires MOUNT_UNMOUNT_FILESYSTEMS permission");
}
- mListener.mountVolume(mountPath);
+ mConnector.doCommand(String.format("mount %s", mountPath));
}
/**
* Attempt to unmount external media to prepare for eject
*/
- public void unmountMedia(String mountPath) throws IllegalStateException {
+ public void unmountVolume(String mountPath) throws IllegalStateException {
if (mContext.checkCallingOrSelfPermission(
android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS)
!= PackageManager.PERMISSION_GRANTED) {
@@ -375,23 +403,51 @@
// to display the notification
mShowSafeUnmountNotificationWhenUnmounted = true;
- // tell mountd to unmount the media
- mListener.unmountVolume(mountPath);
+ mConnector.doCommand(String.format("unmount %s", mountPath));
}
/**
* Attempt to format external media
*/
- public void formatMedia(String formatPath) throws IllegalStateException {
+ public void formatVolume(String formatPath) throws IllegalStateException {
if (mContext.checkCallingOrSelfPermission(
android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires MOUNT_FORMAT_FILESYSTEMS permission");
}
- mListener.formatVolume(formatPath);
+ mConnector.doCommand(String.format("format %s", formatPath));
}
+ boolean getShareAvailable(String method) throws IllegalStateException {
+ ArrayList<String> rsp = mConnector.doCommand("share_available " + method);
+
+ for (String line : rsp) {
+ String []tok = line.split(" ");
+ int code = Integer.parseInt(tok[0]);
+ if (code == VoldResponseCode.ShareAvailabilityResult) {
+ if (tok[2].equals("available"))
+ return true;
+ return false;
+ } else {
+ throw new IllegalStateException(String.format("Unexpected response code %d", code));
+ }
+ }
+ throw new IllegalStateException("Got an empty response");
+ }
+
+ /**
+ * Enables or disables USB mass storage support.
+ *
+ * @param enable true to enable USB mass storage support
+ */
+ void setShareMethodEnabled(String mountPoint, String method,
+ boolean enable) throws IllegalStateException {
+ mConnector.doCommand(String.format(
+ "%sshare %s %s", (enable ? "" : "un"), mountPoint, method));
+ }
+
+
/**
* Returns true if we're playing media notification sounds.
*/
@@ -417,7 +473,7 @@
Log.w(TAG, "Multiple volumes not currently supported");
return;
}
- Log.w(TAG, "State for {" + mountPoint + "} = {" + state + "}");
+ Log.i(TAG, "State for {" + mountPoint + "} = {" + state + "}");
mLegacyState = state;
}
@@ -455,14 +511,18 @@
}
}
- void onVoldConnected() {
+ /**
+ *
+ * Callback from NativeDaemonConnector
+ */
+ public void onDaemonConnected() {
new Thread() {
public void run() {
try {
if (!getVolumeState(Environment.getExternalStorageDirectory().getPath())
.equals(Environment.MEDIA_MOUNTED)) {
try {
- mountMedia(Environment.getExternalStorageDirectory().getPath());
+ mountVolume(Environment.getExternalStorageDirectory().getPath());
} catch (Exception ex) {
Log.w(TAG, "Connection-mount failed");
}
@@ -474,7 +534,7 @@
}
try {
- boolean avail = mListener.getShareAvailable("ums");
+ boolean avail = getShareAvailable("ums");
notifyShareAvailabilityChange("ums", avail);
} catch (Exception ex) {
Log.w(TAG, "Failed to get share availability");
@@ -483,6 +543,49 @@
}.start();
}
+ /**
+ *
+ * Callback from NativeDaemonConnector
+ */
+ public boolean onEvent(int code, String raw, String[] cooked) {
+ // Log.d(TAG, "event {" + raw + "}");
+ if (code == VoldResponseCode.VolumeStateChange) {
+ // FMT: NNN Volume <label> <mountpoint> state changed
+ // from <old_#> (<old_str>) to <new_#> (<new_str>)
+ notifyVolumeStateChange(
+ cooked[2], cooked[3], Integer.parseInt(cooked[7]),
+ Integer.parseInt(cooked[10]));
+ } else if (code == VoldResponseCode.VolumeMountFailedBlank) {
+ // FMT: NNN Volume <label> <mountpoint> mount failed - no supported file-systems
+ notifyMediaNoFs(cooked[3]);
+ // FMT: NNN Volume <label> <mountpoint> mount failed - no media
+ } else if (code == VoldResponseCode.VolumeMountFailedNoMedia) {
+ notifyMediaRemoved(cooked[3]);
+ } else if (code == VoldResponseCode.VolumeMountFailedDamaged) {
+ // FMT: NNN Volume <label> <mountpoint> mount failed - filesystem check failed
+ notifyMediaUnmountable(cooked[3]);
+ } else if (code == VoldResponseCode.ShareAvailabilityChange) {
+ // FMT: NNN Share method <method> now <available|unavailable>
+ boolean avail = false;
+ if (cooked[5].equals("available")) {
+ avail = true;
+ }
+ notifyShareAvailabilityChange(cooked[3], avail);
+ } else if (code == VoldResponseCode.VolumeDiskInserted) {
+ // FMT: NNN Volume <label> <mountpoint> disk inserted (<major>:<minor>)
+ notifyMediaInserted(cooked[3]);
+ } else if (code == VoldResponseCode.VolumeDiskRemoved) {
+ // FMT: NNN Volume <label> <mountpoint> disk removed (<major>:<minor>)
+ notifyMediaRemoved(cooked[3]);
+ } else if (code == VoldResponseCode.VolumeBadRemoval) {
+ // FMT: NNN Volume <label> <mountpoint> bad removal (<major>:<minor>)
+ notifyMediaBadRemoval(cooked[3]);
+ } else {
+ return false;
+ }
+ return true;
+ }
+
void notifyVolumeStateChange(String label, String mountPoint, int oldState,
int newState) throws IllegalStateException {
String vs = getVolumeState(mountPoint);
@@ -587,7 +690,7 @@
new Thread() {
public void run() {
try {
- mountMedia(path);
+ mountVolume(path);
} catch (Exception ex) {
Log.w(TAG, "Failed to mount media on insertion", ex);
}
@@ -903,29 +1006,62 @@
}
public String[] getSecureContainerList() throws IllegalStateException {
- return mListener.listAsec();
+ ArrayList<String> rsp = mConnector.doCommand("list_asec");
+
+ String[] rdata = new String[rsp.size()];
+ int idx = 0;
+
+ for (String line : rsp) {
+ String []tok = line.split(" ");
+ int code = Integer.parseInt(tok[0]);
+ if (code == VoldResponseCode.AsecListResult) {
+ rdata[idx++] = tok[1];
+ } else if (code == NativeDaemonConnector.ResponseCode.CommandOkay) {
+ return rdata;
+ } else {
+ throw new IllegalStateException(String.format("Unexpected response code %d", code));
+ }
+ }
+ throw new IllegalStateException("Got an empty response");
}
public String createSecureContainer(String id, int sizeMb, String fstype,
String key, int ownerUid) throws IllegalStateException {
- return mListener.createAsec(id, sizeMb, fstype, key, ownerUid);
+ String cmd = String.format("create_asec %s %d %s %s %d",
+ id, sizeMb, fstype, key, ownerUid);
+ mConnector.doCommand(cmd);
+ return getSecureContainerPath(id);
}
public void finalizeSecureContainer(String id) throws IllegalStateException {
- mListener.finalizeAsec(id);
+ mConnector.doCommand(String.format("finalize_asec %s", id));
}
public void destroySecureContainer(String id) throws IllegalStateException {
- mListener.destroyAsec(id);
+ mConnector.doCommand(String.format("destroy_asec %s", id));
}
- public String mountSecureContainer(String id, String key, int ownerUid) throws IllegalStateException {
- return mListener.mountAsec(id, key, ownerUid);
+ public String mountSecureContainer(String id, String key,
+ int ownerUid) throws IllegalStateException {
+ String cmd = String.format("mount_asec %s %s %d",
+ id, key, ownerUid);
+ mConnector.doCommand(cmd);
+ return getSecureContainerPath(id);
}
public String getSecureContainerPath(String id) throws IllegalStateException {
- return mListener.getAsecPath(id);
- }
+ ArrayList<String> rsp = mConnector.doCommand("asec_path " + id);
+ for (String line : rsp) {
+ String []tok = line.split(" ");
+ int code = Integer.parseInt(tok[0]);
+ if (code == VoldResponseCode.AsecPathResult) {
+ return tok[1];
+ } else {
+ throw new IllegalStateException(String.format("Unexpected response code %d", code));
+ }
+ }
+ throw new IllegalStateException("Got an empty response");
+ }
}
diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java
new file mode 100644
index 0000000..da3e562
--- /dev/null
+++ b/services/java/com/android/server/NativeDaemonConnector.java
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2007 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;
+
+import android.net.LocalSocketAddress;
+import android.net.LocalSocket;
+import android.os.Environment;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.util.Config;
+import android.util.Log;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.Socket;
+import java.lang.IllegalStateException;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.ListIterator;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+
+/**
+ * Generic connector class for interfacing with a native
+ * daemon which uses the libsysutils FrameworkListener
+ * protocol.
+ */
+final class NativeDaemonConnector implements Runnable {
+
+ private BlockingQueue<String> mResponseQueue;
+ private OutputStream mOutputStream;
+ private String TAG = "NativeDaemonConnector";
+ private String mSocket;
+ private INativeDaemonConnectorCallbacks mCallbacks;
+
+ class ResponseCode {
+ public static final int ActionInitiated = 100;
+
+ public static final int CommandOkay = 200;
+
+ // The range of 400 -> 599 is reserved for cmd failures
+ public static final int OperationFailed = 400;
+ public static final int CommandSyntaxError = 500;
+ public static final int CommandParameterError = 501;
+
+ public static final int UnsolicitedInformational = 600;
+
+ //
+ public static final int FailedRangeStart = 400;
+ public static final int FailedRangeEnd = 599;
+ }
+
+ NativeDaemonConnector(INativeDaemonConnectorCallbacks callbacks,
+ String socket, int responseQueueSize, String logTag) {
+ mCallbacks = callbacks;
+ if (logTag != null)
+ TAG = logTag;
+ mSocket = socket;
+ mResponseQueue = new LinkedBlockingQueue<String>(responseQueueSize);
+ }
+
+ public void run() {
+
+ while (true) {
+ try {
+ listenToSocket();
+ } catch (Exception e) {
+ Log.e(TAG, "Error in NativeDaemonConnector", e);
+ SystemClock.sleep(1000);
+ }
+ }
+ }
+
+ private void listenToSocket() {
+ LocalSocket socket = null;
+
+ try {
+ socket = new LocalSocket();
+ LocalSocketAddress address = new LocalSocketAddress(mSocket,
+ LocalSocketAddress.Namespace.RESERVED);
+
+ socket.connect(address);
+ mCallbacks.onDaemonConnected();
+
+ InputStream inputStream = socket.getInputStream();
+ mOutputStream = socket.getOutputStream();
+
+ byte[] buffer = new byte[4096];
+
+ while (true) {
+ int count = inputStream.read(buffer);
+ if (count < 0) break;
+
+ int start = 0;
+ for (int i = 0; i < count; i++) {
+ if (buffer[i] == 0) {
+ String event = new String(buffer, start, i - start);
+// Log.d(TAG, "Got packet {" + event + "}");
+
+ String[] tokens = event.split(" ");
+ try {
+ int code = Integer.parseInt(tokens[0]);
+
+ if (code >= ResponseCode.UnsolicitedInformational) {
+ try {
+ if (!mCallbacks.onEvent(code, event, tokens)) {
+ Log.w(TAG, String.format(
+ "Unhandled event (%s)", event));
+ }
+ } catch (Exception ex) {
+ Log.e(TAG, String.format(
+ "Error handling '%s'", event), ex);
+ }
+ } else {
+ try {
+ mResponseQueue.put(event);
+ } catch (InterruptedException ex) {
+ Log.e(TAG, "Failed to put response onto queue", ex);
+ }
+ }
+ } catch (NumberFormatException nfe) {
+ Log.w(TAG, String.format("Bad msg (%s)", event));
+ }
+ start = i + 1;
+ }
+ }
+ }
+ } catch (IOException ex) {
+ Log.e(TAG, "Communications error", ex);
+ }
+
+ synchronized (this) {
+ if (mOutputStream != null) {
+ try {
+ mOutputStream.close();
+ } catch (IOException e) {
+ Log.w(TAG, "Failed closing output stream", e);
+ }
+
+ mOutputStream = null;
+ }
+ }
+
+ try {
+ if (socket != null) {
+ socket.close();
+ }
+ } catch (IOException ex) {
+ Log.w(TAG, "Failed closing socket", ex);
+ }
+
+ Log.e(TAG, "Failed to connect to native daemon",
+ new IllegalStateException());
+ SystemClock.sleep(5000);
+ }
+
+ private void sendCommand(String command) {
+ sendCommand(command, null);
+ }
+
+ /**
+ * Sends a command to the daemon with a single argument
+ *
+ * @param command The command to send to the daemon
+ * @param argument The argument to send with the command (or null)
+ */
+ private void sendCommand(String command, String argument) {
+ synchronized (this) {
+ Log.d(TAG, "sendCommand {" + command + "} {" + argument + "}");
+ if (mOutputStream == null) {
+ Log.e(TAG, "No connection to daemon", new IllegalStateException());
+ } else {
+ StringBuilder builder = new StringBuilder(command);
+ if (argument != null) {
+ builder.append(argument);
+ }
+ builder.append('\0');
+
+ try {
+ mOutputStream.write(builder.toString().getBytes());
+ } catch (IOException ex) {
+ Log.e(TAG, "IOException in sendCommand", ex);
+ }
+ }
+ }
+ }
+
+ public synchronized ArrayList<String> doCommand(String cmd) throws IllegalStateException {
+ sendCommand(cmd);
+
+ ArrayList<String> response = new ArrayList<String>();
+ boolean complete = false;
+ int code = -1;
+
+ while (!complete) {
+ try {
+ String line = mResponseQueue.take();
+// Log.d(TAG, "Removed off queue -> " + line);
+ String[] tokens = line.split(" ");
+ try {
+ code = Integer.parseInt(tokens[0]);
+ } catch (NumberFormatException nfe) {
+ throw new IllegalStateException(
+ String.format("Invalid response from daemon (%s)", line));
+ }
+
+ if ((code >= 200) && (code < 600))
+ complete = true;
+ response.add(line);
+ } catch (InterruptedException ex) {
+ Log.e(TAG, "InterruptedException");
+ }
+ }
+
+ if (code >= ResponseCode.FailedRangeStart &&
+ code <= ResponseCode.FailedRangeEnd) {
+ throw new IllegalStateException(String.format(
+ "Command %s failed with code %d",
+ cmd, code));
+ }
+ return response;
+ }
+}
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index de3dcb0..d5de1f0 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -330,6 +330,17 @@
return false;
}
+ /**
+ * Multiple calls to unregisterReceiver() cause exception and a system crash.
+ * This can happen if a supplicant is lost (or firmware crash occurs) and user indicates
+ * disable wifi at the same time.
+ * Avoid doing a disable when the current Wifi state is UNKNOWN
+ * TODO: Handle driver load fail and supplicant lost as seperate states
+ */
+ if (mWifiState == WIFI_STATE_UNKNOWN && !enable) {
+ return false;
+ }
+
setWifiEnabledState(enable ? WIFI_STATE_ENABLING : WIFI_STATE_DISABLING, uid);
if (enable) {
diff --git a/tests/TransformTest/Android.mk b/tests/TransformTest/Android.mk
new file mode 100644
index 0000000..2d3637d
--- /dev/null
+++ b/tests/TransformTest/Android.mk
@@ -0,0 +1,10 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := TransformTest
+
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_PACKAGE)
diff --git a/tests/TransformTest/AndroidManifest.xml b/tests/TransformTest/AndroidManifest.xml
new file mode 100644
index 0000000..5c9995f
--- /dev/null
+++ b/tests/TransformTest/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.google.android.test.transform">
+ <uses-sdk android:minSdkVersion="7" android:targetSdkVersion="7" />
+ <application android:label="TransformTest">
+ <activity android:name="TransformTestActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/tests/TransformTest/res/drawable/logo.png b/tests/TransformTest/res/drawable/logo.png
new file mode 100644
index 0000000..4d717a8
--- /dev/null
+++ b/tests/TransformTest/res/drawable/logo.png
Binary files differ
diff --git a/tests/TransformTest/res/values/strings.xml b/tests/TransformTest/res/values/strings.xml
new file mode 100644
index 0000000..a0eb81f
--- /dev/null
+++ b/tests/TransformTest/res/values/strings.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 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.
+-->
+
+<resources>
+ <string name="act_title">TransformTest</string>
+</resources>
diff --git a/tests/TransformTest/src/com/google/android/test/transform/TransformTestActivity.java b/tests/TransformTest/src/com/google/android/test/transform/TransformTestActivity.java
new file mode 100644
index 0000000..52286d1
--- /dev/null
+++ b/tests/TransformTest/src/com/google/android/test/transform/TransformTestActivity.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2008 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.google.android.test.transform;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.TransformGestureDetector;
+import android.view.View;
+import android.widget.LinearLayout;
+
+public class TransformTestActivity extends Activity {
+ public TransformTestActivity() {
+ super();
+ init(false);
+ }
+
+ public TransformTestActivity(boolean noCompat) {
+ super();
+ init(noCompat);
+ }
+
+ public void init(boolean noCompat) {
+
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ final LayoutInflater li = (LayoutInflater)getSystemService(
+ LAYOUT_INFLATER_SERVICE);
+
+ this.setTitle(R.string.act_title);
+ LinearLayout root = new LinearLayout(this);
+ root.setOrientation(LinearLayout.VERTICAL);
+
+ TransformView view = new TransformView(getApplicationContext());
+ Drawable drawable = getResources().getDrawable(R.drawable.logo);
+ drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicWidth());
+ view.setDrawable(drawable);
+
+ root.addView(view);
+ setContentView(root);
+ }
+
+ private class TransformView extends View {
+ private Drawable mDrawable;
+ private float mPosX;
+ private float mPosY;
+ private float mScale = 1.f;
+ private Matrix mMatrix;
+ private TransformGestureDetector mDetector;
+
+ private class Listener implements TransformGestureDetector.OnTransformGestureListener {
+
+ public boolean onTransform(TransformGestureDetector detector) {
+ Log.d("ttest", "Translation: (" + detector.getTranslateX() +
+ ", " + detector.getTranslateY() + ")");
+ float scale = detector.getScaleFactor();
+ Log.d("ttest", "Scale: " + scale);
+ if (mScale * scale > 0.1f) {
+ if (mScale * scale < 10.f) {
+ mScale *= scale;
+ } else {
+ mScale = 10.f;
+ }
+ } else {
+ mScale = 0.1f;
+ }
+
+ mPosX += detector.getTranslateX();
+ mPosY += detector.getTranslateY();
+
+ Log.d("ttest", "mScale: " + mScale + " mPos: (" + mPosX + ", " + mPosY + ")");
+
+ float sizeX = mDrawable.getIntrinsicWidth()/2;
+ float sizeY = mDrawable.getIntrinsicHeight()/2;
+ float centerX = detector.getCenterX();
+ float centerY = detector.getCenterY();
+ float diffX = centerX - mPosX;
+ float diffY = centerY - mPosY;
+ diffX = diffX*scale - diffX;
+ diffY = diffY*scale - diffY;
+ mPosX -= diffX;
+ mPosY -= diffY;
+ mMatrix.reset();
+ mMatrix.postTranslate(-sizeX, -sizeY);
+ mMatrix.postScale(mScale, mScale);
+ mMatrix.postTranslate(mPosX, mPosY);
+
+ invalidate();
+
+ return true;
+ }
+
+ public boolean onTransformBegin(TransformGestureDetector detector) {
+ return true;
+ }
+
+ public boolean onTransformEnd(TransformGestureDetector detector) {
+ return true;
+ }
+
+ public boolean onTransformFling(TransformGestureDetector detector) {
+ return false;
+ }
+
+ }
+
+ public TransformView(Context context) {
+ super(context);
+ mMatrix = new Matrix();
+ mDetector = new TransformGestureDetector(context, new Listener());
+ DisplayMetrics metrics = context.getResources().getDisplayMetrics();
+ mPosX = metrics.widthPixels/2;
+ mPosY = metrics.heightPixels/2;
+ }
+
+ public void setDrawable(Drawable d) {
+ mDrawable = d;
+
+ float sizeX = mDrawable.getIntrinsicWidth()/2;
+ float sizeY = mDrawable.getIntrinsicHeight()/2;
+ mMatrix.reset();
+ mMatrix.postTranslate(-sizeX, -sizeY);
+ mMatrix.postScale(mScale, mScale);
+ mMatrix.postTranslate(mPosX, mPosY);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ boolean handled = mDetector.onTouchEvent(event);
+
+ int pointerCount = event.getPointerCount();
+ Log.d("ttest", "pointerCount: " + pointerCount);
+
+ return handled;
+ }
+
+ @Override
+ public void onDraw(Canvas canvas) {
+ int saveCount = canvas.getSaveCount();
+ canvas.save();
+ canvas.concat(mMatrix);
+ mDrawable.draw(canvas);
+ canvas.restoreToCount(saveCount);
+ }
+ }
+}
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index de6ff14..ae8f242 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -1768,31 +1768,33 @@
fprintf(stderr, "ERROR: %s\n", error.string());
return -1;
}
- // asdf --> package.asdf
- // .asdf .a.b --> package.asdf package.a.b
- // asdf.adsf --> asdf.asdf
- String8 rule("-keep class ");
- const char* p = name.string();
- const char* q = strchr(p, '.');
- if (p == q) {
- rule += pkg;
- rule += name;
- } else if (q == NULL) {
- rule += pkg;
- rule += ".";
- rule += name;
- } else {
- rule += name;
+ if (name.length() > 0) {
+ // asdf --> package.asdf
+ // .asdf .a.b --> package.asdf package.a.b
+ // asdf.adsf --> asdf.asdf
+ String8 rule("-keep class ");
+ const char* p = name.string();
+ const char* q = strchr(p, '.');
+ if (p == q) {
+ rule += pkg;
+ rule += name;
+ } else if (q == NULL) {
+ rule += pkg;
+ rule += ".";
+ rule += name;
+ } else {
+ rule += name;
+ }
+
+ String8 location = tag;
+ location += " ";
+ location += assFile->getSourceFile();
+ char lineno[20];
+ sprintf(lineno, ":%d", tree.getLineNumber());
+ location += lineno;
+
+ keep->add(rule, location);
}
-
- String8 location = tag;
- location += " ";
- location += assFile->getSourceFile();
- char lineno[20];
- sprintf(lineno, ":%d", tree.getLineNumber());
- location += lineno;
-
- keep->add(rule, location);
}
}
}