diff options
37 files changed, 583 insertions, 392 deletions
diff --git a/api/current.xml b/api/current.xml index 6adf8aa2c861..2c9789222b8b 100644 --- a/api/current.xml +++ b/api/current.xml @@ -39947,7 +39947,7 @@ visibility="public" > </field> -<field name="resizableMode" +<field name="resizeMode" type="int" transient="false" volatile="false" diff --git a/core/java/android/appwidget/AppWidgetProviderInfo.java b/core/java/android/appwidget/AppWidgetProviderInfo.java index 32c239755040..b46802e94e7a 100644 --- a/core/java/android/appwidget/AppWidgetProviderInfo.java +++ b/core/java/android/appwidget/AppWidgetProviderInfo.java @@ -130,6 +130,9 @@ public class AppWidgetProviderInfo implements Parcelable { /** * The view id of the AppWidget subview which should be auto-advanced by the widget's host. + * + * <p>This field corresponds to the <code>android:autoAdvanceViewId</code> attribute in + * the AppWidget meta-data file. */ public int autoAdvanceViewId; @@ -146,8 +149,11 @@ public class AppWidgetProviderInfo implements Parcelable { * The rules by which a widget can be resized. See {@link #RESIZE_NONE}, * {@link #RESIZE_NONE}, {@link #RESIZE_HORIZONTAL}, * {@link #RESIZE_VERTICAL}, {@link #RESIZE_BOTH}. + * + * <p>This field corresponds to the <code>android:resizeMode</code> attribute in + * the AppWidget meta-data file. */ - public int resizableMode; + public int resizeMode; public AppWidgetProviderInfo() { } @@ -170,7 +176,7 @@ public class AppWidgetProviderInfo implements Parcelable { this.icon = in.readInt(); this.previewImage = in.readInt(); this.autoAdvanceViewId = in.readInt(); - this.resizableMode = in.readInt(); + this.resizeMode = in.readInt(); } public void writeToParcel(android.os.Parcel out, int flags) { @@ -194,7 +200,7 @@ public class AppWidgetProviderInfo implements Parcelable { out.writeInt(this.icon); out.writeInt(this.previewImage); out.writeInt(this.autoAdvanceViewId); - out.writeInt(this.resizableMode); + out.writeInt(this.resizeMode); } public int describeContents() { diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java index 31f87198878a..8944f12e6e80 100644 --- a/core/java/android/os/Parcel.java +++ b/core/java/android/os/Parcel.java @@ -31,6 +31,7 @@ import java.io.ObjectOutputStream; import java.io.Serializable; import java.lang.reflect.Field; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -356,7 +357,7 @@ public final class Parcel { public final native void enforceInterface(String interfaceName); /** - * Write a byte array into the parcel at the current {#link #dataPosition}, + * Write a byte array into the parcel at the current {@link #dataPosition}, * growing {@link #dataCapacity} if needed. * @param b Bytes to place into the parcel. */ @@ -365,7 +366,7 @@ public final class Parcel { } /** - * Write an byte array into the parcel at the current {#link #dataPosition}, + * Write an byte array into the parcel at the current {@link #dataPosition}, * growing {@link #dataCapacity} if needed. * @param b Bytes to place into the parcel. * @param offset Index of first byte to be written. @@ -376,9 +377,7 @@ public final class Parcel { writeInt(-1); return; } - if (b.length < offset + len || len < 0 || offset < 0) { - throw new ArrayIndexOutOfBoundsException(); - } + Arrays.checkOffsetAndCount(b.length, offset, len); writeNative(b, offset, len); } diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java index b74806486bf9..126f409d1dab 100644 --- a/core/java/android/view/Display.java +++ b/core/java/android/view/Display.java @@ -79,6 +79,11 @@ public class Display */ native public int getHeight(); + /** @hide special for when we are faking the screen size. */ + native public int getRealWidth(); + /** @hide special for when we are faking the screen size. */ + native public int getRealHeight(); + /** * Returns the rotation of the screen from its "natural" orientation. * The returned value may be {@link Surface#ROTATION_0 Surface.ROTATION_0} @@ -136,11 +141,6 @@ public class Display outMetrics.ydpi = mDpiY; } - /** - * @hide Helper for our fake display size hack. - */ - native public static int unmapDisplaySize(int newSize); - /* * We use a class initializer to allow the native code to cache some * field offsets. diff --git a/core/java/android/view/ScaleGestureDetector.java b/core/java/android/view/ScaleGestureDetector.java index 218ee4f9885a..0124151b5ddc 100644 --- a/core/java/android/view/ScaleGestureDetector.java +++ b/core/java/android/view/ScaleGestureDetector.java @@ -245,6 +245,7 @@ public class ScaleGestureDetector { final float bottomSlop = mBottomSlopEdge; int index0 = event.findPointerIndex(mActiveId0); int index1 = event.findPointerIndex(mActiveId1); + float x0 = getRawX(event, index0); float y0 = getRawY(event, index0); float x1 = getRawX(event, index1); @@ -353,14 +354,24 @@ public class ScaleGestureDetector { if (actionId == mActiveId0) { final int newIndex = findNewActiveIndex(event, mActiveId1, actionIndex); if (newIndex >= 0) { + mListener.onScaleEnd(this); mActiveId0 = event.getPointerId(newIndex); + mActive0MostRecent = true; + mPrevEvent = MotionEvent.obtain(event); + setContext(event); + mGestureInProgress = mListener.onScaleBegin(this); } else { gestureEnded = true; } } else if (actionId == mActiveId1) { final int newIndex = findNewActiveIndex(event, mActiveId0, actionIndex); if (newIndex >= 0) { + mListener.onScaleEnd(this); mActiveId1 = event.getPointerId(newIndex); + mActive0MostRecent = false; + mPrevEvent = MotionEvent.obtain(event); + setContext(event); + mGestureInProgress = mListener.onScaleBegin(this); } else { gestureEnded = true; } @@ -449,6 +460,7 @@ public class ScaleGestureDetector { * MotionEvent has no getRawX(int) method; simulate it pending future API approval. */ private static float getRawX(MotionEvent event, int pointerIndex) { + if (pointerIndex < 0) return Float.MIN_VALUE; if (pointerIndex == 0) return event.getRawX(); float offset = event.getRawX() - event.getX(); return event.getX(pointerIndex) + offset; @@ -458,6 +470,7 @@ public class ScaleGestureDetector { * MotionEvent has no getRawY(int) method; simulate it pending future API approval. */ private static float getRawY(MotionEvent event, int pointerIndex) { + if (pointerIndex < 0) return Float.MIN_VALUE; if (pointerIndex == 0) return event.getRawY(); float offset = event.getRawY() - event.getY(); return event.getY(pointerIndex) + offset; diff --git a/core/java/android/webkit/ZoomManager.java b/core/java/android/webkit/ZoomManager.java index 5e0de27bb173..63038503b238 100644 --- a/core/java/android/webkit/ZoomManager.java +++ b/core/java/android/webkit/ZoomManager.java @@ -227,10 +227,13 @@ class ZoomManager { assert density > 0; if (Math.abs(density - mDefaultScale) > MINIMUM_SCALE_INCREMENT) { + // Remember the current zoom density before it gets changed. + final float originalDefault = mDefaultScale; // set the new default density setDefaultZoomScale(density); + float scaleChange = (originalDefault > 0.0) ? density / originalDefault: 1.0f; // adjust the scale if it falls outside the new zoom bounds - setZoomScale(mActualScale, true); + setZoomScale(mActualScale * scaleChange, true); } } @@ -721,10 +724,7 @@ class ZoomManager { } public boolean onScale(ScaleGestureDetector detector) { - // Prevent scaling beyond overview scale. - float scale = Math.max( - computeScaleWithLimits(detector.getScaleFactor() * mActualScale), - getZoomOverviewScale()); + float scale = computeScaleWithLimits(detector.getScaleFactor() * mActualScale); if (mPinchToZoomAnimating || willScaleTriggerZoom(scale)) { mPinchToZoomAnimating = true; // limit the scale change per step @@ -780,13 +780,6 @@ class ZoomManager { // update mMinZoomScale if the minimum zoom scale is not fixed if (!mMinZoomScaleFixed) { - // when change from narrow screen to wide screen, the new viewWidth - // can be wider than the old content width. We limit the minimum - // scale to 1.0f. The proper minimum scale will be calculated when - // the new picture shows up. - mMinZoomScale = Math.min(1.0f, (float) mWebView.getViewWidth() - / (mWebView.drawHistory() ? mWebView.getHistoryPictureWidth() - : mZoomOverviewWidth)); // limit the minZoomScale to the initialScale if it is set if (mInitialScale > 0 && mInitialScale < mMinZoomScale) { mMinZoomScale = mInitialScale; @@ -823,7 +816,7 @@ class ZoomManager { // Keep overview mode unchanged when rotating. final float zoomOverviewScale = getZoomOverviewScale(); final float newScale = (mInZoomOverviewBeforeSizeChange) ? - zoomOverviewScale : Math.max(mActualScale, zoomOverviewScale); + zoomOverviewScale : mActualScale; setZoomScale(newScale, mUpdateTextWrap, true); // update the zoom buttons as the scale can be changed updateZoomPicker(); @@ -879,21 +872,15 @@ class ZoomManager { } } - if (!mMinZoomScaleFixed) { - mMinZoomScale = newZoomOverviewScale; - } // fit the content width to the current view for the first new picture // after first layout. boolean scaleHasDiff = exceedsMinScaleIncrement(newZoomOverviewScale, mActualScale); - // Make sure the actual scale is no less than zoom overview scale. - boolean scaleLessThanOverview = - (newZoomOverviewScale - mActualScale) >= MINIMUM_SCALE_INCREMENT; // Make sure mobile sites are correctly handled since mobile site will // change content width after rotating. boolean mobileSiteInOverview = mInZoomOverview && !exceedsMinScaleIncrement(newZoomOverviewScale, 1.0f); if (!mWebView.drawHistory() && - (mInitialZoomOverview || scaleLessThanOverview || mobileSiteInOverview) && + (mInitialZoomOverview || mobileSiteInOverview) && scaleHasDiff && zoomOverviewWidthChanged) { mInitialZoomOverview = false; setZoomScale(newZoomOverviewScale, !willScaleTriggerZoom(mTextWrapScale) && @@ -967,10 +954,11 @@ class ZoomManager { mTextWrapScale = viewState.mTextWrapScale; scale = viewState.mViewScale; } else { - scale = overviewScale; - if (!settings.getUseWideViewPort() - || !settings.getLoadWithOverviewMode()) { - scale = Math.max(viewState.mTextWrapScale, scale); + scale = mDefaultScale; + mTextWrapScale = mDefaultScale; + if (settings.getUseWideViewPort() + && settings.getLoadWithOverviewMode()) { + scale = Math.max(overviewScale, scale); } if (settings.isNarrowColumnLayout() && settings.getUseFixedViewport()) { @@ -981,7 +969,7 @@ class ZoomManager { } boolean reflowText = false; if (!viewState.mIsRestored) { - if (settings.getUseFixedViewport()) { + if (settings.getUseFixedViewport() && settings.getLoadWithOverviewMode()) { // Override the scale only in case of fixed viewport. scale = Math.max(scale, overviewScale); mTextWrapScale = Math.max(mTextWrapScale, overviewScale); diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index c2c8d16a928a..1d05d0bf59f3 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -3529,6 +3529,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te post(this); } else { mTouchMode = TOUCH_MODE_REST; + reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE); } } diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java index 7a591782564f..2947ebeb1d4b 100644 --- a/core/java/android/widget/NumberPicker.java +++ b/core/java/android/widget/NumberPicker.java @@ -608,7 +608,7 @@ public class NumberPicker extends LinearLayout { case MotionEvent.ACTION_DOWN: mLastMotionEventY = mLastDownEventY = event.getY(); removeAllCallbacks(); - hideInputControls(); + mShowInputControlsAnimator.cancel(); mBeginEditOnUpEvent = false; mAdjustScrollerOnUpEvent = true; if (mDrawSelectorWheel) { @@ -621,6 +621,7 @@ public class NumberPicker extends LinearLayout { } mBeginEditOnUpEvent = scrollersFinished; mAdjustScrollerOnUpEvent = true; + hideInputControls(); return true; } if (isEventInViewHitRect(event, mInputText) @@ -630,6 +631,7 @@ public class NumberPicker extends LinearLayout { && isEventInViewHitRect(event, mDecrementButton))) { mAdjustScrollerOnUpEvent = false; setDrawSelectorWheel(true); + hideInputControls(); return true; } break; @@ -640,6 +642,7 @@ public class NumberPicker extends LinearLayout { mBeginEditOnUpEvent = false; onScrollStateChange(OnScrollListener.SCROLL_STATE_TOUCH_SCROLL); setDrawSelectorWheel(true); + hideInputControls(); return true; } break; diff --git a/core/java/android/widget/TabWidget.java b/core/java/android/widget/TabWidget.java index 22f6f4ed93d8..d74ef245e5f7 100644 --- a/core/java/android/widget/TabWidget.java +++ b/core/java/android/widget/TabWidget.java @@ -174,8 +174,8 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener { void measureHorizontal(int widthMeasureSpec, int heightMeasureSpec) { // First, measure with no constraint final int unspecifiedWidth = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); - super.measureHorizontal(unspecifiedWidth, heightMeasureSpec); mImposedTabsHeight = -1; + super.measureHorizontal(unspecifiedWidth, heightMeasureSpec); int extraWidth = getMeasuredWidth() - MeasureSpec.getSize(widthMeasureSpec); if (extraWidth > 0) { diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 33d1225e5181..09c1ac5e916a 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -7091,6 +7091,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener // Only track when onStartTemporaryDetach() is called directly, // usually because this instance is an editable field in a list if (!mDispatchTemporaryDetach) mTemporaryDetach = true; + + // Because of View recycling in ListView, there is no easy way to know when a TextView with + // selection becomes visible again. Until a better solution is found, stop text selection + // mode (if any) as soon as this TextView is recycled. + stopSelectionActionMode(); } @Override diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp index 7a53874c6983..7226e31ec39f 100644 --- a/core/jni/android_util_Binder.cpp +++ b/core/jni/android_util_Binder.cpp @@ -31,6 +31,8 @@ #include <binder/IPCThreadState.h> #include <utils/Log.h> #include <utils/SystemClock.h> +#include <utils/List.h> +#include <utils/KeyedVector.h> #include <cutils/logger.h> #include <binder/Parcel.h> #include <binder/ProcessState.h> @@ -322,25 +324,15 @@ private: class JavaBBinderHolder : public RefBase { public: - JavaBBinderHolder(JNIEnv* env, jobject object) - : mObject(object) - { - LOGV("Creating JavaBBinderHolder for Object %p\n", object); - } - ~JavaBBinderHolder() - { - LOGV("Destroying JavaBBinderHolder for Object %p\n", mObject); - } - - sp<JavaBBinder> get(JNIEnv* env) + sp<JavaBBinder> get(JNIEnv* env, jobject obj) { AutoMutex _l(mLock); sp<JavaBBinder> b = mBinder.promote(); if (b == NULL) { - b = new JavaBBinder(env, mObject); + b = new JavaBBinder(env, obj); mBinder = b; LOGV("Creating JavaBinder %p (refs %p) for Object %p, weakCount=%d\n", - b.get(), b->getWeakRefs(), mObject, b->getWeakRefs()->getWeakCount()); + b.get(), b->getWeakRefs(), obj, b->getWeakRefs()->getWeakCount()); } return b; @@ -354,20 +346,41 @@ public: private: Mutex mLock; - jobject mObject; wp<JavaBBinder> mBinder; }; // ---------------------------------------------------------------------------- +// Per-IBinder death recipient bookkeeping. This is how we reconcile local jobject +// death recipient references passed in through JNI with the permanent corresponding +// JavaDeathRecipient objects. + +class JavaDeathRecipient; + +class DeathRecipientList : public RefBase { + List< sp<JavaDeathRecipient> > mList; + Mutex mLock; + +public: + ~DeathRecipientList(); + + void add(const sp<JavaDeathRecipient>& recipient); + void remove(const sp<JavaDeathRecipient>& recipient); + sp<JavaDeathRecipient> find(jobject recipient); +}; + +// ---------------------------------------------------------------------------- + class JavaDeathRecipient : public IBinder::DeathRecipient { public: - JavaDeathRecipient(JNIEnv* env, jobject object) - : mVM(jnienv_to_javavm(env)), mObject(env->NewGlobalRef(object)), - mHoldsRef(true) + JavaDeathRecipient(JNIEnv* env, jobject object, sp<DeathRecipientList>& list) + : mVM(jnienv_to_javavm(env)), mObject(env->NewGlobalRef(object)), mList(list) { - incStrong(this); + // These objects manage their own lifetimes so are responsible for final bookkeeping. + // The list holds a strong reference to this object. + mList->add(this); + android_atomic_inc(&gNumDeathRefs); incRefsCreated(env); } @@ -391,16 +404,12 @@ public: void clearReference() { - bool release = false; - mLock.lock(); - if (mHoldsRef) { - mHoldsRef = false; - release = true; - } - mLock.unlock(); - if (release) { - decStrong(this); - } + mList->remove(this); + } + + bool matches(jobject obj) { + JNIEnv* env = javavm_to_jnienv(mVM); + return env->IsSameObject(obj, mObject); } protected: @@ -415,12 +424,57 @@ protected: private: JavaVM* const mVM; jobject const mObject; - Mutex mLock; - bool mHoldsRef; + sp<DeathRecipientList> mList; }; // ---------------------------------------------------------------------------- +DeathRecipientList::~DeathRecipientList() { + AutoMutex _l(mLock); + + // Should never happen -- the JavaDeathRecipient objects that have added themselves + // to the list are holding references on the list object. Only when they are torn + // down can the list header be destroyed. + if (mList.size() > 0) { + LOGE("Retiring binder %p with extant death recipients\n", this); + } +} + +void DeathRecipientList::add(const sp<JavaDeathRecipient>& recipient) { + AutoMutex _l(mLock); + + mList.push_back(recipient); +} + +void DeathRecipientList::remove(const sp<JavaDeathRecipient>& recipient) { + AutoMutex _l(mLock); + + List< sp<JavaDeathRecipient> >::iterator iter; + for (iter = mList.begin(); iter != mList.end(); iter++) { + if (*iter == recipient) { + mList.erase(iter); + return; + } + } +} + +sp<JavaDeathRecipient> DeathRecipientList::find(jobject recipient) { + AutoMutex _l(mLock); + + List< sp<JavaDeathRecipient> >::iterator iter; + for (iter = mList.begin(); iter != mList.end(); iter++) { + if ((*iter)->matches(recipient)) { + return *iter; + } + } + return NULL; +} + +static KeyedVector<IBinder*, sp<DeathRecipientList> > gDeathRecipientsByIBinder; +static Mutex gDeathRecipientMapLock; + +// ---------------------------------------------------------------------------- + namespace android { static void proxy_cleanup(const void* id, void* obj, void* cleanupCookie) @@ -490,7 +544,7 @@ sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj) if (env->IsInstanceOf(obj, gBinderOffsets.mClass)) { JavaBBinderHolder* jbh = (JavaBBinderHolder*) env->GetIntField(obj, gBinderOffsets.mObject); - return jbh != NULL ? jbh->get(env) : NULL; + return jbh != NULL ? jbh->get(env, obj) : NULL; } if (env->IsInstanceOf(obj, gBinderProxyOffsets.mClass)) { @@ -621,26 +675,26 @@ static void android_os_Binder_flushPendingCommands(JNIEnv* env, jobject clazz) IPCThreadState::self()->flushCommands(); } -static void android_os_Binder_init(JNIEnv* env, jobject clazz) +static void android_os_Binder_init(JNIEnv* env, jobject obj) { - JavaBBinderHolder* jbh = new JavaBBinderHolder(env, clazz); + JavaBBinderHolder* jbh = new JavaBBinderHolder(); if (jbh == NULL) { jniThrowException(env, "java/lang/OutOfMemoryError", NULL); return; } - LOGV("Java Binder %p: acquiring first ref on holder %p", clazz, jbh); - jbh->incStrong(clazz); - env->SetIntField(clazz, gBinderOffsets.mObject, (int)jbh); + LOGV("Java Binder %p: acquiring first ref on holder %p", obj, jbh); + jbh->incStrong((void*)android_os_Binder_init); + env->SetIntField(obj, gBinderOffsets.mObject, (int)jbh); } -static void android_os_Binder_destroy(JNIEnv* env, jobject clazz) +static void android_os_Binder_destroy(JNIEnv* env, jobject obj) { JavaBBinderHolder* jbh = (JavaBBinderHolder*) - env->GetIntField(clazz, gBinderOffsets.mObject); + env->GetIntField(obj, gBinderOffsets.mObject); if (jbh != NULL) { - env->SetIntField(clazz, gBinderOffsets.mObject, 0); - LOGV("Java Binder %p: removing ref on holder %p", clazz, jbh); - jbh->decStrong(clazz); + env->SetIntField(obj, gBinderOffsets.mObject, 0); + LOGV("Java Binder %p: removing ref on holder %p", obj, jbh); + jbh->decStrong((void*)android_os_Binder_init); } else { // Encountering an uninitialized binder is harmless. All it means is that // the Binder was only partially initialized when its finalizer ran and called @@ -648,7 +702,7 @@ static void android_os_Binder_destroy(JNIEnv* env, jobject clazz) // For example, a Binder subclass constructor might have thrown an exception before // it could delegate to its superclass's constructor. Consequently init() would // not have been called and the holder pointer would remain NULL. - LOGV("Java Binder %p: ignoring uninitialized binder", clazz); + LOGV("Java Binder %p: ignoring uninitialized binder", obj); } } @@ -973,8 +1027,25 @@ static void android_os_BinderProxy_linkToDeath(JNIEnv* env, jobject obj, LOGV("linkToDeath: binder=%p recipient=%p\n", target, recipient); if (!target->localBinder()) { - sp<JavaDeathRecipient> jdr = new JavaDeathRecipient(env, recipient); - status_t err = target->linkToDeath(jdr, recipient, flags); + sp<JavaDeathRecipient> jdr; + + { + sp<DeathRecipientList> list; + AutoMutex _maplocker(gDeathRecipientMapLock); + + ssize_t listIndex = gDeathRecipientsByIBinder.indexOfKey(target); + if (listIndex < 0) { + // Set up the death notice bookkeeping for this binder lazily + list = new DeathRecipientList; + gDeathRecipientsByIBinder.add(target, list); + } else { + list = gDeathRecipientsByIBinder.valueAt(listIndex); + } + + jdr = new JavaDeathRecipient(env, recipient, list); + } + + status_t err = target->linkToDeath(jdr, NULL, flags); if (err != NO_ERROR) { // Failure adding the death recipient, so clear its reference // now. @@ -1003,15 +1074,33 @@ static jboolean android_os_BinderProxy_unlinkToDeath(JNIEnv* env, jobject obj, LOGV("unlinkToDeath: binder=%p recipient=%p\n", target, recipient); if (!target->localBinder()) { - wp<IBinder::DeathRecipient> dr; - status_t err = target->unlinkToDeath(NULL, recipient, flags, &dr); - if (err == NO_ERROR && dr != NULL) { - sp<IBinder::DeathRecipient> sdr = dr.promote(); - JavaDeathRecipient* jdr = static_cast<JavaDeathRecipient*>(sdr.get()); - if (jdr != NULL) { - jdr->clearReference(); + status_t err = NAME_NOT_FOUND; + sp<JavaDeathRecipient> origJDR; + { + AutoMutex _maplocker(gDeathRecipientMapLock); + ssize_t listIndex = gDeathRecipientsByIBinder.indexOfKey(target); + if (listIndex >= 0) { + sp<DeathRecipientList> list = gDeathRecipientsByIBinder.valueAt(listIndex); + origJDR = list->find(recipient); + } else { + // If there is no DeathRecipientList for this binder, it means the binder + // is dead and in the process of being cleaned up. + err = DEAD_OBJECT; + } + } + // If we found the matching recipient, proceed to unlink using that + if (origJDR != NULL) { + wp<IBinder::DeathRecipient> dr; + err = target->unlinkToDeath(origJDR, NULL, flags, &dr); + if (err == NO_ERROR && dr != NULL) { + sp<IBinder::DeathRecipient> sdr = dr.promote(); + JavaDeathRecipient* jdr = static_cast<JavaDeathRecipient*>(sdr.get()); + if (jdr != NULL) { + jdr->clearReference(); + } } } + if (err == NO_ERROR || err == DEAD_OBJECT) { res = JNI_TRUE; } else { @@ -1031,6 +1120,15 @@ static void android_os_BinderProxy_destroy(JNIEnv* env, jobject obj) env->SetIntField(obj, gBinderProxyOffsets.mObject, 0); b->decStrong(obj); IPCThreadState::self()->flushCommands(); + + // tear down the death recipient bookkeeping + { + AutoMutex _maplocker(gDeathRecipientMapLock); + ssize_t listIndex = gDeathRecipientsByIBinder.indexOfKey(b); + if (listIndex >= 0) { + gDeathRecipientsByIBinder.removeItemsAt((size_t)listIndex); + } + } } // ---------------------------------------------------------------------------- @@ -1152,15 +1250,13 @@ static void android_os_Parcel_writeNative(JNIEnv* env, jobject clazz, if (parcel == NULL) { return; } - void *dest; const status_t err = parcel->writeInt32(length); if (err != NO_ERROR) { jniThrowException(env, "java/lang/OutOfMemoryError", NULL); } - dest = parcel->writeInplace(length); - + void* dest = parcel->writeInplace(length); if (dest == NULL) { jniThrowException(env, "java/lang/OutOfMemoryError", NULL); return; @@ -1168,7 +1264,7 @@ static void android_os_Parcel_writeNative(JNIEnv* env, jobject clazz, jbyte* ar = (jbyte*)env->GetPrimitiveArrayCritical((jarray)data, 0); if (ar) { - memcpy(dest, ar, length); + memcpy(dest, ar + offset, length); env->ReleasePrimitiveArrayCritical((jarray)data, ar, 0); } } diff --git a/core/jni/android_view_Display.cpp b/core/jni/android_view_Display.cpp index ac8835a60be7..160d654b658f 100644 --- a/core/jni/android_view_Display.cpp +++ b/core/jni/android_view_Display.cpp @@ -44,6 +44,8 @@ struct offsets_t { }; static offsets_t offsets; +static int gShortSize = -1; +static int gLongSize = -1; static int gOldSize = -1; static int gNewSize = -1; @@ -76,6 +78,10 @@ static jint android_view_Display_getWidth( { DisplayID dpy = env->GetIntField(clazz, offsets.display); jint w = SurfaceComposerClient::getDisplayWidth(dpy); + if (gShortSize > 0) { + jint h = SurfaceComposerClient::getDisplayHeight(dpy); + return w < h ? gShortSize : gLongSize; + } return w == gOldSize ? gNewSize : w; } @@ -84,9 +90,27 @@ static jint android_view_Display_getHeight( { DisplayID dpy = env->GetIntField(clazz, offsets.display); int h = SurfaceComposerClient::getDisplayHeight(dpy); + if (gShortSize > 0) { + jint w = SurfaceComposerClient::getDisplayWidth(dpy); + return h < w ? gShortSize : gLongSize; + } return h == gOldSize ? gNewSize : h; } +static jint android_view_Display_getRealWidth( + JNIEnv* env, jobject clazz) +{ + DisplayID dpy = env->GetIntField(clazz, offsets.display); + return SurfaceComposerClient::getDisplayWidth(dpy); +} + +static jint android_view_Display_getRealHeight( + JNIEnv* env, jobject clazz) +{ + DisplayID dpy = env->GetIntField(clazz, offsets.display); + return SurfaceComposerClient::getDisplayHeight(dpy); +} + static jint android_view_Display_getOrientation( JNIEnv* env, jobject clazz) { @@ -100,13 +124,6 @@ static jint android_view_Display_getDisplayCount( return SurfaceComposerClient::getNumberOfDisplays(); } -static jint android_view_Display_unmapDisplaySize( - JNIEnv* env, jclass clazz, jint newSize) -{ - if (newSize == gNewSize) return gOldSize; - return newSize; -} - // ---------------------------------------------------------------------------- const char* const kClassPathName = "android/view/Display"; @@ -124,10 +141,12 @@ static JNINativeMethod gMethods[] = { (void*)android_view_Display_getWidth }, { "getHeight", "()I", (void*)android_view_Display_getHeight }, + { "getRealWidth", "()I", + (void*)android_view_Display_getRealWidth }, + { "getRealHeight", "()I", + (void*)android_view_Display_getRealHeight }, { "getOrientation", "()I", - (void*)android_view_Display_getOrientation }, - { "unmapDisplaySize", "(I)I", - (void*)android_view_Display_unmapDisplaySize } + (void*)android_view_Display_getOrientation } }; void nativeClassInit(JNIEnv* env, jclass clazz) @@ -146,7 +165,15 @@ int register_android_view_Display(JNIEnv* env) int len = property_get("persist.demo.screensizehack", buf, ""); if (len > 0) { int temp1, temp2; - if (sscanf(buf, "%d=%d", &temp1, &temp2) == 2) { + if (sscanf(buf, "%dx%d", &temp1, &temp2) == 2) { + if (temp1 < temp2) { + gShortSize = temp1; + gLongSize = temp2; + } else { + gShortSize = temp2; + gLongSize = temp1; + } + } else if (sscanf(buf, "%d=%d", &temp1, &temp2) == 2) { gOldSize = temp1; gNewSize = temp2; } @@ -157,4 +184,3 @@ int register_android_view_Display(JNIEnv* env) } }; - diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp index be66e9c4d5e9..bd2e6694f3f5 100644 --- a/core/jni/android_view_Surface.cpp +++ b/core/jni/android_view_Surface.cpp @@ -177,7 +177,7 @@ static sp<Surface> getSurface(JNIEnv* env, jobject clazz) sp<ANativeWindow> android_Surface_getNativeWindow( JNIEnv* env, jobject clazz) { - return getSurface(env, clazz).get(); + return getSurface(env, clazz); } static void setSurface(JNIEnv* env, jobject clazz, const sp<Surface>& surface) diff --git a/include/binder/IBinder.h b/include/binder/IBinder.h index 749a977b83b5..81b56c2b2b3b 100644 --- a/include/binder/IBinder.h +++ b/include/binder/IBinder.h @@ -98,7 +98,7 @@ public: * Register the @a recipient for a notification if this binder * goes away. If this binder object unexpectedly goes away * (typically because its hosting process has been killed), - * then DeathRecipient::binderDied() will be called with a referene + * then DeathRecipient::binderDied() will be called with a reference * to this. * * The @a cookie is optional -- if non-NULL, it should be a diff --git a/include/utils/StrongPointer.h b/include/utils/StrongPointer.h index a8c989749b60..49fa3a8d6f62 100644 --- a/include/utils/StrongPointer.h +++ b/include/utils/StrongPointer.h @@ -133,7 +133,7 @@ sp<T>::sp(const sp<T>& other) template<typename T> template<typename U> sp<T>::sp(U* other) : m_ptr(other) { - if (other) other->incStrong(this); + if (other) ((T*)other)->incStrong(this); } template<typename T> template<typename U> @@ -170,7 +170,7 @@ sp<T>& sp<T>::operator = (T* other) template<typename T> template<typename U> sp<T>& sp<T>::operator = (const sp<U>& other) { - U* otherPtr(other.m_ptr); + T* otherPtr(other.m_ptr); if (otherPtr) otherPtr->incStrong(this); if (m_ptr) m_ptr->decStrong(this); m_ptr = otherPtr; @@ -180,7 +180,7 @@ sp<T>& sp<T>::operator = (const sp<U>& other) template<typename T> template<typename U> sp<T>& sp<T>::operator = (U* other) { - if (other) other->incStrong(this); + if (other) ((T*)other)->incStrong(this); if (m_ptr) m_ptr->decStrong(this); m_ptr = other; return *this; diff --git a/libs/surfaceflinger_client/Surface.cpp b/libs/surfaceflinger_client/Surface.cpp index 1e9bd744f51c..68611d6a37e4 100644 --- a/libs/surfaceflinger_client/Surface.cpp +++ b/libs/surfaceflinger_client/Surface.cpp @@ -1040,7 +1040,7 @@ int Surface::getBufferIndex(const sp<GraphicBuffer>& buffer) const // e.g. if GraphicBuffer is used to wrap an android_native_buffer_t that // was dequeued from an ANativeWindow. for (size_t i = 0; i < mBuffers.size(); i++) { - if (buffer->handle == mBuffers[i]->handle) { + if (mBuffers[i] != 0 && buffer->handle == mBuffers[i]->handle) { idx = mBuffers[i]->getIndex(); break; } diff --git a/libs/utils/RefBase.cpp b/libs/utils/RefBase.cpp index 0fd404d66c1e..bb6c1255f38a 100644 --- a/libs/utils/RefBase.cpp +++ b/libs/utils/RefBase.cpp @@ -99,20 +99,38 @@ public: #if DEBUG_REFS_FATAL_SANITY_CHECKS LOG_ALWAYS_FATAL("Strong references remain!"); #else - LOGE("Strong references remain!"); + LOGE("Strong references remain:"); #endif + ref_entry* refs = mStrongRefs; + while (refs) { + char inc = refs->ref >= 0 ? '+' : '-'; + LOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref); +#if DEBUG_REFS_CALLSTACK_ENABLED + refs->stack.dump(); +#endif; + refs = refs->next; + } } if (!mRetain && mWeakRefs != NULL) { dumpStack = true; #if DEBUG_REFS_FATAL_SANITY_CHECKS - LOG_ALWAYS_FATAL("Weak references remain!"); + LOG_ALWAYS_FATAL("Weak references remain:"); #else LOGE("Weak references remain!"); #endif + ref_entry* refs = mWeakRefs; + while (refs) { + char inc = refs->ref >= 0 ? '+' : '-'; + LOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref); +#if DEBUG_REFS_CALLSTACK_ENABLED + refs->stack.dump(); +#endif; + refs = refs->next; + } } - if (dumpStack) { + LOGE("above errors at:"); CallStack stack; stack.update(); stack.dump(); @@ -228,7 +246,8 @@ private: if (mTrackEnabled) { AutoMutex _l(mMutex); - ref_entry* ref = *refs; + ref_entry* const head = *refs; + ref_entry* ref = head; while (ref != NULL) { if (ref->id == id) { *refs = ref->next; @@ -249,6 +268,13 @@ private: "(weakref_type %p) that doesn't exist!", id, mBase, this); + ref = head; + while (ref) { + char inc = ref->ref >= 0 ? '+' : '-'; + LOGD("\t%c ID %p (ref %d):", inc, ref->id, ref->ref); + ref = ref->next; + } + CallStack stack; stack.update(); stack.dump(); diff --git a/media/java/android/media/videoeditor/MediaArtistNativeHelper.java b/media/java/android/media/videoeditor/MediaArtistNativeHelper.java index e0df257eca55..53bbb0ff5531 100644 --- a/media/java/android/media/videoeditor/MediaArtistNativeHelper.java +++ b/media/java/android/media/videoeditor/MediaArtistNativeHelper.java @@ -3556,7 +3556,7 @@ class MediaArtistNativeHelper { case MediaProperties.ASPECT_RATIO_4_3: if (height == MediaProperties.HEIGHT_480) retValue = VideoFrameSize.VGA; - if (height == MediaProperties.HEIGHT_720) + else if (height == MediaProperties.HEIGHT_720) retValue = VideoFrameSize.S720p; break; case MediaProperties.ASPECT_RATIO_5_3: @@ -3566,6 +3566,8 @@ class MediaArtistNativeHelper { case MediaProperties.ASPECT_RATIO_11_9: if (height == MediaProperties.HEIGHT_144) retValue = VideoFrameSize.QCIF; + else if (height == MediaProperties.HEIGHT_288) + retValue = VideoFrameSize.CIF; break; } if (retValue == VideoFrameSize.SIZE_UNDEFINED) { diff --git a/media/java/android/media/videoeditor/MediaProperties.java b/media/java/android/media/videoeditor/MediaProperties.java index 0b7ec081cca3..022580779c37 100755 --- a/media/java/android/media/videoeditor/MediaProperties.java +++ b/media/java/android/media/videoeditor/MediaProperties.java @@ -29,6 +29,7 @@ public class MediaProperties { * Supported heights */ public static final int HEIGHT_144 = 144; + public static final int HEIGHT_288 = 288; public static final int HEIGHT_360 = 360; public static final int HEIGHT_480 = 480; public static final int HEIGHT_720 = 720; @@ -82,7 +83,8 @@ public class MediaProperties { @SuppressWarnings({"unchecked"}) private static final Pair<Integer, Integer>[] ASPECT_RATIO_11_9_RESOLUTIONS = new Pair[] { - new Pair<Integer, Integer>(176, HEIGHT_144) + new Pair<Integer, Integer>(176, HEIGHT_144), + new Pair<Integer, Integer>(352, HEIGHT_288) }; @SuppressWarnings({"unchecked"}) diff --git a/media/java/android/media/videoeditor/VideoEditorImpl.java b/media/java/android/media/videoeditor/VideoEditorImpl.java index 1fb8c615465d..7e1f73aa88fc 100755 --- a/media/java/android/media/videoeditor/VideoEditorImpl.java +++ b/media/java/android/media/videoeditor/VideoEditorImpl.java @@ -389,6 +389,8 @@ public class VideoEditorImpl implements VideoEditor { switch (height) { case MediaProperties.HEIGHT_144: break; + case MediaProperties.HEIGHT_288: + break; case MediaProperties.HEIGHT_360: break; case MediaProperties.HEIGHT_480: diff --git a/media/libstagefright/colorconversion/ColorConverter.cpp b/media/libstagefright/colorconversion/ColorConverter.cpp index d518c9768384..3b92e5d0072e 100644 --- a/media/libstagefright/colorconversion/ColorConverter.cpp +++ b/media/libstagefright/colorconversion/ColorConverter.cpp @@ -187,7 +187,7 @@ status_t ColorConverter::convertCbYCrY( status_t ColorConverter::convertYUV420Planar( const BitmapParams &src, const BitmapParams &dst) { - if (!((dst.mWidth & 3) == 0 + if (!((dst.mWidth & 1) == 0 && (src.mCropLeft & 1) == 0 && src.cropWidth() == dst.cropWidth() && src.cropHeight() == dst.cropHeight())) { diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkPerfTestRunner.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkPerfTestRunner.java index 988b229474b6..a6cf3551ed40 100755 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkPerfTestRunner.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkPerfTestRunner.java @@ -21,9 +21,10 @@ import com.android.mediaframeworktest.performance.MediaPlayerPerformance; import com.android.mediaframeworktest.performance.VideoEditorPerformance; import junit.framework.TestSuite; +import android.os.Bundle; import android.test.InstrumentationTestRunner; import android.test.InstrumentationTestSuite; - +import android.util.Log; /** * Instrumentation Test Runner for all MediaPlayer tests. @@ -36,19 +37,30 @@ import android.test.InstrumentationTestSuite; public class MediaFrameworkPerfTestRunner extends InstrumentationTestRunner { + public static boolean mGetNativeHeapDump = false; + + + @Override + public TestSuite getAllTests() { + TestSuite suite = new InstrumentationTestSuite(this); + suite.addTestSuite(MediaPlayerPerformance.class); + /* Video Editor performance Test cases */ + suite.addTestSuite(VideoEditorPerformance.class); + return suite; + } - @Override - public TestSuite getAllTests() { - TestSuite suite = new InstrumentationTestSuite(this); - suite.addTestSuite(MediaPlayerPerformance.class); - /*Video Editor performance Test cases*/ - suite.addTestSuite(VideoEditorPerformance.class); - return suite; - } + @Override + public ClassLoader getLoader() { + return MediaFrameworkTestRunner.class.getClassLoader(); + } - @Override - public ClassLoader getLoader() { - return MediaFrameworkTestRunner.class.getClassLoader(); - } + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + String get_heap_dump = (String) icicle.get("get_heap_dump"); + if (get_heap_dump != null) { + mGetNativeHeapDump = true; + } + } } diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaTestUtil.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaTestUtil.java new file mode 100755 index 000000000000..0183b5df8d59 --- /dev/null +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaTestUtil.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2011 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.mediaframeworktest; + +import java.io.FileOutputStream; + +import android.os.Debug; +import android.os.Environment; + +/** + * + * Utilities for media framework test. + * + */ +public class MediaTestUtil { + private MediaTestUtil(){ + } + + private static final String STORAGE_PATH = + Environment.getExternalStorageDirectory().toString(); + + //Catpure the heapdump for memory leaksage analysis\ + public static void getNativeHeapDump (String name) throws Exception { + System.gc(); + System.runFinalization(); + Thread.sleep(1000); + FileOutputStream o = new FileOutputStream(STORAGE_PATH + '/' +name + ".dump"); + Debug.dumpNativeHeap(o.getFD()); + o.close(); + } +}
\ No newline at end of file diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaRecorderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaRecorderTest.java index ce6db68aab43..82df6690c571 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaRecorderTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaRecorderTest.java @@ -28,7 +28,7 @@ import android.media.MediaRecorder; import android.media.EncoderCapabilities; import android.media.EncoderCapabilities.VideoEncoderCap; import android.media.EncoderCapabilities.AudioEncoderCap; -import android.test.ActivityInstrumentationTestCase; +import android.test.ActivityInstrumentationTestCase2; import android.util.Log; import android.view.SurfaceHolder; import android.view.SurfaceView; @@ -42,7 +42,7 @@ import java.util.List; /** * Junit / Instrumentation test case for the media recorder api */ -public class MediaRecorderTest extends ActivityInstrumentationTestCase<MediaFrameworkTest> { +public class MediaRecorderTest extends ActivityInstrumentationTestCase2<MediaFrameworkTest> { private String TAG = "MediaRecorderTest"; private int mOutputDuration =0; private int mOutputVideoWidth = 0; @@ -62,9 +62,9 @@ public class MediaRecorderTest extends ActivityInstrumentationTestCase<MediaFram } protected void setUp() throws Exception { - super.setUp(); - Log.v(TAG,"create the media recorder"); + getActivity(); mRecorder = new MediaRecorder(); + super.setUp(); } private void recordVideo(int frameRate, int width, int height, @@ -199,8 +199,6 @@ public class MediaRecorderTest extends ActivityInstrumentationTestCase<MediaFram return false; } - - private void getOutputVideoProperty(String outputFilePath) { MediaPlayer mediaPlayer = new MediaPlayer(); try { @@ -215,8 +213,6 @@ public class MediaRecorderTest extends ActivityInstrumentationTestCase<MediaFram Thread.sleep(1000); mOutputVideoHeight = mediaPlayer.getVideoHeight(); mOutputVideoWidth = mediaPlayer.getVideoWidth(); - //mOutputVideoHeight = CodecTest.videoHeight(outputFilePath); - //mOutputVideoWidth = CodecTest.videoWidth(outputFilePath); mediaPlayer.release(); } catch (Exception e) { Log.v(TAG, e.toString()); @@ -224,11 +220,6 @@ public class MediaRecorderTest extends ActivityInstrumentationTestCase<MediaFram } } - private void removeFile(String filePath) { - File fileRemove = new File(filePath); - fileRemove.delete(); - } - private boolean validateVideo(String filePath, int width, int height) { boolean validVideo = false; getOutputVideoProperty(filePath); @@ -237,72 +228,9 @@ public class MediaRecorderTest extends ActivityInstrumentationTestCase<MediaFram validVideo = true; } Log.v(TAG, "width = " + mOutputVideoWidth + " height = " + mOutputVideoHeight + " Duration = " + mOutputDuration); - //removeFile(filePath); return validVideo; } - - - //Format: HVGA h263 - @Suppress - public void testHVGAH263() throws Exception { - boolean videoRecordedResult = false; - recordVideo(15, 480, 320, MediaRecorder.VideoEncoder.H263, - MediaRecorder.OutputFormat.THREE_GPP, MediaNames.RECORDED_HVGA_H263, false); - videoRecordedResult = validateVideo(MediaNames.RECORDED_HVGA_H263, 480, 320); - assertTrue("HVGAH263", videoRecordedResult); - } - - //Format: QVGA h263 - @Suppress - public void testQVGAH263() throws Exception { - boolean videoRecordedResult = false; - recordVideo(15, 320, 240, MediaRecorder.VideoEncoder.H263, - MediaRecorder.OutputFormat.THREE_GPP, MediaNames.RECORDED_QVGA_H263, false); - videoRecordedResult = validateVideo(MediaNames.RECORDED_QVGA_H263, 320, 240); - assertTrue("QVGAH263", videoRecordedResult); - } - - //Format: SQVGA h263 - @Suppress - public void testSQVGAH263() throws Exception { - boolean videoRecordedResult = false; - recordVideo(15, 240, 160, MediaRecorder.VideoEncoder.H263, - MediaRecorder.OutputFormat.THREE_GPP, MediaNames.RECORDED_SQVGA_H263, false); - videoRecordedResult = validateVideo(MediaNames.RECORDED_SQVGA_H263, 240, 160); - assertTrue("SQVGAH263", videoRecordedResult); - } - - //Format: QCIF h263 - @LargeTest - public void testQCIFH263() throws Exception { - boolean videoRecordedResult = false; - recordVideo(15, 176, 144, MediaRecorder.VideoEncoder.H263, - MediaRecorder.OutputFormat.THREE_GPP, MediaNames.RECORDED_QCIF_H263, false); - videoRecordedResult = validateVideo(MediaNames.RECORDED_QCIF_H263, 176, 144); - assertTrue("QCIFH263", videoRecordedResult); - } - - //Format: CIF h263 - @LargeTest - public void testCIFH263() throws Exception { - boolean videoRecordedResult = false; - recordVideo(15, 352, 288, MediaRecorder.VideoEncoder.H263, - MediaRecorder.OutputFormat.THREE_GPP, MediaNames.RECORDED_CIF_H263, false); - videoRecordedResult = validateVideo(MediaNames.RECORDED_CIF_H263, 352, 288); - assertTrue("CIFH263", videoRecordedResult); - } - - - - @LargeTest - public void testVideoOnly() throws Exception { - boolean videoRecordedResult = false; - recordVideo(15, 176, 144, MediaRecorder.VideoEncoder.H263, - MediaRecorder.OutputFormat.MPEG_4, MediaNames.RECORDED_VIDEO_3GP, true); - videoRecordedResult = validateVideo(MediaNames.RECORDED_VIDEO_3GP, 176, 144); - assertTrue("QCIFH263 Video Only", videoRecordedResult); - } - + @LargeTest /* * This test case set the camera in portrait mode. @@ -332,74 +260,6 @@ public class MediaRecorderTest extends ActivityInstrumentationTestCase<MediaFram assertTrue("PortraitH263", videoRecordedResult); } - @Suppress - public void testHVGAMP4() throws Exception { - boolean videoRecordedResult = false; - recordVideo(15, 480, 320, MediaRecorder.VideoEncoder.MPEG_4_SP, - MediaRecorder.OutputFormat.MPEG_4, MediaNames.RECORDED_HVGA_MP4, false); - videoRecordedResult = validateVideo(MediaNames.RECORDED_HVGA_MP4, 480, 320); - assertTrue("HVGAMP4", videoRecordedResult); - } - - @Suppress - public void testQVGAMP4() throws Exception { - boolean videoRecordedResult = false; - recordVideo(15, 320, 240, MediaRecorder.VideoEncoder.MPEG_4_SP, - MediaRecorder.OutputFormat.MPEG_4, MediaNames.RECORDED_QVGA_MP4, false); - videoRecordedResult = validateVideo(MediaNames.RECORDED_QVGA_MP4, 320, 240); - assertTrue("QVGAMP4", videoRecordedResult); - } - - @Suppress - public void testSQVGAMP4() throws Exception { - boolean videoRecordedResult = false; - recordVideo(15, 240, 160, MediaRecorder.VideoEncoder.MPEG_4_SP, - MediaRecorder.OutputFormat.MPEG_4, MediaNames.RECORDED_SQVGA_MP4, false); - videoRecordedResult = validateVideo(MediaNames.RECORDED_SQVGA_MP4, 240, 160); - assertTrue("SQVGAMP4", videoRecordedResult); - } - - //Format: QCIF MP4 - @LargeTest - public void testQCIFMP4() throws Exception { - boolean videoRecordedResult = false; - recordVideo(15, 176, 144, MediaRecorder.VideoEncoder.MPEG_4_SP, - MediaRecorder.OutputFormat.MPEG_4, MediaNames.RECORDED_QCIF_MP4, false); - videoRecordedResult = validateVideo(MediaNames.RECORDED_QCIF_MP4, 176, 144); - assertTrue("QCIFMP4", videoRecordedResult); - } - - - //Format: CIF MP4 - @LargeTest - public void testCIFMP4() throws Exception { - boolean videoRecordedResult = false; - recordVideo(15, 352, 288, MediaRecorder.VideoEncoder.MPEG_4_SP, - MediaRecorder.OutputFormat.MPEG_4, MediaNames.RECORDED_CIF_MP4, false); - videoRecordedResult = validateVideo(MediaNames.RECORDED_CIF_MP4, 352, 288); - assertTrue("CIFMP4", videoRecordedResult); - } - - - //Format: CIF MP4 output format 3gpp - @LargeTest - public void testCIFMP43GPP() throws Exception { - boolean videoRecordedResult = false; - recordVideo(15, 352, 288, MediaRecorder.VideoEncoder.MPEG_4_SP, - MediaRecorder.OutputFormat.THREE_GPP, MediaNames.RECORDED_VIDEO_3GP, false); - videoRecordedResult = validateVideo(MediaNames.RECORDED_VIDEO_3GP, 352, 288); - assertTrue("CIFMP4 3GPP", videoRecordedResult); - } - - @LargeTest - public void testQCIFH2633GPP() throws Exception { - boolean videoRecordedResult = false; - recordVideo(15, 176, 144, MediaRecorder.VideoEncoder.H263, - MediaRecorder.OutputFormat.THREE_GPP, MediaNames.RECORDED_VIDEO_3GP, false); - videoRecordedResult = validateVideo(MediaNames.RECORDED_VIDEO_3GP, 176, 144); - assertTrue("QCIFH263 3GPP", videoRecordedResult); - } - @LargeTest public void testInvalidVideoPath() throws Exception { boolean isTestInvalidVideoPathSuccessful = false; @@ -408,23 +268,6 @@ public class MediaRecorderTest extends ActivityInstrumentationTestCase<MediaFram assertTrue("Invalid outputFile Path", isTestInvalidVideoPathSuccessful); } - @Suppress - public void testInvalidVideoSize() throws Exception { - boolean isTestInvalidVideoSizeSuccessful = false; - isTestInvalidVideoSizeSuccessful = invalidRecordSetting(15, 800, 600, MediaRecorder.VideoEncoder.H263, - MediaRecorder.OutputFormat.THREE_GPP, MediaNames.RECORDED_VIDEO_3GP, false); - assertTrue("Invalid video Size", isTestInvalidVideoSizeSuccessful); - } - - @Suppress - @LargeTest - public void testInvalidFrameRate() throws Exception { - boolean isTestInvalidFrameRateSuccessful = false; - isTestInvalidFrameRateSuccessful = invalidRecordSetting(50, 176, 144, MediaRecorder.VideoEncoder.H263, - MediaRecorder.OutputFormat.THREE_GPP, MediaNames.RECORDED_VIDEO_3GP, false); - assertTrue("Invalid FrameRate", isTestInvalidFrameRateSuccessful); - } - @LargeTest //test cases for the new codec public void testDeviceSpecificCodec() throws Exception { diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java index 0e3029bbb3d7..34affa7b1cb7 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java @@ -17,7 +17,9 @@ package com.android.mediaframeworktest.performance; import com.android.mediaframeworktest.MediaFrameworkTest; +import com.android.mediaframeworktest.MediaFrameworkPerfTestRunner; import com.android.mediaframeworktest.MediaNames; +import com.android.mediaframeworktest.MediaTestUtil; import android.database.sqlite.SQLiteDatabase; import android.hardware.Camera; @@ -27,7 +29,7 @@ import android.media.MediaRecorder; import android.os.ConditionVariable; import android.os.Looper; import android.os.SystemClock; -import android.test.ActivityInstrumentationTestCase; +import android.test.ActivityInstrumentationTestCase2; import android.test.suitebuilder.annotation.LargeTest; import android.test.suitebuilder.annotation.Suppress; import android.util.Log; @@ -52,7 +54,7 @@ import android.hardware.Camera.PreviewCallback; * Junit / Instrumentation - performance measurement for media player and * recorder */ -public class MediaPlayerPerformance extends ActivityInstrumentationTestCase<MediaFrameworkTest> { +public class MediaPlayerPerformance extends ActivityInstrumentationTestCase2<MediaFrameworkTest> { private String TAG = "MediaPlayerPerformance"; @@ -87,6 +89,15 @@ public class MediaPlayerPerformance extends ActivityInstrumentationTestCase<Medi protected void setUp() throws Exception { super.setUp(); + getActivity(); + if (MediaFrameworkPerfTestRunner.mGetNativeHeapDump) + MediaTestUtil.getNativeHeapDump(this.getName() + "_before"); + } + + protected void tearDown() throws Exception { + super.tearDown(); + if (MediaFrameworkPerfTestRunner.mGetNativeHeapDump) + MediaTestUtil.getNativeHeapDump(this.getName() + "_after"); } public void createDB() { diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_default.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_default.png Binary files differindex e4d5a328bdb3..7b54daff94c7 100644 --- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_default.png +++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_default.png diff --git a/packages/SystemUI/res/drawable-xlarge-mdpi/recents_thumbnail_bg.png b/packages/SystemUI/res/drawable-xlarge-mdpi/recents_thumbnail_bg.png Binary files differindex 9f72549353c6..87a67c9cf474 100644 --- a/packages/SystemUI/res/drawable-xlarge-mdpi/recents_thumbnail_bg.png +++ b/packages/SystemUI/res/drawable-xlarge-mdpi/recents_thumbnail_bg.png diff --git a/packages/SystemUI/res/drawable-xlarge-mdpi/recents_thumbnail_bg_press.png b/packages/SystemUI/res/drawable-xlarge-mdpi/recents_thumbnail_bg_press.png Binary files differnew file mode 100644 index 000000000000..7f86fb35f5e0 --- /dev/null +++ b/packages/SystemUI/res/drawable-xlarge-mdpi/recents_thumbnail_bg_press.png diff --git a/packages/SystemUI/res/layout-xlarge/status_bar_recent_item.xml b/packages/SystemUI/res/layout-xlarge/status_bar_recent_item.xml index d7e16337d47f..bfa6c36a096e 100644 --- a/packages/SystemUI/res/layout-xlarge/status_bar_recent_item.xml +++ b/packages/SystemUI/res/layout-xlarge/status_bar_recent_item.xml @@ -22,14 +22,14 @@ <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_height="wrap_content" - android:layout_width="156dip"> + android:layout_width="@dimen/status_bar_recents_thumbnail_view_width"> <ImageView android:id="@+id/app_thumbnail" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_alignParentTop="true" - android:layout_marginLeft="105dip" + android:layout_marginLeft="@dimen/status_bar_recents_thumbnail_left_margin" android:scaleType="center" /> @@ -40,8 +40,8 @@ android:layout_alignParentTop="true" android:layout_marginLeft="123dip" android:layout_marginTop="16dip" - android:maxWidth="64dip" - android:maxHeight="64dip" + android:maxWidth="@dimen/status_bar_recents_thumbnail_max_width" + android:maxHeight="@dimen/status_bar_recents_thumbnail_max_height" android:adjustViewBounds="true" /> diff --git a/packages/SystemUI/res/layout-xlarge/status_bar_recent_panel.xml b/packages/SystemUI/res/layout-xlarge/status_bar_recent_panel.xml index ecd2b6f225c7..4be57a20c2ca 100644 --- a/packages/SystemUI/res/layout-xlarge/status_bar_recent_panel.xml +++ b/packages/SystemUI/res/layout-xlarge/status_bar_recent_panel.xml @@ -36,36 +36,35 @@ <LinearLayout android:id="@+id/recents_glow" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:orientation="horizontal" - android:layout_marginBottom="-28dip" + android:layout_marginBottom="-52dip" android:layout_gravity="bottom" - android:background="@drawable/recents_blue_glow"> + android:background="@drawable/recents_blue_glow" + android:orientation="horizontal" + > - <LinearLayout android:id="@+id/recents_container" - android:layout_width="356dip" + <ListView android:id="@+id/recents_container" + android:layout_width="@dimen/status_bar_recents_width" android:layout_height="wrap_content" - android:orientation="vertical" android:layout_marginRight="100dip" + android:divider="@null" + android:scrollingCache="true" + android:stackFromBottom="true" + android:fadingEdge="vertical" + android:scrollbars="none" + android:fadingEdgeLength="30dip" + android:listSelector="@drawable/recents_thumbnail_bg_press" /> </LinearLayout> </FrameLayout> - <!-- The outer FrameLayout is just used as an opaque background for the dismiss icon --> - <FrameLayout + <View android:id="@+id/recents_dismiss_button" android:layout_width="80px" android:layout_height="@*android:dimen/status_bar_height" android:layout_alignParentBottom="true" android:layout_alignParentLeft="true" - android:background="#ff000000"> - - <View android:id="@+id/recents_dismiss_button" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:background="@drawable/ic_sysbar_back_ime" - /> - - </FrameLayout> + android:background="@drawable/ic_sysbar_back_ime" + /> </com.android.systemui.statusbar.tablet.RecentAppsPanel> diff --git a/packages/SystemUI/res/layout-xlarge/status_bar_recent_panel_footer.xml b/packages/SystemUI/res/layout-xlarge/status_bar_recent_panel_footer.xml new file mode 100644 index 000000000000..4d14d1fb9fe2 --- /dev/null +++ b/packages/SystemUI/res/layout-xlarge/status_bar_recent_panel_footer.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* apps/common/assets/default/default/skins/StatusBar.xml +** +** Copyright 2011, 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. +*/ +--> + +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/listview_footer_padding" + android:layout_height="24dip" + android:layout_width="match_parent"> +</FrameLayout> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 93cf3778bc9c..88cd43c74da0 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -2,21 +2,34 @@ <!-- * Copyright (c) 2006, 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 + * 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 + * 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 + * 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> <!-- Margin at the edge of the screen to ignore touch events for in the windowshade. --> <dimen name="status_bar_edge_ignore">5dp</dimen> + + <!-- Recent Applications parameters --> + <!-- Width of a recent app view, including all content --> + <dimen name="status_bar_recents_thumbnail_view_width">156dp</dimen> + <!-- How far the thumbnail for a recent app appears from left edge --> + <dimen name="status_bar_recents_thumbnail_left_margin">110dp</dimen> + <!-- Upper width limit for application icon --> + <dimen name="status_bar_recents_thumbnail_max_width">64dp</dimen> + <!-- Upper height limit for application icon --> + <dimen name="status_bar_recents_thumbnail_max_height">64dp</dimen> + <!-- Width of scrollable area in recents --> + <dimen name="status_bar_recents_width">356dp</dimen> + </resources> diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java index e0d558f2580d..ebe1a7c9c622 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java @@ -40,37 +40,43 @@ import android.graphics.RectF; import android.graphics.Shader.TileMode; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; +import android.os.Parcelable; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.Log; import android.util.Slog; +import android.view.LayoutInflater; import android.view.View; -import android.view.View.OnClickListener; -import android.view.animation.DecelerateInterpolator; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemClickListener; +import android.widget.BaseAdapter; import android.widget.ImageView; -import android.widget.LinearLayout; +import android.widget.ListView; import android.widget.RelativeLayout; import android.widget.TextView; import com.android.systemui.R; -public class RecentAppsPanel extends RelativeLayout implements StatusBarPanel, OnClickListener { +public class RecentAppsPanel extends RelativeLayout implements StatusBarPanel, OnItemClickListener { private static final int GLOW_PADDING = 15; private static final String TAG = "RecentAppsPanel"; private static final boolean DEBUG = TabletStatusBar.DEBUG; - private static final int DISPLAY_TASKS_PORTRAIT = 7; // Limited by max binder transaction size - private static final int DISPLAY_TASKS_LANDSCAPE = 5; // number of recent tasks to display - private static final int MAX_TASKS = DISPLAY_TASKS_PORTRAIT + 1; // allow extra for non-apps + private static final int DISPLAY_TASKS = 20; + private static final int MAX_TASKS = DISPLAY_TASKS + 1; // allow extra for non-apps + private static final int BOTTOM_OFFSET = 28; // TODO: Get from dimens.xml private TabletStatusBar mBar; private ArrayList<ActivityDescription> mActivityDescriptions; private int mIconDpi; private View mRecentsScrim; private View mRecentsGlowView; - private LinearLayout mRecentsContainer; + private ListView mRecentsContainer; private Bitmap mGlowBitmap; private boolean mShowing; private Choreographer mChoreo; private View mRecentsDismissButton; + private ActvityDescriptionAdapter mListAdapter; + protected int mLastVisibleItem; static class ActivityDescription { int id; @@ -98,6 +104,63 @@ public class RecentAppsPanel extends RelativeLayout implements StatusBarPanel, O } }; + private static class ViewHolder { + private ImageView thumbnailView; + private ImageView iconView; + private TextView labelView; + private TextView descriptionView; + private ActivityDescription activityDescription; + } + + private class ActvityDescriptionAdapter extends BaseAdapter { + private LayoutInflater mInflater; + + public ActvityDescriptionAdapter(Context context) { + mInflater = LayoutInflater.from(context); + } + + public int getCount() { + return mActivityDescriptions != null ? mActivityDescriptions.size() : 0; + } + + public Object getItem(int position) { + return position; // we only need the index + } + + public long getItemId(int position) { + return position; // we just need something unique for this position + } + + public View getView(int position, View convertView, ViewGroup parent) { + ViewHolder holder; + if (convertView == null) { + convertView = mInflater.inflate(R.layout.status_bar_recent_item, null); + holder = new ViewHolder(); + holder.thumbnailView = (ImageView) convertView.findViewById(R.id.app_thumbnail); + holder.iconView = (ImageView) convertView.findViewById(R.id.app_icon); + holder.labelView = (TextView) convertView.findViewById(R.id.app_label); + holder.descriptionView = (TextView) convertView.findViewById(R.id.app_description); + convertView.setTag(holder); + } else { + holder = (ViewHolder) convertView.getTag(); + } + + // activityId is reverse since most recent appears at the bottom... + final int activityId = mActivityDescriptions.size() - position - 1; + + final ActivityDescription activityDescription = mActivityDescriptions.get(activityId); + final Bitmap thumb = activityDescription.thumbnail; + holder.thumbnailView.setImageBitmap(compositeBitmap(mGlowBitmap, thumb)); + holder.iconView.setImageDrawable(activityDescription.icon); + holder.labelView.setText(activityDescription.label); + holder.descriptionView.setText(activityDescription.description); + holder.thumbnailView.setTag(activityDescription); + holder.activityDescription = activityDescription; + + return convertView; + } + } + public boolean isInContentArea(int x, int y) { // use mRecentsContainer's exact bounds to determine horizontal position final int l = mRecentsContainer.getLeft(); @@ -267,9 +330,41 @@ public class RecentAppsPanel extends RelativeLayout implements StatusBarPanel, O } @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + // Keep track of the last visible item in the list so we can restore it + // to the bottom when the orientation changes. + int childCount = mRecentsContainer.getChildCount(); + if (childCount > 0) { + mLastVisibleItem = mRecentsContainer.getFirstVisiblePosition() + childCount - 1; + View view = mRecentsContainer.getChildAt(childCount - 1); + final int distanceFromBottom = mRecentsContainer.getHeight() - view.getTop(); + //final int distanceFromBottom = view.getHeight() + BOTTOM_OFFSET; + + // This has to happen post-layout, so run it "in the future" + post(new Runnable() { + public void run() { + mRecentsContainer.setSelectionFromTop(mLastVisibleItem, + mRecentsContainer.getHeight() - distanceFromBottom); + } + }); + } + } + + @Override protected void onFinishInflate() { super.onFinishInflate(); - mRecentsContainer = (LinearLayout) findViewById(R.id.recents_container); + LayoutInflater inflater = (LayoutInflater) + mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + + mRecentsContainer = (ListView) findViewById(R.id.recents_container); + View footer = inflater.inflate(R.layout.status_bar_recent_panel_footer, + mRecentsContainer, false); + mRecentsContainer.setScrollbarFadingEnabled(true); + mRecentsContainer.addFooterView(footer); + mRecentsContainer.setAdapter(mListAdapter = new ActvityDescriptionAdapter(mContext)); + mRecentsContainer.setOnItemClickListener(this); + mRecentsGlowView = findViewById(R.id.recents_glow); mRecentsScrim = (View) findViewById(R.id.recents_bg_protect); mChoreo = new Choreographer(this, mRecentsScrim, mRecentsGlowView); @@ -287,20 +382,16 @@ public class RecentAppsPanel extends RelativeLayout implements StatusBarPanel, O } @Override - protected void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - // we show more in portrait mode, so update UI if orientation changes - updateUiElements(newConfig, false); - } - - @Override protected void onVisibilityChanged(View changedView, int visibility) { super.onVisibilityChanged(changedView, visibility); if (DEBUG) Log.v(TAG, "onVisibilityChanged(" + changedView + ", " + visibility + ")"); if (visibility == View.VISIBLE && changedView == this) { refreshApplicationList(); - mRecentsContainer.setScrollbarFadingEnabled(true); - mRecentsContainer.scrollTo(0, 0); + post(new Runnable() { + public void run() { + mRecentsContainer.setSelection(mActivityDescriptions.size() - 1); + } + }); } } @@ -402,11 +493,12 @@ public class RecentAppsPanel extends RelativeLayout implements StatusBarPanel, O private void refreshApplicationList() { mActivityDescriptions = getRecentTasks(); + mListAdapter.notifyDataSetInvalidated(); if (mActivityDescriptions.size() > 0) { - updateUiElements(getResources().getConfiguration(), true); + mLastVisibleItem = mActivityDescriptions.size() - 1; // scroll to bottom after reloading + updateUiElements(getResources().getConfiguration()); } else { // Immediately hide this panel - mShowing = false; hide(false); } } @@ -426,44 +518,29 @@ public class RecentAppsPanel extends RelativeLayout implements StatusBarPanel, O canvas.drawBitmap(thumbnail, new Rect(0, 0, srcWidth-1, srcHeight-1), new RectF(GLOW_PADDING, - GLOW_PADDING - 4.0f, - outBitmap.getWidth() - GLOW_PADDING + 2.0f, - outBitmap.getHeight() - GLOW_PADDING + 3.0f), paint); + GLOW_PADDING - 7.0f, + outBitmap.getWidth() - GLOW_PADDING + 3.0f, + outBitmap.getHeight() - GLOW_PADDING + 7.0f), paint); } return outBitmap; } - private void updateUiElements(Configuration config, boolean animate) { - mRecentsContainer.removeAllViews(); - - final int first = 0; - final boolean isPortrait = config.orientation == Configuration.ORIENTATION_PORTRAIT; - final int taskCount = isPortrait ? DISPLAY_TASKS_PORTRAIT : DISPLAY_TASKS_LANDSCAPE; - final int last = Math.min(mActivityDescriptions.size(), taskCount) - 1; - for (int i = last; i >= first; i--) { - ActivityDescription activityDescription = mActivityDescriptions.get(i); - View view = View.inflate(mContext, R.layout.status_bar_recent_item, null); - ImageView appThumbnail = (ImageView) view.findViewById(R.id.app_thumbnail); - ImageView appIcon = (ImageView) view.findViewById(R.id.app_icon); - TextView appLabel = (TextView) view.findViewById(R.id.app_label); - TextView appDesc = (TextView) view.findViewById(R.id.app_description); - final Bitmap thumb = activityDescription.thumbnail; - appThumbnail.setImageBitmap(compositeBitmap(mGlowBitmap, thumb)); - appIcon.setImageDrawable(activityDescription.icon); - appLabel.setText(activityDescription.label); - appDesc.setText(activityDescription.description); - appThumbnail.setOnClickListener(this); - appThumbnail.setTag(activityDescription); - mRecentsContainer.addView(view); - } + private void updateUiElements(Configuration config) { + final int items = mActivityDescriptions.size(); + + mRecentsContainer.setVisibility(items > 0 ? View.VISIBLE : View.GONE); + mRecentsGlowView.setVisibility(items > 0 ? View.VISIBLE : View.GONE); + } - int views = mRecentsContainer.getChildCount(); - mRecentsContainer.setVisibility(views > 0 ? View.VISIBLE : View.GONE); - mRecentsGlowView.setVisibility(views > 0 ? View.VISIBLE : View.GONE); + private void hide(boolean animate) { + if (!animate) { + setVisibility(View.GONE); + } + mBar.animateCollapse(); } - public void onClick(View v) { - ActivityDescription ad = (ActivityDescription)v.getTag(); + public void onItemClick(AdapterView<?> parent, View view, int position, long id) { + ActivityDescription ad = ((ViewHolder) view.getTag()).activityDescription; final ActivityManager am = (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE); if (ad.id >= 0) { @@ -478,11 +555,4 @@ public class RecentAppsPanel extends RelativeLayout implements StatusBarPanel, O } hide(true); } - - private void hide(boolean animate) { - setVisibility(View.GONE); - if (animate) { - mBar.animateCollapse(); - } - } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java index 233d601b6fda..f0408a28a00f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java @@ -267,6 +267,8 @@ public class TabletStatusBar extends StatusBar implements lp.gravity = Gravity.BOTTOM | Gravity.LEFT; lp.setTitle("RecentsPanel"); lp.windowAnimations = R.style.Animation_RecentPanel; + lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED + | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING; WindowManagerImpl.getDefault().addView(mRecentsPanel, lp); mRecentsPanel.setBar(this); @@ -509,7 +511,7 @@ public class TabletStatusBar extends StatusBar implements final int peekIndex = m.arg1; if (peekIndex < N) { //Slog.d(TAG, "loading peek: " + peekIndex); - NotificationData.Entry entry = + NotificationData.Entry entry = mNotificationDNDMode ? mNotificationDNDDummyEntry : mNotificationData.get(N-1-peekIndex); @@ -555,7 +557,7 @@ public class TabletStatusBar extends StatusBar implements final int N = mNotificationData.size(); if (mNotificationPeekIndex >= 0 && mNotificationPeekIndex < N) { - NotificationData.Entry entry = + NotificationData.Entry entry = mNotificationDNDMode ? mNotificationDNDDummyEntry : mNotificationData.get(N-1-mNotificationPeekIndex); @@ -584,6 +586,8 @@ public class TabletStatusBar extends StatusBar implements case MSG_OPEN_RECENTS_PANEL: if (DEBUG) Slog.d(TAG, "opening recents panel"); if (mRecentsPanel != null) { + disable(StatusBarManager.DISABLE_NAVIGATION + | StatusBarManager.DISABLE_BACK); mRecentsPanel.setVisibility(View.VISIBLE); mRecentsPanel.show(true, true); } @@ -591,6 +595,7 @@ public class TabletStatusBar extends StatusBar implements case MSG_CLOSE_RECENTS_PANEL: if (DEBUG) Slog.d(TAG, "closing recents panel"); if (mRecentsPanel != null && mRecentsPanel.isShowing()) { + disable(StatusBarManager.DISABLE_NONE); mRecentsPanel.show(false, true); } break; @@ -701,7 +706,7 @@ public class TabletStatusBar extends StatusBar implements && oldContentView.getLayoutId() == contentView.getLayoutId(); ViewGroup rowParent = (ViewGroup) oldEntry.row.getParent(); boolean orderUnchanged = notification.notification.when==oldNotification.notification.when - && notification.priority == oldNotification.priority; + && notification.priority == oldNotification.priority; // priority now encompasses isOngoing() boolean isLastAnyway = rowParent.indexOfChild(oldEntry.row) == rowParent.getChildCount()-1; if (contentsUnchanged && (orderUnchanged || isLastAnyway)) { diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java index afa8d69c3596..f28e2b12ce55 100644 --- a/services/java/com/android/server/AppWidgetService.java +++ b/services/java/com/android/server/AppWidgetService.java @@ -1029,7 +1029,7 @@ class AppWidgetService extends IAppWidgetService.Stub com.android.internal.R.styleable.AppWidgetProviderInfo_previewImage, 0); info.autoAdvanceViewId = sa.getResourceId( com.android.internal.R.styleable.AppWidgetProviderInfo_autoAdvanceViewId, -1); - info.resizableMode = sa.getInt( + info.resizeMode = sa.getInt( com.android.internal.R.styleable.AppWidgetProviderInfo_resizeMode, AppWidgetProviderInfo.RESIZE_NONE); diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index b7cc3243255a..e3218c852b17 100644 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -5812,8 +5812,7 @@ public class WindowManagerService extends IWindowManager.Stub mDisplay = wm.getDefaultDisplay(); mInitialDisplayWidth = mDisplay.getWidth(); mInitialDisplayHeight = mDisplay.getHeight(); - mInputManager.setDisplaySize(0, Display.unmapDisplaySize(mInitialDisplayWidth), - Display.unmapDisplaySize(mInitialDisplayHeight)); + mInputManager.setDisplaySize(0, mDisplay.getRealWidth(), mDisplay.getRealHeight()); } try { diff --git a/test-runner/src/android/test/SingleLaunchActivityTestCase.java b/test-runner/src/android/test/SingleLaunchActivityTestCase.java index b63b3ce19759..79c554a46391 100644 --- a/test-runner/src/android/test/SingleLaunchActivityTestCase.java +++ b/test-runner/src/android/test/SingleLaunchActivityTestCase.java @@ -75,7 +75,7 @@ public abstract class SingleLaunchActivityTestCase<T extends Activity> protected void tearDown() throws Exception { // If it is the last test case, call finish on the activity. sTestCaseCounter --; - if (sTestCaseCounter == 1) { + if (sTestCaseCounter == 0) { sActivity.finish(); } super.tearDown(); |