Merge "Load opaque assets in RGB-565 until Bitmap.hasAlpha() works properly."
diff --git a/Android.mk b/Android.mk
index 39bbbdd..4fab976 100644
--- a/Android.mk
+++ b/Android.mk
@@ -39,6 +39,9 @@
core/java/android/webkit/EventLogTags.logtags \
telephony/java/com/android/internal/telephony/EventLogTags.logtags \
+# RenderScript files for internal widgets
+LOCAL_SRC_FILES += $(call all-renderscript-files-under, core/java/com/android/internal/widget)
+
# The following filters out code we are temporarily not including at all.
# TODO: Move AWT and beans (and associated harmony code) back into libcore.
# TODO: Maybe remove javax.microedition entirely?
diff --git a/core/java/android/webkit/ZoomManager.java b/core/java/android/webkit/ZoomManager.java
index ea975c2..33ebcf5 100644
--- a/core/java/android/webkit/ZoomManager.java
+++ b/core/java/android/webkit/ZoomManager.java
@@ -727,7 +727,8 @@
if (mWebView.getWebViewCore() != null) {
// we always force, in case our height changed, in which case we
// still want to send the notification over to webkit.
- refreshZoomScale(mUpdateTextWrap);
+ setZoomScale(Math.max(mActualScale, getZoomOverviewScale()),
+ mUpdateTextWrap, true);
// update the zoom buttons as the scale can be changed
updateZoomPicker();
}
@@ -787,8 +788,6 @@
&& Math.abs((viewWidth * mInvActualScale) - mZoomOverviewWidth) > 1))) {
mInitialZoomOverview = false;
setZoomScale(zoomOverviewScale, !willScaleTriggerZoom(mTextWrapScale));
- } else {
- mInZoomOverview = !exceedsMinScaleIncrement(mActualScale, zoomOverviewScale);
}
}
diff --git a/core/java/android/widget/AdapterViewAnimator.java b/core/java/android/widget/AdapterViewAnimator.java
index f11c5c6..b6c8e47 100644
--- a/core/java/android/widget/AdapterViewAnimator.java
+++ b/core/java/android/widget/AdapterViewAnimator.java
@@ -340,9 +340,14 @@
for (int i = 0; i < mPreviousViews.size(); i++) {
View viewToRemove = mPreviousViews.get(i);
viewToRemove.clearAnimation();
+ if (viewToRemove instanceof ViewGroup) {
+ ViewGroup vg = (ViewGroup) viewToRemove;
+ vg.removeAllViewsInLayout();
+ }
// applyTransformForChildAtIndex here just allows for any cleanup
// associated with this view that may need to be done by a subclass
applyTransformForChildAtIndex(viewToRemove, -1);
+
removeViewInLayout(viewToRemove);
}
mPreviousViews.clear();
@@ -405,10 +410,14 @@
// and apply any transform / animation
View newView = mAdapter.getView(i, null, this);
if (newView != null) {
- mActiveViews[index] = newView;
- addViewInLayout(newView, -1, createOrReuseLayoutParams(newView));
- applyTransformForChildAtIndex(newView, newRelativeIndex);
- animateViewForTransition(-1, newRelativeIndex, newView);
+ // We wrap the new view in a FrameLayout so as to respect the contract
+ // with the adapter, that is, that we don't modify this view directly
+ FrameLayout fl = new FrameLayout(mContext);
+ fl.addView(newView);
+ mActiveViews[index] = fl;
+ addViewInLayout(fl, -1, createOrReuseLayoutParams(fl));
+ applyTransformForChildAtIndex(fl, newRelativeIndex);
+ animateViewForTransition(-1, newRelativeIndex, fl);
}
}
mActiveViews[index].bringToFront();
diff --git a/core/java/android/widget/StackView.java b/core/java/android/widget/StackView.java
index 5797cbb..c3e8838 100644
--- a/core/java/android/widget/StackView.java
+++ b/core/java/android/widget/StackView.java
@@ -48,7 +48,7 @@
/**
* Default animation parameters
*/
- private final int DEFAULT_ANIMATION_DURATION = 500;
+ private final int DEFAULT_ANIMATION_DURATION = 400;
private final int MINIMUM_ANIMATION_DURATION = 50;
/**
@@ -141,9 +141,9 @@
view.setVisibility(VISIBLE);
LayoutParams lp = (LayoutParams) view.getLayoutParams();
+ int largestDuration =
+ Math.round(mStackSlider.getDurationForNeutralPosition()*DEFAULT_ANIMATION_DURATION);
- int largestDuration = Math.round(
- (lp.verticalOffset*1.0f/-mViewHeight)*DEFAULT_ANIMATION_DURATION);
int duration = largestDuration;
if (mYVelocity != 0) {
duration = 1000*(0 - lp.verticalOffset)/Math.abs(mYVelocity);
@@ -165,7 +165,8 @@
// Slide item out
LayoutParams lp = (LayoutParams) view.getLayoutParams();
- int largestDuration = Math.round(mStackSlider.getYProgress()*DEFAULT_ANIMATION_DURATION);
+ int largestDuration = Math.round(mStackSlider.getDurationForOffscreenPosition()*
+ DEFAULT_ANIMATION_DURATION);
int duration = largestDuration;
if (mYVelocity != 0) {
duration = 1000*(lp.verticalOffset + mViewHeight)/Math.abs(mYVelocity);
@@ -245,6 +246,7 @@
// ClipChildren and ClipToPadding. We're probably going to want to reset
// these flags as well.
setClipChildren(false);
+ setClipToPadding(false);
ViewGroup view = this;
while (view.getParent() != null && view.getParent() instanceof ViewGroup) {
view = (ViewGroup) view.getParent();
@@ -297,22 +299,37 @@
private void beginGestureIfNeeded(float deltaY) {
if ((int) Math.abs(deltaY) > mTouchSlop && mSwipeGestureType == GESTURE_NONE) {
- mSwipeGestureType = deltaY < 0 ? GESTURE_SLIDE_UP : GESTURE_SLIDE_DOWN;
+ int swipeGestureType = deltaY < 0 ? GESTURE_SLIDE_UP : GESTURE_SLIDE_DOWN;
cancelLongPress();
requestDisallowInterceptTouchEvent(true);
- int activeIndex = mSwipeGestureType == GESTURE_SLIDE_DOWN ? mNumActiveViews - 1
+ int activeIndex = swipeGestureType == GESTURE_SLIDE_DOWN ? mNumActiveViews - 1
: mNumActiveViews - 2;
- View v = getViewAtRelativeIndex(activeIndex);
- if (v != null) {
- mHighlight.setImageBitmap(createOutline(v));
- mHighlight.bringToFront();
- v.bringToFront();
- mStackSlider.setView(v);
- if (mSwipeGestureType == GESTURE_SLIDE_DOWN)
- v.setVisibility(VISIBLE);
+ if (mAdapter == null) return;
+
+ if (mCurrentWindowStartUnbounded + activeIndex == 0) {
+ mStackSlider.setMode(StackSlider.BEGINNING_OF_STACK_MODE);
+ } else if (mCurrentWindowStartUnbounded + activeIndex == mAdapter.getCount()) {
+ activeIndex--;
+ mStackSlider.setMode(StackSlider.END_OF_STACK_MODE);
+ } else {
+ mStackSlider.setMode(StackSlider.NORMAL_MODE);
}
+
+ View v = getViewAtRelativeIndex(activeIndex);
+ if (v == null) return;
+
+ mHighlight.setImageBitmap(createOutline(v));
+ mHighlight.bringToFront();
+ v.bringToFront();
+ mStackSlider.setView(v);
+
+ if (swipeGestureType == GESTURE_SLIDE_DOWN)
+ v.setVisibility(VISIBLE);
+
+ // We only register this gesture if we've made it this far without a problem
+ mSwipeGestureType = swipeGestureType;
}
}
@@ -339,7 +356,7 @@
case MotionEvent.ACTION_MOVE: {
beginGestureIfNeeded(deltaY);
- float rx = 0.3f*deltaX/(mViewHeight*1.0f);
+ float rx = deltaX/(mViewHeight*1.0f);
if (mSwipeGestureType == GESTURE_SLIDE_DOWN) {
float r = (deltaY-mTouchSlop*1.0f)/mViewHeight*1.0f;
mStackSlider.setYProgress(1 - r);
@@ -351,7 +368,6 @@
mStackSlider.setXProgress(rx);
return true;
}
-
break;
}
case MotionEvent.ACTION_UP: {
@@ -412,7 +428,7 @@
}
}
// if we made it this far, it means we didn't find a satisfactory new pointer :(,
- // so end the
+ // so end the gesture
handlePointerUp(ev);
}
}
@@ -422,25 +438,30 @@
float newY = ev.getY(pointerIndex);
int deltaY = (int) (newY - mInitialY);
- mVelocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
- mYVelocity = (int) mVelocityTracker.getYVelocity(mActivePointerId);
+ if (mVelocityTracker != null) {
+ mVelocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
+ mYVelocity = (int) mVelocityTracker.getYVelocity(mActivePointerId);
+ }
if (mVelocityTracker != null) {
mVelocityTracker.recycle();
mVelocityTracker = null;
}
- if (deltaY > mSwipeThreshold && mSwipeGestureType == GESTURE_SLIDE_DOWN) {
+ if (deltaY > mSwipeThreshold && mSwipeGestureType == GESTURE_SLIDE_DOWN
+ && mStackSlider.mMode == StackSlider.NORMAL_MODE) {
// Swipe threshold exceeded, swipe down
showNext();
mHighlight.bringToFront();
- } else if (deltaY < -mSwipeThreshold && mSwipeGestureType == GESTURE_SLIDE_UP) {
+ } else if (deltaY < -mSwipeThreshold && mSwipeGestureType == GESTURE_SLIDE_UP
+ && mStackSlider.mMode == StackSlider.NORMAL_MODE) {
// Swipe threshold exceeded, swipe up
showPrevious();
mHighlight.bringToFront();
} else if (mSwipeGestureType == GESTURE_SLIDE_UP) {
// Didn't swipe up far enough, snap back down
- int duration = Math.round(mStackSlider.getYProgress()*DEFAULT_ANIMATION_DURATION);
+ int duration =
+ Math.round(mStackSlider.getDurationForNeutralPosition()*DEFAULT_ANIMATION_DURATION);
StackSlider animationSlider = new StackSlider(mStackSlider);
PropertyAnimator snapBackY = new PropertyAnimator(duration, animationSlider,
@@ -453,8 +474,9 @@
snapBackX.start();
} else if (mSwipeGestureType == GESTURE_SLIDE_DOWN) {
// Didn't swipe down far enough, snap back up
- int duration = Math.round((1 -
- mStackSlider.getYProgress())*DEFAULT_ANIMATION_DURATION);
+ int duration = Math.round(mStackSlider.getDurationForOffscreenPosition()*
+ DEFAULT_ANIMATION_DURATION);
+
StackSlider animationSlider = new StackSlider(mStackSlider);
PropertyAnimator snapBackY = new PropertyAnimator(duration, animationSlider,
"YProgress", mStackSlider.getYProgress(), 1);
@@ -475,6 +497,12 @@
float mYProgress;
float mXProgress;
+ static final int NORMAL_MODE = 0;
+ static final int BEGINNING_OF_STACK_MODE = 1;
+ static final int END_OF_STACK_MODE = 2;
+
+ int mMode = NORMAL_MODE;
+
public StackSlider() {
}
@@ -482,6 +510,7 @@
mView = copy.mView;
mYProgress = copy.mYProgress;
mXProgress = copy.mXProgress;
+ mMode = copy.mMode;
}
private float cubic(float r) {
@@ -525,43 +554,85 @@
r = Math.max(0, r);
mYProgress = r;
-
final LayoutParams viewLp = (LayoutParams) mView.getLayoutParams();
final LayoutParams highlightLp = (LayoutParams) mHighlight.getLayoutParams();
- viewLp.setVerticalOffset(Math.round(-r*mViewHeight));
- highlightLp.setVerticalOffset(Math.round(-r*mViewHeight));
- mHighlight.setAlpha(highlightAlphaInterpolator(r));
+ switch (mMode) {
+ case NORMAL_MODE:
+ viewLp.setVerticalOffset(Math.round(-r*mViewHeight));
+ highlightLp.setVerticalOffset(Math.round(-r*mViewHeight));
+ mHighlight.setAlpha(highlightAlphaInterpolator(r));
- float alpha = viewAlphaInterpolator(1-r);
+ float alpha = viewAlphaInterpolator(1-r);
- // We make sure that views which can't be seen (have 0 alpha) are also invisible
- // so that they don't interfere with click events.
- if (mView.getAlpha() == 0 && alpha != 0 && mView.getVisibility() != VISIBLE) {
- mView.setVisibility(VISIBLE);
- } else if (alpha == 0 && mView.getAlpha() != 0 && mView.getVisibility() == VISIBLE) {
- mView.setVisibility(INVISIBLE);
+ // We make sure that views which can't be seen (have 0 alpha) are also invisible
+ // so that they don't interfere with click events.
+ if (mView.getAlpha() == 0 && alpha != 0 && mView.getVisibility() != VISIBLE) {
+ mView.setVisibility(VISIBLE);
+ } else if (alpha == 0 && mView.getAlpha() != 0
+ && mView.getVisibility() == VISIBLE) {
+ mView.setVisibility(INVISIBLE);
+ }
+
+ mView.setAlpha(alpha);
+ mView.setRotationX(90.0f*rotationInterpolator(r));
+ mHighlight.setRotationX(90.0f*rotationInterpolator(r));
+ break;
+ case BEGINNING_OF_STACK_MODE:
+ r = r*0.2f;
+ viewLp.setVerticalOffset(Math.round(-r*mViewHeight));
+ highlightLp.setVerticalOffset(Math.round(-r*mViewHeight));
+ mHighlight.setAlpha(highlightAlphaInterpolator(r));
+ break;
+ case END_OF_STACK_MODE:
+ r = (1-r)*0.2f;
+ viewLp.setVerticalOffset(Math.round(r*mViewHeight));
+ highlightLp.setVerticalOffset(Math.round(r*mViewHeight));
+ mHighlight.setAlpha(highlightAlphaInterpolator(r));
+ break;
}
-
- mView.setAlpha(viewAlphaInterpolator(1-r));
- mView.setRotationX(90.0f*rotationInterpolator(r));
- mHighlight.setRotationX(90.0f*rotationInterpolator(r));
}
public void setXProgress(float r) {
// enforce r between 0 and 1
- r = Math.min(1.0f, r);
- r = Math.max(-1.0f, r);
+ r = Math.min(2.0f, r);
+ r = Math.max(-2.0f, r);
mXProgress = r;
final LayoutParams viewLp = (LayoutParams) mView.getLayoutParams();
final LayoutParams highlightLp = (LayoutParams) mHighlight.getLayoutParams();
+ r *= 0.2f;
viewLp.setHorizontalOffset(Math.round(r*mViewHeight));
highlightLp.setHorizontalOffset(Math.round(r*mViewHeight));
}
+ void setMode(int mode) {
+ mMode = mode;
+ }
+
+ float getDurationForNeutralPosition() {
+ return getDuration(false);
+ }
+
+ float getDurationForOffscreenPosition() {
+ return getDuration(mMode == END_OF_STACK_MODE ? false : true);
+ }
+
+ private float getDuration(boolean invert) {
+ if (mView != null) {
+ final LayoutParams viewLp = (LayoutParams) mView.getLayoutParams();
+
+ float d = (float) Math.sqrt(Math.pow(viewLp.horizontalOffset,2) +
+ Math.pow(viewLp.verticalOffset,2));
+ float maxd = (float) Math.sqrt(Math.pow(mViewHeight, 2) +
+ Math.pow(0.4f*mViewHeight, 2));
+ return invert ? (1-d/maxd) : d/maxd;
+ }
+ return 0;
+ }
+
float getYProgress() {
return mYProgress;
}
@@ -569,6 +640,7 @@
float getXProgress() {
return mXProgress;
}
+
}
@Override
diff --git a/core/java/com/android/internal/widget/CarouselRS.java b/core/java/com/android/internal/widget/CarouselRS.java
new file mode 100644
index 0000000..7589531
--- /dev/null
+++ b/core/java/com/android/internal/widget/CarouselRS.java
@@ -0,0 +1,372 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.widget;
+
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.renderscript.*;
+import android.renderscript.RenderScript.RSMessage;
+import android.renderscript.Sampler.Value;
+import android.renderscript.ProgramRaster.CullMode;
+import android.util.Log;
+
+import com.android.internal.R;
+
+import static android.renderscript.Element.*;
+import static android.renderscript.Sampler.Value.LINEAR;
+import static android.renderscript.Sampler.Value.WRAP;
+import static android.renderscript.Sampler.Value.CLAMP;
+
+public class CarouselRS {
+ private static final int DEFAULT_VISIBLE_SLOTS = 1;
+ private static final int DEFAULT_CARD_COUNT = 1;
+
+ // Client messages *** THIS LIST MUST MATCH THOSE IN carousel.rs ***
+ public static final int CMD_CARD_SELECTED = 100;
+ public static final int CMD_REQUEST_TEXTURE = 200;
+ public static final int CMD_INVALIDATE_TEXTURE = 210;
+ public static final int CMD_REQUEST_GEOMETRY = 300;
+ public static final int CMD_INVALIDATE_GEOMETRY = 310;
+ public static final int CMD_ANIMATION_STARTED = 400;
+ public static final int CMD_ANIMATION_FINISHED = 500;
+ public static final int CMD_PING = 600; // for debugging
+
+ private static final String TAG = "CarouselRS";
+ private static final int DEFAULT_SLOT_COUNT = 10;
+ private static final boolean MIPMAP = false;
+
+ private RenderScriptGL mRS;
+ private Resources mRes;
+ private ScriptC_Carousel mScript;
+ private ScriptField_Card mCards;
+ private Sampler mSampler;
+ private ProgramRaster mProgramRaster;
+ private ProgramStore mProgramStore;
+ private ProgramFragment mFragmentProgram;
+ private ProgramVertex mVertexProgram;
+ private ProgramRaster mRasterProgram;
+ private CarouselCallback mCallback;
+ private float[] mEyePoint = new float[3];
+ private float[] mAtPoint = new float[3];
+ private float[] mUp = new float[3];
+
+ public static interface CarouselCallback {
+ /**
+ * Called when a card is selected
+ * @param n the id of the card
+ */
+ void onCardSelected(int n);
+
+ /**
+ * Called when texture is needed for card n. This happens when the given card becomes
+ * visible.
+ * @param n the id of the card
+ */
+ void onRequestTexture(int n);
+
+ /**
+ * Called when a texture is no longer needed for card n. This happens when the card
+ * goes out of view.
+ * @param n the id of the card
+ */
+ void onInvalidateTexture(int n);
+
+ /**
+ * Called when geometry is needed for card n.
+ * @param n the id of the card.
+ */
+ void onRequestGeometry(int n);
+
+ /**
+ * Called when geometry is no longer needed for card n. This happens when the card goes
+ * out of view.
+ * @param n the id of the card
+ */
+ void onInvalidateGeometry(int n);
+
+ /**
+ * Called when card animation (e.g. a fling) has started.
+ */
+ void onAnimationStarted();
+
+ /**
+ * Called when card animation has stopped.
+ */
+ void onAnimationFinished();
+ };
+
+ private RSMessage mRsMessage = new RSMessage() {
+ public void run() {
+ if (mCallback == null) return;
+ switch (mID) {
+ case CMD_CARD_SELECTED:
+ mCallback.onCardSelected(mData[0]);
+ break;
+
+ case CMD_REQUEST_TEXTURE:
+ mCallback.onRequestTexture(mData[0]);
+ break;
+
+ case CMD_INVALIDATE_TEXTURE:
+ mCallback.onInvalidateTexture(mData[0]);
+ break;
+
+ case CMD_REQUEST_GEOMETRY:
+ mCallback.onRequestGeometry(mData[0]);
+ break;
+
+ case CMD_INVALIDATE_GEOMETRY:
+ mCallback.onInvalidateGeometry(mData[0]);
+ break;
+
+ case CMD_ANIMATION_STARTED:
+ mCallback.onAnimationStarted();
+ break;
+
+ case CMD_ANIMATION_FINISHED:
+ mCallback.onAnimationFinished();
+ break;
+
+ case CMD_PING:
+ Log.v(TAG, "PING...");
+ break;
+
+ default:
+ Log.e(TAG, "Unknown RSMessage: " + mID);
+ }
+ }
+ };
+
+ public void init(RenderScriptGL rs, Resources res) {
+ mRS = rs;
+ mRes = res;
+
+ // create the script object
+ mScript = new ScriptC_Carousel(mRS, mRes, R.raw.carousel, true);
+ mRS.mMessageCallback = mRsMessage;
+
+ initProgramStore();
+ initFragmentProgram();
+ initRasterProgram();
+ initVertexProgram();
+
+ setSlotCount(DEFAULT_SLOT_COUNT);
+ setVisibleSlots(DEFAULT_VISIBLE_SLOTS);
+ createCards(DEFAULT_CARD_COUNT);
+
+ setStartAngle(0.0f);
+ setRadius(1.0f);
+
+ // update the camera
+ boolean pcam = true;
+ if (pcam) {
+ float eye[] = { 20.6829f, 2.77081f, 16.7314f };
+ float at[] = { 14.7255f, -3.40001f, -1.30184f };
+ float up[] = { 0.0f, 1.0f, 0.0f };
+ setLookAt(eye, at, up);
+ setRadius(20.0f);
+ // Fov: 25
+ } else {
+ mScript.invoke_lookAt(2.5f, 2.0f, 2.5f, 0.0f, -0.75f, 0.0f, 0.0f, 1.0f, 0.0f);
+ mScript.set_cardRotation(0.0f);
+ setRadius(1.5f);
+ }
+
+ resumeRendering();
+ }
+
+ public void setLookAt(float[] eye, float[] at, float[] up) {
+ for (int i = 0; i < 3; i++) {
+ mEyePoint[i] = eye[i];
+ mAtPoint[i] = at[i];
+ mUp[i] = up[i];
+ }
+ mScript.invoke_lookAt(eye[0], eye[1], eye[2], at[0], at[1], at[2], up[0], up[1], up[2]);
+ }
+
+ public void setRadius(float radius) {
+ mScript.set_radius(radius);
+ }
+
+ private void initVertexProgram() {
+ ProgramVertex.Builder pvb = new ProgramVertex.Builder(mRS, null, null);
+ mVertexProgram = pvb.create();
+ ProgramVertex.MatrixAllocation pva = new ProgramVertex.MatrixAllocation(mRS);
+ mVertexProgram.bindAllocation(pva);
+ pva.setupProjectionNormalized(1, 1);
+ mScript.set_vertexProgram(mVertexProgram);
+ }
+
+ private void initRasterProgram() {
+ ProgramRaster.Builder programRasterBuilder = new ProgramRaster.Builder(mRS);
+ mRasterProgram = programRasterBuilder.create();
+ //mRasterProgram.setCullMode(CullMode.NONE);
+ mScript.set_rasterProgram(mRasterProgram);
+ }
+
+ private void initFragmentProgram() {
+ Sampler.Builder sampleBuilder = new Sampler.Builder(mRS);
+ sampleBuilder.setMin(Value.LINEAR_MIP_LINEAR);
+ sampleBuilder.setMag(LINEAR);
+ sampleBuilder.setWrapS(CLAMP);
+ sampleBuilder.setWrapT(CLAMP);
+ mSampler = sampleBuilder.create();
+ ProgramFragment.Builder fragmentBuilder = new ProgramFragment.Builder(mRS);
+ fragmentBuilder.setTexture(ProgramFragment.Builder.EnvMode.DECAL,
+ ProgramFragment.Builder.Format.RGBA, 0);
+ mFragmentProgram = fragmentBuilder.create();
+ mFragmentProgram.bindSampler(mSampler, 0);
+ mScript.set_fragmentProgram(mFragmentProgram);
+ }
+
+ private void initProgramStore() {
+ ProgramStore.Builder programStoreBuilder = new ProgramStore.Builder(mRS, null, null);
+ programStoreBuilder.setDepthFunc(ProgramStore.DepthFunc.LESS);
+ programStoreBuilder.setBlendFunc(ProgramStore.BlendSrcFunc.SRC_ALPHA,
+ ProgramStore.BlendDstFunc.ONE_MINUS_SRC_ALPHA);
+ programStoreBuilder.setDitherEnable(false);
+ programStoreBuilder.setDepthMask(true);
+ mProgramStore = programStoreBuilder.create();
+ mScript.set_programStore(mProgramStore);
+ }
+
+ public void createCards(int count)
+ {
+ mCards = count > 0 ? new ScriptField_Card(mRS, count) : null;
+ mScript.bind_cards(mCards);
+ mScript.invoke_createCards(count);
+ }
+
+ public void setVisibleSlots(int count)
+ {
+ mScript.set_visibleSlotCount(count);
+ }
+
+ public void setDefaultBitmap(Bitmap bitmap)
+ {
+ mScript.set_defaultTexture(allocationFromBitmap(bitmap, MIPMAP));
+ }
+
+ public void setLoadingBitmap(Bitmap bitmap)
+ {
+ mScript.set_loadingTexture(allocationFromBitmap(bitmap, MIPMAP));
+ }
+
+ public void setDefaultGeometry(Mesh mesh)
+ {
+ mScript.set_defaultGeometry(mesh);
+ }
+
+ public void setLoadingGeometry(Mesh mesh)
+ {
+ mScript.set_loadingGeometry(mesh);
+ }
+
+ public void setStartAngle(float theta)
+ {
+ mScript.set_startAngle(theta);
+ }
+
+ public void setCallback(CarouselCallback callback)
+ {
+ mCallback = callback;
+ }
+
+ private Allocation allocationFromBitmap(Bitmap bitmap, boolean mipmap)
+ {
+ if (bitmap == null) return null;
+ Allocation allocation = Allocation.createFromBitmap(mRS, bitmap, RGB_565(mRS), mipmap);
+ allocation.uploadToTexture(0);
+ return allocation;
+ }
+
+ public void setTexture(int n, Bitmap bitmap)
+ {
+ ScriptField_Card.Item item = mCards.get(n);
+ if (item == null) {
+ Log.v(TAG, "setTexture(): no item at index " + n);
+ item = new ScriptField_Card.Item();
+ }
+ if (bitmap != null) {
+ Log.v(TAG, "creating new bitmap");
+ item.texture = Allocation.createFromBitmap(mRS, bitmap, RGB_565(mRS), MIPMAP);
+ Log.v(TAG, "uploadToTexture(" + n + ")");
+ item.texture.uploadToTexture(0);
+ Log.v(TAG, "done...");
+ } else {
+ if (item.texture != null) {
+ Log.v(TAG, "unloading texture " + n);
+ // Don't wait for GC to free native memory.
+ // Only works if textures are not shared.
+ item.texture.destroy();
+ item.texture = null;
+ }
+ }
+ mCards.set(item, n, false); // This is primarily used for reference counting.
+ mScript.invoke_setTexture(n, item.texture);
+ }
+
+ public void setGeometry(int n, Mesh geometry)
+ {
+ final boolean mipmap = false;
+ ScriptField_Card.Item item = mCards.get(n);
+ if (item == null) {
+ Log.v(TAG, "setGeometry(): no item at index " + n);
+ item = new ScriptField_Card.Item();
+ }
+ if (geometry != null) {
+ item.geometry = geometry;
+ } else {
+ Log.v(TAG, "unloading geometry " + n);
+ if (item.geometry != null) {
+ // item.geometry.destroy();
+ item.geometry = null;
+ }
+ }
+ mCards.set(item, n, false);
+ mScript.invoke_setGeometry(n, item.geometry);
+ }
+
+ public void pauseRendering() {
+ // Used to update multiple states at once w/o redrawing for each.
+ mRS.contextBindRootScript(null);
+ }
+
+ public void resumeRendering() {
+ mRS.contextBindRootScript(mScript);
+ }
+
+ public void doMotion(float x, float y) {
+ mScript.invoke_doMotion(x,y);
+ }
+
+ public void doSelection(float x, float y) {
+ mScript.invoke_doSelection(x, y);
+ }
+
+ public void doStart(float x, float y) {
+ mScript.invoke_doStart(x, y);
+ }
+
+ public void doStop(float x, float y) {
+ mScript.invoke_doStop(x, y);
+ }
+
+ public void setSlotCount(int n) {
+ mScript.set_slotCount(n);
+ }
+}
diff --git a/core/java/com/android/internal/widget/CarouselView.java b/core/java/com/android/internal/widget/CarouselView.java
new file mode 100644
index 0000000..e0c65dc
--- /dev/null
+++ b/core/java/com/android/internal/widget/CarouselView.java
@@ -0,0 +1,244 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.widget;
+
+import com.android.internal.widget.CarouselRS.CarouselCallback;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.renderscript.FileA3D;
+import android.renderscript.Mesh;
+import android.renderscript.RSSurfaceView;
+import android.renderscript.RenderScriptGL;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.SurfaceHolder;
+
+public class CarouselView extends RSSurfaceView {
+ private final int DEFAULT_SLOT_COUNT = 10;
+ private final Bitmap DEFAULT_BITMAP = Bitmap.createBitmap(1, 1, Config.RGB_565);
+ private static final String TAG = "CarouselView";
+ private CarouselRS mRenderScript;
+ private RenderScriptGL mRS;
+ private Context mContext;
+ private boolean mTracking;
+ private Bitmap mDefaultBitmap;
+ private Bitmap mLoadingBitmap;
+ private Mesh mDefaultGeometry;
+ private Mesh mLoadingGeometry;
+ private int mCardCount = 0;
+ private int mVisibleSlots = 0;
+ private float mStartAngle;
+ private int mSlotCount = DEFAULT_SLOT_COUNT;
+
+ public CarouselView(Context context) {
+ super(context);
+ mContext = context;
+ boolean useDepthBuffer = true;
+ mRS = createRenderScript(useDepthBuffer);
+ mRenderScript = new CarouselRS();
+ mRenderScript.init(mRS, getResources());
+ }
+
+ @Override
+ public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
+ super.surfaceChanged(holder, format, w, h);
+ mRS.contextSetSurface(w, h, holder.getSurface());
+ mRenderScript.init(mRS, getResources());
+ setSlotCount(mSlotCount);
+ createCards(mCardCount);
+ setVisibleSlots(mVisibleSlots);
+ setCallback(mCarouselCallback);
+ setDefaultBitmap(mDefaultBitmap);
+ setLoadingBitmap(mLoadingBitmap);
+ setDefaultGeometry(mDefaultGeometry);
+ setLoadingGeometry(mLoadingGeometry);
+ setStartAngle(mStartAngle);
+ }
+
+ /**
+ * Loads geometry from a resource id.
+ *
+ * @param resId
+ * @return the loaded mesh or null if it cannot be loaded
+ */
+ public Mesh loadGeometry(int resId) {
+ Resources res = mContext.getResources();
+ FileA3D model = FileA3D.createFromResource(mRS, res, resId);
+ FileA3D.IndexEntry entry = model.getIndexEntry(0);
+ if(entry == null || entry.getClassID() != FileA3D.ClassID.MESH) {
+ return null;
+ }
+ return (Mesh) entry.getObject();
+ }
+
+ /**
+ * Load A3D file from resource. If resId == 0, will clear geometry for this item.
+ * @param n
+ * @param resId
+ */
+ public void setGeometryForItem(int n, Mesh mesh) {
+ mRenderScript.setGeometry(n, mesh);
+ }
+
+ public void setSlotCount(int n) {
+ mSlotCount = n;
+ if (mRenderScript != null) {
+ mRenderScript.setSlotCount(n);
+ }
+ }
+
+ public void setVisibleSlots(int n) {
+ mVisibleSlots = n;
+ if (mRenderScript != null) {
+ mRenderScript.setVisibleSlots(n);
+ }
+ }
+
+ public void createCards(int n) {
+ mCardCount = n;
+ if (mRenderScript != null) {
+ mRenderScript.createCards(n);
+ }
+ }
+
+ public void setTextureForItem(int n, Bitmap bitmap) {
+ if (mRenderScript != null) {
+ Log.v(TAG, "setTextureForItem(" + n + ")");
+ mRenderScript.setTexture(n, bitmap);
+ Log.v(TAG, "done");
+ }
+ }
+
+ public void setDefaultBitmap(Bitmap bitmap) {
+ mDefaultBitmap = bitmap;
+ if (mRenderScript != null) {
+ mRenderScript.setDefaultBitmap(bitmap);
+ }
+ }
+
+ public void setLoadingBitmap(Bitmap bitmap) {
+ mLoadingBitmap = bitmap;
+ if (mRenderScript != null) {
+ mRenderScript.setLoadingBitmap(bitmap);
+ }
+ }
+
+ public void setDefaultGeometry(Mesh mesh) {
+ mDefaultGeometry = mesh;
+ if (mRenderScript != null) {
+ mRenderScript.setDefaultGeometry(mesh);
+ }
+ }
+
+ public void setLoadingGeometry(Mesh mesh) {
+ mLoadingGeometry = mesh;
+ if (mRenderScript != null) {
+ mRenderScript.setLoadingGeometry(mesh);
+ }
+ }
+
+ public void setCallback(CarouselCallback callback)
+ {
+ mCarouselCallback = callback;
+ if (mRenderScript != null) {
+ mRenderScript.setCallback(callback);
+ }
+ }
+
+ public void setStartAngle(float angle)
+ {
+ mStartAngle = angle;
+ if (mRenderScript != null) {
+ mRenderScript.setStartAngle(angle);
+ }
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ if(mRS != null) {
+ mRS = null;
+ destroyRenderScript();
+ }
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ final int action = event.getAction();
+ final float x = event.getX();
+ final float y = event.getY();
+
+ if (mRenderScript == null) {
+ return true;
+ }
+
+ switch (action) {
+ case MotionEvent.ACTION_DOWN:
+ mTracking = true;
+ mRenderScript.doStart(x, y);
+ break;
+
+ case MotionEvent.ACTION_MOVE:
+ if (mTracking) {
+ mRenderScript.doMotion(x, y);
+ }
+ break;
+
+ case MotionEvent.ACTION_UP:
+ mRenderScript.doStop(x, y);
+ mTracking = false;
+ break;
+ }
+
+ return true;
+ }
+
+ private final CarouselCallback DEBUG_CALLBACK = new CarouselCallback() {
+ public void onAnimationStarted() {
+ Log.v(TAG, "onAnimationStarted()");
+ }
+
+ public void onAnimationFinished() {
+ Log.v(TAG, "onAnimationFinished()");
+ }
+
+ public void onCardSelected(int n) {
+ Log.v(TAG, "onCardSelected(" + n + ")");
+ }
+
+ public void onRequestGeometry(int n) {
+ Log.v(TAG, "onRequestGeometry(" + n + ")");
+ }
+
+ public void onInvalidateGeometry(int n) {
+ Log.v(TAG, "onInvalidateGeometry(" + n + ")");
+ }
+
+ public void onRequestTexture(final int n) {
+ Log.v(TAG, "onRequestTexture(" + n + ")");
+ }
+
+ public void onInvalidateTexture(int n) {
+ Log.v(TAG, "onInvalidateTexture(" + n + ")");
+ }
+
+ };
+
+ private CarouselCallback mCarouselCallback = DEBUG_CALLBACK;
+}
diff --git a/core/java/com/android/internal/widget/carousel.rs b/core/java/com/android/internal/widget/carousel.rs
new file mode 100644
index 0000000..4cfcbf4
--- /dev/null
+++ b/core/java/com/android/internal/widget/carousel.rs
@@ -0,0 +1,753 @@
+/*
+ * 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.
+ */
+
+#pragma version(1)
+#pragma rs java_package_name(com.android.internal.widget)
+#pragma rs set_reflect_license()
+
+#include "rs_graphics.rsh"
+
+typedef struct __attribute__((aligned(4))) Card {
+ rs_allocation texture;
+ rs_mesh geometry;
+ //rs_matrix4x4 matrix; // custom transform for this card/geometry
+ int textureState; // whether or not the texture is loaded.
+ int geometryState; // whether or not geometry is loaded
+ int visible; // not bool because of packing bug?
+} Card_t;
+
+typedef struct Ray_s {
+ float3 position;
+ float3 direction;
+} Ray;
+
+typedef struct PerspectiveCamera_s {
+ float3 from;
+ float3 at;
+ float3 up;
+ float fov;
+ float aspect;
+ float near;
+ float far;
+} PerspectiveCamera;
+
+// Request states. Used for loading 3D object properties from the Java client.
+// Typical properties: texture, geometry and matrices.
+enum {
+ STATE_INVALID = 0, // item hasn't been loaded
+ STATE_LOADING, // we've requested an item but are waiting for it to load
+ STATE_LOADED // item was delivered
+};
+
+// Client messages *** THIS LIST MUST MATCH THOSE IN CarouselRS.java. ***
+const int CMD_CARD_SELECTED = 100;
+const int CMD_REQUEST_TEXTURE = 200;
+const int CMD_INVALIDATE_TEXTURE = 210;
+const int CMD_REQUEST_GEOMETRY = 300;
+const int CMD_INVALIDATE_GEOMETRY = 310;
+const int CMD_ANIMATION_STARTED = 400;
+const int CMD_ANIMATION_FINISHED = 500;
+const int CMD_PING = 600;
+
+
+// Debug flags
+bool debugCamera = false;
+bool debugPicking = false;
+
+// Exported variables. These will be reflected to Java set_* variables.
+Card_t *cards; // array of cards to draw
+float startAngle; // position of initial card, in radians
+int slotCount; // number of positions where a card can be
+int cardCount; // number of cards in stack
+int visibleSlotCount; // number of visible slots (for culling)
+float radius; // carousel radius. Cards will be centered on a circle with this radius
+float cardRotation; // rotation of card in XY plane relative to Z=1
+rs_program_store programStore;
+rs_program_fragment fragmentProgram;
+rs_program_vertex vertexProgram;
+rs_program_raster rasterProgram;
+rs_allocation defaultTexture; // shown when no other texture is assigned
+rs_allocation loadingTexture; // progress texture (shown when app is fetching the texture)
+rs_mesh defaultGeometry; // shown when no geometry is loaded
+rs_mesh loadingGeometry; // shown when geometry is loading
+rs_matrix4x4 projectionMatrix;
+rs_matrix4x4 modelviewMatrix;
+
+#pragma rs export_var(radius, cards, slotCount, visibleSlotCount, cardRotation)
+#pragma rs export_var(programStore, fragmentProgram, vertexProgram, rasterProgram)
+#pragma rs export_var(startAngle, defaultTexture, loadingTexture, defaultGeometry, loadingGeometry)
+#pragma rs export_func(createCards, lookAt, doStart, doStop, doMotion, doSelection, setTexture)
+#pragma rs export_func(setGeometry, debugCamera, debugPicking)
+
+// Local variables
+static float bias; // rotation bias, in radians. Used for animation and dragging.
+static bool updateCamera; // force a recompute of projection and lookat matrices
+static bool initialized;
+static float3 backgroundColor = { 0.5f, 0.5f, 0.5f };
+static const float FLT_MAX = 1.0e37;
+
+// Default geometry when card.geometry is not set.
+static const float3 cardVertices[4] = {
+ { -1.0, -1.0, 0.0 },
+ { 1.0, -1.0, 0.0 },
+ { 1.0, 1.0, 0.0 },
+ {-1.0, 1.0, 0.0 }
+};
+
+// Default camera
+static PerspectiveCamera camera = {
+ {2,2,2}, // from
+ {0,0,0}, // at
+ {0,1,0}, // up
+ 25.0f, // field of view
+ 1.0f, // aspect
+ 0.1f, // near
+ 100.0f // far
+};
+
+// Forward references
+static int intersectGeometry(Ray* ray, float *bestTime);
+static bool makeRayForPixelAt(Ray* ray, float x, float y);
+
+void init() {
+ // initializers currently have a problem when the variables are exported, so initialize
+ // globals here.
+ startAngle = 0.0f;
+ slotCount = 10;
+ visibleSlotCount = 1;
+ bias = 0.0f;
+ radius = 1.0f;
+ cardRotation = 0.0f;
+ updateCamera = true;
+ initialized = false;
+}
+
+static void updateAllocationVars()
+{
+ // Cards
+ rs_allocation cardAlloc = rsGetAllocation(cards);
+ // TODO: use new rsIsObject()
+ cardCount = cardAlloc.p != 0 ? rsAllocationGetDimX(cardAlloc) : 0;
+}
+
+void createCards(int n)
+{
+ rsDebug("CreateCards: ", n);
+ initialized = false;
+ updateAllocationVars();
+}
+
+// Return angle for position p. Typically p will be an integer position, but can be fractional.
+static float cardPosition(float p)
+{
+ return startAngle + bias + 2.0f * M_PI * p / slotCount;
+}
+
+// Return slot for a card in position p. Typically p will be an integer slot, but can be fractional.
+static float slotPosition(float p)
+{
+ return startAngle + 2.0f * M_PI * p / slotCount;
+}
+
+// Return the lowest slot number for a given angular position.
+static int cardIndex(float angle)
+{
+ return floor(angle - startAngle - bias) * slotCount / (2.0f * M_PI);
+}
+
+// Set basic camera properties:
+// from - position of the camera in x,y,z
+// at - target we're looking at - used to compute view direction
+// up - a normalized vector indicating up (typically { 0, 1, 0})
+//
+// NOTE: the view direction and up vector cannot be parallel/antiparallel with each other
+void lookAt(float fromX, float fromY, float fromZ,
+ float atX, float atY, float atZ,
+ float upX, float upY, float upZ)
+{
+ camera.from.x = fromX;
+ camera.from.y = fromY;
+ camera.from.z = fromZ;
+ camera.at.x = atX;
+ camera.at.y = atY;
+ camera.at.z = atZ;
+ camera.up.x = upX;
+ camera.up.y = upY;
+ camera.up.z = upZ;
+ updateCamera = true;
+}
+
+// Load a projection matrix for the given parameters. This is equivalent to gluPerspective()
+static void loadPerspectiveMatrix(rs_matrix4x4* matrix, float fovy, float aspect, float near, float far)
+{
+ rsMatrixLoadIdentity(matrix);
+ float top = near * tan((float) (fovy * M_PI / 360.0f));
+ float bottom = -top;
+ float left = bottom * aspect;
+ float right = top * aspect;
+ rsMatrixLoadFrustum(matrix, left, right, bottom, top, near, far);
+}
+
+// Construct a matrix based on eye point, center and up direction. Based on the
+// man page for gluLookat(). Up must be normalized.
+static void loadLookatMatrix(rs_matrix4x4* matrix, float3 eye, float3 center, float3 up)
+{
+ float3 f = normalize(center - eye);
+ float3 s = normalize(cross(f, up));
+ float3 u = cross(s, f);
+ float m[16];
+ m[0] = s.x;
+ m[4] = s.y;
+ m[8] = s.z;
+ m[12] = 0.0f;
+ m[1] = u.x;
+ m[5] = u.y;
+ m[9] = u.z;
+ m[13] = 0.0f;
+ m[2] = -f.x;
+ m[6] = -f.y;
+ m[10] = -f.z;
+ m[14] = 0.0f;
+ m[3] = m[7] = m[11] = 0.0f;
+ m[15] = 1.0f;
+ rsMatrixLoad(matrix, m);
+ rsMatrixTranslate(matrix, -eye.x, -eye.y, -eye.z);
+}
+
+void setTexture(int n, rs_allocation texture)
+{
+ cards[n].texture = texture;
+ if (cards[n].texture.p != 0)
+ cards[n].textureState = STATE_LOADED;
+ else
+ cards[n].textureState = STATE_INVALID;
+}
+
+void setGeometry(int n, rs_mesh geometry)
+{
+ cards[n].geometry = geometry;
+ if (cards[n].geometry.p != 0)
+ cards[n].geometryState = STATE_LOADED;
+ else
+ cards[n].geometryState = STATE_INVALID;
+}
+
+static void getMatrixForCard(rs_matrix4x4* matrix, int i)
+{
+ float theta = cardPosition(i);
+ rsMatrixRotate(matrix, degrees(theta), 0, 1, 0);
+ rsMatrixTranslate(matrix, radius, 0, 0);
+ rsMatrixRotate(matrix, degrees(-theta + cardRotation), 0, 1, 0);
+ // TODO: apply custom matrix for cards[i].geometry
+}
+
+static void drawCards()
+{
+ float depth = 1.0f;
+ for (int i = 0; i < cardCount; i++) {
+ if (cards[i].visible) {
+ // Bind texture
+ if (cards[i].textureState == STATE_LOADED) {
+ rsgBindTexture(fragmentProgram, 0, cards[i].texture);
+ } else if (cards[i].textureState == STATE_LOADING) {
+ rsgBindTexture(fragmentProgram, 0, loadingTexture);
+ } else {
+ rsgBindTexture(fragmentProgram, 0, defaultTexture);
+ }
+
+ // Draw geometry
+ rs_matrix4x4 matrix = modelviewMatrix;
+ getMatrixForCard(&matrix, i);
+ rsgProgramVertexLoadModelMatrix(&matrix);
+ if (cards[i].geometryState == STATE_LOADED && cards[i].geometry.p != 0) {
+ rsgDrawMesh(cards[i].geometry);
+ } else if (cards[i].geometryState == STATE_LOADING && loadingGeometry.p != 0) {
+ rsgDrawMesh(loadingGeometry);
+ } else if (defaultGeometry.p != 0) {
+ rsgDrawMesh(defaultGeometry);
+ } else {
+ // Draw place-holder geometry
+ rsgDrawQuad(
+ cardVertices[0].x, cardVertices[0].y, cardVertices[0].z,
+ cardVertices[1].x, cardVertices[1].y, cardVertices[1].z,
+ cardVertices[2].x, cardVertices[2].y, cardVertices[2].z,
+ cardVertices[3].x, cardVertices[3].y, cardVertices[3].z);
+ }
+ }
+ }
+}
+
+static void updateCameraMatrix(float width, float height)
+{
+ float aspect = width / height;
+ if (aspect != camera.aspect || updateCamera) {
+ camera.aspect = aspect;
+ loadPerspectiveMatrix(&projectionMatrix, camera.fov, camera.aspect, camera.near, camera.far);
+ rsgProgramVertexLoadProjectionMatrix(&projectionMatrix);
+
+ loadLookatMatrix(&modelviewMatrix, camera.from, camera.at, camera.up);
+ rsgProgramVertexLoadModelMatrix(&modelviewMatrix);
+ updateCamera = false;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Behavior/Physics
+////////////////////////////////////////////////////////////////////////////////////////////////////
+static float velocity = 0.0f; // angular velocity in radians/s
+static bool isDragging;
+static int64_t lastTime = 0L; // keep track of how much time has passed between frames
+static float2 lastPosition;
+static bool animating = false;
+static float velocityThreshold = 0.1f * M_PI / 180.0f;
+static float velocityTracker;
+static int velocityTrackerCount;
+static float mass = 5.0f; // kg
+
+static const float G = 9.80f; // gravity constant, in m/s
+static const float springConstant = 0.0f;
+static const float frictionCoeff = 10.0f;
+static const float dragFactor = 0.25f;
+
+static float dragFunction(float x, float y)
+{
+ return dragFactor * ((x - lastPosition.x) / rsgGetWidth()) * M_PI;
+}
+
+static float deltaTimeInSeconds(int64_t current)
+{
+ return (lastTime > 0L) ? (float) (current - lastTime) / 1000.0f : 0.0f;
+}
+
+int doSelection(float x, float y)
+{
+ Ray ray;
+ if (makeRayForPixelAt(&ray, x, y)) {
+ float bestTime = FLT_MAX;
+ return intersectGeometry(&ray, &bestTime);
+ }
+ return -1;
+}
+
+void doStart(float x, float y)
+{
+ lastPosition.x = x;
+ lastPosition.y = y;
+ velocity = 0.0f;
+ if (animating) {
+ rsSendToClient(CMD_ANIMATION_FINISHED);
+ animating = false;
+ }
+ velocityTracker = 0.0f;
+ velocityTrackerCount = 0;
+}
+
+
+void doStop(float x, float y)
+{
+ updateAllocationVars();
+
+ velocity = velocityTrackerCount > 0 ?
+ (velocityTracker / velocityTrackerCount) : 0.0f; // avg velocity
+ if (fabs(velocity) > velocityThreshold) {
+ animating = true;
+ rsSendToClient(CMD_ANIMATION_STARTED);
+ } else {
+ const int selection = doSelection(x, y); // velocity too small; treat as a tap
+ if (selection != -1) {
+ rsDebug("HIT!", selection);
+ int data[1];
+ data[0] = selection;
+ rsSendToClient(CMD_CARD_SELECTED, data, sizeof(data));
+ }
+ }
+ lastTime = rsUptimeMillis();
+}
+
+void doMotion(float x, float y)
+{
+ int64_t currentTime = rsUptimeMillis();
+ float deltaOmega = dragFunction(x, y);
+ bias += deltaOmega;
+ lastPosition.x = x;
+ lastPosition.y = y;
+ float dt = deltaTimeInSeconds(currentTime);
+ if (dt > 0.0f) {
+ float v = deltaOmega / dt;
+ //if ((velocityTracker > 0.0f) == (v > 0.0f)) {
+ velocityTracker += v;
+ velocityTrackerCount++;
+ //} else {
+ // velocityTracker = v;
+ // velocityTrackerCount = 1;
+ //}
+ }
+ lastTime = currentTime;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Hit detection using ray casting.
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+static bool
+rayTriangleIntersect(Ray* ray, float3 p0, float3 p1, float3 p2, float *tout)
+{
+ static const float tmin = 0.0f;
+
+ float3 e1 = p1 - p0;
+ float3 e2 = p2 - p0;
+ float3 s1 = cross(ray->direction, e2);
+
+ float div = dot(s1, e1);
+ if (div == 0.0f) return false; // ray is parallel to plane.
+
+ float3 d = ray->position - p0;
+ float invDiv = 1.0f / div;
+
+ float u = dot(d, s1) * invDiv;
+ if (u < 0.0f || u > 1.0f) return false;
+
+ float3 s2 = cross(d, e1);
+ float v = dot(ray->direction, s2) * invDiv;
+ if ( v < 0.0f || (u+v) > 1.0f) return false;
+
+ float t = dot(e2, s2) * invDiv;
+ if (t < tmin || t > *tout)
+ return false;
+ *tout = t;
+ return true;
+}
+
+static bool makeRayForPixelAt(Ray* ray, float x, float y)
+{
+ if (debugCamera) {
+ rsDebug("------ makeRay() -------", 0);
+ rsDebug("Camera.from:", camera.from);
+ rsDebug("Camera.at:", camera.at);
+ rsDebug("Camera.dir:", normalize(camera.at - camera.from));
+ }
+
+ // Vector math. This has the potential to be much faster.
+ // TODO: pre-compute lowerLeftRay, du, dv to eliminate most of this math.
+ if (true) {
+ const float u = x / rsgGetWidth();
+ const float v = (y / rsgGetHeight());
+ const float aspect = (float) rsgGetWidth() / rsgGetHeight();
+ const float tanfov2 = 2.0f * tan(radians(camera.fov / 2.0f));
+ float3 dir = normalize(camera.at - camera.from);
+ float3 du = tanfov2 * normalize(cross(dir, camera.up));
+ float3 dv = tanfov2 * normalize(cross(du, dir));
+ du *= aspect;
+ float3 lowerLeftRay = dir - (0.5f * du) - (0.5f * dv);
+ const float3 rayPoint = camera.from;
+ const float3 rayDir = normalize(lowerLeftRay + u*du + v*dv);
+ if (debugCamera) {
+ rsDebug("Ray direction (vector math) = ", rayDir);
+ }
+
+ ray->position = rayPoint;
+ ray->direction = rayDir;
+ }
+
+ // Matrix math. This is more generic if we allow setting model view and projection matrices
+ // directly
+ else {
+ rs_matrix4x4 pm = modelviewMatrix;
+ rsMatrixLoadMultiply(&pm, &projectionMatrix, &modelviewMatrix);
+ if (!rsMatrixInverse(&pm)) {
+ rsDebug("ERROR: SINGULAR PM MATRIX", 0);
+ return false;
+ }
+ const float width = rsgGetWidth();
+ const float height = rsgGetHeight();
+ const float winx = 2.0f * x / width - 1.0f;
+ const float winy = 2.0f * y / height - 1.0f;
+
+ float4 eye = { 0.0f, 0.0f, 0.0f, 1.0f };
+ float4 at = { winx, winy, 1.0f, 1.0f };
+
+ eye = rsMatrixMultiply(&pm, eye);
+ eye *= 1.0f / eye.w;
+
+ at = rsMatrixMultiply(&pm, at);
+ at *= 1.0f / at.w;
+
+ const float3 rayPoint = { eye.x, eye.y, eye.z };
+ const float3 atPoint = { at.x, at.y, at.z };
+ const float3 rayDir = normalize(atPoint - rayPoint);
+ if (debugCamera) {
+ rsDebug("winx: ", winx);
+ rsDebug("winy: ", winy);
+ rsDebug("Ray position (transformed) = ", eye);
+ rsDebug("Ray direction (transformed) = ", rayDir);
+ }
+ ray->position = rayPoint;
+ ray->direction = rayDir;
+ }
+
+ return true;
+}
+
+static int intersectGeometry(Ray* ray, float *bestTime)
+{
+ int hit = -1;
+ for (int id = 0; id < cardCount; id++) {
+ if (cards[id].visible) {
+ rs_matrix4x4 matrix;
+ float3 p[4];
+
+ // Transform card vertices to world space
+ rsMatrixLoadIdentity(&matrix);
+ getMatrixForCard(&matrix, id);
+ for (int vertex = 0; vertex < 4; vertex++) {
+ float4 tmp = rsMatrixMultiply(&matrix, cardVertices[vertex]);
+ if (tmp.w != 0.0f) {
+ p[vertex].x = tmp.x;
+ p[vertex].y = tmp.y;
+ p[vertex].z = tmp.z;
+ p[vertex] *= 1.0f / tmp.w;
+ } else {
+ rsDebug("Bad w coord: ", tmp);
+ }
+ }
+
+ // Intersect card geometry
+ if (rayTriangleIntersect(ray, p[0], p[1], p[2], bestTime)
+ || rayTriangleIntersect(ray, p[2], p[3], p[0], bestTime)) {
+ hit = id;
+ }
+ }
+ }
+ return hit;
+}
+
+// This method computes the position of all the cards by updating bias based on a
+// simple physics model.
+// If the cards are still in motion, returns true.
+static bool updateNextPosition()
+{
+ int64_t currentTime = rsUptimeMillis();
+ if (animating) {
+ float dt = deltaTimeInSeconds(currentTime);
+ if (dt <= 0.0f)
+ return animating;
+ const float minStepTime = 1.0f / 300.0f; // ~5 steps per frame
+ const int N = (dt > minStepTime) ? (1 + round(dt / minStepTime)) : 1;
+ dt /= N;
+ for (int i = 0; i < N; i++) {
+ // Force friction - always opposes motion
+ const float Ff = -frictionCoeff * velocity;
+
+ // Restoring force to match cards with slots
+ const float theta = startAngle + bias;
+ const float dtheta = 2.0f * M_PI / slotCount;
+ const float position = theta / dtheta;
+ const float fraction = position - floor(position); // fractional position between slots
+ float x;
+ if (fraction > 0.5f) {
+ x = - (1.0f - fraction);
+ } else {
+ x = fraction;
+ }
+ const float Fr = - springConstant * x;
+
+ // compute velocity
+ const float momentum = mass * velocity + (Ff + Fr)*dt;
+ velocity = momentum / mass;
+ bias += velocity * dt;
+ }
+
+ // TODO: Add animation to smoothly move back to slots. Currently snaps to location.
+ if (cardCount <= visibleSlotCount) {
+ // TODO: this aligns the cards to the first slot (theta = startAngle) when there aren't
+ // enough visible cards. It should be generalized to allow alignment to front,
+ // middle or back of the stack.
+ if (cardPosition(0) != slotPosition(0)) {
+ bias = 0.0f;
+ }
+ } else {
+ if (cardPosition(cardCount) < 0.0f) {
+ bias = -slotPosition(cardCount);
+ } else if (cardPosition(0) > slotPosition(0)) {
+ bias = 0.0f;
+ }
+ }
+
+ animating = fabs(velocity) > velocityThreshold;
+ if (!animating) {
+ const float dtheta = 2.0f * M_PI / slotCount;
+ bias = round((startAngle + bias) / dtheta) * dtheta - startAngle;
+ rsSendToClient(CMD_ANIMATION_FINISHED);
+ }
+ }
+ lastTime = currentTime;
+
+ return animating;
+}
+
+// Cull cards based on visibility and visibleSlotCount.
+// If visibleSlotCount is > 0, then only show those slots and cull the rest.
+// Otherwise, it should cull based on bounds of geometry.
+static int cullCards()
+{
+ const float thetaFirst = slotPosition(-1); // -1 keeps the card in front around a bit longer
+ const float thetaLast = slotPosition(visibleSlotCount);
+
+ int count = 0;
+ for (int i = 0; i < cardCount; i++) {
+ if (visibleSlotCount > 0) {
+ // If visibleSlotCount is specified, then only show up to visibleSlotCount cards.
+ float p = cardPosition(i);
+ if (p >= thetaFirst && p < thetaLast) {
+ cards[i].visible = true;
+ count++;
+ } else {
+ cards[i].visible = false;
+ }
+ } else {
+ // Cull the rest of the cards using bounding box of geometry.
+ // TODO
+ cards[i].visible = true;
+ count++;
+ }
+ }
+ return count;
+}
+
+// Request texture/geometry for items that have come into view
+// or doesn't have a texture yet.
+static void updateCardResources()
+{
+ for (int i = 0; i < cardCount; i++) {
+ int data[1];
+ if (cards[i].visible) {
+ // request texture from client if not loaded
+ if (cards[i].textureState == STATE_INVALID) {
+ data[0] = i;
+ bool enqueued = rsSendToClient(CMD_REQUEST_TEXTURE, data, sizeof(data));
+ if (enqueued) {
+ cards[i].textureState = STATE_LOADING;
+ } else {
+ rsDebug("Couldn't send CMD_REQUEST_TEXTURE", 0);
+ }
+ }
+ // request geometry from client if not loaded
+ if (cards[i].geometryState == STATE_INVALID) {
+ data[0] = i;
+ bool enqueued = rsSendToClient(CMD_REQUEST_GEOMETRY, data, sizeof(data));
+ if (enqueued) {
+ cards[i].geometryState = STATE_LOADING;
+ } else {
+ rsDebug("Couldn't send CMD_REQUEST_GEOMETRY", 0);
+ }
+ }
+ } else {
+ // ask the host to remove the texture
+ if (cards[i].textureState == STATE_LOADED) {
+ data[0] = i;
+ bool enqueued = true;
+ rsSendToClientBlocking(CMD_INVALIDATE_TEXTURE, data, sizeof(data));
+ if (enqueued) {
+ cards[i].textureState = STATE_INVALID;
+ } else {
+ rsDebug("Couldn't send CMD_INVALIDATE_TEXTURE", 0);
+ }
+ }
+ // ask the host to remove the geometry
+ if (cards[i].geometryState == STATE_LOADED) {
+ data[0] = i;
+ bool enqueued = true;
+ rsSendToClientBlocking(CMD_INVALIDATE_GEOMETRY, data, sizeof(data));
+ if (enqueued) {
+ cards[i].geometryState = STATE_INVALID;
+ } else {
+ rsDebug("Couldn't send CMD_INVALIDATE_GEOMETRY", 0);
+ }
+ }
+
+ }
+ }
+}
+
+// Places dots on geometry to visually inspect that objects can be seen by rays.
+// NOTE: the color of the dot is somewhat random, as it depends on texture of previously-rendered
+// card.
+static void renderWithRays()
+{
+ const float w = rsgGetWidth();
+ const float h = rsgGetHeight();
+ const int skip = 8;
+ color(1.0f, 0.0f, 0.0f, 1.0f);
+ for (int j = 0; j < (int) h; j+=skip) {
+ float posY = (float) j;
+ for (int i = 0; i < (int) w; i+=skip) {
+ float posX = (float) i;
+ Ray ray;
+ if (makeRayForPixelAt(&ray, posX, posY)) {
+ float bestTime = FLT_MAX;
+ if (intersectGeometry(&ray, &bestTime) != -1) {
+ rsgDrawSpriteScreenspace(posX, posY, 0.0f, 2.0f, 2.0f);
+ }
+ }
+ }
+ }
+}
+
+int root() {
+ rsgClearDepth(1.0f);
+
+ rsgBindProgramVertex(vertexProgram);
+ rsgBindProgramFragment(fragmentProgram);
+ rsgBindProgramStore(programStore);
+ rsgBindProgramRaster(rasterProgram);
+
+ updateAllocationVars();
+
+ if (!initialized) {
+ for (int i = 0; i < cardCount; i++)
+ cards[i].textureState = STATE_INVALID;
+ initialized = true;
+ }
+
+ if (false) { // for debugging - flash the screen so we know we're still rendering
+ static bool toggle;
+ if (toggle)
+ rsgClearColor(backgroundColor.x, backgroundColor.y, backgroundColor.z, 1.0);
+ else
+ rsgClearColor(1.0f, 0.0f, 0.0f, 1.f);
+ toggle = !toggle;
+ } else {
+ rsgClearColor(backgroundColor.x, backgroundColor.y, backgroundColor.z, 1.0);
+ }
+
+ updateCameraMatrix(rsgGetWidth(), rsgGetHeight());
+
+ bool stillAnimating = updateNextPosition();
+
+ cullCards();
+
+ updateCardResources();
+
+ drawCards();
+
+ if (debugPicking) {
+ renderWithRays();
+ }
+
+ //rsSendToClient(CMD_PING);
+
+ return stillAnimating ? 1 : 0;
+}
diff --git a/core/res/Android.mk b/core/res/Android.mk
index 7d11148..9fafc59 100644
--- a/core/res/Android.mk
+++ b/core/res/Android.mk
@@ -33,8 +33,16 @@
# PRODUCT-agnostic resource data like IDs and type definitions.
LOCAL_EXPORT_PACKAGE_RESOURCES := true
+# Include resources generated by system RenderScript files.
+framework_GENERATED_SOURCE_DIR := $(call intermediates-dir-for,JAVA_LIBRARIES,framework,,COMMON)/src
+framework_RenderScript_STAMP_FILE := $(framework_GENERATED_SOURCE_DIR)/RenderScript.stamp
+LOCAL_RESOURCE_DIR := $(framework_GENERATED_SOURCE_DIR)/renderscript/res $(LOCAL_PATH)/res
+
include $(BUILD_PACKAGE)
+# Make sure the system .rs files get compiled before building the package-export.apk.
+$(resource_export_package): $(framework_RenderScript_STAMP_FILE)
+
# define a global intermediate target that other module may depend on.
.PHONY: framework-res-package-target
framework-res-package-target: $(LOCAL_BUILT_MODULE)
diff --git a/graphics/java/android/renderscript/Font.java b/graphics/java/android/renderscript/Font.java
index d79909e..de25014 100644
--- a/graphics/java/android/renderscript/Font.java
+++ b/graphics/java/android/renderscript/Font.java
@@ -18,6 +18,8 @@
import java.io.IOException;
import java.io.InputStream;
+import java.util.Map;
+import java.util.HashMap;
import android.content.res.Resources;
import android.content.res.AssetManager;
@@ -30,10 +32,100 @@
**/
public class Font extends BaseObj {
+ //These help us create a font by family name
+ private static final String[] sSansNames = {
+ "sans-serif", "arial", "helvetica", "tahoma", "verdana"
+ };
+
+ private static final String[] sSerifNames = {
+ "serif", "times", "times new roman", "palatino", "georgia", "baskerville",
+ "goudy", "fantasy", "cursive", "ITC Stone Serif"
+ };
+
+ private static final String[] sMonoNames = {
+ "monospace", "courier", "courier new", "monaco"
+ };
+
+ private static class FontFamily {
+ String[] mNames;
+ String mNormalFileName;
+ String mBoldFileName;
+ String mItalicFileName;
+ String mBoldItalicFileName;
+ }
+
+ private static Map<String, FontFamily> sFontFamilyMap;
+
+ public enum Style {
+ NORMAL,
+ BOLD,
+ ITALIC,
+ BOLD_ITALIC;
+ }
+
+ private static void addFamilyToMap(FontFamily family) {
+ for(int i = 0; i < family.mNames.length; i ++) {
+ sFontFamilyMap.put(family.mNames[i], family);
+ }
+ }
+
+ private static void initFontFamilyMap() {
+ sFontFamilyMap = new HashMap<String, FontFamily>();
+
+ FontFamily sansFamily = new FontFamily();
+ sansFamily.mNames = sSansNames;
+ sansFamily.mNormalFileName = "DroidSans.ttf";
+ sansFamily.mBoldFileName = "DroidSans-Bold.ttf";
+ sansFamily.mItalicFileName = "DroidSans.ttf";
+ sansFamily.mBoldItalicFileName = "DroidSans-Bold.ttf";
+ addFamilyToMap(sansFamily);
+
+ FontFamily serifFamily = new FontFamily();
+ serifFamily.mNames = sSerifNames;
+ serifFamily.mNormalFileName = "DroidSerif-Regular.ttf";
+ serifFamily.mBoldFileName = "DroidSerif-Bold.ttf";
+ serifFamily.mItalicFileName = "DroidSerif-Italic.ttf";
+ serifFamily.mBoldItalicFileName = "DroidSerif-BoldItalic.ttf";
+ addFamilyToMap(serifFamily);
+
+ FontFamily monoFamily = new FontFamily();
+ monoFamily.mNames = sMonoNames;
+ monoFamily.mNormalFileName = "DroidSansMono.ttf";
+ monoFamily.mBoldFileName = "DroidSansMono.ttf";
+ monoFamily.mItalicFileName = "DroidSansMono.ttf";
+ monoFamily.mBoldItalicFileName = "DroidSansMono.ttf";
+ addFamilyToMap(monoFamily);
+ }
+
+ static {
+ initFontFamilyMap();
+ }
+
+ static String getFontFileName(String familyName, Style style) {
+ FontFamily family = sFontFamilyMap.get(familyName);
+ if(family != null) {
+ switch(style) {
+ case NORMAL:
+ return family.mNormalFileName;
+ case BOLD:
+ return family.mBoldFileName;
+ case ITALIC:
+ return family.mItalicFileName;
+ case BOLD_ITALIC:
+ return family.mBoldItalicFileName;
+ }
+ }
+ // Fallback if we could not find the desired family
+ return "DroidSans.ttf";
+ }
+
Font(int id, RenderScript rs) {
super(id, rs);
}
+ /**
+ * Takes a specific file name as an argument
+ */
static public Font create(RenderScript rs, Resources res, String fileName, int size)
throws IllegalArgumentException {
@@ -43,7 +135,7 @@
int fontId = rs.nFontCreateFromFile(fileName, size, dpi);
if(fontId == 0) {
- throw new IllegalStateException("Load loading a font");
+ throw new IllegalStateException("Failed loading a font");
}
Font rsFont = new Font(fontId, rs);
@@ -55,4 +147,19 @@
return null;
}
+
+ /**
+ * Accepts one of the following family names as an argument
+ * and will attemp to produce the best match with a system font
+ * "sans-serif" "arial" "helvetica" "tahoma" "verdana"
+ * "serif" "times" "times new roman" "palatino" "georgia" "baskerville"
+ * "goudy" "fantasy" "cursive" "ITC Stone Serif"
+ * "monospace" "courier" "courier new" "monaco"
+ * Returns default font if no match could be found
+ */
+ static public Font createFromFamily(RenderScript rs, Resources res, String familyName, Style fontStyle, int size)
+ throws IllegalArgumentException {
+ String fileName = getFontFileName(familyName, fontStyle);
+ return create(rs, res, fileName, size);
+ }
}
diff --git a/libs/rs/java/ModelViewer/AndroidManifest.xml b/libs/rs/java/ModelViewer/AndroidManifest.xml
index ebbe743..39976d2 100644
--- a/libs/rs/java/ModelViewer/AndroidManifest.xml
+++ b/libs/rs/java/ModelViewer/AndroidManifest.xml
@@ -10,5 +10,13 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
+ <activity android:name="SceneGraph"
+ android:label="SceneGraph"
+ android:theme="@android:style/Theme.Black.NoTitleBar">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
</application>
</manifest>
diff --git a/libs/rs/java/SceneGraph/src/com/android/scenegraph/SceneGraph.java b/libs/rs/java/ModelViewer/src/com/android/modelviewer/SceneGraph.java
similarity index 97%
rename from libs/rs/java/SceneGraph/src/com/android/scenegraph/SceneGraph.java
rename to libs/rs/java/ModelViewer/src/com/android/modelviewer/SceneGraph.java
index 5daa4ac..557e0cc 100644
--- a/libs/rs/java/SceneGraph/src/com/android/scenegraph/SceneGraph.java
+++ b/libs/rs/java/ModelViewer/src/com/android/modelviewer/SceneGraph.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.scenegraph;
+package com.android.modelviewer;
import android.renderscript.RSSurfaceView;
import android.renderscript.RenderScript;
diff --git a/libs/rs/java/SceneGraph/src/com/android/scenegraph/SceneGraphRS.java b/libs/rs/java/ModelViewer/src/com/android/modelviewer/SceneGraphRS.java
similarity index 99%
rename from libs/rs/java/SceneGraph/src/com/android/scenegraph/SceneGraphRS.java
rename to libs/rs/java/ModelViewer/src/com/android/modelviewer/SceneGraphRS.java
index 3db4a2b6..3f4d930 100644
--- a/libs/rs/java/SceneGraph/src/com/android/scenegraph/SceneGraphRS.java
+++ b/libs/rs/java/ModelViewer/src/com/android/modelviewer/SceneGraphRS.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.scenegraph;
+package com.android.modelviewer;
import java.io.Writer;
import java.util.Map;
diff --git a/libs/rs/java/SceneGraph/src/com/android/scenegraph/SceneGraphView.java b/libs/rs/java/ModelViewer/src/com/android/modelviewer/SceneGraphView.java
similarity index 98%
rename from libs/rs/java/SceneGraph/src/com/android/scenegraph/SceneGraphView.java
rename to libs/rs/java/ModelViewer/src/com/android/modelviewer/SceneGraphView.java
index ae94869..44a59b2 100644
--- a/libs/rs/java/SceneGraph/src/com/android/scenegraph/SceneGraphView.java
+++ b/libs/rs/java/ModelViewer/src/com/android/modelviewer/SceneGraphView.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.scenegraph;
+package com.android.modelviewer;
import java.io.Writer;
import java.util.ArrayList;
diff --git a/libs/rs/java/SceneGraph/src/com/android/scenegraph/SgTransform.java b/libs/rs/java/ModelViewer/src/com/android/modelviewer/SgTransform.java
similarity index 98%
rename from libs/rs/java/SceneGraph/src/com/android/scenegraph/SgTransform.java
rename to libs/rs/java/ModelViewer/src/com/android/modelviewer/SgTransform.java
index e81f1a7..bfc9bb7 100644
--- a/libs/rs/java/SceneGraph/src/com/android/scenegraph/SgTransform.java
+++ b/libs/rs/java/ModelViewer/src/com/android/modelviewer/SgTransform.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.scenegraph;
+package com.android.modelviewer;
import java.io.Writer;
import java.util.Map;
diff --git a/libs/rs/java/SceneGraph/src/com/android/scenegraph/scenegraph.rs b/libs/rs/java/ModelViewer/src/com/android/modelviewer/scenegraph.rs
similarity index 97%
rename from libs/rs/java/SceneGraph/src/com/android/scenegraph/scenegraph.rs
rename to libs/rs/java/ModelViewer/src/com/android/modelviewer/scenegraph.rs
index e6ae6df..8053306 100644
--- a/libs/rs/java/SceneGraph/src/com/android/scenegraph/scenegraph.rs
+++ b/libs/rs/java/ModelViewer/src/com/android/modelviewer/scenegraph.rs
@@ -14,7 +14,7 @@
#pragma version(1)
-#pragma rs java_package_name(com.android.scenegraph)
+#pragma rs java_package_name(com.android.modelviewer)
#include "rs_graphics.rsh"
#include "transform_def.rsh"
diff --git a/libs/rs/java/SceneGraph/src/com/android/scenegraph/transform.rs b/libs/rs/java/ModelViewer/src/com/android/modelviewer/transform.rs
similarity index 97%
rename from libs/rs/java/SceneGraph/src/com/android/scenegraph/transform.rs
rename to libs/rs/java/ModelViewer/src/com/android/modelviewer/transform.rs
index a62d12b..7b9cd1c 100644
--- a/libs/rs/java/SceneGraph/src/com/android/scenegraph/transform.rs
+++ b/libs/rs/java/ModelViewer/src/com/android/modelviewer/transform.rs
@@ -14,7 +14,7 @@
#pragma version(1)
-#pragma rs java_package_name(com.android.scenegraph)
+#pragma rs java_package_name(com.android.modelviewer)
#include "transform_def.rsh"
diff --git a/libs/rs/java/SceneGraph/src/com/android/scenegraph/transform_def.rsh b/libs/rs/java/ModelViewer/src/com/android/modelviewer/transform_def.rsh
similarity index 96%
rename from libs/rs/java/SceneGraph/src/com/android/scenegraph/transform_def.rsh
rename to libs/rs/java/ModelViewer/src/com/android/modelviewer/transform_def.rsh
index 10aac37..a66e6c5 100644
--- a/libs/rs/java/SceneGraph/src/com/android/scenegraph/transform_def.rsh
+++ b/libs/rs/java/ModelViewer/src/com/android/modelviewer/transform_def.rsh
@@ -14,7 +14,7 @@
#pragma version(1)
-#pragma rs java_package_name(com.android.scenegraph)
+#pragma rs java_package_name(com.android.modelviewer)
#define TRANSFORM_NONE 0
#define TRANSFORM_TRANSLATE 1
diff --git a/libs/rs/java/SceneGraph/Android.mk b/libs/rs/java/Samples/Android.mk
similarity index 96%
rename from libs/rs/java/SceneGraph/Android.mk
rename to libs/rs/java/Samples/Android.mk
index 5520446..65ae734 100644
--- a/libs/rs/java/SceneGraph/Android.mk
+++ b/libs/rs/java/Samples/Android.mk
@@ -24,7 +24,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
#LOCAL_STATIC_JAVA_LIBRARIES := android.renderscript
-LOCAL_PACKAGE_NAME := SceneGraph
+LOCAL_PACKAGE_NAME := Samples
include $(BUILD_PACKAGE)
diff --git a/libs/rs/java/SceneGraph/AndroidManifest.xml b/libs/rs/java/Samples/AndroidManifest.xml
similarity index 73%
rename from libs/rs/java/SceneGraph/AndroidManifest.xml
rename to libs/rs/java/Samples/AndroidManifest.xml
index 8a8f87a..85d7547 100644
--- a/libs/rs/java/SceneGraph/AndroidManifest.xml
+++ b/libs/rs/java/Samples/AndroidManifest.xml
@@ -1,8 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.scenegraph">
- <application android:label="SceneGraph">
- <activity android:name="SceneGraph"
+ package="com.android.samples">
+ <application android:label="Samples">
+ <activity android:name="RsList"
+ android:label="RsList"
android:theme="@android:style/Theme.Black.NoTitleBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
diff --git a/libs/rs/java/SceneGraph/src/com/android/scenegraph/SceneGraph.java b/libs/rs/java/Samples/src/com/android/samples/RsList.java
similarity index 91%
copy from libs/rs/java/SceneGraph/src/com/android/scenegraph/SceneGraph.java
copy to libs/rs/java/Samples/src/com/android/samples/RsList.java
index 5daa4ac..d8c733d 100644
--- a/libs/rs/java/SceneGraph/src/com/android/scenegraph/SceneGraph.java
+++ b/libs/rs/java/Samples/src/com/android/samples/RsList.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.scenegraph;
+package com.android.samples;
import android.renderscript.RSSurfaceView;
import android.renderscript.RenderScript;
@@ -37,9 +37,9 @@
import java.lang.Runtime;
-public class SceneGraph extends Activity {
+public class RsList extends Activity {
- private SceneGraphView mView;
+ private RsListView mView;
@Override
public void onCreate(Bundle icicle) {
@@ -47,7 +47,7 @@
// Create our Preview view and set it as the content of our
// Activity
- mView = new SceneGraphView(this);
+ mView = new RsListView(this);
setContentView(mView);
}
diff --git a/libs/rs/java/Samples/src/com/android/samples/RsListRS.java b/libs/rs/java/Samples/src/com/android/samples/RsListRS.java
new file mode 100644
index 0000000..a782e0e
--- /dev/null
+++ b/libs/rs/java/Samples/src/com/android/samples/RsListRS.java
@@ -0,0 +1,145 @@
+/*
+ * 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.android.samples;
+
+import java.io.Writer;
+import java.util.Vector;
+
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.renderscript.ProgramStore.DepthFunc;
+import android.util.Log;
+
+
+public class RsListRS {
+
+ private final int STATE_LAST_FOCUS = 1;
+
+ private static final String[] DATA_LIST = {
+ "Afghanistan", "Albania", "Algeria", "American Samoa", "Andorra",
+ "Angola", "Anguilla", "Antarctica", "Antigua and Barbuda", "Argentina",
+ "Armenia", "Aruba", "Australia", "Austria", "Azerbaijan",
+ "Bahrain", "Bangladesh", "Barbados", "Belarus", "Belgium",
+ "Belize", "Benin", "Bermuda", "Bhutan", "Bolivia",
+ "Bosnia and Herzegovina", "Botswana", "Bouvet Island", "Brazil",
+ "British Indian Ocean Territory", "British Virgin Islands", "Brunei", "Bulgaria",
+ "Burkina Faso", "Burundi", "Cote d'Ivoire", "Cambodia", "Cameroon", "Canada", "Cape Verde",
+ "Cayman Islands", "Central African Republic", "Chad", "Chile", "China",
+ "Christmas Island", "Cocos (Keeling) Islands", "Colombia", "Comoros", "Congo",
+ "Cook Islands", "Costa Rica", "Croatia", "Cuba", "Cyprus", "Czech Republic",
+ "Democratic Republic of the Congo", "Denmark", "Djibouti", "Dominica", "Dominican Republic",
+ "East Timor", "Ecuador", "Egypt", "El Salvador", "Equatorial Guinea", "Eritrea",
+ "Estonia", "Ethiopia", "Faeroe Islands", "Falkland Islands", "Fiji", "Finland",
+ "Former Yugoslav Republic of Macedonia", "France", "French Guiana", "French Polynesia",
+ "French Southern Territories", "Gabon", "Georgia", "Germany", "Ghana", "Gibraltar",
+ "Greece", "Greenland", "Grenada", "Guadeloupe", "Guam", "Guatemala", "Guinea", "Guinea-Bissau",
+ "Guyana", "Haiti", "Heard Island and McDonald Islands", "Honduras", "Hong Kong", "Hungary",
+ "Iceland", "India", "Indonesia", "Iran", "Iraq", "Ireland", "Israel", "Italy", "Jamaica",
+ "Japan", "Jordan", "Kazakhstan", "Kenya", "Kiribati", "Kuwait", "Kyrgyzstan", "Laos",
+ "Latvia", "Lebanon", "Lesotho", "Liberia", "Libya", "Liechtenstein", "Lithuania", "Luxembourg",
+ "Macau", "Madagascar", "Malawi", "Malaysia", "Maldives", "Mali", "Malta", "Marshall Islands",
+ "Martinique", "Mauritania", "Mauritius", "Mayotte", "Mexico", "Micronesia", "Moldova",
+ "Monaco", "Mongolia", "Montserrat", "Morocco", "Mozambique", "Myanmar", "Namibia",
+ "Nauru", "Nepal", "Netherlands", "Netherlands Antilles", "New Caledonia", "New Zealand",
+ "Nicaragua", "Niger", "Nigeria", "Niue", "Norfolk Island", "North Korea", "Northern Marianas",
+ "Norway", "Oman", "Pakistan", "Palau", "Panama", "Papua New Guinea", "Paraguay", "Peru",
+ "Philippines", "Pitcairn Islands", "Poland", "Portugal", "Puerto Rico", "Qatar",
+ "Reunion", "Romania", "Russia", "Rwanda", "Sqo Tome and Principe", "Saint Helena",
+ "Saint Kitts and Nevis", "Saint Lucia", "Saint Pierre and Miquelon",
+ "Saint Vincent and the Grenadines", "Samoa", "San Marino", "Saudi Arabia", "Senegal",
+ "Seychelles", "Sierra Leone", "Singapore", "Slovakia", "Slovenia", "Solomon Islands",
+ "Somalia", "South Africa", "South Georgia and the South Sandwich Islands", "South Korea",
+ "Spain", "Sri Lanka", "Sudan", "Suriname", "Svalbard and Jan Mayen", "Swaziland", "Sweden",
+ "Switzerland", "Syria", "Taiwan", "Tajikistan", "Tanzania", "Thailand", "The Bahamas",
+ "The Gambia", "Togo", "Tokelau", "Tonga", "Trinidad and Tobago", "Tunisia", "Turkey",
+ "Turkmenistan", "Turks and Caicos Islands", "Tuvalu", "Virgin Islands", "Uganda",
+ "Ukraine", "United Arab Emirates", "United Kingdom",
+ "United States", "United States Minor Outlying Islands", "Uruguay", "Uzbekistan",
+ "Vanuatu", "Vatican City", "Venezuela", "Vietnam", "Wallis and Futuna", "Western Sahara",
+ "Yemen", "Yugoslavia", "Zambia", "Zimbabwe"
+ };
+
+ int mWidth;
+ int mHeight;
+
+ public RsListRS() {
+ }
+
+ public void init(RenderScriptGL rs, Resources res, int width, int height) {
+ mRS = rs;
+ mRes = res;
+ mWidth = width;
+ mHeight = height;
+ initRS();
+ }
+
+ private Resources mRes;
+ private RenderScriptGL mRS;
+ private Font mItalic;
+
+ ScriptField_ListAllocs_s mListAllocs;
+
+ private ScriptC_Rslist mScript;
+
+ int mLastX;
+ int mLastY;
+
+ public void onActionDown(int x, int y) {
+ mScript.set_gDY(0.0f);
+
+ mLastX = x;
+ mLastY = y;
+ }
+
+ public void onActionMove(int x, int y) {
+ int dx = mLastX - x;
+ int dy = mLastY - y;
+
+ if(Math.abs(dy) <= 2) {
+ dy = 0;
+ }
+
+ mScript.set_gDY(dy);
+
+ mLastX = x;
+ mLastY = y;
+ }
+
+ private void initRS() {
+
+ mScript = new ScriptC_Rslist(mRS, mRes, R.raw.rslist, true);
+
+ mListAllocs = new ScriptField_ListAllocs_s(mRS, DATA_LIST.length);
+ for(int i = 0; i < DATA_LIST.length; i ++) {
+ ScriptField_ListAllocs_s.Item listElem = new ScriptField_ListAllocs_s.Item();
+ listElem.text = Allocation.createFromString(mRS, DATA_LIST[i]);
+ mListAllocs.set(listElem, i, false);
+ }
+
+ mListAllocs.copyAll();
+
+ mScript.bind_gList(mListAllocs);
+
+ mItalic = Font.createFromFamily(mRS, mRes, "serif", Font.Style.BOLD_ITALIC, 8);
+ mScript.set_gItalic(mItalic);
+
+ mRS.contextBindRootScript(mScript);
+ }
+}
+
+
+
diff --git a/libs/rs/java/SceneGraph/src/com/android/scenegraph/SceneGraphView.java b/libs/rs/java/Samples/src/com/android/samples/RsListView.java
similarity index 82%
copy from libs/rs/java/SceneGraph/src/com/android/scenegraph/SceneGraphView.java
copy to libs/rs/java/Samples/src/com/android/samples/RsListView.java
index ae94869..b98ea08 100644
--- a/libs/rs/java/SceneGraph/src/com/android/scenegraph/SceneGraphView.java
+++ b/libs/rs/java/Samples/src/com/android/samples/RsListView.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.scenegraph;
+package com.android.samples;
import java.io.Writer;
import java.util.ArrayList;
@@ -39,15 +39,15 @@
import android.view.KeyEvent;
import android.view.MotionEvent;
-public class SceneGraphView extends RSSurfaceView {
+public class RsListView extends RSSurfaceView {
- public SceneGraphView(Context context) {
+ public RsListView(Context context) {
super(context);
//setFocusable(true);
}
private RenderScriptGL mRS;
- private SceneGraphRS mRender;
+ private RsListRS mRender;
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
@@ -55,7 +55,7 @@
if (mRS == null) {
mRS = createRenderScript(true);
mRS.contextSetSurface(w, h, holder.getSurface());
- mRender = new SceneGraphRS();
+ mRender = new RsListRS();
mRender.init(mRS, getResources(), w, h);
}
}
@@ -80,13 +80,17 @@
@Override
public boolean onTouchEvent(MotionEvent ev)
{
- boolean ret = true;
+ boolean ret = false;
int act = ev.getAction();
- if (act == ev.ACTION_UP) {
- ret = false;
+ if (act == ev.ACTION_DOWN) {
+ mRender.onActionDown((int)ev.getX(), (int)ev.getY());
+ ret = true;
+ }
+ else if (act == ev.ACTION_MOVE) {
+ mRender.onActionMove((int)ev.getX(), (int)ev.getY());
+ ret = true;
}
- mRender.touchEvent((int)ev.getX(), (int)ev.getY());
return ret;
}
}
diff --git a/libs/rs/java/Samples/src/com/android/samples/rslist.rs b/libs/rs/java/Samples/src/com/android/samples/rslist.rs
new file mode 100644
index 0000000..3c3f463
--- /dev/null
+++ b/libs/rs/java/Samples/src/com/android/samples/rslist.rs
@@ -0,0 +1,73 @@
+// Copyright (C) 2009 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.
+
+#pragma version(1)
+
+#pragma rs java_package_name(com.android.samples)
+
+#include "rs_graphics.rsh"
+
+float gDY;
+
+rs_font gItalic;
+
+typedef struct ListAllocs_s {
+ rs_allocation text;
+} ListAllocs;
+
+ListAllocs *gList;
+
+#pragma rs export_var(gDY, gItalic, gList)
+
+void init() {
+ gDY = 0.0f;
+}
+
+int textPos = 0;
+
+int root(int launchID) {
+
+ rsgClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+ rsgClearDepth(1.0f);
+
+ textPos -= (int)gDY*2;
+ gDY *= 0.95;
+
+ rsgFontColor(0.9f, 0.9f, 0.9f, 1.0f);
+ rsgBindFont(gItalic);
+ color(0.2, 0.2, 0.2, 0);
+
+ rs_allocation listAlloc = rsGetAllocation(gList);
+ int allocSize = rsAllocationGetDimX(listAlloc);
+
+ int width = rsgGetWidth();
+ int height = rsgGetHeight();
+
+ int itemHeight = 80;
+ int currentYPos = itemHeight + textPos;
+
+ for(int i = 0; i < allocSize; i ++) {
+ if(currentYPos - itemHeight > height) {
+ break;
+ }
+
+ if(currentYPos > 0) {
+ rsgDrawRect(0, currentYPos - 1, width, currentYPos, 0);
+ rsgDrawText(gList[i].text, 30, currentYPos - 32);
+ }
+ currentYPos += itemHeight;
+ }
+
+ return 10;
+}
diff --git a/libs/rs/java/SceneGraph/res/drawable/robot.png b/libs/rs/java/SceneGraph/res/drawable/robot.png
deleted file mode 100644
index f7353fd..0000000
--- a/libs/rs/java/SceneGraph/res/drawable/robot.png
+++ /dev/null
Binary files differ
diff --git a/libs/rs/java/SceneGraph/res/raw/robot.a3d b/libs/rs/java/SceneGraph/res/raw/robot.a3d
deleted file mode 100644
index 2d7d32b..0000000
--- a/libs/rs/java/SceneGraph/res/raw/robot.a3d
+++ /dev/null
Binary files differ
diff --git a/libs/rs/rsFont.cpp b/libs/rs/rsFont.cpp
index 1ef9c93..7661d499 100644
--- a/libs/rs/rsFont.cpp
+++ b/libs/rs/rsFont.cpp
@@ -218,6 +218,7 @@
Font * Font::create(Context *rsc, const char *name, uint32_t fontSize, uint32_t dpi)
{
+ rsc->mStateFont.checkInit();
Vector<Font*> &activeFonts = rsc->mStateFont.mActiveFonts;
for(uint32_t i = 0; i < activeFonts.size(); i ++) {
@@ -513,6 +514,12 @@
initVertexArrayBuffers();
+ // We store a string with letters in a rough frequency of occurrence
+ mLatinPrecache = String8(" eisarntolcdugpmhbyfvkwzxjq");
+ mLatinPrecache += String8("EISARNTOLCDUGPMHBYFVKWZXJQ");
+ mLatinPrecache += String8(",.?!()-+@;:`'");
+ mLatinPrecache += String8("0123456789");
+
mInitialized = true;
}
@@ -622,7 +629,7 @@
uint32_t FontState::getRemainingCacheCapacity() {
uint32_t remainingCapacity = 0;
- float totalPixels = 0;
+ uint32_t totalPixels = 0;
for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
totalPixels += mCacheLines[i]->mMaxWidth;
@@ -666,12 +673,6 @@
issueDrawCommand();
mCurrentQuadIndex = 0;
}
-
- // We store a string with letters in a rough frequency of occurrence
- mLatinPrecache = String8(" eisarntolcdugpmhbyfvkwzxjq");
- mLatinPrecache += String8("EISARNTOLCDUGPMHBYFVKWZXJQ");
- mLatinPrecache += String8(",.?!()-+@;:`'");
- mLatinPrecache += String8("0123456789");
}
void FontState::renderText(const char *text, int x, int y)
diff --git a/packages/SystemUI/res/layout-xlarge/sysbar_panel_system.xml b/packages/SystemUI/res/layout-xlarge/sysbar_panel_system.xml
index e5b2f53..273674f 100644
--- a/packages/SystemUI/res/layout-xlarge/sysbar_panel_system.xml
+++ b/packages/SystemUI/res/layout-xlarge/sysbar_panel_system.xml
@@ -86,19 +86,24 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
- <ImageView android:id="@+id/battery_meter"
- android:layout_width="wrap_content"
+ <RelativeLayout
+ android:layout_width="120dip"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
- android:src="@drawable/dots_empty"
- />
+ >
+ <ImageView android:id="@+id/battery_meter"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/battery"
+ />
- <TextView android:id="@+id/battery_info"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:layout_below="@id/battery_meter"
- />
+ <TextView android:id="@+id/battery_info"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:layout_below="@id/battery_meter"
+ />
+ </RelativeLayout>
<com.android.systemui.statusbar.Clock
style="@*android:style/TextAppearance.StatusBar.Icon"
@@ -118,19 +123,24 @@
android:layout_below="@id/clock"
/>
- <ImageView android:id="@+id/signal_meter"
- android:layout_width="wrap_content"
+ <RelativeLayout
+ android:layout_width="120dip"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
- android:src="@drawable/signal"
- />
+ >
+ <ImageView android:id="@+id/signal_meter"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/signal"
+ />
- <TextView android:id="@+id/signal_info"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:layout_below="@id/signal_meter"
- />
+ <TextView android:id="@+id/signal_info"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:layout_below="@id/signal_meter"
+ />
+ </RelativeLayout>
</RelativeLayout>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SystemPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SystemPanel.java
index c864daa..a03393b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SystemPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SystemPanel.java
@@ -29,6 +29,11 @@
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.media.AudioManager;
+import android.net.NetworkInfo;
+import android.net.wifi.SupplicantState;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.IBinder;
@@ -59,6 +64,8 @@
import android.widget.TextView;
import android.widget.Toast;
+import java.util.List;
+
import com.android.systemui.statusbar.*;
import com.android.systemui.R;
@@ -85,6 +92,7 @@
private TextView mSignalText;
private final AudioManager mAudioManager;
+ private final WifiManager mWifiManager;
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
@@ -94,21 +102,100 @@
if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) {
mSoundButton.setAlpha(getSilentMode() ? 0x7F : 0xFF);
} else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
- // hack for now
- mBar.updateBatteryDisplay(intent.getIntExtra("level", 0),
- (intent.getIntExtra("plugged", 0) != 0));
+ updateBattery(intent);
+ } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)
+ || action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)
+ || action.equals(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION)
+ || action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
+ updateWifi(intent);
}
}
};
+ boolean mWifiEnabled, mWifiConnected;
+ int mWifiLevel;
+ String mWifiSsid;
+
+ private void updateWifi(Intent intent) {
+ if (TabletStatusBarService.DEBUG)
+ Slog.d(TabletStatusBarService.TAG, "updateWifi: " + intent);
+
+ final String action = intent.getAction();
+ final boolean wasConnected = mWifiConnected;
+
+ if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
+ mWifiEnabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
+ WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED;
+ } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
+ final NetworkInfo networkInfo = (NetworkInfo)
+ intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
+ mWifiConnected = networkInfo != null && networkInfo.isConnected();
+ } else if (action.equals(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION)) {
+ final NetworkInfo.DetailedState detailedState = WifiInfo.getDetailedStateOf(
+ (SupplicantState)intent.getParcelableExtra(WifiManager.EXTRA_NEW_STATE));
+ mWifiConnected = detailedState == NetworkInfo.DetailedState.CONNECTED;
+ } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
+ final int newRssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200);
+ int newSignalLevel = WifiManager.calculateSignalLevel(newRssi, 6) * 20;
+ mWifiLevel = mWifiConnected ? newSignalLevel : 0;
+ }
+
+ if (mWifiConnected && !wasConnected) {
+ WifiInfo info = mWifiManager.getConnectionInfo();
+ if (TabletStatusBarService.DEBUG)
+ Slog.d(TabletStatusBarService.TAG, "updateWifi: just connected: info=" + info);
+
+ if (info != null) {
+ // grab the initial signal strength
+ mWifiLevel = WifiManager.calculateSignalLevel(info.getRssi(), 101);
+
+ // find the SSID
+ mWifiSsid = info.getSSID();
+ if (mWifiSsid == null) {
+ // OK, it's not in the connectionInfo; we have to go hunting for it
+ List<WifiConfiguration> networks = mWifiManager.getConfiguredNetworks();
+ for (WifiConfiguration net : networks) {
+ if (net.networkId == info.getNetworkId()) {
+ mWifiSsid = net.SSID;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (!mWifiEnabled) {
+ mWifiSsid = "disabled";
+ mWifiLevel = 0;
+ } else if (!mWifiConnected) {
+ mWifiSsid = "disconnected";
+ mWifiLevel = 0;
+ } else if (mWifiSsid == null) {
+ mWifiSsid = "unknown";
+ }
+
+ mSignalMeter.setImageResource(R.drawable.signal);
+ mSignalMeter.setImageLevel(mWifiLevel);
+ mSignalText.setText(String.format("Wi-Fi: %s", mWifiSsid)); // XXX: localize
+
+ // hack for now
+ mBar.setWifiMeter(mWifiLevel);
+ }
+
public void setBar(TabletStatusBarService bar) {
mBar = bar;
}
- public void setBatteryLevel(int level, boolean plugged) {
+ public void updateBattery(Intent intent) {
+ final int level = intent.getIntExtra("level", 0);
+ final boolean plugged = intent.getIntExtra("plugged", 0) != 0;
+
mBatteryMeter.setImageResource(plugged ? R.drawable.battery_charging : R.drawable.battery);
mBatteryMeter.setImageLevel(level);
mBatteryText.setText(String.format("Battery: %d%%", level));
+
+ // hack for now
+ mBar.setBatteryMeter(level, plugged);
}
public SystemPanel(Context context, AttributeSet attrs) {
@@ -123,6 +210,10 @@
(TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
telephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_SERVICE_STATE);
+ // wifi status info
+ mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
+
+ // audio status notifications
mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
}
@@ -171,7 +262,10 @@
IntentFilter filter = new IntentFilter();
filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
- filter.addAction(Intent.ACTION_POWER_CONNECTED);
+ filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
+ filter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
+ filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
+ filter.addAction(WifiManager.RSSI_CHANGED_ACTION);
getContext().registerReceiver(mReceiver, filter);
mBatteryMeter = (ImageView)findViewById(R.id.battery_meter);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarService.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarService.java
index b0ffaa5..022470e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarService.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarService.java
@@ -54,7 +54,7 @@
import com.android.systemui.R;
public class TabletStatusBarService extends StatusBarService {
- public static final boolean DEBUG = false;
+ public static final boolean DEBUG = true;
public static final String TAG = "TabletStatusBar";
@@ -206,13 +206,16 @@
}
}
- StatusBarIcon mBatterySBI;
- StatusBarIcon mSignalSBI;
- public void updateBatteryDisplay(int level, boolean plugged) {
+ public void setBatteryMeter(int level, boolean plugged) {
if (DEBUG) Slog.d(TAG, "battery=" + level + (plugged ? " - plugged" : " - unplugged"));
mBatteryMeter.setImageResource(plugged ? R.drawable.battery_charging : R.drawable.battery);
mBatteryMeter.setImageLevel(level);
- mSystemPanel.setBatteryLevel(level, plugged);
+ }
+
+ public void setWifiMeter(int level) {
+ if (DEBUG) Slog.d(TAG, "wifi=" + level);
+ mSignalMeter.setImageResource(R.drawable.signal);
+ mSignalMeter.setImageLevel(level);
}
public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon) {
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index a774c12..9156358 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -765,8 +765,9 @@
} else if (rssi >= MAX_RSSI) {
return numLevels - 1;
} else {
- int partitionSize = (MAX_RSSI - MIN_RSSI) / (numLevels - 1);
- return (rssi - MIN_RSSI) / partitionSize;
+ float inputRange = (MAX_RSSI - MIN_RSSI);
+ float outputRange = (numLevels - 1);
+ return (int)((float)(rssi - MIN_RSSI) * outputRange / inputRange);
}
}