From f96eac569b9010a26a99ee965609b52046849b20 Mon Sep 17 00:00:00 2001 From: Gilles Debunne Date: Tue, 7 Feb 2012 16:08:39 -0800 Subject: [PATCH 001/132] Invalidate text display list when text properties change. Bug 5887530, Bug 5945886, Bug 5904371 Added more invalidation when other properties of the text are changed. Change-Id: I618dbaae9da64bf72dd29e444215b7de1c644573 --- core/java/android/widget/TextView.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 971d910736f20..99349b0473eac 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -1205,6 +1205,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (imm != null) imm.restartInput(this); } + mTextDisplayListIsValid = false; prepareCursorControllers(); // start or stop the cursor blinking as appropriate @@ -2310,6 +2311,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener public void setHighlightColor(int color) { if (mHighlightColor != color) { mHighlightColor = color; + mTextDisplayListIsValid = false; invalidate(); } } @@ -2330,6 +2332,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener mShadowDx = dx; mShadowDy = dy; + mTextDisplayListIsValid = false; invalidate(); } @@ -2821,6 +2824,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } if (inval) { + mTextDisplayListIsValid = false; invalidate(); } } From d27e62402239f22bb3ecf0bfba77688bcbc076af Mon Sep 17 00:00:00 2001 From: Romain Guy Date: Wed, 8 Feb 2012 11:19:11 -0800 Subject: [PATCH 002/132] Tentative fix for mysteriously recycled bitmap This code should not be triggered with scale == 1.0f because of the density comparisons above though. Change-Id: I9e39e3769a3b6550c97df3b213457947ec1f554b --- graphics/java/android/graphics/BitmapFactory.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java index 8d1756152eca8..bff2a76d729bb 100644 --- a/graphics/java/android/graphics/BitmapFactory.java +++ b/graphics/java/android/graphics/BitmapFactory.java @@ -518,15 +518,16 @@ public class BitmapFactory { byte[] np = bm.getNinePatchChunk(); final boolean isNinePatch = np != null && NinePatch.isNinePatchChunk(np); if (opts.inScaled || isNinePatch) { - float scale = targetDensity / (float)density; - // TODO: This is very inefficient and should be done in native by Skia - final Bitmap oldBitmap = bm; - bm = Bitmap.createScaledBitmap(oldBitmap, (int) (bm.getWidth() * scale + 0.5f), - (int) (bm.getHeight() * scale + 0.5f), true); - oldBitmap.recycle(); + float scale = targetDensity / (float) density; + if (scale != 1.0f) { + final Bitmap oldBitmap = bm; + bm = Bitmap.createScaledBitmap(oldBitmap, (int) (bm.getWidth() * scale + 0.5f), + (int) (bm.getHeight() * scale + 0.5f), true); + if (bm != oldBitmap) oldBitmap.recycle(); + } if (isNinePatch) { - np = nativeScaleNinePatch(np, scale, outPadding); + if (scale != 1.0f) np = nativeScaleNinePatch(np, scale, outPadding); bm.setNinePatchChunk(np); } bm.setDensity(targetDensity); From f48c147f1dbe41de799656facc6911e85c9fcac2 Mon Sep 17 00:00:00 2001 From: Adam Powell Date: Wed, 22 Feb 2012 10:31:16 -0800 Subject: [PATCH 003/132] Fix bug 6048643 - verify ListView layoutparams while tracking stable IDs Account for adapters that don't inflate item views using the ListView as a parent. Unify how AbsListView and subclasses generate layoutparams. Change-Id: I963a5fcb4d98b721210a4d92d0db307f56acdf59 --- core/java/android/widget/AbsListView.java | 27 +++++++++++++++++------ core/java/android/widget/GridView.java | 10 ++++----- core/java/android/widget/ListView.java | 6 ++--- 3 files changed, 26 insertions(+), 17 deletions(-) diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index e7bc1e1f661ba..2602523c283ff 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -2035,13 +2035,6 @@ public abstract class AbsListView extends AdapterView implements Te } child = mAdapter.getView(position, scrapView, this); - if (mAdapterHasStableIds) { - LayoutParams lp = (LayoutParams) child.getLayoutParams(); - if (lp == null) { - lp = (LayoutParams) generateDefaultLayoutParams(); - } - lp.itemId = mAdapter.getItemId(position); - } if (ViewDebug.TRACE_RECYCLER) { ViewDebug.trace(child, ViewDebug.RecyclerTraceType.BIND_VIEW, @@ -2072,6 +2065,20 @@ public abstract class AbsListView extends AdapterView implements Te } } + if (mAdapterHasStableIds) { + final ViewGroup.LayoutParams vlp = child.getLayoutParams(); + LayoutParams lp; + if (vlp == null) { + lp = (LayoutParams) generateDefaultLayoutParams(); + } else if (!checkLayoutParams(vlp)) { + lp = (LayoutParams) generateLayoutParams(vlp); + } else { + lp = (LayoutParams) vlp; + } + lp.itemId = mAdapter.getItemId(position); + child.setLayoutParams(lp); + } + return child; } @@ -5382,6 +5389,12 @@ public abstract class AbsListView extends AdapterView implements Te } } + @Override + protected ViewGroup.LayoutParams generateDefaultLayoutParams() { + return new AbsListView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT, 0); + } + @Override protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { return new LayoutParams(p); diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java index 6bc5a15f531de..0dedf8b61d329 100644 --- a/core/java/android/widget/GridView.java +++ b/core/java/android/widget/GridView.java @@ -1029,10 +1029,9 @@ public class GridView extends AbsListView { if (count > 0) { final View child = obtainView(0, mIsScrap); - AbsListView.LayoutParams p = (AbsListView.LayoutParams)child.getLayoutParams(); + AbsListView.LayoutParams p = (AbsListView.LayoutParams) child.getLayoutParams(); if (p == null) { - p = new AbsListView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT, 0); + p = (AbsListView.LayoutParams) generateDefaultLayoutParams(); child.setLayoutParams(p); } p.viewType = mAdapter.getItemViewType(0); @@ -1362,10 +1361,9 @@ public class GridView extends AbsListView { // Respect layout params that are already in the view. Otherwise make // some up... - AbsListView.LayoutParams p = (AbsListView.LayoutParams)child.getLayoutParams(); + AbsListView.LayoutParams p = (AbsListView.LayoutParams) child.getLayoutParams(); if (p == null) { - p = new AbsListView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT, 0); + p = (AbsListView.LayoutParams) generateDefaultLayoutParams(); } p.viewType = mAdapter.getItemViewType(position); diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java index 46c2c0725d0d9..71700b367b40a 100644 --- a/core/java/android/widget/ListView.java +++ b/core/java/android/widget/ListView.java @@ -1163,8 +1163,7 @@ public class ListView extends AbsListView { private void measureScrapChild(View child, int position, int widthMeasureSpec) { LayoutParams p = (LayoutParams) child.getLayoutParams(); if (p == null) { - p = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT, 0); + p = (AbsListView.LayoutParams) generateDefaultLayoutParams(); child.setLayoutParams(p); } p.viewType = mAdapter.getItemViewType(position); @@ -1808,8 +1807,7 @@ public class ListView extends AbsListView { // noinspection unchecked AbsListView.LayoutParams p = (AbsListView.LayoutParams) child.getLayoutParams(); if (p == null) { - p = new AbsListView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT, 0); + p = (AbsListView.LayoutParams) generateDefaultLayoutParams(); } p.viewType = mAdapter.getItemViewType(position); From 2de93bc1fa1244d903e7fe94f8941063a37e6be8 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Thu, 23 Feb 2012 10:25:35 -0800 Subject: [PATCH 004/132] Fix issue #6049410: 3rd party app crashing in JB: Uber Change-Id: Ie3f8c91a2c0fdd5a80824fe2fa7da2afd2913174 --- core/res/res/values/public.xml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 6a887db4f23ff..0950bdbe4b44f 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -1542,6 +1542,21 @@ + + + + + + + + + + + + + + + From 3eca8b276ca20f26f0a9f8689329ef858b505fca Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Thu, 23 Feb 2012 21:20:01 -0800 Subject: [PATCH 005/132] workaround for an issue where the screen would flicker sometimes bug: 6020860 Change-Id: I97807db66b66c5f4dcbed0df79d5d257cfc7c0bd --- services/surfaceflinger/SurfaceFlinger.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 9e3f54839574f..67fc7bba7bceb 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1000,6 +1000,12 @@ void SurfaceFlinger::composeSurfaces(const Region& dirty) drawWormhole(); } + // FIXME: workaroud for b/6020860 + glEnable(GL_SCISSOR_TEST); + glScissor(0,0,0,0); + glClear(GL_COLOR_BUFFER_BIT); + // end-workaround + /* * and then, render the layers targeted at the framebuffer */ From 6f4aaee3208c552a602f5f67a5eb6d163edab9fc Mon Sep 17 00:00:00 2001 From: Daniel Lam Date: Mon, 27 Feb 2012 11:32:06 -0800 Subject: [PATCH 006/132] Revert "Removed dependecies between BufferQueue and SurfaceTexture" This reverts commit a631399f71dbc7659d2f241968f85d337726ae61 --- include/gui/BufferQueue.h | 119 +++------------- include/gui/SurfaceTexture.h | 54 +------- libs/gui/BufferQueue.cpp | 256 ++++++----------------------------- libs/gui/SurfaceTexture.cpp | 175 ++++++++++++++---------- 4 files changed, 167 insertions(+), 437 deletions(-) diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h index 039e7b0745c92..ae991601817ab 100644 --- a/include/gui/BufferQueue.h +++ b/include/gui/BufferQueue.h @@ -40,7 +40,6 @@ public: }; enum { NUM_BUFFER_SLOTS = 32 }; enum { NO_CONNECTED_API = 0 }; - enum { INVALID_BUFFER_SLOT = -1 }; struct FrameAvailableListener : public virtual RefBase { // onFrameAvailable() is called from queueBuffer() each time an @@ -120,91 +119,8 @@ public: // connected to the specified client API. virtual status_t disconnect(int api); - // dump our state in a String - virtual void dump(String8& result) const; - virtual void dump(String8& result, const char* prefix, char* buffer, size_t SIZE) const; +protected: - // public facing structure for BufferSlot - struct BufferItem { - - BufferItem() - : - mTransform(0), - mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), - mTimestamp(0), - mFrameNumber(0), - mBuf(INVALID_BUFFER_SLOT) { - mCrop.makeInvalid(); - } - // mGraphicBuffer points to the buffer allocated for this slot or is NULL - // if no buffer has been allocated. - sp mGraphicBuffer; - - // mCrop is the current crop rectangle for this buffer slot. This gets - // set to mNextCrop each time queueBuffer gets called for this buffer. - Rect mCrop; - - // mTransform is the current transform flags for this buffer slot. This - // gets set to mNextTransform each time queueBuffer gets called for this - // slot. - uint32_t mTransform; - - // mScalingMode is the current scaling mode for this buffer slot. This - // gets set to mNextScalingMode each time queueBuffer gets called for - // this slot. - uint32_t mScalingMode; - - // mTimestamp is the current timestamp for this buffer slot. This gets - // to set by queueBuffer each time this slot is queued. - int64_t mTimestamp; - - // mFrameNumber is the number of the queued frame for this slot. - uint64_t mFrameNumber; - - // buf is the slot index of this buffer - int mBuf; - - }; - - // The following public functions is the consumer facing interface - - // acquire consumes a buffer by transferring its ownership to a consumer. - // buffer contains the GraphicBuffer and its corresponding information. - // buffer.mGraphicsBuffer will be NULL when the buffer has been already - // acquired by the consumer. - - status_t acquire(BufferItem *buffer); - - // releaseBuffer releases a buffer slot from the consumer back to the - // BufferQueue pending a fence sync. - status_t releaseBuffer(int buf, EGLDisplay display, EGLSyncKHR fence); - - // consumerDisconnect disconnects a consumer from the BufferQueue. All - // buffers will be freed. - status_t consumerDisconnect(); - - // setDefaultBufferSize is used to set the size of buffers returned by - // requestBuffers when a with and height of zero is requested. - status_t setDefaultBufferSize(uint32_t w, uint32_t h); - - // setBufferCountServer set the buffer count. If the client has requested - // a buffer count using setBufferCount, the server-buffer count will - // take effect once the client sets the count back to zero. - status_t setBufferCountServer(int bufferCount); - - // isSynchronousMode returns whether the SurfaceTexture is currently in - // synchronous mode. - bool isSynchronousMode() const; - - // setConsumerName sets the name used in logging - void setConsumerName(const String8& name); - - // setFrameAvailableListener sets the listener object that will be notified - // when a new frame becomes available. - void setFrameAvailableListener(const sp& listener); - - -private: // freeBufferLocked frees the resources (both GraphicBuffer and EGLImage) // for the given slot. void freeBufferLocked(int index); @@ -229,18 +145,20 @@ private: status_t setBufferCountServerLocked(int bufferCount); + enum { INVALID_BUFFER_SLOT = -1 }; + struct BufferSlot { BufferSlot() - : mEglDisplay(EGL_NO_DISPLAY), + : mEglImage(EGL_NO_IMAGE_KHR), + mEglDisplay(EGL_NO_DISPLAY), mBufferState(BufferSlot::FREE), mRequestBufferCalled(false), mTransform(0), mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), mTimestamp(0), mFrameNumber(0), - mFence(EGL_NO_SYNC_KHR), - mAcquireCalled(false) { + mFence(EGL_NO_SYNC_KHR) { mCrop.makeInvalid(); } @@ -248,6 +166,9 @@ private: // if no buffer has been allocated. sp mGraphicBuffer; + // mEglImage is the EGLImage created from mGraphicBuffer. + EGLImageKHR mEglImage; + // mEglDisplay is the EGLDisplay used to create mEglImage. EGLDisplay mEglDisplay; @@ -257,7 +178,6 @@ private: // FREE indicates that the buffer is not currently being used and // will not be used in the future until it gets dequeued and // subsequently queued by the client. - // aka "owned by BufferQueue, ready to be dequeued" FREE = 0, // DEQUEUED indicates that the buffer has been dequeued by the @@ -270,7 +190,6 @@ private: // dequeued by the client. That means that the current buffer can // be in either the DEQUEUED or QUEUED state. In asynchronous mode, // however, the current buffer is always in the QUEUED state. - // aka "owned by producer, ready to be queued" DEQUEUED = 1, // QUEUED indicates that the buffer has been queued by the client, @@ -280,11 +199,7 @@ private: // the current buffer may be dequeued by the client under some // circumstances. See the note about the current buffer in the // documentation for DEQUEUED. - // aka "owned by BufferQueue, ready to be acquired" QUEUED = 2, - - // aka "owned by consumer, ready to be released" - ACQUIRED = 3 }; // mBufferState is the current state of this buffer slot. @@ -321,9 +236,6 @@ private: // to EGL_NO_SYNC_KHR when the buffer is created and (optionally, based // on a compile-time option) set to a new sync object in updateTexImage. EGLSyncKHR mFence; - - // Indicates whether this buffer has been seen by a consumer yet - bool mAcquireCalled; }; // mSlots is the array of buffer slots that must be mirrored on the client @@ -333,6 +245,7 @@ private: // for a slot when requestBuffer is called with that slot's index. BufferSlot mSlots[NUM_BUFFER_SLOTS]; + // mDefaultWidth holds the default width of allocated buffers. It is used // in requestBuffers() if a width and height of zero is specified. uint32_t mDefaultWidth; @@ -358,6 +271,14 @@ private: // mServerBufferCount buffer count requested by the server-side int mServerBufferCount; + // mCurrentTexture is the buffer slot index of the buffer that is currently + // bound to the OpenGL texture. It is initialized to INVALID_BUFFER_SLOT, + // indicating that no buffer slot is currently bound to the texture. Note, + // however, that a value of INVALID_BUFFER_SLOT does not necessarily mean + // that no buffer is bound to the texture. A call to setBufferCount will + // reset mCurrentTexture to INVALID_BUFFER_SLOT. + int mCurrentTexture; + // mNextCrop is the crop rectangle that will be used for the next buffer // that gets queued. It is set by calling setCrop. Rect mNextCrop; @@ -406,7 +327,7 @@ private: // mName is a string used to identify the BufferQueue in log messages. // It is set by the setName method. - String8 mConsumerName; + String8 mName; // mMutex is the mutex used to prevent concurrent access to the member // variables of BufferQueue objects. It must be locked whenever the @@ -416,8 +337,6 @@ private: // mFrameCounter is the free running counter, incremented for every buffer queued // with the surface Texture. uint64_t mFrameCounter; - - bool mBufferHasBeenQueued; }; // ---------------------------------------------------------------------------- diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h index 5531e539bfdbf..dcab049ef06da 100644 --- a/include/gui/SurfaceTexture.h +++ b/include/gui/SurfaceTexture.h @@ -153,8 +153,8 @@ public: void setName(const String8& name); // dump our state in a String - virtual void dump(String8& result) const; - virtual void dump(String8& result, const char* prefix, char* buffer, size_t SIZE) const; + void dump(String8& result) const; + void dump(String8& result, const char* prefix, char* buffer, size_t SIZE) const; protected: @@ -217,56 +217,6 @@ private: // browser's tile cache exceeds. const GLenum mTexTarget; - // SurfaceTexture maintains EGL information about GraphicBuffers that corresponds - // directly with BufferQueue's buffers - struct EGLSlot { - EGLSlot() - : mEglImage(EGL_NO_IMAGE_KHR), - mEglDisplay(EGL_NO_DISPLAY), - mFence(EGL_NO_SYNC_KHR) { - } - - sp mGraphicBuffer; - - // mEglImage is the EGLImage created from mGraphicBuffer. - EGLImageKHR mEglImage; - - // mEglDisplay is the EGLDisplay used to create mEglImage. - EGLDisplay mEglDisplay; - - // mFence is the EGL sync object that must signal before the buffer - // associated with this buffer slot may be dequeued. It is initialized - // to EGL_NO_SYNC_KHR when the buffer is created and (optionally, based - // on a compile-time option) set to a new sync object in updateTexImage. - EGLSyncKHR mFence; - }; - - EGLSlot mEGLSlots[NUM_BUFFER_SLOTS]; - - // mAbandoned indicates that the BufferQueue will no longer be used to - // consume images buffers pushed to it using the ISurfaceTexture interface. - // It is initialized to false, and set to true in the abandon method. A - // BufferQueue that has been abandoned will return the NO_INIT error from - // all ISurfaceTexture methods capable of returning an error. - bool mAbandoned; - - // mName is a string used to identify the SurfaceTexture in log messages. - // It can be set by the setName method. - String8 mName; - - // mMutex is the mutex used to prevent concurrent access to the member - // variables of SurfaceTexture objects. It must be locked whenever the - // member variables are accessed. - mutable Mutex mMutex; - - // mCurrentTexture is the buffer slot index of the buffer that is currently - // bound to the OpenGL texture. It is initialized to INVALID_BUFFER_SLOT, - // indicating that no buffer slot is currently bound to the texture. Note, - // however, that a value of INVALID_BUFFER_SLOT does not necessarily mean - // that no buffer is bound to the texture. A call to setBufferCount will - // reset mCurrentTexture to INVALID_BUFFER_SLOT. - int mCurrentTexture; - }; // ---------------------------------------------------------------------------- diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp index f4214c7d47411..0791de2269ef3 100644 --- a/libs/gui/BufferQueue.cpp +++ b/libs/gui/BufferQueue.cpp @@ -15,7 +15,6 @@ */ #define LOG_TAG "BufferQueue" -//#define LOG_NDEBUG 0 #define GL_GLEXT_PROTOTYPES #define EGL_EGLEXT_PROTOTYPES @@ -28,7 +27,6 @@ #include #include -#include // This compile option causes SurfaceTexture to return the buffer that is currently // attached to the GL texture from dequeueBuffer when no other buffers are @@ -44,11 +42,11 @@ #endif // Macros for including the BufferQueue name in log messages -#define ST_LOGV(x, ...) ALOGV("[%s] "x, mConsumerName.string(), ##__VA_ARGS__) -#define ST_LOGD(x, ...) ALOGD("[%s] "x, mConsumerName.string(), ##__VA_ARGS__) -#define ST_LOGI(x, ...) ALOGI("[%s] "x, mConsumerName.string(), ##__VA_ARGS__) -#define ST_LOGW(x, ...) ALOGW("[%s] "x, mConsumerName.string(), ##__VA_ARGS__) -#define ST_LOGE(x, ...) ALOGE("[%s] "x, mConsumerName.string(), ##__VA_ARGS__) +#define ST_LOGV(x, ...) ALOGV("[%s] "x, mName.string(), ##__VA_ARGS__) +#define ST_LOGD(x, ...) ALOGD("[%s] "x, mName.string(), ##__VA_ARGS__) +#define ST_LOGI(x, ...) ALOGI("[%s] "x, mName.string(), ##__VA_ARGS__) +#define ST_LOGW(x, ...) ALOGW("[%s] "x, mName.string(), ##__VA_ARGS__) +#define ST_LOGE(x, ...) ALOGE("[%s] "x, mName.string(), ##__VA_ARGS__) namespace android { @@ -65,17 +63,17 @@ BufferQueue::BufferQueue( bool allowSynchronousMode ) : mBufferCount(MIN_ASYNC_BUFFER_SLOTS), mClientBufferCount(0), mServerBufferCount(MIN_ASYNC_BUFFER_SLOTS), + mCurrentTexture(INVALID_BUFFER_SLOT), mNextTransform(0), mNextScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), mSynchronousMode(false), mAllowSynchronousMode(allowSynchronousMode), mConnectedApi(NO_CONNECTED_API), mAbandoned(false), - mFrameCounter(0), - mBufferHasBeenQueued(false) + mFrameCounter(0) { // Choose a name using the PID and a process-unique ID. - mConsumerName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId()); + mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId()); ST_LOGV("BufferQueue"); sp composer(ComposerService::getComposerService()); @@ -121,23 +119,6 @@ status_t BufferQueue::setBufferCountServerLocked(int bufferCount) { return OK; } -bool BufferQueue::isSynchronousMode() const { - Mutex::Autolock lock(mMutex); - return mSynchronousMode; -} - -void BufferQueue::setConsumerName(const String8& name) { - Mutex::Autolock lock(mMutex); - mConsumerName = name; -} - -void BufferQueue::setFrameAvailableListener( - const sp& listener) { - ST_LOGV("setFrameAvailableListener"); - Mutex::Autolock lock(mMutex); - mFrameAvailableListener = listener; -} - status_t BufferQueue::setBufferCount(int bufferCount) { ST_LOGV("setBufferCount: count=%d", bufferCount); Mutex::Autolock lock(mMutex); @@ -179,7 +160,7 @@ status_t BufferQueue::setBufferCount(int bufferCount) { freeAllBuffersLocked(); mBufferCount = bufferCount; mClientBufferCount = bufferCount; - mBufferHasBeenQueued = false; + mCurrentTexture = INVALID_BUFFER_SLOT; mQueue.clear(); mDequeueCondition.signal(); return OK; @@ -295,7 +276,7 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, mBufferCount = mServerBufferCount; if (mBufferCount < minBufferCountNeeded) mBufferCount = minBufferCountNeeded; - mBufferHasBeenQueued = false; + mCurrentTexture = INVALID_BUFFER_SLOT; returnFlags |= ISurfaceTexture::RELEASE_ALL_BUFFERS; } @@ -309,10 +290,19 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, dequeuedCount++; } + // if buffer is FREE it CANNOT be current + ALOGW_IF((state == BufferSlot::FREE) && (mCurrentTexture==i), + "dequeueBuffer: buffer %d is both FREE and current!", + i); + if (FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER) { - // This functionality has been temporarily removed so - // BufferQueue and SurfaceTexture can be refactored into - // separate objects + if (state == BufferSlot::FREE || i == mCurrentTexture) { + foundSync = i; + if (i != mCurrentTexture) { + found = i; + break; + } + } } else { if (state == BufferSlot::FREE) { /* We return the oldest of the free buffers to avoid @@ -341,7 +331,8 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, // See whether a buffer has been queued since the last // setBufferCount so we know whether to perform the // MIN_UNDEQUEUED_BUFFERS check below. - if (mBufferHasBeenQueued) { + bool bufferHasBeenQueued = mCurrentTexture != INVALID_BUFFER_SLOT; + if (bufferHasBeenQueued) { // make sure the client is not trying to dequeue more buffers // than allowed. const int avail = mBufferCount - (dequeuedCount+1); @@ -413,23 +404,27 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, if (updateFormat) { mPixelFormat = format; } - - mSlots[buf].mAcquireCalled = false; mSlots[buf].mGraphicBuffer = graphicBuffer; mSlots[buf].mRequestBufferCalled = false; mSlots[buf].mFence = EGL_NO_SYNC_KHR; - mSlots[buf].mEglDisplay = EGL_NO_DISPLAY; - - - - + if (mSlots[buf].mEglImage != EGL_NO_IMAGE_KHR) { + eglDestroyImageKHR(mSlots[buf].mEglDisplay, + mSlots[buf].mEglImage); + mSlots[buf].mEglImage = EGL_NO_IMAGE_KHR; + mSlots[buf].mEglDisplay = EGL_NO_DISPLAY; + } + if (mCurrentTexture == buf) { + // The current texture no longer references the buffer in this slot + // since we just allocated a new buffer. + mCurrentTexture = INVALID_BUFFER_SLOT; + } returnFlags |= ISurfaceTexture::BUFFER_NEEDS_REALLOCATION; } dpy = mSlots[buf].mEglDisplay; fence = mSlots[buf].mFence; mSlots[buf].mFence = EGL_NO_SYNC_KHR; - } // end lock scope + } if (fence != EGL_NO_SYNC_KHR) { EGLint result = eglClientWaitSyncKHR(dpy, fence, 0, 1000000000); @@ -442,7 +437,6 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, ALOGE("dequeueBuffer: timeout waiting for fence"); } eglDestroySyncKHR(dpy, fence); - } ST_LOGV("dequeueBuffer: returning slot=%d buf=%p flags=%#x", *outBuf, @@ -502,6 +496,9 @@ status_t BufferQueue::queueBuffer(int buf, int64_t timestamp, ST_LOGE("queueBuffer: slot %d is not owned by the client " "(state=%d)", buf, mSlots[buf].mBufferState); return -EINVAL; + } else if (buf == mCurrentTexture) { + ST_LOGE("queueBuffer: slot %d is current!", buf); + return -EINVAL; } else if (!mSlots[buf].mRequestBufferCalled) { ST_LOGE("queueBuffer: slot %d was enqueued without requesting a " "buffer", buf); @@ -541,7 +538,6 @@ status_t BufferQueue::queueBuffer(int buf, int64_t timestamp, mFrameCounter++; mSlots[buf].mFrameNumber = mFrameCounter; - mBufferHasBeenQueued = true; mDequeueCondition.signal(); *outWidth = mDefaultWidth; @@ -651,9 +647,6 @@ status_t BufferQueue::connect(int api, err = -EINVAL; break; } - - mBufferHasBeenQueued = false; - return err; } @@ -694,185 +687,26 @@ status_t BufferQueue::disconnect(int api) { return err; } -void BufferQueue::dump(String8& result) const -{ - char buffer[1024]; - BufferQueue::dump(result, "", buffer, 1024); -} - -void BufferQueue::dump(String8& result, const char* prefix, - char* buffer, size_t SIZE) const -{ - Mutex::Autolock _l(mMutex); - snprintf(buffer, SIZE, - "%snext : {crop=[%d,%d,%d,%d], transform=0x%02x}\n" - ,prefix, mNextCrop.left, mNextCrop.top, mNextCrop.right, - mNextCrop.bottom, mNextTransform - ); - result.append(buffer); - - String8 fifo; - int fifoSize = 0; - Fifo::const_iterator i(mQueue.begin()); - while (i != mQueue.end()) { - snprintf(buffer, SIZE, "%02d ", *i++); - fifoSize++; - fifo.append(buffer); - } - - snprintf(buffer, SIZE, - "%s-BufferQueue mBufferCount=%d, mSynchronousMode=%d, default-size=[%dx%d], " - "mPixelFormat=%d, FIFO(%d)={%s}\n", - prefix, mBufferCount, mSynchronousMode, mDefaultWidth, - mDefaultHeight, mPixelFormat, fifoSize, fifo.string()); - result.append(buffer); - - - struct { - const char * operator()(int state) const { - switch (state) { - case BufferSlot::DEQUEUED: return "DEQUEUED"; - case BufferSlot::QUEUED: return "QUEUED"; - case BufferSlot::FREE: return "FREE"; - case BufferSlot::ACQUIRED: return "ACQUIRED"; - default: return "Unknown"; - } - } - } stateName; - - for (int i=0 ; i":" ", i, - stateName(slot.mBufferState), - slot.mCrop.left, slot.mCrop.top, slot.mCrop.right, - slot.mCrop.bottom, slot.mTransform, slot.mTimestamp - ); - result.append(buffer); - - const sp& buf(slot.mGraphicBuffer); - if (buf != NULL) { - snprintf(buffer, SIZE, - ", %p [%4ux%4u:%4u,%3X]", - buf->handle, buf->width, buf->height, buf->stride, - buf->format); - result.append(buffer); - } - result.append("\n"); - } -} - void BufferQueue::freeBufferLocked(int i) { mSlots[i].mGraphicBuffer = 0; mSlots[i].mBufferState = BufferSlot::FREE; mSlots[i].mFrameNumber = 0; - mSlots[i].mAcquireCalled = false; - - // destroy fence as BufferQueue now takes ownership - if (mSlots[i].mFence != EGL_NO_SYNC_KHR) { - eglDestroySyncKHR(mSlots[i].mEglDisplay, mSlots[i].mFence); - mSlots[i].mFence = EGL_NO_SYNC_KHR; + if (mSlots[i].mEglImage != EGL_NO_IMAGE_KHR) { + eglDestroyImageKHR(mSlots[i].mEglDisplay, mSlots[i].mEglImage); + mSlots[i].mEglImage = EGL_NO_IMAGE_KHR; + mSlots[i].mEglDisplay = EGL_NO_DISPLAY; } } void BufferQueue::freeAllBuffersLocked() { ALOGW_IF(!mQueue.isEmpty(), "freeAllBuffersLocked called but mQueue is not empty"); - mQueue.clear(); - mBufferHasBeenQueued = false; + mCurrentTexture = INVALID_BUFFER_SLOT; for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { freeBufferLocked(i); } } -status_t BufferQueue::acquire(BufferItem *buffer) { - Mutex::Autolock _l(mMutex); - // check if queue is empty - // In asynchronous mode the list is guaranteed to be one buffer - // deep, while in synchronous mode we use the oldest buffer. - if (!mQueue.empty()) { - Fifo::iterator front(mQueue.begin()); - int buf = *front; - - if (mSlots[buf].mAcquireCalled) { - buffer->mGraphicBuffer = NULL; - } - else { - buffer->mGraphicBuffer = mSlots[buf].mGraphicBuffer; - } - buffer->mCrop = mSlots[buf].mCrop; - buffer->mTransform = mSlots[buf].mTransform; - buffer->mScalingMode = mSlots[buf].mScalingMode; - buffer->mFrameNumber = mSlots[buf].mFrameNumber; - buffer->mBuf = buf; - mSlots[buf].mAcquireCalled = true; - - mSlots[buf].mBufferState = BufferSlot::ACQUIRED; - mQueue.erase(front); - } - else { - return -EINVAL; //should be a better return code - } - - return OK; -} - -status_t BufferQueue::releaseBuffer(int buf, EGLDisplay display, - EGLSyncKHR fence) { - Mutex::Autolock _l(mMutex); - - if (buf == INVALID_BUFFER_SLOT) { - return -EINVAL; - } - - mSlots[buf].mEglDisplay = display; - mSlots[buf].mFence = fence; - - // The current buffer becomes FREE if it was still in the queued - // state. If it has already been given to the client - // (synchronous mode), then it stays in DEQUEUED state. - if (mSlots[buf].mBufferState == BufferSlot::QUEUED - || mSlots[buf].mBufferState == BufferSlot::ACQUIRED) { - mSlots[buf].mBufferState = BufferSlot::FREE; - } - mDequeueCondition.signal(); - - return OK; -} - -status_t BufferQueue::consumerDisconnect() { - Mutex::Autolock lock(mMutex); - // Once the SurfaceTexture disconnects, the BufferQueue - // is considered abandoned - mAbandoned = true; - freeAllBuffersLocked(); - mDequeueCondition.signal(); - return OK; -} - -status_t BufferQueue::setDefaultBufferSize(uint32_t w, uint32_t h) -{ - ST_LOGV("setDefaultBufferSize: w=%d, h=%d", w, h); - if (!w || !h) { - ST_LOGE("setDefaultBufferSize: dimensions cannot be 0 (w=%d, h=%d)", - w, h); - return BAD_VALUE; - } - - Mutex::Autolock lock(mMutex); - mDefaultWidth = w; - mDefaultHeight = h; - return OK; -} - -status_t BufferQueue::setBufferCountServer(int bufferCount) { - Mutex::Autolock lock(mMutex); - return setBufferCountServerLocked(bufferCount); -} - void BufferQueue::freeAllBuffersExceptHeadLocked() { ALOGW_IF(!mQueue.isEmpty(), "freeAllBuffersExceptCurrentLocked called but mQueue is not empty"); @@ -881,7 +715,7 @@ void BufferQueue::freeAllBuffersExceptHeadLocked() { Fifo::iterator front(mQueue.begin()); head = *front; } - mBufferHasBeenQueued = false; + mCurrentTexture = INVALID_BUFFER_SLOT; for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { if (i != head) { freeBufferLocked(i); diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp index ee5deb3b20893..a7bfc613aa25f 100644 --- a/libs/gui/SurfaceTexture.cpp +++ b/libs/gui/SurfaceTexture.cpp @@ -97,11 +97,6 @@ static float mtxRot270[16] = { static void mtxMul(float out[16], const float a[16], const float b[16]); -// Get an ID that's unique within this process. -static int32_t createProcessUniqueId() { - static volatile int32_t globalCounter = 0; - return android_atomic_inc(&globalCounter); -} SurfaceTexture::SurfaceTexture(GLuint tex, bool allowSynchronousMode, GLenum texTarget, bool useFenceSync) : @@ -114,13 +109,8 @@ SurfaceTexture::SurfaceTexture(GLuint tex, bool allowSynchronousMode, #else mUseFenceSync(false), #endif - mTexTarget(texTarget), - mAbandoned(false), - mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT) + mTexTarget(texTarget) { - // Choose a name using the PID and a process-unique ID. - mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId()); - BufferQueue::setConsumerName(mName); ST_LOGV("SurfaceTexture"); memcpy(mCurrentTransformMatrix, mtxIdentity, @@ -129,18 +119,28 @@ SurfaceTexture::SurfaceTexture(GLuint tex, bool allowSynchronousMode, SurfaceTexture::~SurfaceTexture() { ST_LOGV("~SurfaceTexture"); - abandon(); + freeAllBuffersLocked(); } status_t SurfaceTexture::setBufferCountServer(int bufferCount) { Mutex::Autolock lock(mMutex); - return BufferQueue::setBufferCountServer(bufferCount); + return setBufferCountServerLocked(bufferCount); } status_t SurfaceTexture::setDefaultBufferSize(uint32_t w, uint32_t h) { - return BufferQueue::setDefaultBufferSize(w, h); + ST_LOGV("setDefaultBufferSize: w=%d, h=%d", w, h); + if (!w || !h) { + ST_LOGE("setDefaultBufferSize: dimensions cannot be 0 (w=%d, h=%d)", + w, h); + return BAD_VALUE; + } + + Mutex::Autolock lock(mMutex); + mDefaultWidth = w; + mDefaultHeight = h; + return OK; } status_t SurfaceTexture::updateTexImage() { @@ -152,35 +152,23 @@ status_t SurfaceTexture::updateTexImage() { return NO_INIT; } - BufferItem item; - // In asynchronous mode the list is guaranteed to be one buffer // deep, while in synchronous mode we use the oldest buffer. - if (acquire(&item) == NO_ERROR) { - int buf = item.mBuf; - // This buffer was newly allocated, so we need to clean up on our side - if (item.mGraphicBuffer != NULL) { - mEGLSlots[buf].mGraphicBuffer = 0; - if (mEGLSlots[buf].mEglImage != EGL_NO_IMAGE_KHR) { - eglDestroyImageKHR(mEGLSlots[buf].mEglDisplay, - mEGLSlots[buf].mEglImage); - mEGLSlots[buf].mEglImage = EGL_NO_IMAGE_KHR; - mEGLSlots[buf].mEglDisplay = EGL_NO_DISPLAY; - } - mEGLSlots[buf].mGraphicBuffer = item.mGraphicBuffer; - } + if (!mQueue.empty()) { + Fifo::iterator front(mQueue.begin()); + int buf = *front; // Update the GL texture object. - EGLImageKHR image = mEGLSlots[buf].mEglImage; + EGLImageKHR image = mSlots[buf].mEglImage; EGLDisplay dpy = eglGetCurrentDisplay(); if (image == EGL_NO_IMAGE_KHR) { - if (item.mGraphicBuffer == 0) { + if (mSlots[buf].mGraphicBuffer == 0) { ST_LOGE("buffer at slot %d is null", buf); return BAD_VALUE; } - image = createImage(dpy, item.mGraphicBuffer); - mEGLSlots[buf].mEglImage = image; - mEGLSlots[buf].mEglDisplay = dpy; + image = createImage(dpy, mSlots[buf].mGraphicBuffer); + mSlots[buf].mEglImage = image; + mSlots[buf].mEglDisplay = dpy; if (image == EGL_NO_IMAGE_KHR) { // NOTE: if dpy was invalid, createImage() is guaranteed to // fail. so we'd end up here. @@ -203,8 +191,6 @@ status_t SurfaceTexture::updateTexImage() { failed = true; } if (failed) { - releaseBuffer(buf, mEGLSlots[buf].mEglDisplay, - mEGLSlots[buf].mFence); return -EINVAL; } @@ -215,37 +201,40 @@ status_t SurfaceTexture::updateTexImage() { if (fence == EGL_NO_SYNC_KHR) { ALOGE("updateTexImage: error creating fence: %#x", eglGetError()); - releaseBuffer(buf, mEGLSlots[buf].mEglDisplay, - mEGLSlots[buf].mFence); return -EINVAL; } glFlush(); - mEGLSlots[mCurrentTexture].mFence = fence; + mSlots[mCurrentTexture].mFence = fence; } } ST_LOGV("updateTexImage: (slot=%d buf=%p) -> (slot=%d buf=%p)", mCurrentTexture, mCurrentTextureBuf != NULL ? mCurrentTextureBuf->handle : 0, - buf, item.mGraphicBuffer->handle); + buf, mSlots[buf].mGraphicBuffer->handle); - // release old buffer - releaseBuffer(mCurrentTexture, - mEGLSlots[mCurrentTexture].mEglDisplay, - mEGLSlots[mCurrentTexture].mFence); + if (mCurrentTexture != INVALID_BUFFER_SLOT) { + // The current buffer becomes FREE if it was still in the queued + // state. If it has already been given to the client + // (synchronous mode), then it stays in DEQUEUED state. + if (mSlots[mCurrentTexture].mBufferState == BufferSlot::QUEUED) { + mSlots[mCurrentTexture].mBufferState = BufferSlot::FREE; + } + } // Update the SurfaceTexture state. mCurrentTexture = buf; - mCurrentTextureBuf = mEGLSlots[buf].mGraphicBuffer; - mCurrentCrop = item.mCrop; - mCurrentTransform = item.mTransform; - mCurrentScalingMode = item.mScalingMode; - mCurrentTimestamp = item.mTimestamp; + mCurrentTextureBuf = mSlots[buf].mGraphicBuffer; + mCurrentCrop = mSlots[buf].mCrop; + mCurrentTransform = mSlots[buf].mTransform; + mCurrentScalingMode = mSlots[buf].mScalingMode; + mCurrentTimestamp = mSlots[buf].mTimestamp; computeCurrentTransformMatrix(); // Now that we've passed the point at which failures can happen, // it's safe to remove the buffer from the front of the queue. - + mQueue.erase(front); + mDequeueCondition.signal(); } else { // We always bind the texture even if we don't update its contents. glBindTexture(mTexTarget, mTexName); @@ -311,7 +300,7 @@ void SurfaceTexture::computeCurrentTransformMatrix() { } } - sp& buf(mCurrentTextureBuf); + sp& buf(mSlots[mCurrentTexture].mGraphicBuffer); float tx, ty, sx, sy; if (!mCurrentCrop.isEmpty()) { // In order to prevent bilinear sampling at the of the crop rectangle we @@ -383,7 +372,7 @@ void SurfaceTexture::setFrameAvailableListener( const sp& listener) { ST_LOGV("setFrameAvailableListener"); Mutex::Autolock lock(mMutex); - BufferQueue::setFrameAvailableListener(listener); + mFrameAvailableListener = listener; } EGLImageKHR SurfaceTexture::createImage(EGLDisplay dpy, @@ -424,33 +413,22 @@ uint32_t SurfaceTexture::getCurrentScalingMode() const { bool SurfaceTexture::isSynchronousMode() const { Mutex::Autolock lock(mMutex); - return BufferQueue::isSynchronousMode(); + return mSynchronousMode; } + + void SurfaceTexture::abandon() { Mutex::Autolock lock(mMutex); + mQueue.clear(); mAbandoned = true; mCurrentTextureBuf.clear(); - - // destroy all egl buffers - for (int i =0; i < NUM_BUFFER_SLOTS; i++) { - mEGLSlots[i].mGraphicBuffer = 0; - if (mEGLSlots[i].mEglImage != EGL_NO_IMAGE_KHR) { - eglDestroyImageKHR(mEGLSlots[i].mEglDisplay, - mEGLSlots[i].mEglImage); - mEGLSlots[i].mEglImage = EGL_NO_IMAGE_KHR; - mEGLSlots[i].mEglDisplay = EGL_NO_DISPLAY; - } - } - - // disconnect from the BufferQueue - BufferQueue::consumerDisconnect(); + freeAllBuffersLocked(); + mDequeueCondition.signal(); } void SurfaceTexture::setName(const String8& name) { - Mutex::Autolock _l(mMutex); mName = name; - BufferQueue::setConsumerName(name); } void SurfaceTexture::dump(String8& result) const @@ -463,19 +441,68 @@ void SurfaceTexture::dump(String8& result, const char* prefix, char* buffer, size_t SIZE) const { Mutex::Autolock _l(mMutex); - snprintf(buffer, SIZE, "%smTexName=%d\n", prefix, mTexName); + snprintf(buffer, SIZE, + "%smBufferCount=%d, mSynchronousMode=%d, default-size=[%dx%d], " + "mPixelFormat=%d, mTexName=%d\n", + prefix, mBufferCount, mSynchronousMode, mDefaultWidth, + mDefaultHeight, mPixelFormat, mTexName); result.append(buffer); + String8 fifo; + int fifoSize = 0; + Fifo::const_iterator i(mQueue.begin()); + while (i != mQueue.end()) { + snprintf(buffer, SIZE, "%02d ", *i++); + fifoSize++; + fifo.append(buffer); + } + snprintf(buffer, SIZE, - "%snext : {crop=[%d,%d,%d,%d], transform=0x%02x, current=%d}\n" - ,prefix, mCurrentCrop.left, + "%scurrent: {crop=[%d,%d,%d,%d], transform=0x%02x, current=%d}\n" + "%snext : {crop=[%d,%d,%d,%d], transform=0x%02x, FIFO(%d)={%s}}\n" + , + prefix, mCurrentCrop.left, mCurrentCrop.top, mCurrentCrop.right, mCurrentCrop.bottom, - mCurrentTransform, mCurrentTexture + mCurrentTransform, mCurrentTexture, + prefix, mNextCrop.left, mNextCrop.top, mNextCrop.right, + mNextCrop.bottom, mNextTransform, fifoSize, fifo.string() ); result.append(buffer); + struct { + const char * operator()(int state) const { + switch (state) { + case BufferSlot::DEQUEUED: return "DEQUEUED"; + case BufferSlot::QUEUED: return "QUEUED"; + case BufferSlot::FREE: return "FREE"; + default: return "Unknown"; + } + } + } stateName; - BufferQueue::dump(result, prefix, buffer, SIZE); + for (int i=0 ; i":" ", i, + stateName(slot.mBufferState), + slot.mCrop.left, slot.mCrop.top, slot.mCrop.right, + slot.mCrop.bottom, slot.mTransform, slot.mTimestamp + ); + result.append(buffer); + + const sp& buf(slot.mGraphicBuffer); + if (buf != NULL) { + snprintf(buffer, SIZE, + ", %p [%4ux%4u:%4u,%3X]", + buf->handle, buf->width, buf->height, buf->stride, + buf->format); + result.append(buffer); + } + result.append("\n"); + } } static void mtxMul(float out[16], const float a[16], const float b[16]) { From 5348069b4a0a1d4b3f56e356e0442395453539c9 Mon Sep 17 00:00:00 2001 From: John Wang Date: Fri, 24 Feb 2012 22:26:34 -0800 Subject: [PATCH 007/132] Prevent dial() return null in a racing condition. The racing condition happens between dial() returns and the first GET_CURRENT_CALLS query gets handled. If GET_CURRENT_CALLS gets handled before dial() finishs, the pendingMO can be set to null in handlePollCalls() so that dial() will return null. This null connection causes error in PhoneUtils.placeCall(). The Synchronized dial() and handlePollCalls() Methods will make sure the dial() returns before the first GET_CURRENT_CALLS gets handled. bug:6028290 Change-Id: I41b024760acb7dd13b342866180dffe3fdbe1c03 --- .../com/android/internal/telephony/gsm/GsmCallTracker.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java index 425afe6527586..b4e0775b51894 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java @@ -167,7 +167,7 @@ public final class GsmCallTracker extends CallTracker { /** * clirMode is one of the CLIR_ constants */ - Connection + synchronized Connection dial (String dialString, int clirMode, UUSInfo uusInfo) throws CallStateException { // note that this triggers call state changed notif clearDisconnected(); @@ -406,7 +406,7 @@ public final class GsmCallTracker extends CallTracker { } } - protected void + protected synchronized void handlePollCalls(AsyncResult ar) { List polledCalls; From 4c3f22d18a7cee2063d5ce1be64379a777106a1c Mon Sep 17 00:00:00 2001 From: Craig Mautner Date: Mon, 27 Feb 2012 16:15:13 -0800 Subject: [PATCH 008/132] Fix bug introduced when moving animation step out from between assignments to wasAnimating and nowAnimating. Now wasAnimating once again contains the animation state prior to the animation step. Change-Id: I2b53bd3f62228183233ab36f0ebe44c0344d2351 --- services/java/com/android/server/wm/WindowManagerService.java | 2 +- services/java/com/android/server/wm/WindowState.java | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index 21cb3e8dd975f..96142a1bb29e8 100644 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -7685,7 +7685,7 @@ public class WindowManagerService extends IWindowManager.Stub } } - final boolean wasAnimating = w.mAnimating; + final boolean wasAnimating = w.mWasAnimating; // If the window has moved due to its containing // content frame changing, then we'd like to animate diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java index d7a7cb0d34a3c..fc435f71b4823 100644 --- a/services/java/com/android/server/wm/WindowState.java +++ b/services/java/com/android/server/wm/WindowState.java @@ -91,6 +91,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { boolean mAttachedHidden; // is our parent window hidden? boolean mLastHidden; // was this window last hidden? boolean mWallpaperVisible; // for wallpaper, what was last vis report? + boolean mWasAnimating; // Were we animating going into the most recent animation step? /** * The window size that was requested by the application. These are in @@ -979,6 +980,9 @@ final class WindowState implements WindowManagerPolicy.WindowState { // This must be called while inside a transaction. Returns true if // there is more animation to run. boolean stepAnimationLocked(long currentTime) { + // Save the animation state as it was before this step so WindowManagerService can tell if + // we just started or just stopped animating by comparing mWasAnimating with isAnimating(). + mWasAnimating = isAnimating(); if (!mService.mDisplayFrozen && mService.mPolicy.isScreenOnFully()) { // We will run animations as long as the display isn't frozen. From 515fa33bcd92e600474ed0b2c85fd2730390f0e1 Mon Sep 17 00:00:00 2001 From: Craig Mautner Date: Thu, 1 Mar 2012 18:59:14 -0800 Subject: [PATCH 009/132] Separate animation steps into start, step and finish phases. Fixes bug 6089126. Change-Id: Iafbde36ff719640335a7ecf762e1d991cf7915e4 --- .../com/android/server/wm/AppWindowToken.java | 42 +-- .../server/wm/ScreenRotationAnimation.java | 277 +++++++++--------- .../server/wm/WindowManagerService.java | 70 ++++- .../com/android/server/wm/WindowState.java | 36 ++- 4 files changed, 247 insertions(+), 178 deletions(-) diff --git a/services/java/com/android/server/wm/AppWindowToken.java b/services/java/com/android/server/wm/AppWindowToken.java index 0e3d20aa35c0c..b84fbdbd6629b 100644 --- a/services/java/com/android/server/wm/AppWindowToken.java +++ b/services/java/com/android/server/wm/AppWindowToken.java @@ -37,7 +37,7 @@ import java.util.ArrayList; * Version of WindowToken that is specifically for a particular application (or * really activity) that is displaying windows. */ -class AppWindowToken extends WindowToken { +class AppWindowToken extends WindowToken implements WindowManagerService.StepAnimator { // Non-null only for application tokens. final IApplicationToken appToken; @@ -195,8 +195,28 @@ class AppWindowToken extends WindowToken { } } + @Override + public boolean stepAnimation(long currentTime) { + if (animation == null) { + return false; + } + transformation.clear(); + final boolean more = animation.getTransformation(currentTime, transformation); + if (WindowManagerService.DEBUG_ANIM) Slog.v( + WindowManagerService.TAG, "Stepped animation in " + this + + ": more=" + more + ", xform=" + transformation); + if (!more) { + animation = null; + if (WindowManagerService.DEBUG_ANIM) Slog.v( + WindowManagerService.TAG, "Finished animation in " + this + + " @ " + currentTime); + } + hasTransformation = more; + return more; + } + // This must be called while inside a transaction. - boolean stepAnimationLocked(long currentTime, int dw, int dh) { + boolean startAndFinishAnimationLocked(long currentTime, int dw, int dh) { if (!service.mDisplayFrozen && service.mPolicy.isScreenOnFully()) { // We will run animations as long as the display isn't frozen. @@ -219,21 +239,8 @@ class AppWindowToken extends WindowToken { animation.setStartTime(currentTime); animating = true; } - transformation.clear(); - final boolean more = animation.getTransformation( - currentTime, transformation); - if (WindowManagerService.DEBUG_ANIM) Slog.v( - WindowManagerService.TAG, "Stepped animation in " + this + - ": more=" + more + ", xform=" + transformation); - if (more) { - // we're done! - hasTransformation = true; - return true; - } - if (WindowManagerService.DEBUG_ANIM) Slog.v( - WindowManagerService.TAG, "Finished animation in " + this + - " @ " + currentTime); - animation = null; + // we're done! + return true; } } else if (animation != null) { // If the display is frozen, and there is a pending animation, @@ -369,6 +376,7 @@ class AppWindowToken extends WindowToken { return null; } + @Override void dump(PrintWriter pw, String prefix) { super.dump(pw, prefix); if (appToken != null) { diff --git a/services/java/com/android/server/wm/ScreenRotationAnimation.java b/services/java/com/android/server/wm/ScreenRotationAnimation.java index 04a039fbcd56a..1335a44c88273 100644 --- a/services/java/com/android/server/wm/ScreenRotationAnimation.java +++ b/services/java/com/android/server/wm/ScreenRotationAnimation.java @@ -29,7 +29,7 @@ import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.view.animation.Transformation; -class ScreenRotationAnimation { +class ScreenRotationAnimation implements WindowManagerService.StepAnimator { static final String TAG = "ScreenRotationAnimation"; static final boolean DEBUG_STATE = false; static final boolean DEBUG_TRANSFORMS = false; @@ -97,6 +97,12 @@ class ScreenRotationAnimation { final Matrix mSnapshotFinalMatrix = new Matrix(); final Matrix mTmpMatrix = new Matrix(); final float[] mTmpFloats = new float[9]; + private boolean mMoreRotateEnter; + private boolean mMoreRotateExit; + private boolean mMoreFinishEnter; + private boolean mMoreFinishExit; + private boolean mMoreStartEnter; + private boolean mMoreStartExit; public void printTo(String prefix, PrintWriter pw) { pw.print(prefix); pw.print("mSurface="); pw.print(mSurface); @@ -456,7 +462,144 @@ class ScreenRotationAnimation { && mRotateEnterAnimation != null || mRotateExitAnimation != null; } + @Override public boolean stepAnimation(long now) { + + if (mFinishAnimReady && mFinishAnimStartTime < 0) { + if (DEBUG_STATE) Slog.v(TAG, "Step: finish anim now ready"); + mFinishAnimStartTime = now; + } + + // If the start animation is no longer running, we want to keep its + // transformation intact until the finish animation also completes. + + mMoreStartExit = false; + if (mStartExitAnimation != null) { + mStartExitTransformation.clear(); + mMoreStartExit = mStartExitAnimation.getTransformation(now, mStartExitTransformation); + if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped start exit: " + mStartExitTransformation); + if (!mMoreStartExit) { + if (DEBUG_STATE) Slog.v(TAG, "Start exit animation done!"); + mStartExitAnimation.cancel(); + mStartExitAnimation = null; + } + } + + mMoreStartEnter = false; + if (mStartEnterAnimation != null) { + mStartEnterTransformation.clear(); + mMoreStartEnter = mStartEnterAnimation.getTransformation(now, mStartEnterTransformation); + if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped start enter: " + mStartEnterTransformation); + if (!mMoreStartEnter) { + if (DEBUG_STATE) Slog.v(TAG, "Start enter animation done!"); + mStartEnterAnimation.cancel(); + mStartEnterAnimation = null; + } + } + + long finishNow = mFinishAnimReady ? (now - mFinishAnimStartTime) : 0; + if (DEBUG_STATE) Slog.v(TAG, "Step: finishNow=" + finishNow); + + mFinishExitTransformation.clear(); + mMoreFinishExit = false; + if (mFinishExitAnimation != null) { + mMoreFinishExit = mFinishExitAnimation.getTransformation(finishNow, mFinishExitTransformation); + if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped finish exit: " + mFinishExitTransformation); + if (!mMoreStartExit && !mMoreFinishExit) { + if (DEBUG_STATE) Slog.v(TAG, "Finish exit animation done, clearing start/finish anims!"); + mStartExitTransformation.clear(); + mFinishExitAnimation.cancel(); + mFinishExitAnimation = null; + mFinishExitTransformation.clear(); + } + } + + mFinishEnterTransformation.clear(); + mMoreFinishEnter = false; + if (mFinishEnterAnimation != null) { + mMoreFinishEnter = mFinishEnterAnimation.getTransformation(finishNow, mFinishEnterTransformation); + if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped finish enter: " + mFinishEnterTransformation); + if (!mMoreStartEnter && !mMoreFinishEnter) { + if (DEBUG_STATE) Slog.v(TAG, "Finish enter animation done, clearing start/finish anims!"); + mStartEnterTransformation.clear(); + mFinishEnterAnimation.cancel(); + mFinishEnterAnimation = null; + mFinishEnterTransformation.clear(); + } + } + + mRotateExitTransformation.clear(); + mMoreRotateExit = false; + if (mRotateExitAnimation != null) { + mMoreRotateExit = mRotateExitAnimation.getTransformation(now, mRotateExitTransformation); + if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped rotate exit: " + mRotateExitTransformation); + } + + if (!mMoreFinishExit && !mMoreRotateExit) { + if (DEBUG_STATE) Slog.v(TAG, "Rotate exit animation done!"); + mRotateExitAnimation.cancel(); + mRotateExitAnimation = null; + mRotateExitTransformation.clear(); + } + + mRotateEnterTransformation.clear(); + mMoreRotateEnter = false; + if (mRotateEnterAnimation != null) { + mMoreRotateEnter = mRotateEnterAnimation.getTransformation(now, mRotateEnterTransformation); + if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped rotate enter: " + mRotateEnterTransformation); + } + + if (!mMoreFinishEnter && !mMoreRotateEnter) { + if (DEBUG_STATE) Slog.v(TAG, "Rotate enter animation done!"); + mRotateEnterAnimation.cancel(); + mRotateEnterAnimation = null; + mRotateEnterTransformation.clear(); + } + + mExitTransformation.set(mRotateExitTransformation); + mExitTransformation.compose(mStartExitTransformation); + mExitTransformation.compose(mFinishExitTransformation); + + mEnterTransformation.set(mRotateEnterTransformation); + mEnterTransformation.compose(mStartEnterTransformation); + mEnterTransformation.compose(mFinishEnterTransformation); + + if (DEBUG_TRANSFORMS) Slog.v(TAG, "Final exit: " + mExitTransformation); + if (DEBUG_TRANSFORMS) Slog.v(TAG, "Final enter: " + mEnterTransformation); + + final boolean more = mMoreStartEnter || mMoreStartExit || mMoreFinishEnter + || mMoreFinishExit || mMoreRotateEnter || mMoreRotateExit || !mFinishAnimReady; + + mSnapshotFinalMatrix.setConcat(mExitTransformation.getMatrix(), mSnapshotInitialMatrix); + + if (DEBUG_STATE) Slog.v(TAG, "Step: more=" + more); + + return more; + } + + void updateSurfaces() { + if (!mMoreStartExit && !mMoreFinishExit && !mMoreRotateExit) { + if (mSurface != null) { + if (DEBUG_STATE) Slog.v(TAG, "Exit animations done, hiding screenshot surface"); + mSurface.hide(); + } + } + + if (!mMoreStartEnter && !mMoreFinishEnter && !mMoreRotateEnter) { + if (mBlackFrame != null) { + if (DEBUG_STATE) Slog.v(TAG, "Enter animations done, hiding black frame"); + mBlackFrame.hide(); + } + } else { + if (mBlackFrame != null) { + mBlackFrame.setMatrix(mEnterTransformation.getMatrix()); + } + } + + setSnapshotTransform(mSnapshotFinalMatrix, mExitTransformation.getAlpha()); + } + + public boolean startAndFinishAnimationLocked(long now) { if (!isAnimating()) { if (DEBUG_STATE) Slog.v(TAG, "Step: no animations running"); return false; @@ -484,136 +627,8 @@ class ScreenRotationAnimation { } mAnimRunning = true; } - - if (mFinishAnimReady && mFinishAnimStartTime < 0) { - if (DEBUG_STATE) Slog.v(TAG, "Step: finish anim now ready"); - mFinishAnimStartTime = now; - } - - // If the start animation is no longer running, we want to keep its - // transformation intact until the finish animation also completes. - - boolean moreStartExit = false; - if (mStartExitAnimation != null) { - mStartExitTransformation.clear(); - moreStartExit = mStartExitAnimation.getTransformation(now, mStartExitTransformation); - if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped start exit: " + mStartExitTransformation); - if (!moreStartExit) { - if (DEBUG_STATE) Slog.v(TAG, "Start exit animation done!"); - mStartExitAnimation.cancel(); - mStartExitAnimation = null; - } - } - - boolean moreStartEnter = false; - if (mStartEnterAnimation != null) { - mStartEnterTransformation.clear(); - moreStartEnter = mStartEnterAnimation.getTransformation(now, mStartEnterTransformation); - if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped start enter: " + mStartEnterTransformation); - if (!moreStartEnter) { - if (DEBUG_STATE) Slog.v(TAG, "Start enter animation done!"); - mStartEnterAnimation.cancel(); - mStartEnterAnimation = null; - } - } - - long finishNow = mFinishAnimReady ? (now - mFinishAnimStartTime) : 0; - if (DEBUG_STATE) Slog.v(TAG, "Step: finishNow=" + finishNow); - - mFinishExitTransformation.clear(); - boolean moreFinishExit = false; - if (mFinishExitAnimation != null) { - moreFinishExit = mFinishExitAnimation.getTransformation(finishNow, mFinishExitTransformation); - if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped finish exit: " + mFinishExitTransformation); - if (!moreStartExit && !moreFinishExit) { - if (DEBUG_STATE) Slog.v(TAG, "Finish exit animation done, clearing start/finish anims!"); - mStartExitTransformation.clear(); - mFinishExitAnimation.cancel(); - mFinishExitAnimation = null; - mFinishExitTransformation.clear(); - } - } - - mFinishEnterTransformation.clear(); - boolean moreFinishEnter = false; - if (mFinishEnterAnimation != null) { - moreFinishEnter = mFinishEnterAnimation.getTransformation(finishNow, mFinishEnterTransformation); - if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped finish enter: " + mFinishEnterTransformation); - if (!moreStartEnter && !moreFinishEnter) { - if (DEBUG_STATE) Slog.v(TAG, "Finish enter animation done, clearing start/finish anims!"); - mStartEnterTransformation.clear(); - mFinishEnterAnimation.cancel(); - mFinishEnterAnimation = null; - mFinishEnterTransformation.clear(); - } - } - - mRotateExitTransformation.clear(); - boolean moreRotateExit = false; - if (mRotateExitAnimation != null) { - moreRotateExit = mRotateExitAnimation.getTransformation(now, mRotateExitTransformation); - if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped rotate exit: " + mRotateExitTransformation); - } - - if (!moreFinishExit && !moreRotateExit) { - if (DEBUG_STATE) Slog.v(TAG, "Rotate exit animation done!"); - mRotateExitAnimation.cancel(); - mRotateExitAnimation = null; - mRotateExitTransformation.clear(); - } - - mRotateEnterTransformation.clear(); - boolean moreRotateEnter = false; - if (mRotateEnterAnimation != null) { - moreRotateEnter = mRotateEnterAnimation.getTransformation(now, mRotateEnterTransformation); - if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped rotate enter: " + mRotateEnterTransformation); - } - - if (!moreFinishEnter && !moreRotateEnter) { - if (DEBUG_STATE) Slog.v(TAG, "Rotate enter animation done!"); - mRotateEnterAnimation.cancel(); - mRotateEnterAnimation = null; - mRotateEnterTransformation.clear(); - } - - mExitTransformation.set(mRotateExitTransformation); - mExitTransformation.compose(mStartExitTransformation); - mExitTransformation.compose(mFinishExitTransformation); - - mEnterTransformation.set(mRotateEnterTransformation); - mEnterTransformation.compose(mStartEnterTransformation); - mEnterTransformation.compose(mFinishEnterTransformation); - - if (DEBUG_TRANSFORMS) Slog.v(TAG, "Final exit: " + mExitTransformation); - if (DEBUG_TRANSFORMS) Slog.v(TAG, "Final enter: " + mEnterTransformation); - - if (!moreStartExit && !moreFinishExit && !moreRotateExit) { - if (mSurface != null) { - if (DEBUG_STATE) Slog.v(TAG, "Exit animations done, hiding screenshot surface"); - mSurface.hide(); - } - } - - if (!moreStartEnter && !moreFinishEnter && !moreRotateEnter) { - if (mBlackFrame != null) { - if (DEBUG_STATE) Slog.v(TAG, "Enter animations done, hiding black frame"); - mBlackFrame.hide(); - } - } else { - if (mBlackFrame != null) { - mBlackFrame.setMatrix(mEnterTransformation.getMatrix()); - } - } - - mSnapshotFinalMatrix.setConcat(mExitTransformation.getMatrix(), mSnapshotInitialMatrix); - setSnapshotTransform(mSnapshotFinalMatrix, mExitTransformation.getAlpha()); - - final boolean more = moreStartEnter || moreStartExit || moreFinishEnter || moreFinishExit - || moreRotateEnter || moreRotateExit || !mFinishAnimReady; - - if (DEBUG_STATE) Slog.v(TAG, "Step: more=" + more); - - return more; + + return true; } public Transformation getEnterTransformation() { diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index 008793c453bb0..6221b9028e18c 100644 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -617,6 +617,18 @@ public class WindowManagerService extends IWindowManager.Stub final AnimationRunnable mAnimationRunnable = new AnimationRunnable(); boolean mAnimationScheduled; + interface StepAnimator { + /** + * Continue the stepping of an ongoing animation. When the animation completes this method + * must disable the animation on the StepAnimator. + * @param currentTime Animation time in milliseconds. Use SystemClock.uptimeMillis(). + * @return True if the animation is still going on, false if the animation has completed + * and stepAnimation has cleared the animation locally. + */ + boolean stepAnimation(long currentTime); + } + final ArrayList mStepAnimators = new ArrayList(); + final class DragInputEventReceiver extends InputEventReceiver { public DragInputEventReceiver(InputChannel inputChannel, Looper looper) { super(inputChannel, looper); @@ -7614,6 +7626,20 @@ public class WindowManagerService extends IWindowManager.Stub } } + /** + * Run through each of the animating objects saved in mStepAnimators. + */ + private void stepAnimations() { + final long currentTime = SystemClock.uptimeMillis(); + for (final StepAnimator stepAnimator : mStepAnimators) { + final boolean more = stepAnimator.stepAnimation(currentTime); + if (DEBUG_ANIM) { + Slog.v(TAG, "stepAnimations: " + currentTime + ": Stepped " + stepAnimator + + (more ? " more" : " done")); + } + } + } + /** * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method. * Update animations of all applications, including those associated with exiting/removed apps. @@ -7621,31 +7647,33 @@ public class WindowManagerService extends IWindowManager.Stub * @param currentTime The time which animations use for calculating transitions. * @param innerDw Width of app window. * @param innerDh Height of app window. - * @return true if rotation has stopped, false otherwise */ private void updateWindowsAppsAndRotationAnimationsLocked(long currentTime, int innerDw, int innerDh) { int i; - for (i = mWindows.size() - 1; i >= 0; i--) { - mInnerFields.mAnimating |= mWindows.get(i).stepAnimationLocked(currentTime); - } - final int NAT = mAppTokens.size(); for (i=0; i=0; i--) { - pw.print(" App #"); pw.print(i); pw.print(": "); - pw.println(mAppTokens.get(i)); + pw.print(" App #"); pw.print(i); pw.println(": "); + mAppTokens.get(i).dump(pw, " "); } } if (mFinishedStarting.size() > 0) { diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java index eeecad1da205d..b9ee660f2f317 100644 --- a/services/java/com/android/server/wm/WindowState.java +++ b/services/java/com/android/server/wm/WindowState.java @@ -54,7 +54,8 @@ import java.util.ArrayList; /** * A window in the window manager. */ -final class WindowState implements WindowManagerPolicy.WindowState { +final class WindowState implements WindowManagerPolicy.WindowState, + WindowManagerService.StepAnimator { static final boolean DEBUG_VISIBILITY = WindowManagerService.DEBUG_VISIBILITY; static final boolean SHOW_TRANSACTIONS = WindowManagerService.SHOW_TRANSACTIONS; static final boolean SHOW_LIGHT_TRANSACTIONS = WindowManagerService.SHOW_LIGHT_TRANSACTIONS; @@ -977,9 +978,26 @@ final class WindowState implements WindowManagerPolicy.WindowState { return true; } + @Override + public boolean stepAnimation(long currentTime) { + if ((mAnimation == null) || !mLocalAnimating) { + return false; + } + mTransformation.clear(); + final boolean more = mAnimation.getTransformation(currentTime, mTransformation); + if (WindowManagerService.DEBUG_ANIM) Slog.v( + WindowManagerService.TAG, "Stepped animation in " + this + + ": more=" + more + ", xform=" + mTransformation); + if (!more) { + mAnimation.cancel(); + mAnimation = null; + } + return more; + } + // This must be called while inside a transaction. Returns true if // there is more animation to run. - boolean stepAnimationLocked(long currentTime) { + boolean startAndFinishAnimationLocked(long currentTime) { // Save the animation state as it was before this step so WindowManagerService can tell if // we just started or just stopped animating by comparing mWasAnimating with isAnimating(). mWasAnimating = mAnimating; @@ -1001,24 +1019,12 @@ final class WindowState implements WindowManagerPolicy.WindowState { mLocalAnimating = true; mAnimating = true; } - mTransformation.clear(); - final boolean more = mAnimation.getTransformation( - currentTime, mTransformation); - if (WindowManagerService.DEBUG_ANIM) Slog.v( - WindowManagerService.TAG, "Stepped animation in " + this + - ": more=" + more + ", xform=" + mTransformation); - if (more) { - // we're not done! + if ((mAnimation != null) && mLocalAnimating) { return true; } if (WindowManagerService.DEBUG_ANIM) Slog.v( WindowManagerService.TAG, "Finished animation in " + this + " @ " + currentTime); - - if (mAnimation != null) { - mAnimation.cancel(); - mAnimation = null; - } //WindowManagerService.this.dump(); } mHasLocalTransformation = false; From a7a99653ad8370b7dc6e09824de0dde35c2e2d96 Mon Sep 17 00:00:00 2001 From: Daniel Lam Date: Fri, 2 Mar 2012 10:17:34 -0800 Subject: [PATCH 010/132] BufferQueue: fixed acquire operation Bug: 6082872 Change-Id: I897dc61eb84fed953e51f97871cd3ae6321505d4 --- libs/gui/BufferQueue.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp index d76168023a62c..f0641e08b1ace 100644 --- a/libs/gui/BufferQueue.cpp +++ b/libs/gui/BufferQueue.cpp @@ -828,6 +828,7 @@ status_t BufferQueue::acquire(BufferItem *buffer) { buffer->mTransform = mSlots[buf].mTransform; buffer->mScalingMode = mSlots[buf].mScalingMode; buffer->mFrameNumber = mSlots[buf].mFrameNumber; + buffer->mTimestamp = mSlots[buf].mTimestamp; buffer->mBuf = buf; mSlots[buf].mAcquireCalled = true; From 169eed9f624060fb90eb753b18e971dd2e035b82 Mon Sep 17 00:00:00 2001 From: Romain Guy Date: Fri, 2 Mar 2012 13:37:47 -0800 Subject: [PATCH 011/132] Deferred layer updates Change-Id: I83d9e564fe274db658dcee9e0cc5bbf9223ebb49 --- core/java/android/view/GLES20Canvas.java | 9 +++ core/java/android/view/GLES20RenderLayer.java | 8 +++ .../java/android/view/GLES20TextureLayer.java | 5 ++ core/java/android/view/HardwareLayer.java | 10 +++ core/java/android/view/TextureView.java | 2 +- core/java/android/view/View.java | 65 ++++++++----------- core/jni/android_view_GLES20Canvas.cpp | 10 ++- libs/hwui/Layer.h | 24 +++++++ libs/hwui/OpenGLRenderer.cpp | 18 +++++ 9 files changed, 112 insertions(+), 39 deletions(-) diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java index ee0fa86642e5e..1f75e70a1d4ae 100644 --- a/core/java/android/view/GLES20Canvas.java +++ b/core/java/android/view/GLES20Canvas.java @@ -157,6 +157,8 @@ class GLES20Canvas extends HardwareCanvas { static native void nDestroyLayer(int layerId); static native void nDestroyLayerDeferred(int layerId); static native void nFlushLayer(int layerId); + static native void nUpdateRenderLayer(int layerId, int renderer, int displayList, + int left, int top, int right, int bottom); static native boolean nCopyLayer(int layerId, int bitmap); /////////////////////////////////////////////////////////////////////////// @@ -191,6 +193,13 @@ class GLES20Canvas extends HardwareCanvas { private static native int nGetMaximumTextureWidth(); private static native int nGetMaximumTextureHeight(); + /** + * Returns the native OpenGLRenderer object. + */ + int getRenderer() { + return mRenderer; + } + /////////////////////////////////////////////////////////////////////////// // Setup /////////////////////////////////////////////////////////////////////////// diff --git a/core/java/android/view/GLES20RenderLayer.java b/core/java/android/view/GLES20RenderLayer.java index 23a7166215899..c727a367180d5 100644 --- a/core/java/android/view/GLES20RenderLayer.java +++ b/core/java/android/view/GLES20RenderLayer.java @@ -18,6 +18,7 @@ package android.view; import android.graphics.Canvas; import android.graphics.Matrix; +import android.graphics.Rect; /** * An OpenGL ES 2.0 implementation of {@link HardwareLayer}. This @@ -95,4 +96,11 @@ class GLES20RenderLayer extends GLES20Layer { @Override void setTransform(Matrix matrix) { } + + @Override + void redraw(DisplayList displayList, Rect dirtyRect) { + GLES20Canvas.nUpdateRenderLayer(mLayer, mCanvas.getRenderer(), + ((GLES20DisplayList) displayList).getNativeDisplayList(), + dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom); + } } diff --git a/core/java/android/view/GLES20TextureLayer.java b/core/java/android/view/GLES20TextureLayer.java index 6c41023c98bb3..cbb908bf34941 100644 --- a/core/java/android/view/GLES20TextureLayer.java +++ b/core/java/android/view/GLES20TextureLayer.java @@ -18,6 +18,7 @@ package android.view; import android.graphics.Canvas; import android.graphics.Matrix; +import android.graphics.Rect; import android.graphics.SurfaceTexture; /** @@ -81,4 +82,8 @@ class GLES20TextureLayer extends GLES20Layer { void setTransform(Matrix matrix) { GLES20Canvas.nSetTextureLayerTransform(mLayer, matrix.native_instance); } + + @Override + void redraw(DisplayList displayList, Rect dirtyRect) { + } } diff --git a/core/java/android/view/HardwareLayer.java b/core/java/android/view/HardwareLayer.java index d5666f37d7ab5..49450bd82bb84 100644 --- a/core/java/android/view/HardwareLayer.java +++ b/core/java/android/view/HardwareLayer.java @@ -19,6 +19,7 @@ package android.view; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Matrix; +import android.graphics.Rect; /** * A hardware layer can be used to render graphics operations into a hardware @@ -163,4 +164,13 @@ abstract class HardwareLayer { * @param matrix The transform to apply to the layer. */ abstract void setTransform(Matrix matrix); + + /** + * Specifies the display list to use to refresh the layer. + * + * @param displayList The display list containing the drawing commands to + * execute in this layer + * @param dirtyRect The dirty region of the layer that needs to be redrawn + */ + abstract void redraw(DisplayList displayList, Rect dirtyRect); } diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java index 74916f0516354..865f9d27976e4 100644 --- a/core/java/android/view/TextureView.java +++ b/core/java/android/view/TextureView.java @@ -315,7 +315,7 @@ public class TextureView extends View { } @Override - HardwareLayer getHardwareLayer() { + HardwareLayer getHardwareLayer(boolean immediateRefresh) { if (mLayer == null) { if (mAttachInfo == null || mAttachInfo.mHardwareRenderer == null) { return null; diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index f7dc73cb4daeb..49f6023d1b3ba 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -10123,7 +10123,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal * dynamic. */ boolean hasStaticLayer() { - return mLayerType == LAYER_TYPE_NONE; + return true; } /** @@ -10170,7 +10170,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled() && mAttachInfo.mHardwareRenderer.validate()) { - getHardwareLayer(); + getHardwareLayer(true); } break; case LAYER_TYPE_SOFTWARE: @@ -10192,7 +10192,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal * * @return A HardwareLayer ready to render, or null if an error occurred. */ - HardwareLayer getHardwareLayer() { + HardwareLayer getHardwareLayer(boolean immediateRefresh) { if (mAttachInfo == null || mAttachInfo.mHardwareRenderer == null || !mAttachInfo.mHardwareRenderer.isEnabled()) { return null; @@ -10222,41 +10222,32 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal return null; } - HardwareCanvas currentCanvas = mAttachInfo.mHardwareCanvas; - final HardwareCanvas canvas = mHardwareLayer.start(currentCanvas); - - // Make sure all the GPU resources have been properly allocated - if (canvas == null) { - mHardwareLayer.end(currentCanvas); - return null; - } - - mAttachInfo.mHardwareCanvas = canvas; - try { - canvas.setViewport(width, height); - canvas.onPreDraw(mLocalDirtyRect); + if (!immediateRefresh) { + mHardwareLayer.redraw(getDisplayList(), mLocalDirtyRect); mLocalDirtyRect.setEmpty(); - - final int restoreCount = canvas.save(); - - computeScroll(); - canvas.translate(-mScrollX, -mScrollY); - - mPrivateFlags |= DRAWN | DRAWING_CACHE_VALID; - - // Fast path for layouts with no backgrounds - if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) { - mPrivateFlags &= ~DIRTY_MASK; - dispatchDraw(canvas); - } else { - draw(canvas); + } else { + HardwareCanvas currentCanvas = mAttachInfo.mHardwareCanvas; + final HardwareCanvas canvas = mHardwareLayer.start(currentCanvas); + + // Make sure all the GPU resources have been properly allocated + if (canvas == null) { + mHardwareLayer.end(currentCanvas); + return null; + } + + mAttachInfo.mHardwareCanvas = canvas; + try { + canvas.setViewport(width, height); + canvas.onPreDraw(mLocalDirtyRect); + mLocalDirtyRect.setEmpty(); + + canvas.drawDisplayList(getDisplayList(), mRight - mLeft, mBottom - mTop, null, + DisplayList.FLAG_CLIP_CHILDREN); + } finally { + canvas.onPostDraw(); + mHardwareLayer.end(currentCanvas); + mAttachInfo.mHardwareCanvas = currentCanvas; } - - canvas.restoreToCount(restoreCount); - } finally { - canvas.onPostDraw(); - mHardwareLayer.end(currentCanvas); - mAttachInfo.mHardwareCanvas = currentCanvas; } } @@ -11224,7 +11215,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal if (hasNoCache) { boolean layerRendered = false; if (layerType == LAYER_TYPE_HARDWARE) { - final HardwareLayer layer = getHardwareLayer(); + final HardwareLayer layer = getHardwareLayer(false); if (layer != null && layer.isValid()) { mLayerPaint.setAlpha((int) (alpha * 255)); ((HardwareCanvas) canvas).drawHardwareLayer(layer, 0, 0, mLayerPaint); diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp index f0560c1e02bb9..77a6e525c49a2 100644 --- a/core/jni/android_view_GLES20Canvas.cpp +++ b/core/jni/android_view_GLES20Canvas.cpp @@ -770,6 +770,12 @@ static void android_view_GLES20Canvas_updateTextureLayer(JNIEnv* env, jobject cl LayerRenderer::updateTextureLayer(layer, width, height, isOpaque, renderTarget, transform); } +static void android_view_GLES20Canvas_updateRenderLayer(JNIEnv* env, jobject clazz, + Layer* layer, OpenGLRenderer* renderer, DisplayList* displayList, + jint left, jint top, jint right, jint bottom) { + layer->updateDeferred(renderer, displayList, left, top, right, bottom); +} + static void android_view_GLES20Canvas_setTextureLayerTransform(JNIEnv* env, jobject clazz, Layer* layer, SkMatrix* matrix) { @@ -953,13 +959,15 @@ static JNINativeMethod gMethods[] = { { "nCreateTextureLayer", "(Z[I)I", (void*) android_view_GLES20Canvas_createTextureLayer }, { "nUpdateTextureLayer", "(IIIZLandroid/graphics/SurfaceTexture;)V", (void*) android_view_GLES20Canvas_updateTextureLayer }, - { "nSetTextureLayerTransform", "(II)V", (void*) android_view_GLES20Canvas_setTextureLayerTransform }, + { "nUpdateRenderLayer", "(IIIIIII)V", (void*) android_view_GLES20Canvas_updateRenderLayer }, { "nDestroyLayer", "(I)V", (void*) android_view_GLES20Canvas_destroyLayer }, { "nDestroyLayerDeferred", "(I)V", (void*) android_view_GLES20Canvas_destroyLayerDeferred }, { "nFlushLayer", "(I)V", (void*) android_view_GLES20Canvas_flushLayer }, { "nDrawLayer", "(IIFFI)V", (void*) android_view_GLES20Canvas_drawLayer }, { "nCopyLayer", "(II)Z", (void*) android_view_GLES20Canvas_copyLayer }, + { "nSetTextureLayerTransform", "(II)V", (void*) android_view_GLES20Canvas_setTextureLayerTransform }, + { "nGetMaximumTextureWidth", "()I", (void*) android_view_GLES20Canvas_getMaxTextureWidth }, { "nGetMaximumTextureHeight", "()I", (void*) android_view_GLES20Canvas_getMaxTextureHeight }, diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h index ee6ef1aca720d..f2431771bd8b8 100644 --- a/libs/hwui/Layer.h +++ b/libs/hwui/Layer.h @@ -37,6 +37,10 @@ namespace uirenderer { // Layers /////////////////////////////////////////////////////////////////////////////// +// Forward declarations +class OpenGLRenderer; +class DisplayList; + /** * A layer has dimensions and is backed by an OpenGL texture or FBO. */ @@ -51,6 +55,9 @@ struct Layer { texture.width = layerWidth; texture.height = layerHeight; colorFilter = NULL; + deferredUpdateScheduled = false; + renderer = NULL; + displayList = NULL; } ~Layer() { @@ -77,6 +84,15 @@ struct Layer { regionRect.translate(layer.left, layer.top); } + void updateDeferred(OpenGLRenderer* renderer, DisplayList* displayList, + int left, int top, int right, int bottom) { + this->renderer = renderer; + this->displayList = displayList; + const Rect r(left, top, right, bottom); + dirtyRect.unionWith(r); + deferredUpdateScheduled = true; + } + inline uint32_t getWidth() { return texture.width; } @@ -234,6 +250,14 @@ struct Layer { uint16_t* meshIndices; GLsizei meshElementCount; + /** + * Used for deferred updates. + */ + bool deferredUpdateScheduled; + OpenGLRenderer* renderer; + DisplayList* displayList; + Rect dirtyRect; + private: /** * Name of the FBO used to render the layer. If the name is 0 diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index e3148e8996db4..339ae0a5dea0f 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -2364,6 +2364,24 @@ void OpenGLRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* paint) { return; } + if (layer->deferredUpdateScheduled && layer->renderer && layer->displayList) { + OpenGLRenderer* renderer = layer->renderer; + Rect& dirty = layer->dirtyRect; + + interrupt(); + renderer->setViewport(layer->layer.getWidth(), layer->layer.getHeight()); + renderer->prepareDirty(dirty.left, dirty.top, dirty.right, dirty.bottom, !layer->isBlend()); + renderer->drawDisplayList(layer->displayList, layer->getWidth(), layer->getHeight(), + dirty, DisplayList::kReplayFlag_ClipChildren); + renderer->finish(); + resume(); + + dirty.setEmpty(); + layer->deferredUpdateScheduled = false; + layer->renderer = NULL; + layer->displayList = NULL; + } + mCaches.activeTexture(0); int alpha; From d634489f45aeed3a353964937b6cd726f62d08c6 Mon Sep 17 00:00:00 2001 From: Michael Jurka Date: Tue, 6 Mar 2012 15:57:06 -0800 Subject: [PATCH 012/132] Don't draw layers in buildLayer() Creating the layer, if necessary, takes the bulk of the time - just do the creation, and schedule a deferred update Change-Id: I21399ebd5d2929a4f242ec1c08e3f97fed1ef58a --- core/java/android/view/HardwareLayer.java | 2 +- core/java/android/view/TextureView.java | 2 +- core/java/android/view/View.java | 35 ++++------------------- 3 files changed, 7 insertions(+), 32 deletions(-) diff --git a/core/java/android/view/HardwareLayer.java b/core/java/android/view/HardwareLayer.java index 49450bd82bb84..a97167b6ff74b 100644 --- a/core/java/android/view/HardwareLayer.java +++ b/core/java/android/view/HardwareLayer.java @@ -167,7 +167,7 @@ abstract class HardwareLayer { /** * Specifies the display list to use to refresh the layer. - * + * * @param displayList The display list containing the drawing commands to * execute in this layer * @param dirtyRect The dirty region of the layer that needs to be redrawn diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java index c1e9946db8c9e..fc02cc1fc7f72 100644 --- a/core/java/android/view/TextureView.java +++ b/core/java/android/view/TextureView.java @@ -315,7 +315,7 @@ public class TextureView extends View { } @Override - HardwareLayer getHardwareLayer(boolean immediateRefresh) { + HardwareLayer getHardwareLayer() { if (mLayer == null) { if (mAttachInfo == null || mAttachInfo.mHardwareRenderer == null) { return null; diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index c982d7a9388c0..9457067f5651b 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -10221,7 +10221,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled() && mAttachInfo.mHardwareRenderer.validate()) { - getHardwareLayer(true); + getHardwareLayer(); } break; case LAYER_TYPE_SOFTWARE: @@ -10243,7 +10243,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal * * @return A HardwareLayer ready to render, or null if an error occurred. */ - HardwareLayer getHardwareLayer(boolean immediateRefresh) { + HardwareLayer getHardwareLayer() { if (mAttachInfo == null || mAttachInfo.mHardwareRenderer == null || !mAttachInfo.mHardwareRenderer.isEnabled()) { return null; @@ -10273,33 +10273,8 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal return null; } - if (!immediateRefresh) { - mHardwareLayer.redraw(getDisplayList(), mLocalDirtyRect); - mLocalDirtyRect.setEmpty(); - } else { - HardwareCanvas currentCanvas = mAttachInfo.mHardwareCanvas; - final HardwareCanvas canvas = mHardwareLayer.start(currentCanvas); - - // Make sure all the GPU resources have been properly allocated - if (canvas == null) { - mHardwareLayer.end(currentCanvas); - return null; - } - - mAttachInfo.mHardwareCanvas = canvas; - try { - canvas.setViewport(width, height); - canvas.onPreDraw(mLocalDirtyRect); - mLocalDirtyRect.setEmpty(); - - canvas.drawDisplayList(getDisplayList(), mRight - mLeft, mBottom - mTop, null, - DisplayList.FLAG_CLIP_CHILDREN); - } finally { - canvas.onPostDraw(); - mHardwareLayer.end(currentCanvas); - mAttachInfo.mHardwareCanvas = currentCanvas; - } - } + mHardwareLayer.redraw(getDisplayList(), mLocalDirtyRect); + mLocalDirtyRect.setEmpty(); } return mHardwareLayer; @@ -11266,7 +11241,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal if (hasNoCache) { boolean layerRendered = false; if (layerType == LAYER_TYPE_HARDWARE) { - final HardwareLayer layer = getHardwareLayer(false); + final HardwareLayer layer = getHardwareLayer(); if (layer != null && layer.isValid()) { mLayerPaint.setAlpha((int) (alpha * 255)); ((HardwareCanvas) canvas).drawHardwareLayer(layer, 0, 0, mLayerPaint); From 2b7832096aec0c2da64b4d84b0f1e4560ad685f4 Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Tue, 6 Mar 2012 18:26:54 -0800 Subject: [PATCH 013/132] attempt to fix a deadlock in SurfaceTextureClient::disconnect - condition wasn't signaled if an error happened between acquire and release - also replace signal with broadcasts Bug: 6109450 Change-Id: Iaf9371b829f772f559daae42e06d4dbd9505d6a0 --- libs/gui/BufferQueue.cpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp index 25a4c227ff6e9..7d641057a8e5b 100644 --- a/libs/gui/BufferQueue.cpp +++ b/libs/gui/BufferQueue.cpp @@ -111,7 +111,7 @@ status_t BufferQueue::setBufferCountServerLocked(int bufferCount) { // easy, we just have more buffers mBufferCount = bufferCount; mServerBufferCount = bufferCount; - mDequeueCondition.signal(); + mDequeueCondition.broadcast(); } else { // we're here because we're either // - reducing the number of available buffers @@ -192,7 +192,7 @@ status_t BufferQueue::setBufferCount(int bufferCount) { mClientBufferCount = bufferCount; mBufferHasBeenQueued = false; mQueue.clear(); - mDequeueCondition.signal(); + mDequeueCondition.broadcast(); return OK; } @@ -306,6 +306,7 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, if (numberOfBuffersNeedsToChange) { // here we're guaranteed that mQueue is empty freeAllBuffersLocked(); + // XXX: signal? mBufferCount = mServerBufferCount; if (mBufferCount < minBufferCountNeeded) mBufferCount = minBufferCountNeeded; @@ -496,7 +497,7 @@ status_t BufferQueue::setSynchronousMode(bool enabled) { // - if the client set the number of buffers, we're guaranteed that // we have at least 3 (because we don't allow less) mSynchronousMode = enabled; - mDequeueCondition.signal(); + mDequeueCondition.broadcast(); } return err; } @@ -564,7 +565,7 @@ status_t BufferQueue::queueBuffer(int buf, int64_t timestamp, mSlots[buf].mFrameNumber = mFrameCounter; mBufferHasBeenQueued = true; - mDequeueCondition.signal(); + mDequeueCondition.broadcast(); *outWidth = mDefaultWidth; *outHeight = mDefaultHeight; @@ -601,7 +602,7 @@ void BufferQueue::cancelBuffer(int buf) { } mSlots[buf].mBufferState = BufferSlot::FREE; mSlots[buf].mFrameNumber = 0; - mDequeueCondition.signal(); + mDequeueCondition.broadcast(); } status_t BufferQueue::setCrop(const Rect& crop) { @@ -709,7 +710,7 @@ status_t BufferQueue::disconnect(int api) { mNextCrop.makeInvalid(); mNextScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE; mNextTransform = 0; - mDequeueCondition.signal(); + mDequeueCondition.broadcast(); } else { ST_LOGE("disconnect: connected to another api (cur=%d, req=%d)", mConnectedApi, api); @@ -846,6 +847,7 @@ status_t BufferQueue::acquire(BufferItem *buffer) { mSlots[buf].mBufferState = BufferSlot::ACQUIRED; mQueue.erase(front); + mDequeueCondition.broadcast(); ATRACE_INT(mConsumerName.string(), mQueue.size()); } @@ -877,7 +879,8 @@ status_t BufferQueue::releaseBuffer(int buf, EGLDisplay display, || mSlots[buf].mBufferState == BufferSlot::ACQUIRED) { mSlots[buf].mBufferState = BufferSlot::FREE; } - mDequeueCondition.signal(); + + mDequeueCondition.broadcast(); return OK; } @@ -888,7 +891,7 @@ status_t BufferQueue::consumerDisconnect() { // is considered abandoned mAbandoned = true; freeAllBuffersLocked(); - mDequeueCondition.signal(); + mDequeueCondition.broadcast(); return OK; } From a808002680b57c7bf51f7b0e1c97dbd892db1fcd Mon Sep 17 00:00:00 2001 From: Jim Miller Date: Wed, 7 Mar 2012 14:19:56 -0800 Subject: [PATCH 014/132] Fix 6119433: disambiguate screen brightness changes from other lights This fixes a bug where the code asked to change the keyboard brightness on a device that doesn't support it. Instead of animating the keyboard brightness, it ended up animating the display brightness and invoking the power off animation as a result. The fix is to ignore keyboard brightness because we don't have any devices that currently support it. Change-Id: I672d89f92f991812ea676f19c40058b2d3008656 --- services/java/com/android/server/PowerManagerService.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java index d9d3f4e61ad05..63418db2cb335 100644 --- a/services/java/com/android/server/PowerManagerService.java +++ b/services/java/com/android/server/PowerManagerService.java @@ -2234,14 +2234,18 @@ public class PowerManagerService extends IPowerManager.Stub } if (target != currentValue) { + final boolean doScreenAnim = (mask & (SCREEN_BRIGHT_BIT | SCREEN_ON_BIT)) != 0; final boolean turningOff = endValue == Power.BRIGHTNESS_OFF; - if (turningOff && ((mask & (SCREEN_ON_BIT | SCREEN_BRIGHT_BIT)) != 0)) { + if (turningOff && doScreenAnim) { // Cancel all pending animations since we're turning off mScreenBrightnessHandler.removeCallbacksAndMessages(null); screenOffFinishedAnimatingLocked(mScreenOffReason); duration = 200; // TODO: how long should this be? } - animateInternal(mask, turningOff, 0); + if (doScreenAnim) { + animateInternal(mask, turningOff, 0); + } + // TODO: Handle keyboard light animation when we have devices that support it } } } From fbcf6823da0c707b1e6f1184da8c00407438e989 Mon Sep 17 00:00:00 2001 From: Eino-Ville Talvala Date: Thu, 8 Mar 2012 14:18:06 -0800 Subject: [PATCH 015/132] Allow multiple releases to be called on MediaActionSound. Bug: 6136088 Change-Id: I80ff09a90cd65d874ae016d450c4cc8c6a56d387 --- media/java/android/media/MediaActionSound.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/media/java/android/media/MediaActionSound.java b/media/java/android/media/MediaActionSound.java index d0e6910ba6795..7a520feb6af07 100644 --- a/media/java/android/media/MediaActionSound.java +++ b/media/java/android/media/MediaActionSound.java @@ -185,10 +185,14 @@ public class MediaActionSound { }; /** - * Free up all audio resources used by this MediaActionSound instance + * Free up all audio resources used by this MediaActionSound instance. Do + * not call any other methods on a MediaActionSound instance after calling + * release(). */ public void release() { - mSoundPool.release(); - mSoundPool = null; + if (mSoundPool != null) { + mSoundPool.release(); + mSoundPool = null; + } } } From 5cf3a71f593247875b7a9db1dbe5626cac45935b Mon Sep 17 00:00:00 2001 From: Xia Wang Date: Thu, 8 Mar 2012 15:57:26 -0800 Subject: [PATCH 016/132] Fix CM test http://b/issue?id=6125619 Change-Id: I33306619424ab54281aaf592c78581179ebbfc6e --- .../connectivitymanagertest/ConnectivityManagerTestActivity.java | 1 + 1 file changed, 1 insertion(+) diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java index 259f15fcdc2a2..19aa77baf94fb 100644 --- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java +++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java @@ -241,6 +241,7 @@ public class ConnectivityManagerTestActivity extends Activity { mCM = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE); // Get an instance of WifiManager mWifiManager =(WifiManager)getSystemService(Context.WIFI_SERVICE); + mContext = this; mChannel = mWifiManager.initialize(mContext, mContext.getMainLooper(), null); initializeNetworkStates(); From d465a5053f3265af0220cd3f74f2a6ed394a1852 Mon Sep 17 00:00:00 2001 From: Stephen Hines Date: Mon, 12 Mar 2012 14:42:05 -0700 Subject: [PATCH 017/132] Fix argument passing with dimLOD. BUG=6152130 Change-Id: I5c857b692af8ec45e4cbef8140c44d72aec6600e --- libs/rs/rsType.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/rs/rsType.cpp b/libs/rs/rsType.cpp index 9ac553ed86379..b668a78caf660 100644 --- a/libs/rs/rsType.cpp +++ b/libs/rs/rsType.cpp @@ -257,14 +257,14 @@ ObjectBaseRef Type::getTypeRef(Context *rsc, const Element *e, ObjectBaseRef Type::cloneAndResize1D(Context *rsc, uint32_t dimX) const { return getTypeRef(rsc, mElement.get(), dimX, - mHal.state.dimY, mHal.state.dimZ, mHal.state.lodCount, mHal.state.faces); + getDimY(), getDimZ(), getDimLOD(), getDimFaces()); } ObjectBaseRef Type::cloneAndResize2D(Context *rsc, uint32_t dimX, uint32_t dimY) const { return getTypeRef(rsc, mElement.get(), dimX, dimY, - mHal.state.dimZ, mHal.state.lodCount, mHal.state.faces); + getDimZ(), getDimLOD(), getDimFaces()); } From bb46535bdac51fa8fe5897ea6daed5143e0080a1 Mon Sep 17 00:00:00 2001 From: Chet Haase Date: Tue, 13 Mar 2012 11:13:13 -0700 Subject: [PATCH 018/132] Fix garbage deref in DisplayList structures Issue #6158892: Device runtime restarts frequently Change-Id: I4e6afaaf9ac66d6846caf0ed82ea67163d8b15c2 --- libs/hwui/DisplayListRenderer.cpp | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp index 24f4f1cf84b65..2ba87c09d080c 100644 --- a/libs/hwui/DisplayListRenderer.cpp +++ b/libs/hwui/DisplayListRenderer.cpp @@ -140,17 +140,19 @@ void DisplayList::destroyDisplayListDeferred(DisplayList* displayList) { void DisplayList::clearResources() { sk_free((void*) mReader.base()); - if (mTransformMatrix) { - delete mTransformMatrix; - mTransformMatrix = NULL; - } - if (mTransformCamera) { - delete mTransformCamera; - mTransformCamera = NULL; - } - if (mTransformMatrix3D) { - delete mTransformMatrix3D; - mTransformMatrix3D = NULL; + if (USE_DISPLAY_LIST_PROPERTIES) { + if (mTransformMatrix) { + delete mTransformMatrix; + mTransformMatrix = NULL; + } + if (mTransformCamera) { + delete mTransformCamera; + mTransformCamera = NULL; + } + if (mTransformMatrix3D) { + delete mTransformMatrix3D; + mTransformMatrix3D = NULL; + } } Caches& caches = Caches::getInstance(); From 951e71547b1b5efa7b29872ff12b2653966c6e79 Mon Sep 17 00:00:00 2001 From: Chet Haase Date: Tue, 13 Mar 2012 11:42:34 -0700 Subject: [PATCH 019/132] Fix garbage deref with DisplayList property structures This is the real fix to issue 6158892. We currently delete transform/camera structures at DisplayList destructor time, if these structures are not NULL. We set the fields to NULL in an init() method called (eventually) by the constructor. But it is possible for the object to be destroyed before that init code is called, resulting in the deref bug reported. The fi is to set these structures to NULL directly in the constructor. Issue 6158892i: Device runtime restarts frequently Change-Id: Ibfa0f9314767eed6fd51f4ec7edc0d0edd5fdd0f --- libs/hwui/DisplayListRenderer.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp index 2ba87c09d080c..3bd87d53f805e 100644 --- a/libs/hwui/DisplayListRenderer.cpp +++ b/libs/hwui/DisplayListRenderer.cpp @@ -91,7 +91,9 @@ void DisplayList::outputLogBuffer(int fd) { fflush(file); } -DisplayList::DisplayList(const DisplayListRenderer& recorder) { +DisplayList::DisplayList(const DisplayListRenderer& recorder) : + mTransformMatrix(NULL), mTransformCamera(NULL), mTransformMatrix3D(NULL) { + initFromDisplayListRenderer(recorder); } @@ -124,9 +126,6 @@ void DisplayList::initProperties() { mWidth = 0; mHeight = 0; mPivotExplicitlySet = false; - mTransformMatrix = NULL; - mTransformCamera = NULL; - mTransformMatrix3D = NULL; mCaching = false; } From 557ac54268e9255f1f7afb7c813204e8b02cdafb Mon Sep 17 00:00:00 2001 From: Craig Mautner Date: Fri, 16 Mar 2012 14:01:16 -0700 Subject: [PATCH 020/132] Perform finish animation actions. When stepAnimation returns false, do not return false immediately. Instead carry out finish actions. Also, remove state machine that is no longer necessary. Fixes bug 6184070. Change-Id: I530eb2b62b864bbce929f573d10b31b102152f1f --- .../com/android/server/wm/AppWindowToken.java | 6 +++-- .../com/android/server/wm/WindowState.java | 25 ++++++------------- 2 files changed, 11 insertions(+), 20 deletions(-) diff --git a/services/java/com/android/server/wm/AppWindowToken.java b/services/java/com/android/server/wm/AppWindowToken.java index 5ca09e78bb8aa..67b667ad1557b 100644 --- a/services/java/com/android/server/wm/AppWindowToken.java +++ b/services/java/com/android/server/wm/AppWindowToken.java @@ -240,8 +240,10 @@ class AppWindowToken extends WindowToken { animation.setStartTime(currentTime); animating = true; } - // we're done! - return stepAnimation(currentTime); + if (stepAnimation(currentTime)) { + // we're done! + return true; + } } } else if (animation != null) { // If the display is frozen, and there is a pending animation, diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java index 48788e7fc6f88..b9d302510e531 100644 --- a/services/java/com/android/server/wm/WindowState.java +++ b/services/java/com/android/server/wm/WindowState.java @@ -305,11 +305,6 @@ final class WindowState implements WindowManagerPolicy.WindowState { int mAnimDw; int mAnimDh; - static final int ANIM_STATE_IDLE = 0; - static final int ANIM_STATE_RUNNING = 1; - static final int ANIM_STATE_STOPPING = 2; - int mAnimState = ANIM_STATE_IDLE; - WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token, WindowState attachedWindow, int seq, WindowManager.LayoutParams a, int viewVisibility) { @@ -653,7 +648,6 @@ final class WindowState implements WindowManagerPolicy.WindowState { mLocalAnimating = false; mAnimation.cancel(); mAnimation = null; - mAnimState = ANIM_STATE_IDLE; } } @@ -665,7 +659,6 @@ final class WindowState implements WindowManagerPolicy.WindowState { mAnimation.cancel(); mAnimation = null; destroySurfaceLocked(); - mAnimState = ANIM_STATE_IDLE; } mExiting = false; } @@ -971,7 +964,8 @@ final class WindowState implements WindowManagerPolicy.WindowState { mAppToken.firstWindowDrawn = true; if (mAppToken.startingData != null) { - if (WindowManagerService.DEBUG_STARTING_WINDOW || WindowManagerService.DEBUG_ANIM) Slog.v(WindowManagerService.TAG, + if (WindowManagerService.DEBUG_STARTING_WINDOW || + WindowManagerService.DEBUG_ANIM) Slog.v(WindowManagerService.TAG, "Finish starting " + mToken + ": first real window is shown, no animation"); // If this initial window is animating, stop it -- we @@ -983,7 +977,6 @@ final class WindowState implements WindowManagerPolicy.WindowState { mAnimation = null; // Make sure we clean up the animation. mAnimating = true; - mAnimState = ANIM_STATE_IDLE; } mService.mFinishedStarting.add(mAppToken); mService.mH.sendEmptyMessage(H.FINISHED_STARTING); @@ -995,7 +988,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { } private boolean stepAnimation(long currentTime) { - if ((mAnimation == null) || !mLocalAnimating || (mAnimState != ANIM_STATE_RUNNING)) { + if ((mAnimation == null) || !mLocalAnimating) { return false; } mTransformation.clear(); @@ -1003,9 +996,6 @@ final class WindowState implements WindowManagerPolicy.WindowState { if (WindowManagerService.DEBUG_ANIM) Slog.v( WindowManagerService.TAG, "Stepped animation in " + this + ": more=" + more + ", xform=" + mTransformation); - if (!more) { - mAnimState = ANIM_STATE_STOPPING; - } return more; } @@ -1032,11 +1022,11 @@ final class WindowState implements WindowManagerPolicy.WindowState { mAnimation.setStartTime(currentTime); mLocalAnimating = true; mAnimating = true; - mAnimState = ANIM_STATE_RUNNING; } - if ((mAnimation != null) && mLocalAnimating && - (mAnimState != ANIM_STATE_STOPPING)) { - return stepAnimation(currentTime); + if ((mAnimation != null) && mLocalAnimating) { + if (stepAnimation(currentTime)) { + return true; + } } if (WindowManagerService.DEBUG_ANIM) Slog.v( WindowManagerService.TAG, "Finished animation in " + this + @@ -1137,7 +1127,6 @@ final class WindowState implements WindowManagerPolicy.WindowState { mAppToken.updateReportedVisibilityLocked(); } - mAnimState = ANIM_STATE_IDLE; return false; } From 4850aac6eb1aa17278c5e0a89288ab4237ee8ddc Mon Sep 17 00:00:00 2001 From: Amith Yamasani Date: Wed, 14 Mar 2012 14:53:36 -0700 Subject: [PATCH 021/132] Fix sync tests failure. Bug: 6156819 Contacts initial sync test fails Earlier commit was incorrectly cloning the currentSyncs list, so it wasn't being updated. Change-Id: I23cea8a190127746e9a1218e7bfda630599cef17 --- core/java/android/content/SyncStorageEngine.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/java/android/content/SyncStorageEngine.java b/core/java/android/content/SyncStorageEngine.java index 7bb986610b472..9c81c9e3a3207 100644 --- a/core/java/android/content/SyncStorageEngine.java +++ b/core/java/android/content/SyncStorageEngine.java @@ -1171,7 +1171,7 @@ public class SyncStorageEngine extends Handler { syncs = new ArrayList(); mCurrentSyncs.put(userId, syncs); } - return new ArrayList(syncs); + return syncs; } } From 0c6b3ddfd0fab230d90fbc2485b52926a06480f3 Mon Sep 17 00:00:00 2001 From: Craig Mautner Date: Thu, 15 Mar 2012 11:28:53 -0700 Subject: [PATCH 022/132] Separate layout ops from surface ops. Further work to isolate layout from animation and surface operations. Remove cruft and minor refactoring. Change-Id: I6f910ed72c7c614996641c353870c2b2ab5e8bb4 --- .../server/wm/ScreenRotationAnimation.java | 21 +-- .../server/wm/WindowManagerService.java | 173 ++++++++++-------- .../com/android/server/wm/WindowState.java | 11 +- 3 files changed, 104 insertions(+), 101 deletions(-) diff --git a/services/java/com/android/server/wm/ScreenRotationAnimation.java b/services/java/com/android/server/wm/ScreenRotationAnimation.java index 58187b699e534..ab084f9aa48f9 100644 --- a/services/java/com/android/server/wm/ScreenRotationAnimation.java +++ b/services/java/com/android/server/wm/ScreenRotationAnimation.java @@ -41,7 +41,6 @@ class ScreenRotationAnimation { BlackFrame mBlackFrame; int mWidth, mHeight; - int mSnapshotRotation; int mSnapshotDeltaRotation; int mOriginalRotation; int mOriginalWidth, mOriginalHeight; @@ -125,8 +124,7 @@ class ScreenRotationAnimation { if (mBlackFrame != null) { mBlackFrame.printTo(prefix + " ", pw); } - pw.print(prefix); pw.print("mSnapshotRotation="); pw.print(mSnapshotRotation); - pw.print(" mSnapshotDeltaRotation="); pw.print(mSnapshotDeltaRotation); + pw.print(prefix); pw.print(" mSnapshotDeltaRotation="); pw.print(mSnapshotDeltaRotation); pw.print(" mCurRotation="); pw.println(mCurRotation); pw.print(prefix); pw.print("mOriginalRotation="); pw.print(mOriginalRotation); pw.print(" mOriginalWidth="); pw.print(mOriginalWidth); @@ -173,7 +171,6 @@ class ScreenRotationAnimation { mContext = context; // Screenshot does NOT include rotation! - mSnapshotRotation = 0; if (originalRotation == Surface.ROTATION_90 || originalRotation == Surface.ROTATION_270) { mWidth = originalHeight; @@ -197,7 +194,7 @@ class ScreenRotationAnimation { try { mSurface = new Surface(session, 0, "FreezeSurface", -1, mWidth, mHeight, PixelFormat.OPAQUE, Surface.FX_SURFACE_SCREENSHOT | Surface.HIDDEN); - if (mSurface == null || !mSurface.isValid()) { + if (!mSurface.isValid()) { // Screenshot failed, punt. mSurface = null; return; @@ -281,7 +278,7 @@ class ScreenRotationAnimation { // Compute the transformation matrix that must be applied // to the snapshot to make it stay in the same original position // with the current screen rotation. - int delta = deltaRotation(rotation, mSnapshotRotation); + int delta = deltaRotation(rotation, Surface.ROTATION_0); createRotationMatrix(delta, mWidth, mHeight, mSnapshotInitialMatrix); if (DEBUG_STATE) Slog.v(TAG, "**** ROTATION: " + delta); @@ -703,20 +700,18 @@ class ScreenRotationAnimation { } void updateSurfaces() { - if (!mMoreStartExit && !mMoreFinishExit && !mMoreRotateExit) { - if (mSurface != null) { + if (mSurface != null) { + if (!mMoreStartExit && !mMoreFinishExit && !mMoreRotateExit) { if (DEBUG_STATE) Slog.v(TAG, "Exit animations done, hiding screenshot surface"); mSurface.hide(); } } - if (!mMoreStartFrame && !mMoreFinishFrame && !mMoreRotateFrame) { - if (mBlackFrame != null) { + if (mBlackFrame != null) { + if (!mMoreStartFrame && !mMoreFinishFrame && !mMoreRotateFrame) { if (DEBUG_STATE) Slog.v(TAG, "Frame animations done, hiding black frame"); mBlackFrame.hide(); - } - } else { - if (mBlackFrame != null) { + } else { mBlackFrame.setMatrix(mFrameTransformation.getMatrix()); } } diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index 4f5521787cbc7..f4c4069e3c337 100644 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -1581,8 +1581,7 @@ public class WindowManagerService extends IWindowManager.Stub + w.isReadyForDisplay() + " drawpending=" + w.mDrawPending + " commitdrawpending=" + w.mCommitDrawPending); if ((w.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0 && w.isReadyForDisplay() - && (mWallpaperTarget == w - || (!w.mDrawPending && !w.mCommitDrawPending))) { + && (mWallpaperTarget == w || w.isDrawnLw())) { if (DEBUG_WALLPAPER) Slog.v(TAG, "Found wallpaper activity: #" + i + "=" + w); foundW = w; @@ -2688,8 +2687,7 @@ public class WindowManagerService extends IWindowManager.Stub win.mEnterAnimationPending = true; } if (displayed) { - if (win.mSurface != null && !win.mDrawPending - && !win.mCommitDrawPending && !mDisplayFrozen + if (win.isDrawnLw() && !mDisplayFrozen && mDisplayEnabled && mPolicy.isScreenOnFully()) { applyEnterAnimationLocked(win); } @@ -3983,8 +3981,7 @@ public class WindowManagerService extends IWindowManager.Stub // If we are being set visible, and the starting window is // not yet displayed, then make sure it doesn't get displayed. WindowState swin = wtoken.startingWindow; - if (swin != null && (swin.mDrawPending - || swin.mCommitDrawPending)) { + if (swin != null && !swin.isDrawnLw()) { swin.mPolicyVisibility = false; swin.mPolicyVisibilityAfterAnim = false; } @@ -7669,21 +7666,76 @@ public class WindowManagerService extends IWindowManager.Stub } } - if (mScreenRotationAnimation != null) { - if (mScreenRotationAnimation.isAnimating() || - mScreenRotationAnimation.mFinishAnimReady) { - if (mScreenRotationAnimation.stepAnimationLocked(currentTime)) { - mInnerFields.mUpdateRotation = false; - mInnerFields.mAnimating = true; - } else { - mInnerFields.mUpdateRotation = true; - mScreenRotationAnimation.kill(); - mScreenRotationAnimation = null; - } + if (mScreenRotationAnimation != null && + (mScreenRotationAnimation.isAnimating() || + mScreenRotationAnimation.mFinishAnimReady)) { + if (mScreenRotationAnimation.stepAnimationLocked(currentTime)) { + mInnerFields.mUpdateRotation = false; + mInnerFields.mAnimating = true; + } else { + mInnerFields.mUpdateRotation = true; + mScreenRotationAnimation.kill(); + mScreenRotationAnimation = null; } } } + private void animateAndUpdateSurfaces(final long currentTime, final int dw, final int dh, + final int innerDw, final int innerDh, + final boolean recoveringMemory) { + // Update animations of all applications, including those + // associated with exiting/removed apps + Surface.openTransaction(); + + try { + mPendingLayoutChanges = performAnimationsLocked(currentTime, dw, dh, + innerDw, innerDh); + updateWindowsAppsAndRotationAnimationsLocked(currentTime, innerDw, innerDh); + + // THIRD LOOP: Update the surfaces of all windows. + + if (mScreenRotationAnimation != null) { + mScreenRotationAnimation.updateSurfaces(); + } + + final int N = mWindows.size(); + for (int i=N-1; i>=0; i--) { + WindowState w = mWindows.get(i); + prepareSurfaceLocked(w, recoveringMemory); + } + + if (mDimAnimator != null && mDimAnimator.mDimShown) { + mInnerFields.mAnimating |= + mDimAnimator.updateSurface(mInnerFields.mDimming, currentTime, + mDisplayFrozen || !mDisplayEnabled || !mPolicy.isScreenOnFully()); + } + + if (!mInnerFields.mBlurring && mBlurShown) { + if (SHOW_TRANSACTIONS) Slog.i(TAG, " BLUR " + mBlurSurface + + ": HIDE"); + try { + mBlurSurface.hide(); + } catch (IllegalArgumentException e) { + Slog.w(TAG, "Illegal argument exception hiding blur surface"); + } + mBlurShown = false; + } + + if (mBlackFrame != null) { + if (mScreenRotationAnimation != null) { + mBlackFrame.setMatrix( + mScreenRotationAnimation.getEnterTransformation().getMatrix()); + } else { + mBlackFrame.clearMatrix(); + } + } + } catch (RuntimeException e) { + Log.wtf(TAG, "Unhandled exception in Window Manager", e); + } finally { + Surface.closeTransaction(); + } + } + /** * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method. * @@ -8357,7 +8409,7 @@ public class WindowManagerService extends IWindowManager.Stub mResizingWindows.add(w); } } else if (w.mOrientationChanging) { - if (!w.mDrawPending && !w.mCommitDrawPending) { + if (w.isDrawnLw()) { if (DEBUG_ORIENTATION) Slog.v(TAG, "Orientation not waiting for draw in " + w + ", surface " + w.mSurface); @@ -8388,6 +8440,16 @@ public class WindowManagerService extends IWindowManager.Stub // cases while they are hidden such as when first showing a // window. + if (w.mSurface == null) { + if (w.mOrientationChanging) { + if (DEBUG_ORIENTATION) { + Slog.v(TAG, "Orientation change skips hidden " + w); + } + w.mOrientationChanging = false; + } + return; + } + boolean displayed = false; w.computeShownFrameLocked(); @@ -8521,8 +8583,7 @@ public class WindowManagerService extends IWindowManager.Stub } } - if (w.mLastHidden && !w.mDrawPending - && !w.mCommitDrawPending + if (w.mLastHidden && w.isDrawnLw() && !w.mReadyToShow) { if (SHOW_TRANSACTIONS) logSurface(w, "SHOW (performLayout)", null); @@ -8544,7 +8605,7 @@ public class WindowManagerService extends IWindowManager.Stub if (displayed) { if (w.mOrientationChanging) { - if (w.mDrawPending || w.mCommitDrawPending) { + if (!w.isDrawnLw()) { mInnerFields.mOrientationChangeComplete = false; if (DEBUG_ORIENTATION) Slog.v(TAG, "Orientation continue waiting for draw in " + w); @@ -8832,48 +8893,20 @@ public class WindowManagerService extends IWindowManager.Stub } while (mPendingLayoutChanges != 0); - // Update animations of all applications, including those - // associated with exiting/removed apps - - mPendingLayoutChanges = performAnimationsLocked(currentTime, dw, dh, - innerDw, innerDh); - updateWindowsAppsAndRotationAnimationsLocked(currentTime, innerDw, innerDh); - - // THIRD LOOP: Update the surfaces of all windows. - - final boolean someoneLosingFocus = mLosingFocus.size() != 0; + final boolean someoneLosingFocus = !mLosingFocus.isEmpty(); mInnerFields.mObscured = false; mInnerFields.mBlurring = false; mInnerFields.mDimming = false; mInnerFields.mSyswin = false; - - if (mScreenRotationAnimation != null) { - mScreenRotationAnimation.updateSurfaces(); - } - + final int N = mWindows.size(); - for (i=N-1; i>=0; i--) { WindowState w = mWindows.get(i); + //Slog.i(TAG, "Window " + this + " clearing mContentChanged - done placing"); + w.mContentChanged = false; - if (w.mSurface != null) { - prepareSurfaceLocked(w, recoveringMemory); - } else if (w.mOrientationChanging) { - if (DEBUG_ORIENTATION) { - Slog.v(TAG, "Orientation change skips hidden " + w); - } - w.mOrientationChanging = false; - } - - if (w.mContentChanged) { - //Slog.i(TAG, "Window " + this + " clearing mContentChanged - done placing"); - w.mContentChanged = false; - } - - final boolean canBeSeen = w.isDisplayedLw(); - - if (someoneLosingFocus && w == mCurrentFocus && canBeSeen) { + if (someoneLosingFocus && w == mCurrentFocus && w.isDisplayedLw()) { focusDisplayed = true; } @@ -8892,37 +8925,15 @@ public class WindowManagerService extends IWindowManager.Stub updateWallpaperVisibilityLocked(); } } - - if (mDimAnimator != null && mDimAnimator.mDimShown) { - mInnerFields.mAnimating |= - mDimAnimator.updateSurface(mInnerFields.mDimming, currentTime, - mDisplayFrozen || !mDisplayEnabled || !mPolicy.isScreenOnFully()); - } - - if (!mInnerFields.mBlurring && mBlurShown) { - if (SHOW_TRANSACTIONS) Slog.i(TAG, " BLUR " + mBlurSurface - + ": HIDE"); - try { - mBlurSurface.hide(); - } catch (IllegalArgumentException e) { - Slog.w(TAG, "Illegal argument exception hiding blur surface"); - } - mBlurShown = false; - } - - if (mBlackFrame != null) { - if (mScreenRotationAnimation != null) { - mBlackFrame.setMatrix( - mScreenRotationAnimation.getEnterTransformation().getMatrix()); - } else { - mBlackFrame.clearMatrix(); - } - } } catch (RuntimeException e) { Log.wtf(TAG, "Unhandled exception in Window Manager", e); + } finally { + Surface.closeTransaction(); } - Surface.closeTransaction(); + // Update animations of all applications, including those + // associated with exiting/removed apps + animateAndUpdateSurfaces(currentTime, dw, dh, innerDw, innerDh, recoveringMemory); if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION performLayoutAndPlaceSurfaces"); diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java index b9d302510e531..57d03741309ae 100644 --- a/services/java/com/android/server/wm/WindowState.java +++ b/services/java/com/android/server/wm/WindowState.java @@ -1008,7 +1008,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { if (!mService.mDisplayFrozen && mService.mPolicy.isScreenOnFully()) { // We will run animations as long as the display isn't frozen. - if (!mDrawPending && !mCommitDrawPending && mAnimation != null) { + if (isDrawnLw() && mAnimation != null) { mHasTransformation = true; mHasLocalTransformation = true; if (!mLocalAnimating) { @@ -1467,8 +1467,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { */ public boolean isDisplayedLw() { final AppWindowToken atoken = mAppToken; - return mSurface != null && mPolicyVisibility && !mDestroying - && !mDrawPending && !mCommitDrawPending + return isDrawnLw() && mPolicyVisibility && ((!mAttachedHidden && (atoken == null || !atoken.hiddenRequested)) || mAnimating); @@ -1489,7 +1488,6 @@ final class WindowState implements WindowManagerPolicy.WindowState { * complete UI in to. */ public boolean isDrawnLw() { - final AppWindowToken atoken = mAppToken; return mSurface != null && !mDestroying && !mDrawPending && !mCommitDrawPending; } @@ -1501,9 +1499,8 @@ final class WindowState implements WindowManagerPolicy.WindowState { boolean isOpaqueDrawn() { return (mAttrs.format == PixelFormat.OPAQUE || mAttrs.type == TYPE_WALLPAPER) - && mSurface != null && mAnimation == null - && (mAppToken == null || mAppToken.animation == null) - && !mDrawPending && !mCommitDrawPending; + && isDrawnLw() && mAnimation == null + && (mAppToken == null || mAppToken.animation == null); } /** From 61109a58aa3ef36fd06699f9cdbdbe8f9998eb4e Mon Sep 17 00:00:00 2001 From: Craig Mautner Date: Fri, 16 Mar 2012 15:26:01 -0700 Subject: [PATCH 023/132] Fix black screen on app transition. The layer adjustment to an animating window upon completion was masking the window behind the mWindowAnimationBackgroundSurface, a DimSurface. The DimSurface was not being hidden because the step was happening too late. Swapping the order of performAnimationsLocked and updateWindowsAppsAndRotationAnimationsLocked fixes this ordering issue. Fixes bug 6185920. Change-Id: I0ff64c019e821fa3a92505ac6351f2648897e592 --- services/java/com/android/server/wm/WindowManagerService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index f4c4069e3c337..69936577e57be 100644 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -7688,9 +7688,9 @@ public class WindowManagerService extends IWindowManager.Stub Surface.openTransaction(); try { + updateWindowsAppsAndRotationAnimationsLocked(currentTime, innerDw, innerDh); mPendingLayoutChanges = performAnimationsLocked(currentTime, dw, dh, innerDw, innerDh); - updateWindowsAppsAndRotationAnimationsLocked(currentTime, innerDw, innerDh); // THIRD LOOP: Update the surfaces of all windows. From 9148263d2c2544c70ebe8eb8a605ab3ed5f7b76d Mon Sep 17 00:00:00 2001 From: Craig Mautner Date: Tue, 20 Mar 2012 17:24:00 -0700 Subject: [PATCH 024/132] Minor refactoring prior to major refactoring. Removal of blur layer. Deferral of Surface actions in BlackFrame from ctor to first use. Combine common test into single method okToDisplay(). Remove redundant logic in DimAnimator. Change-Id: I43af0415794a8f142803ce94d7e17539aafac67d --- .../com/android/server/wm/AppWindowToken.java | 2 +- .../com/android/server/wm/BlackFrame.java | 6 +- .../com/android/server/wm/DimAnimator.java | 16 +- .../server/wm/WindowManagerService.java | 200 ++++++------------ .../com/android/server/wm/WindowState.java | 11 +- 5 files changed, 79 insertions(+), 156 deletions(-) diff --git a/services/java/com/android/server/wm/AppWindowToken.java b/services/java/com/android/server/wm/AppWindowToken.java index 3ae9f24056497..4b3d904e994f5 100644 --- a/services/java/com/android/server/wm/AppWindowToken.java +++ b/services/java/com/android/server/wm/AppWindowToken.java @@ -222,7 +222,7 @@ class AppWindowToken extends WindowToken { // This must be called while inside a transaction. boolean stepAnimationLocked(long currentTime, int dw, int dh) { - if (!service.mDisplayFrozen && service.mPolicy.isScreenOnFully()) { + if (service.okToDisplay()) { // We will run animations as long as the display isn't frozen. if (animation == WindowManagerService.sDummyAnimation) { diff --git a/services/java/com/android/server/wm/BlackFrame.java b/services/java/com/android/server/wm/BlackFrame.java index 40e452a96a5ec..c915932a3648b 100644 --- a/services/java/com/android/server/wm/BlackFrame.java +++ b/services/java/com/android/server/wm/BlackFrame.java @@ -32,12 +32,14 @@ public class BlackFrame { class BlackSurface { final int left; final int top; + final int layer; final Surface surface; BlackSurface(SurfaceSession session, int layer, int l, int t, int r, int b) throws Surface.OutOfResourcesException { left = l; top = t; + this.layer = layer; int w = r-l; int h = b-t; surface = new Surface(session, 0, "BlackSurface", @@ -45,8 +47,6 @@ public class BlackFrame { if (WindowManagerService.SHOW_TRANSACTIONS || WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i(WindowManagerService.TAG, " BLACK " + surface + ": CREATE layer=" + layer); - surface.setAlpha(1.0f); - surface.setLayer(layer); } void setMatrix(Matrix matrix) { @@ -58,6 +58,8 @@ public class BlackFrame { surface.setMatrix( mTmpFloats[Matrix.MSCALE_X], mTmpFloats[Matrix.MSKEW_Y], mTmpFloats[Matrix.MSKEW_X], mTmpFloats[Matrix.MSCALE_Y]); + surface.setAlpha(1.0f); + surface.setLayer(layer); if (false) { Slog.i(WindowManagerService.TAG, "Black Surface @ (" + left + "," + top + "): (" + mTmpFloats[Matrix.MTRANS_X] + "," diff --git a/services/java/com/android/server/wm/DimAnimator.java b/services/java/com/android/server/wm/DimAnimator.java index a9d4e01aedb19..85495ea21e57d 100644 --- a/services/java/com/android/server/wm/DimAnimator.java +++ b/services/java/com/android/server/wm/DimAnimator.java @@ -130,33 +130,31 @@ class DimAnimator { } } - boolean animating = false; - if (mLastDimAnimTime != 0) { + boolean animating = mLastDimAnimTime != 0; + if (animating) { mDimCurrentAlpha += mDimDeltaPerMs * (currentTime-mLastDimAnimTime); - boolean more = true; if (displayFrozen) { // If the display is frozen, there is no reason to animate. - more = false; + animating = false; } else if (mDimDeltaPerMs > 0) { if (mDimCurrentAlpha > mDimTargetAlpha) { - more = false; + animating = false; } } else if (mDimDeltaPerMs < 0) { if (mDimCurrentAlpha < mDimTargetAlpha) { - more = false; + animating = false; } } else { - more = false; + animating = false; } // Do we need to continue animating? - if (more) { + if (animating) { if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, " DIM " + mDimSurface + ": alpha=" + mDimCurrentAlpha); mLastDimAnimTime = currentTime; mDimSurface.setAlpha(mDimCurrentAlpha); - animating = true; } else { mDimCurrentAlpha = mDimTargetAlpha; mLastDimAnimTime = 0; diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index 407b7324806cc..79d2dd4a317a7 100644 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -18,7 +18,6 @@ package com.android.server.wm; import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW; -import static android.view.WindowManager.LayoutParams.FLAG_BLUR_BEHIND; import static android.view.WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW; import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND; import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON; @@ -173,7 +172,6 @@ public class WindowManagerService extends IWindowManager.Stub static final boolean HIDE_STACK_CRAWLS = true; static final boolean PROFILE_ORIENTATION = false; - static final boolean BLUR = true; static final boolean localLOGV = DEBUG; /** How much to multiply the policy's type layer, to reserve room @@ -195,11 +193,6 @@ public class WindowManagerService extends IWindowManager.Stub */ static final int LAYER_OFFSET_DIM = 1; - /** - * Blur surface layer is immediately below dim layer. - */ - static final int LAYER_OFFSET_BLUR = 2; - /** * Layer at which to put the rotation freeze snapshot. */ @@ -416,8 +409,6 @@ public class WindowManagerService extends IWindowManager.Stub SurfaceSession mFxSession; private DimAnimator mDimAnimator = null; - Surface mBlurSurface; - boolean mBlurShown; Watermark mWatermark; StrictModeFlash mStrictModeFlash; ScreenRotationAnimation mScreenRotationAnimation; @@ -597,7 +588,6 @@ public class WindowManagerService extends IWindowManager.Stub private int mAdjResult = 0; private Session mHoldScreen = null; private boolean mObscured = false; - private boolean mBlurring = false; private boolean mDimming = false; private boolean mSyswin = false; private float mScreenBrightness = -1; @@ -735,6 +725,7 @@ public class WindowManagerService extends IWindowManager.Stub mAllowBootMessages = allowBootMsgs; } + @Override public void run() { Looper.prepare(); WindowManagerService s = new WindowManagerService(mContext, mPM, @@ -774,6 +765,7 @@ public class WindowManagerService extends IWindowManager.Stub mPM = pm; } + @Override public void run() { Looper.prepare(); WindowManagerPolicyThread.set(this, Looper.myLooper()); @@ -2302,8 +2294,7 @@ public class WindowManagerService extends IWindowManager.Stub // to hold off on removing the window until the animation is done. // If the display is frozen, just remove immediately, since the // animation wouldn't be seen. - if (win.mSurface != null && !mDisplayFrozen && mDisplayEnabled - && mPolicy.isScreenOnFully()) { + if (win.mSurface != null && okToDisplay()) { // If we are not currently running the exit animation, we // need to see about starting one. if (wasVisible=win.isWinVisibleLw()) { @@ -2687,8 +2678,7 @@ public class WindowManagerService extends IWindowManager.Stub win.mEnterAnimationPending = true; } if (displayed) { - if (win.isDrawnLw() && !mDisplayFrozen - && mDisplayEnabled && mPolicy.isScreenOnFully()) { + if (win.isDrawnLw() && okToDisplay()) { applyEnterAnimationLocked(win); } if ((win.mAttrs.flags @@ -3015,7 +3005,7 @@ public class WindowManagerService extends IWindowManager.Stub // frozen, there is no reason to animate and it can cause strange // artifacts when we unfreeze the display if some different animation // is running. - if (!mDisplayFrozen && mDisplayEnabled && mPolicy.isScreenOnFully()) { + if (okToDisplay()) { int anim = mPolicy.selectAnimationLw(win, transit); int attr = -1; Animation a = null; @@ -3101,7 +3091,7 @@ public class WindowManagerService extends IWindowManager.Stub // frozen, there is no reason to animate and it can cause strange // artifacts when we unfreeze the display if some different animation // is running. - if (!mDisplayFrozen && mDisplayEnabled && mPolicy.isScreenOnFully()) { + if (okToDisplay()) { Animation a; if (mNextAppTransitionPackage != null) { a = loadAnimation(mNextAppTransitionPackage, enter ? @@ -3234,6 +3224,10 @@ public class WindowManagerService extends IWindowManager.Stub Slog.w(TAG, msg); return false; } + + boolean okToDisplay() { + return !mDisplayFrozen && mDisplayEnabled && mPolicy.isScreenOnFully(); + } AppWindowToken findAppWindowToken(IBinder token) { WindowToken wtoken = mTokenMap.get(token); @@ -3665,7 +3659,7 @@ public class WindowManagerService extends IWindowManager.Stub if (DEBUG_APP_TRANSITIONS) Slog.v( TAG, "Prepare app transition: transit=" + transit + " mNextAppTransition=" + mNextAppTransition); - if (!mDisplayFrozen && mDisplayEnabled && mPolicy.isScreenOnFully()) { + if (okToDisplay()) { if (mNextAppTransition == WindowManagerPolicy.TRANSIT_UNSET || mNextAppTransition == WindowManagerPolicy.TRANSIT_NONE) { mNextAppTransition = transit; @@ -3749,7 +3743,7 @@ public class WindowManagerService extends IWindowManager.Stub // If the display is frozen, we won't do anything until the // actual window is displayed so there is no reason to put in // the starting window. - if (mDisplayFrozen || !mDisplayEnabled || !mPolicy.isScreenOnFully()) { + if (!okToDisplay()) { return; } @@ -4039,8 +4033,7 @@ public class WindowManagerService extends IWindowManager.Stub // If we are preparing an app transition, then delay changing // the visibility of this token until we execute that transition. - if (!mDisplayFrozen && mDisplayEnabled && mPolicy.isScreenOnFully() - && mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) { + if (okToDisplay() && mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) { // Already in requested state, don't do anything more. if (wtoken.hiddenRequested != visible) { return; @@ -4168,7 +4161,7 @@ public class WindowManagerService extends IWindowManager.Stub } synchronized(mWindowMap) { - if (configChanges == 0 && !mDisplayFrozen && mPolicy.isScreenOnFully()) { + if (configChanges == 0 && okToDisplay()) { if (DEBUG_ORIENTATION) Slog.v(TAG, "Skipping set freeze of " + token); return; } @@ -5476,7 +5469,7 @@ public class WindowManagerService extends IWindowManager.Stub } } - rebuildBlackFrame(inTransaction); + rebuildBlackFrame(); for (int i=mWindows.size()-1; i>=0; i--) { WindowState w = mWindows.get(i); @@ -7151,45 +7144,32 @@ public class WindowManagerService extends IWindowManager.Stub } } - private void rebuildBlackFrame(boolean inTransaction) { - if (!inTransaction) { - if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, - ">>> OPEN TRANSACTION rebuildBlackFrame"); - Surface.openTransaction(); + private void rebuildBlackFrame() { + if (mBlackFrame != null) { + mBlackFrame.kill(); + mBlackFrame = null; } - try { - if (mBlackFrame != null) { - mBlackFrame.kill(); - mBlackFrame = null; + if (mBaseDisplayWidth < mInitialDisplayWidth + || mBaseDisplayHeight < mInitialDisplayHeight) { + int initW, initH, baseW, baseH; + final boolean rotated = (mRotation == Surface.ROTATION_90 + || mRotation == Surface.ROTATION_270); + if (rotated) { + initW = mInitialDisplayHeight; + initH = mInitialDisplayWidth; + baseW = mBaseDisplayHeight; + baseH = mBaseDisplayWidth; + } else { + initW = mInitialDisplayWidth; + initH = mInitialDisplayHeight; + baseW = mBaseDisplayWidth; + baseH = mBaseDisplayHeight; } - if (mBaseDisplayWidth < mInitialDisplayWidth - || mBaseDisplayHeight < mInitialDisplayHeight) { - int initW, initH, baseW, baseH; - final boolean rotated = (mRotation == Surface.ROTATION_90 - || mRotation == Surface.ROTATION_270); - if (rotated) { - initW = mInitialDisplayHeight; - initH = mInitialDisplayWidth; - baseW = mBaseDisplayHeight; - baseH = mBaseDisplayWidth; - } else { - initW = mInitialDisplayWidth; - initH = mInitialDisplayHeight; - baseW = mBaseDisplayWidth; - baseH = mBaseDisplayHeight; - } - Rect outer = new Rect(0, 0, initW, initH); - Rect inner = new Rect(0, 0, baseW, baseH); - try { - mBlackFrame = new BlackFrame(mFxSession, outer, inner, MASK_LAYER); - } catch (Surface.OutOfResourcesException e) { - } - } - } finally { - if (!inTransaction) { - Surface.closeTransaction(); - if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, - "<<< CLOSE TRANSACTION rebuildBlackFrame"); + Rect outer = new Rect(0, 0, initW, initH); + Rect inner = new Rect(0, 0, baseW, baseH); + try { + mBlackFrame = new BlackFrame(mFxSession, outer, inner, MASK_LAYER); + } catch (Surface.OutOfResourcesException e) { } } } @@ -7240,7 +7220,7 @@ public class WindowManagerService extends IWindowManager.Stub mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION); } - rebuildBlackFrame(false); + rebuildBlackFrame(); performLayoutAndPlaceSurfacesLocked(); } @@ -7625,7 +7605,7 @@ public class WindowManagerService extends IWindowManager.Stub // If the screen is currently frozen or off, then keep // it frozen/off until this window draws at its new // orientation. - if (mDisplayFrozen || !mPolicy.isScreenOnFully()) { + if (!okToDisplay()) { if (DEBUG_ORIENTATION) Slog.v(TAG, "Changing surface while display frozen: " + w); w.mOrientationChanging = true; @@ -7707,18 +7687,7 @@ public class WindowManagerService extends IWindowManager.Stub if (mDimAnimator != null && mDimAnimator.mDimShown) { mInnerFields.mAnimating |= mDimAnimator.updateSurface(mInnerFields.mDimming, currentTime, - mDisplayFrozen || !mDisplayEnabled || !mPolicy.isScreenOnFully()); - } - - if (!mInnerFields.mBlurring && mBlurShown) { - if (SHOW_TRANSACTIONS) Slog.i(TAG, " BLUR " + mBlurSurface - + ": HIDE"); - try { - mBlurSurface.hide(); - } catch (IllegalArgumentException e) { - Slog.w(TAG, "Illegal argument exception hiding blur surface"); - } - mBlurShown = false; + !okToDisplay()); } if (mBlackFrame != null) { @@ -7747,6 +7716,8 @@ public class WindowManagerService extends IWindowManager.Stub */ private int updateWindowsAndWallpaperLocked(final long currentTime, final int dw, final int dh, final int innerDw, final int innerDh) { + ++mTransactionSequence; + int changes = 0; for (int i = mWindows.size() - 1; i >= 0; i--) { WindowState w = mWindows.get(i); @@ -8301,9 +8272,9 @@ public class WindowManagerService extends IWindowManager.Stub // target, then the black goes *below* the wallpaper so we // don't cause the wallpaper to suddenly disappear. WindowState target = mInnerFields.mWindowAnimationBackground; - if (mWallpaperTarget == mInnerFields.mWindowAnimationBackground - || mLowerWallpaperTarget == mInnerFields.mWindowAnimationBackground - || mUpperWallpaperTarget == mInnerFields.mWindowAnimationBackground) { + if (mWallpaperTarget == target + || mLowerWallpaperTarget == target + || mUpperWallpaperTarget == target) { for (int i=0; i Date: Thu, 22 Mar 2012 08:33:09 -0700 Subject: [PATCH 028/132] Disable DisplayList properties DisplayList properties are (again) disabled by default, via flags in View.java and DisplayListRenderer.h. There are various artifacts to chase down before enabling by default. Issue #6198472 Native crash at pc 00076428 in many different apps in JRM80 Issue #6204173 Date/time picker isn't rendering all parts of UI Issue #6203941 All Apps overscroll effect is rendered weirdly/has flickering Issue #6200058 CAB rendering issue - not drawing items? Issue #6198578 Front camera shows black screen after taking picture. Change-Id: I045dc82ce1d85fedbae3bb88eb2a2dfb6891d41f --- core/java/android/view/View.java | 2 +- libs/hwui/DisplayListRenderer.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index d403cb9e603a6..ffffc7328c74d 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -1459,7 +1459,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal * apps. * @hide */ - public static final boolean USE_DISPLAY_LIST_PROPERTIES = true; + public static final boolean USE_DISPLAY_LIST_PROPERTIES = false; /** * Map used to store views' tags. diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h index 38d0374ca0894..4bbb04f36a417 100644 --- a/libs/hwui/DisplayListRenderer.h +++ b/libs/hwui/DisplayListRenderer.h @@ -51,7 +51,7 @@ namespace uirenderer { // Set to 1 to enable native processing of View properties. 0 by default. Eventually this // will go away and we will always use this approach for accelerated apps. -#define USE_DISPLAY_LIST_PROPERTIES 1 +#define USE_DISPLAY_LIST_PROPERTIES 0 #define TRANSLATION 0x0001 #define ROTATION 0x0002 From 1e6989e0f1f8d3eb42caddae889486de340f4287 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Mon, 26 Mar 2012 10:25:59 -0700 Subject: [PATCH 029/132] Turn off "too slow" logs. Change-Id: I6ec306ca1c55226269c4644a869a984c4fa00f0d --- services/java/com/android/server/am/ActivityManagerService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 60749b3e568d0..699bd50da16dd 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -3038,7 +3038,7 @@ public final class ActivityManagerService extends ActivityManagerNative } final void logAppTooSlow(ProcessRecord app, long startTime, String msg) { - if (IS_USER_BUILD) { + if (true && IS_USER_BUILD) { return; } String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null); From f015d6a564712c526517d80d9f8e3ded6c10b3f4 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Mon, 26 Mar 2012 10:50:54 -0700 Subject: [PATCH 030/132] Okay now let's really turn it off. Change-Id: Idda3c13339a6a29a300555d31e67219c9af4ae68 --- services/java/com/android/server/am/ActivityManagerService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 699bd50da16dd..37a594eef0e7a 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -3038,7 +3038,7 @@ public final class ActivityManagerService extends ActivityManagerNative } final void logAppTooSlow(ProcessRecord app, long startTime, String msg) { - if (true && IS_USER_BUILD) { + if (true || IS_USER_BUILD) { return; } String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null); From a7834574c1d7fa945ed61db4ea31f505d208764b Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Fri, 23 Mar 2012 17:24:07 -0700 Subject: [PATCH 031/132] Fixed headset detection broken on stingray commit 5e64321e broke the headset detection on stingray. This is because the name passed with the UEvent upon headset insertion/removal is different from the dev path (h2w). It actually indicates the type of headset connected. The fix consists in using the dev path received with the UEvent to find the corresponding entry in uEventInfo. Change-Id: I8481cfa17a7af3c8f5d83fc87d0f7c0d2c981098 --- .../server/WiredAccessoryObserver.java | 23 ++++++------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/services/java/com/android/server/WiredAccessoryObserver.java b/services/java/com/android/server/WiredAccessoryObserver.java index a7a46ddd5aa70..9b4eddc60bb60 100644 --- a/services/java/com/android/server/WiredAccessoryObserver.java +++ b/services/java/com/android/server/WiredAccessoryObserver.java @@ -66,7 +66,7 @@ class WiredAccessoryObserver extends UEventObserver { public String getDevName() { return mDevName; } public String getDevPath() { - return String.format("DEVPATH=/devices/virtual/switch/%s", mDevName); + return String.format("/devices/virtual/switch/%s", mDevName); } public String getSwitchStatePath() { @@ -158,7 +158,7 @@ class WiredAccessoryObserver extends UEventObserver { init(); // set initial status for (int i = 0; i < uEventInfo.size(); ++i) { UEventInfo uei = uEventInfo.get(i); - startObserving(uei.getDevPath()); + startObserving("DEVPATH="+uei.getDevPath()); } } } @@ -168,29 +168,20 @@ class WiredAccessoryObserver extends UEventObserver { if (LOG) Slog.v(TAG, "Headset UEVENT: " + event.toString()); try { + String devPath = event.get("DEVPATH"); String name = event.get("SWITCH_NAME"); int state = Integer.parseInt(event.get("SWITCH_STATE")); - updateState(name, state); + updateState(devPath, name, state); } catch (NumberFormatException e) { Slog.e(TAG, "Could not parse switch state from event " + event); } } - private synchronized final void updateState(String name, int state) + private synchronized final void updateState(String devPath, String name, int state) { - // FIXME: When ueventd informs of a change in state for a switch, it does not have to be - // the case that the name reported by /sys/class/switch//name is the same as - // . For normal users of the linux switch class driver, it will be. But it is - // technically possible to hook the print_name method in the class driver and return a - // different name each and every time the name sysfs entry is queried. - // - // Right now this is not the case for any of the switch implementations used here. I'm not - // certain anyone would ever choose to implement such a dynamic name, or what it would mean - // for the implementation at this level, but if it ever happens, we will need to revisit - // this code. for (int i = 0; i < uEventInfo.size(); ++i) { UEventInfo uei = uEventInfo.get(i); - if (name.equals(uei.getDevName())) { + if (devPath.equals(uei.getDevPath())) { update(name, uei.computeNewHeadsetState(mHeadsetState, state)); return; } @@ -213,7 +204,7 @@ class WiredAccessoryObserver extends UEventObserver { curState = Integer.valueOf((new String(buffer, 0, len)).trim()); if (curState > 0) { - updateState(uei.getDevName(), curState); + updateState(uei.getDevPath(), uei.getDevName(), curState); } } catch (FileNotFoundException e) { From b7b61b3af8319c6d00de7995c725e1a0f5f1ae4d Mon Sep 17 00:00:00 2001 From: Gilles Debunne Date: Tue, 27 Mar 2012 18:21:34 -0700 Subject: [PATCH 032/132] Handle non DynamicLayout in Editable draw method. An Editable text will use a BoringLayout when the text is empty. Fallback on the regular layout draw text method when the layout does not support the block optimisation. Change-Id: Ie4bdb4381f2f58b71d7c35b2f5734e544e3115ea --- core/java/android/widget/TextView.java | 107 +++++++++++++------------ 1 file changed, 54 insertions(+), 53 deletions(-) diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 1f2410bf3c04e..2c7a120d2d1d7 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -11708,66 +11708,67 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener layout.drawBackground(canvas, highlight, mHighlightPaint, cursorOffsetVertical, firstLine, lastLine); - if (mTextDisplayLists == null) { - mTextDisplayLists = new DisplayList[ArrayUtils.idealObjectArraySize(0)]; - } - if (! (layout instanceof DynamicLayout)) { - Log.e(LOG_TAG, "Editable TextView is not using a DynamicLayout"); - return; - } - - DynamicLayout dynamicLayout = (DynamicLayout) layout; - int[] blockEnds = dynamicLayout.getBlockEnds(); - int[] blockIndices = dynamicLayout.getBlockIndices(); - final int numberOfBlocks = dynamicLayout.getNumberOfBlocks(); - - canvas.translate(mScrollX, mScrollY); - int endOfPreviousBlock = -1; - int searchStartIndex = 0; - for (int i = 0; i < numberOfBlocks; i++) { - int blockEnd = blockEnds[i]; - int blockIndex = blockIndices[i]; - - final boolean blockIsInvalid = blockIndex == DynamicLayout.INVALID_BLOCK_INDEX; - if (blockIsInvalid) { - blockIndex = getAvailableDisplayListIndex(blockIndices, numberOfBlocks, - searchStartIndex); - // Dynamic layout internal block indices structure is updated from Editor - blockIndices[i] = blockIndex; - searchStartIndex = blockIndex + 1; + if (layout instanceof DynamicLayout) { + if (mTextDisplayLists == null) { + mTextDisplayLists = new DisplayList[ArrayUtils.idealObjectArraySize(0)]; } - DisplayList blockDisplayList = mTextDisplayLists[blockIndex]; - if (blockDisplayList == null) { - blockDisplayList = mTextDisplayLists[blockIndex] = - getHardwareRenderer().createDisplayList("Text " + blockIndex); - } else { - if (blockIsInvalid) blockDisplayList.invalidate(); - } + DynamicLayout dynamicLayout = (DynamicLayout) layout; + int[] blockEnds = dynamicLayout.getBlockEnds(); + int[] blockIndices = dynamicLayout.getBlockIndices(); + final int numberOfBlocks = dynamicLayout.getNumberOfBlocks(); - if (!blockDisplayList.isValid()) { - final HardwareCanvas hardwareCanvas = blockDisplayList.start(); - try { - hardwareCanvas.setViewport(width, height); - // The dirty rect should always be null for a display list - hardwareCanvas.onPreDraw(null); - hardwareCanvas.translate(-mScrollX, -mScrollY); - layout.drawText(hardwareCanvas, endOfPreviousBlock + 1, blockEnd); - hardwareCanvas.translate(mScrollX, mScrollY); - } finally { - hardwareCanvas.onPostDraw(); - blockDisplayList.end(); - if (USE_DISPLAY_LIST_PROPERTIES) { - blockDisplayList.setLeftTopRightBottom(0, 0, width, height); + canvas.translate(mScrollX, mScrollY); + int endOfPreviousBlock = -1; + int searchStartIndex = 0; + for (int i = 0; i < numberOfBlocks; i++) { + int blockEnd = blockEnds[i]; + int blockIndex = blockIndices[i]; + + final boolean blockIsInvalid = blockIndex == DynamicLayout.INVALID_BLOCK_INDEX; + if (blockIsInvalid) { + blockIndex = getAvailableDisplayListIndex(blockIndices, numberOfBlocks, + searchStartIndex); + // Dynamic layout internal block indices structure is updated from Editor + blockIndices[i] = blockIndex; + searchStartIndex = blockIndex + 1; + } + + DisplayList blockDisplayList = mTextDisplayLists[blockIndex]; + if (blockDisplayList == null) { + blockDisplayList = mTextDisplayLists[blockIndex] = + getHardwareRenderer().createDisplayList("Text " + blockIndex); + } else { + if (blockIsInvalid) blockDisplayList.invalidate(); + } + + if (!blockDisplayList.isValid()) { + final HardwareCanvas hardwareCanvas = blockDisplayList.start(); + try { + hardwareCanvas.setViewport(width, height); + // The dirty rect should always be null for a display list + hardwareCanvas.onPreDraw(null); + hardwareCanvas.translate(-mScrollX, -mScrollY); + layout.drawText(hardwareCanvas, endOfPreviousBlock + 1, blockEnd); + hardwareCanvas.translate(mScrollX, mScrollY); + } finally { + hardwareCanvas.onPostDraw(); + blockDisplayList.end(); + if (USE_DISPLAY_LIST_PROPERTIES) { + blockDisplayList.setLeftTopRightBottom(0, 0, width, height); + } } } - } - ((HardwareCanvas) canvas).drawDisplayList(blockDisplayList, width, height, null, - DisplayList.FLAG_CLIP_CHILDREN); - endOfPreviousBlock = blockEnd; + ((HardwareCanvas) canvas).drawDisplayList(blockDisplayList, width, height, null, + DisplayList.FLAG_CLIP_CHILDREN); + endOfPreviousBlock = blockEnd; + } + canvas.translate(-mScrollX, -mScrollY); + } else { + // Fallback on the layout method (a BoringLayout is used when the text is empty) + layout.drawText(canvas, firstLine, lastLine); } - canvas.translate(-mScrollX, -mScrollY); } private int getAvailableDisplayListIndex(int[] blockIndices, int numberOfBlocks, From bef6fde16a719428231c3c27f06d4987f899f332 Mon Sep 17 00:00:00 2001 From: Daniel Sandler Date: Thu, 29 Mar 2012 11:50:51 -0400 Subject: [PATCH 033/132] Fix NPE on tablets. Change-Id: I2128daac06988e4bae25ec48a874901ba731ebf9 --- .../statusbar/tablet/TabletStatusBar.java | 23 +------------------ 1 file changed, 1 insertion(+), 22 deletions(-) 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 87eb9ccfe8de7..9d5faa4ed0146 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java @@ -936,10 +936,8 @@ public class TabletStatusBar extends BaseStatusBar implements if (contentIntent != null) { final View.OnClickListener listener = new NotificationClicker(contentIntent, notification.pkg, notification.tag, notification.id); - oldEntry.largeIcon.setOnClickListener(listener); oldEntry.content.setOnClickListener(listener); } else { - oldEntry.largeIcon.setOnClickListener(null); oldEntry.content.setOnClickListener(null); } // Update the icon. @@ -951,13 +949,6 @@ public class TabletStatusBar extends BaseStatusBar implements handleNotificationError(key, notification, "Couldn't update icon: " + ic); return; } - // Update the large icon - if (notification.notification.largeIcon != null) { - oldEntry.largeIcon.setImageBitmap(notification.notification.largeIcon); - } else { - oldEntry.largeIcon.getLayoutParams().width = 0; - oldEntry.largeIcon.setVisibility(View.INVISIBLE); - } if (NOTIFICATION_PEEK_ENABLED && key == mNotificationPeekKey) { // must update the peek window @@ -1860,16 +1851,7 @@ public class TabletStatusBar extends BaseStatusBar implements vetoButton.setContentDescription(mContext.getString( R.string.accessibility_remove_notification)); - // the large icon - ImageView largeIcon = (ImageView)row.findViewById(R.id.large_icon); - if (sbn.notification.largeIcon != null) { - largeIcon.setImageBitmap(sbn.notification.largeIcon); - largeIcon.setContentDescription(sbn.notification.tickerText); - } else { - largeIcon.getLayoutParams().width = 0; - largeIcon.setVisibility(View.INVISIBLE); - } - largeIcon.setContentDescription(sbn.notification.tickerText); + // NB: the large icon is now handled entirely by the template // bind the click event to the content area ViewGroup content = (ViewGroup)row.findViewById(R.id.content); @@ -1880,10 +1862,8 @@ public class TabletStatusBar extends BaseStatusBar implements if (contentIntent != null) { final View.OnClickListener listener = new NotificationClicker( contentIntent, sbn.pkg, sbn.tag, sbn.id); - largeIcon.setOnClickListener(listener); content.setOnClickListener(listener); } else { - largeIcon.setOnClickListener(null); content.setOnClickListener(null); } @@ -1909,7 +1889,6 @@ public class TabletStatusBar extends BaseStatusBar implements entry.row = row; entry.content = content; entry.expanded = expanded; - entry.largeIcon = largeIcon; return true; } From c5d77a6ab234c25f86d97c6c6f9d3c7f468ea860 Mon Sep 17 00:00:00 2001 From: Chet Haase Date: Thu, 29 Mar 2012 09:42:34 -0700 Subject: [PATCH 034/132] Disable DisplayList properties pending fixes for AlphaAnimation The new DisplayList properties design has ordering conflicts with the way that alpha works with old animations (AlphaAnimation). This CL disables DiksplayList properties while I'm working on a fix and some more thorough tests for old animations-vs-DL properties in general. Change-Id: I8f6893138f939171491c2ec3c889214ee55d17b7 --- core/java/android/view/View.java | 2 +- libs/hwui/DisplayListRenderer.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 2deeba689397c..3afdfff348b3e 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -1459,7 +1459,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal * apps. * @hide */ - public static final boolean USE_DISPLAY_LIST_PROPERTIES = true; + public static final boolean USE_DISPLAY_LIST_PROPERTIES = false; /** * Map used to store views' tags. diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h index 4a9886b01f97a..fff1d7c64bbd7 100644 --- a/libs/hwui/DisplayListRenderer.h +++ b/libs/hwui/DisplayListRenderer.h @@ -51,7 +51,7 @@ namespace uirenderer { // Set to 1 to enable native processing of View properties. 0 by default. Eventually this // will go away and we will always use this approach for accelerated apps. -#define USE_DISPLAY_LIST_PROPERTIES 1 +#define USE_DISPLAY_LIST_PROPERTIES 0 #define TRANSLATION 0x0001 #define ROTATION 0x0002 From 513a2d14c818a00943de5c81d5e3988904d2f0a1 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Thu, 5 Apr 2012 10:50:05 -0700 Subject: [PATCH 035/132] Make sure initial activity state is correct. Change-Id: Ic6199b42e59afa06a0f38f866e2924b84cd234b3 --- core/java/android/nfc/NfcActivityManager.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/java/android/nfc/NfcActivityManager.java b/core/java/android/nfc/NfcActivityManager.java index 83354595eeb41..f80dae423f60a 100644 --- a/core/java/android/nfc/NfcActivityManager.java +++ b/core/java/android/nfc/NfcActivityManager.java @@ -114,6 +114,10 @@ public final class NfcActivityManager extends INdefPushCallback.Stub if (activity.getWindow().isDestroyed()) { throw new IllegalStateException("activity is already destroyed"); } + // Check if activity is resumed right now, as we will not + // immediately get a callback for that. + resumed = activity.isResumed(); + this.activity = activity; registerApplication(activity.getApplication()); } From f142beb2cba2422e8865985197f36cc97d2652a5 Mon Sep 17 00:00:00 2001 From: Craig Mautner Date: Thu, 5 Apr 2012 13:10:37 -0700 Subject: [PATCH 036/132] Fix failure to animate away exiting AppWindowToken A previous check in changed the collection we were pulling exiting AppWindowTokens from. Instead of pulling them from mExitingAppTokens they came from mAppTokens and hence were not animated away. Fixes bug 6296433. Change-Id: I23347085658fce5412abb8ea119ce7e6152cab8b --- services/java/com/android/server/wm/WindowAnimator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/java/com/android/server/wm/WindowAnimator.java b/services/java/com/android/server/wm/WindowAnimator.java index 77f94d95e55a8..9b196cc790a39 100644 --- a/services/java/com/android/server/wm/WindowAnimator.java +++ b/services/java/com/android/server/wm/WindowAnimator.java @@ -139,7 +139,7 @@ public class WindowAnimator { final int NEAT = mService.mExitingAppTokens.size(); for (i=0; i Date: Thu, 5 Apr 2012 17:08:46 -0700 Subject: [PATCH 037/132] Minor twaek to the focus behavior. bug:6296603 Change-Id: I3bd0b291e6013cae019ca9049d9d3dc506845ab0 --- core/java/android/view/View.java | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 5d7c8cd15669c..3c4b866c461dd 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -4059,14 +4059,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal void ensureInputFocusOnFirstFocusable() { View root = getRootView(); if (root != null) { - // Find the first focusble from the top. - View next = root.focusSearch(FOCUS_FORWARD); - if (next != null) { - // Giving focus to the found focusable will not - // perform a search since we found a view that is - // guaranteed to be able to take focus. - next.requestFocus(FOCUS_FORWARD); - } + root.requestFocus(FOCUS_FORWARD); } } From f90ee959c45a23309baf92a79b77b453126c250c Mon Sep 17 00:00:00 2001 From: Craig Mautner Date: Thu, 5 Apr 2012 19:25:51 -0700 Subject: [PATCH 038/132] Fix looping to turn off dimming. Dimming was constantly being turned off if it wasn't time to turn it on. This caused endless reentry into the Window Manager and consumed lots of CPU. Fixes bug 6293953. Change-Id: Id87e60c7c70e96e66ce0b6297442f5ac0d2ff477 --- .../java/com/android/server/wm/WindowAnimator.java | 11 +++++------ .../com/android/server/wm/WindowManagerService.java | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/services/java/com/android/server/wm/WindowAnimator.java b/services/java/com/android/server/wm/WindowAnimator.java index 9b196cc790a39..67e057e7b8454 100644 --- a/services/java/com/android/server/wm/WindowAnimator.java +++ b/services/java/com/android/server/wm/WindowAnimator.java @@ -440,9 +440,12 @@ public class WindowAnimator { w.mWinAnimator.prepareSurfaceLocked(true); } + if (mDimParams != null) { + mDimAnimator.updateParameters(mContext.getResources(), mDimParams, mCurrentTime); + } if (mDimAnimator != null && mDimAnimator.mDimShown) { - mAnimating |= mDimAnimator.updateSurface(mService.mInnerFields.mDimming, - mCurrentTime, !mService.okToDisplay()); + mAnimating |= mDimAnimator.updateSurface(mDimParams != null, mCurrentTime, + !mService.okToDisplay()); } if (mService.mBlackFrame != null) { @@ -453,10 +456,6 @@ public class WindowAnimator { mService.mBlackFrame.clearMatrix(); } } - - if (mDimParams != null) { - mDimAnimator.updateParameters(mContext.getResources(), mDimParams, mCurrentTime); - } } catch (RuntimeException e) { Log.wtf(TAG, "Unhandled exception in Window Manager", e); } finally { diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index 7eca401bcfea2..7a9a4f8efc82a 100644 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -8419,7 +8419,7 @@ public class WindowManagerService extends IWindowManager.Stub updateWallpaperVisibilityLocked(); } } - if (!mInnerFields.mDimming) { + if (!mInnerFields.mDimming && mAnimator.mDimParams != null) { mAnimator.stopDimming(); } } catch (RuntimeException e) { From f61847476b493f5a5f7d8b99119070383c8ab8d7 Mon Sep 17 00:00:00 2001 From: Gilles Debunne Date: Mon, 9 Apr 2012 16:02:31 -0700 Subject: [PATCH 039/132] Faster and simpler replace in SSB, take two This is a new version of CL 179343 which had to be reverted. This problem of the previous CL is that the ComposingSpan that was part of the replacement text was correctly added during the replace but was immediately removed because it had a zero-length size. Swapping the add and remove blocks solves the problem. The new non-zero length enforcement also revealed a bug in the spell checker where we were creating useless range spans. Change-Id: I59cebd4708af3becc7ab625ae41bc36837f1a1cf --- .../android/text/SpannableStringBuilder.java | 147 ++++++++---------- core/java/android/widget/SpellChecker.java | 13 +- 2 files changed, 70 insertions(+), 90 deletions(-) diff --git a/core/java/android/text/SpannableStringBuilder.java b/core/java/android/text/SpannableStringBuilder.java index ae9042cf3952a..0f8efd10f4360 100644 --- a/core/java/android/text/SpannableStringBuilder.java +++ b/core/java/android/text/SpannableStringBuilder.java @@ -50,6 +50,8 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable public SpannableStringBuilder(CharSequence text, int start, int end) { int srclen = end - start; + if (srclen < 0) throw new StringIndexOutOfBoundsException(); + int len = ArrayUtils.idealCharArraySize(srclen + 1); mText = new char[len]; mGapStart = srclen; @@ -87,7 +89,7 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable if (en > end - start) en = end - start; - setSpan(spans[i], st, en, fl); + setSpan(false, spans[i], st, en, fl); } } } @@ -149,7 +151,7 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable if (where == mGapStart) return; - boolean atend = (where == length()); + boolean atEnd = (where == length()); if (where < mGapStart) { int overlap = mGapStart - where; @@ -171,7 +173,7 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable else if (start == where) { int flag = (mSpanFlags[i] & START_MASK) >> START_SHIFT; - if (flag == POINT || (atend && flag == PARAGRAPH)) + if (flag == POINT || (atEnd && flag == PARAGRAPH)) start += mGapLength; } @@ -182,7 +184,7 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable else if (end == where) { int flag = (mSpanFlags[i] & END_MASK); - if (flag == POINT || (atend && flag == PARAGRAPH)) + if (flag == POINT || (atEnd && flag == PARAGRAPH)) end += mGapLength; } @@ -284,7 +286,7 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable } if (st != ost || en != oen) - setSpan(mSpans[i], st, en, mSpanFlags[i]); + setSpan(false, mSpans[i], st, en, mSpanFlags[i]); } } @@ -305,28 +307,6 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable TextUtils.getChars(tb, tbstart, tbend, mText, start); - if (tb instanceof Spanned) { - Spanned sp = (Spanned) tb; - Object[] spans = sp.getSpans(tbstart, tbend, Object.class); - - for (int i = 0; i < spans.length; i++) { - int st = sp.getSpanStart(spans[i]); - int en = sp.getSpanEnd(spans[i]); - - if (st < tbstart) - st = tbstart; - if (en > tbend) - en = tbend; - - if (getSpanStart(spans[i]) < 0) { - setSpan(false, spans[i], - st - tbstart + start, - en - tbstart + start, - sp.getSpanFlags(spans[i])); - } - } - } - if (end > start) { // no need for span fixup on pure insertion boolean atEnd = (mGapStart + mGapLength == mText.length); @@ -358,6 +338,25 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable } } } + + if (tb instanceof Spanned) { + Spanned sp = (Spanned) tb; + Object[] spans = sp.getSpans(tbstart, tbend, Object.class); + + for (int i = 0; i < spans.length; i++) { + int st = sp.getSpanStart(spans[i]); + int en = sp.getSpanEnd(spans[i]); + + if (st < tbstart) st = tbstart; + if (en > tbend) en = tbend; + + // Add span only if this object is not yet used as a span in this string + if (getSpanStart(spans[i]) < 0) { + setSpan(false, spans[i], st - tbstart + start, en - tbstart + start, + sp.getSpanFlags(spans[i])); + } + } + } } private void removeSpan(int i) { @@ -389,7 +388,7 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable // Documentation from interface public SpannableStringBuilder replace(final int start, final int end, - CharSequence tb, int tbstart, int tbend) { + CharSequence tb, int tbstart, int tbend) { int filtercount = mFilters.length; for (int i = 0; i < filtercount; i++) { CharSequence repl = mFilters[i].filter(tb, tbstart, tbend, this, start, end); @@ -411,53 +410,26 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable TextWatcher[] textWatchers = getSpans(start, start + origLen, TextWatcher.class); sendBeforeTextChanged(textWatchers, start, origLen, newLen); - if (origLen == 0 || newLen == 0) { - change(start, end, tb, tbstart, tbend); - } else { - int selstart = Selection.getSelectionStart(this); - int selend = Selection.getSelectionEnd(this); + // Try to keep the cursor / selection at the same relative position during + // a text replacement. If replaced or replacement text length is zero, this + // is already taken care of. + boolean adjustSelection = origLen != 0 && newLen != 0; + int selstart = 0; + int selend = 0; + if (adjustSelection) { + selstart = Selection.getSelectionStart(this); + selend = Selection.getSelectionEnd(this); + } - // XXX just make the span fixups in change() do the right thing - // instead of this madness! + checkRange("replace", start, end); - checkRange("replace", start, end); - moveGapTo(end); + change(start, end, tb, tbstart, tbend); - if (mGapLength < 2) - resizeFor(length() + 1); - - for (int i = mSpanCount - 1; i >= 0; i--) { - if (mSpanStarts[i] == mGapStart) - mSpanStarts[i]++; - - if (mSpanEnds[i] == mGapStart) - mSpanEnds[i]++; - } - - mText[mGapStart] = ' '; - mGapStart++; - mGapLength--; - - if (mGapLength < 1) { - new Exception("mGapLength < 1").printStackTrace(); - } - - change(start + 1, start + 1, tb, tbstart, tbend); - change(start, start + 1, "", 0, 0); - change(start + newLen, start + newLen + origLen, "", 0, 0); - - /* - * Special case to keep the cursor in the same position - * if it was somewhere in the middle of the replaced region. - * If it was at the start or the end or crossing the whole - * replacement, it should already be where it belongs. - * TODO: Is there some more general mechanism that could - * accomplish this? - */ + if (adjustSelection) { if (selstart > start && selstart < end) { long off = selstart - start; - off = off * newLen / (end - start); + off = off * newLen / origLen; selstart = (int) off + start; setSpan(false, Selection.SELECTION_START, selstart, selstart, @@ -466,7 +438,7 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable if (selend > start && selend < end) { long off = selend - start; - off = off * newLen / (end - start); + off = off * newLen / origLen; selend = (int) off + start; setSpan(false, Selection.SELECTION_END, selend, selend, Spanned.SPAN_POINT_POINT); @@ -489,12 +461,10 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable } private void setSpan(boolean send, Object what, int start, int end, int flags) { - int nstart = start; - int nend = end; - checkRange("setSpan", start, end); - if ((flags & START_MASK) == (PARAGRAPH << START_SHIFT)) { + int flagsStart = (flags & START_MASK) >> START_SHIFT; + if (flagsStart == PARAGRAPH) { if (start != 0 && start != length()) { char c = charAt(start - 1); @@ -503,7 +473,8 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable } } - if ((flags & END_MASK) == PARAGRAPH) { + int flagsEnd = flags & END_MASK; + if (flagsEnd == PARAGRAPH) { if (end != 0 && end != length()) { char c = charAt(end - 1); @@ -512,26 +483,33 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable } } - if (flags == Spanned.SPAN_EXCLUSIVE_EXCLUSIVE && start == end) { - throw new IllegalArgumentException( - "SPAN_EXCLUSIVE_EXCLUSIVE spans cannot have a zero length"); + // 0-length Spanned.SPAN_EXCLUSIVE_EXCLUSIVE + if (flagsStart == POINT && flagsEnd == MARK && start == end) { + if (send) { + throw new IllegalArgumentException( + "SPAN_EXCLUSIVE_EXCLUSIVE spans cannot have a zero length"); + } else { + // Silently ignore invalid spans when they are created from this class. + // This avoids the duplication of the above test code before all the + // calls to setSpan that are done in this class + return; + } } + int nstart = start; + int nend = end; + if (start > mGapStart) { start += mGapLength; } else if (start == mGapStart) { - int flag = (flags & START_MASK) >> START_SHIFT; - - if (flag == POINT || (flag == PARAGRAPH && start == length())) + if (flagsStart == POINT || (flagsStart == PARAGRAPH && start == length())) start += mGapLength; } if (end > mGapStart) { end += mGapLength; } else if (end == mGapStart) { - int flag = (flags & END_MASK); - - if (flag == POINT || (flag == PARAGRAPH && end == length())) + if (flagsEnd == POINT || (flagsEnd == PARAGRAPH && end == length())) end += mGapLength; } @@ -1231,6 +1209,7 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable private int mSpanCount; // TODO These value are tightly related to the public SPAN_MARK/POINT values in {@link Spanned} + private static final int MARK = 1; private static final int POINT = 2; private static final int PARAGRAPH = 3; diff --git a/core/java/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java index 9afaee3c786c8..c725b64bf8d19 100644 --- a/core/java/android/widget/SpellChecker.java +++ b/core/java/android/widget/SpellChecker.java @@ -227,8 +227,7 @@ public class SpellChecker implements SpellCheckerSessionListener { for (int i = 0; i < length; i++) { final SpellParser spellParser = mSpellParsers[i]; if (spellParser.isFinished()) { - spellParser.init(start, end); - spellParser.parse(); + spellParser.parse(start, end); return; } } @@ -240,8 +239,7 @@ public class SpellChecker implements SpellCheckerSessionListener { SpellParser spellParser = new SpellParser(); mSpellParsers[length] = spellParser; - spellParser.init(start, end); - spellParser.parse(); + spellParser.parse(start, end); } private void spellCheck() { @@ -421,8 +419,11 @@ public class SpellChecker implements SpellCheckerSessionListener { private class SpellParser { private Object mRange = new Object(); - public void init(int start, int end) { - setRangeSpan((Editable) mTextView.getText(), start, end); + public void parse(int start, int end) { + if (end > start) { + setRangeSpan((Editable) mTextView.getText(), start, end); + parse(); + } } public boolean isFinished() { From 302279ae23565b9f2d616ca6f3e5f71aafe429cb Mon Sep 17 00:00:00 2001 From: Craig Mautner Date: Tue, 10 Apr 2012 12:56:27 -0700 Subject: [PATCH 040/132] Reduce load on CPU when animating rotation. This change keeps requestTraversalLocked from being called on virtually every call to animate while rotating. Change-Id: I6d2db37db3bb82f4f9ecc84b17dbf121819a6c1b --- .../com/android/server/wm/WindowAnimator.java | 4 +--- .../server/wm/WindowManagerService.java | 22 +++++++++++++------ 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/services/java/com/android/server/wm/WindowAnimator.java b/services/java/com/android/server/wm/WindowAnimator.java index 0d64b68cfdd48..1198a77936d79 100644 --- a/services/java/com/android/server/wm/WindowAnimator.java +++ b/services/java/com/android/server/wm/WindowAnimator.java @@ -471,9 +471,7 @@ public class WindowAnimator { Surface.closeTransaction(); } - if (mBulkUpdateParams != 0) { - mService.bulkSetParameters(mBulkUpdateParams); - } + mService.bulkSetParameters(mBulkUpdateParams); } WindowState mCurrentFocus; diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index 00972fae48f11..86f4ca31ce453 100644 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -6882,22 +6882,33 @@ public class WindowManagerService extends IWindowManager.Stub case BULK_UPDATE_PARAMETERS: { // Used to send multiple changes from the animation side to the layout side. synchronized (mWindowMap) { + boolean doRequest = false; // TODO(cmautner): As the number of bits grows, use masks of bit groups to // eliminate unnecessary tests. if ((msg.arg1 & LayoutFields.SET_UPDATE_ROTATION) != 0) { mInnerFields.mUpdateRotation = true; + doRequest = true; } if ((msg.arg1 & LayoutFields.SET_WALLPAPER_MAY_CHANGE) != 0) { mInnerFields.mWallpaperMayChange = true; + doRequest = true; } if ((msg.arg1 & LayoutFields.SET_FORCE_HIDING_CHANGED) != 0) { mInnerFields.mWallpaperForceHidingChanged = true; + doRequest = true; } if ((msg.arg1 & LayoutFields.CLEAR_ORIENTATION_CHANGE_COMPLETE) != 0) { mInnerFields.mOrientationChangeComplete = false; + } else { + mInnerFields.mOrientationChangeComplete = true; + if (mWindowsFreezingScreen) { + doRequest = true; + } } - requestTraversalLocked(); + if (doRequest) { + requestTraversalLocked(); + } } break; } @@ -8472,11 +8483,13 @@ public class WindowManagerService extends IWindowManager.Stub !mInnerFields.mUpdateRotation) { checkDrawnWindowsLocked(); } - mInnerFields.mOrientationChangeComplete = true; // Check to see if we are now in a state where the screen should // be enabled, because the window obscured flags have changed. enableScreenIfNeededLocked(); +// Slog.e(TAG, "performLayoutAndPlaceSurfacesLockedInner exit: mPendingLayoutChanges=" +// + Integer.toHexString(mPendingLayoutChanges) + " mLayoutNeeded=" + mLayoutNeeded +// + " animating=" + mAnimator.mAnimating); } void checkDrawnWindowsLocked() { @@ -9512,11 +9525,6 @@ public class WindowManagerService extends IWindowManager.Stub public void onHardKeyboardStatusChange(boolean available, boolean enabled); } - void notifyAnimationChangedLayout(final int pendingLayoutChanges) { - mPendingLayoutChanges |= pendingLayoutChanges; - requestTraversalLocked(); - } - void debugLayoutRepeats(final String msg, int pendingLayoutChanges) { if (mLayoutRepeatCount >= LAYOUT_REPEAT_THRESHOLD) { Slog.v(TAG, "Layouts looping: " + msg + ", mPendingLayoutChanges = 0x" + From 184c6498befcf666ea5da45329d724d67de2b36a Mon Sep 17 00:00:00 2001 From: Gilles Debunne Date: Tue, 10 Apr 2012 13:25:33 -0700 Subject: [PATCH 041/132] Removed exception from SpannableStringBuilder Bug 6312196 Change-Id: I9cece36b40d8948e0e85bd433954818991009ad5 --- .../android/text/SpannableStringBuilder.java | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/core/java/android/text/SpannableStringBuilder.java b/core/java/android/text/SpannableStringBuilder.java index 0f8efd10f4360..6056c75f3b967 100644 --- a/core/java/android/text/SpannableStringBuilder.java +++ b/core/java/android/text/SpannableStringBuilder.java @@ -18,6 +18,7 @@ package android.text; import android.graphics.Canvas; import android.graphics.Paint; +import android.util.Log; import com.android.internal.util.ArrayUtils; @@ -485,15 +486,12 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable // 0-length Spanned.SPAN_EXCLUSIVE_EXCLUSIVE if (flagsStart == POINT && flagsEnd == MARK && start == end) { - if (send) { - throw new IllegalArgumentException( - "SPAN_EXCLUSIVE_EXCLUSIVE spans cannot have a zero length"); - } else { - // Silently ignore invalid spans when they are created from this class. - // This avoids the duplication of the above test code before all the - // calls to setSpan that are done in this class - return; - } + if (send) Log.e("SpannableStringBuilder", + "SPAN_EXCLUSIVE_EXCLUSIVE spans cannot have a zero length"); + // Silently ignore invalid spans when they are created from this class. + // This avoids the duplication of the above test code before all the + // calls to setSpan that are done in this class + return; } int nstart = start; From 4d07a53c7c9dddf8f7852b4a57d687b9ec9af10c Mon Sep 17 00:00:00 2001 From: Jack Palevich Date: Tue, 10 Apr 2012 05:56:19 -0700 Subject: [PATCH 042/132] Notify monitor waiters when changing mSurfaceIsBad value. Otherwise the waiters might not wake up, leading to ANRs. Bug: 6307843 Change-Id: I0646b4e8368f80dbff46342f75709992796973fd --- opengl/java/android/opengl/GLSurfaceView.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/opengl/java/android/opengl/GLSurfaceView.java b/opengl/java/android/opengl/GLSurfaceView.java index c937a09317c6f..2a4d59b9443e3 100644 --- a/opengl/java/android/opengl/GLSurfaceView.java +++ b/opengl/java/android/opengl/GLSurfaceView.java @@ -1459,7 +1459,10 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback Log.w("GLThread", "egl createSurface"); } if (!mEglHelper.createSurface()) { - mSurfaceIsBad = true; + synchronized(sGLThreadManager) { + mSurfaceIsBad = true; + sGLThreadManager.notifyAll(); + } continue; } createEglSurface = false; @@ -1519,7 +1522,11 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback // but we haven't been notified yet. // Log the error to help developers understand why rendering stopped. EglHelper.logEglErrorAsWarning("GLThread", "eglSwapBuffers", swapError); - mSurfaceIsBad = true; + + synchronized(sGLThreadManager) { + mSurfaceIsBad = true; + sGLThreadManager.notifyAll(); + } break; } From 92096a18421b4f65549d811c5be5c61dad31c665 Mon Sep 17 00:00:00 2001 From: Craig Mautner Date: Mon, 9 Apr 2012 15:23:59 -0700 Subject: [PATCH 043/132] Fix IndexOutOfBoundsException. This fix resolves an exception thrown when the snapshot ArrayList has no entries. Fixes bug 6311207. Change-Id: I84383417116a4a62eb2842792ed04096aebc8ee2 --- .../systemui/statusbar/phone/PhoneStatusBar.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index 804ae06aaf864..3f611fc1620c5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -2047,7 +2047,10 @@ public class PhoneStatusBar extends BaseStatusBar { snapshot.add(child); } } - final int N = snapshot.size(); + if (snapshot.isEmpty()) { + animateCollapse(false); + return; + } new Thread(new Runnable() { @Override public void run() { @@ -2063,6 +2066,7 @@ public class PhoneStatusBar extends BaseStatusBar { mPile.setViewRemoval(false); mPostCollapseCleanup = new Runnable() { + @Override public void run() { try { mPile.setViewRemoval(true); @@ -2073,9 +2077,8 @@ public class PhoneStatusBar extends BaseStatusBar { View sampleView = snapshot.get(0); int width = sampleView.getWidth(); - final int velocity = (int)(width * 8); // 1000/8 = 125 ms duration - for (View v : snapshot) { - final View _v = v; + final int velocity = width * 8; // 1000/8 = 125 ms duration + for (final View _v : snapshot) { mHandler.postDelayed(new Runnable() { @Override public void run() { @@ -2091,6 +2094,7 @@ public class PhoneStatusBar extends BaseStatusBar { // synchronize the end of those animations with the start of the collaps // exactly. mHandler.postDelayed(new Runnable() { + @Override public void run() { animateCollapse(false); } From 2c242e0baa894592815334d512ea7780d1d538f3 Mon Sep 17 00:00:00 2001 From: Craig Mautner Date: Tue, 10 Apr 2012 14:24:38 -0700 Subject: [PATCH 044/132] Fix NPE in setTransparentRegion. Check for null Surface before using it. Fixes bug 6312835. Change-Id: Iaaac2a5d88e81b88e369815e09818c268085e4b7 --- services/java/com/android/server/wm/WindowManagerService.java | 2 -- services/java/com/android/server/wm/WindowStateAnimator.java | 4 ++++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index 86f4ca31ce453..8d65dc3539c0f 100644 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -6919,8 +6919,6 @@ public class WindowManagerService extends IWindowManager.Stub (Pair) msg.obj; final WindowStateAnimator winAnimator = pair.first; winAnimator.setTransparentRegionHint(pair.second); - - scheduleAnimationLocked(); break; } diff --git a/services/java/com/android/server/wm/WindowStateAnimator.java b/services/java/com/android/server/wm/WindowStateAnimator.java index 220f5e08406b7..941a5e1b68d27 100644 --- a/services/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/java/com/android/server/wm/WindowStateAnimator.java @@ -943,6 +943,10 @@ class WindowStateAnimator { } void setTransparentRegionHint(final Region region) { + if (mSurface == null) { + Slog.w(TAG, "setTransparentRegionHint: null mSurface after mHasSurface true"); + return; + } if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION setTransparentRegion"); Surface.openTransaction(); From 34414ae190ba940523ae89c0d9ad36c3ec5dda2f Mon Sep 17 00:00:00 2001 From: Jeff Brown Date: Tue, 10 Apr 2012 20:36:07 -0700 Subject: [PATCH 045/132] Be more careful about exceptions in input callbacks. consumeEvents() may be called reentrantly so we need to be careful when handling exceptions. When called directly through JNI, the exception should be allowed to bubble up to the caller. When called from a Looper callback, the exception should be recorded on the MessageQueue and bubbled when the call to nativePollOnce() returns. Bug: 6312938 Change-Id: Ief5e315802f586aa85af7eef1bd6e9bea4ce24ab --- core/jni/android_view_InputEventReceiver.cpp | 89 +++++++++++--------- 1 file changed, 47 insertions(+), 42 deletions(-) diff --git a/core/jni/android_view_InputEventReceiver.cpp b/core/jni/android_view_InputEventReceiver.cpp index 348437d0f34ab..8f6f5f4966a3b 100644 --- a/core/jni/android_view_InputEventReceiver.cpp +++ b/core/jni/android_view_InputEventReceiver.cpp @@ -52,8 +52,7 @@ public: status_t initialize(); status_t finishInputEvent(uint32_t seq, bool handled); - status_t consumeEvents(bool consumeBatches); - static int handleReceiveCallback(int receiveFd, int events, void* data); + status_t consumeEvents(JNIEnv* env, bool consumeBatches); protected: virtual ~NativeInputEventReceiver(); @@ -68,6 +67,8 @@ private: const char* getInputChannelName() { return mInputConsumer.getChannel()->getName().string(); } + + static int handleReceiveCallback(int receiveFd, int events, void* data); }; @@ -128,11 +129,13 @@ int NativeInputEventReceiver::handleReceiveCallback(int receiveFd, int events, v return 1; } - status_t status = r->consumeEvents(false /*consumeBatches*/); + JNIEnv* env = AndroidRuntime::getJNIEnv(); + status_t status = r->consumeEvents(env, false /*consumeBatches*/); + r->mMessageQueue->raiseAndClearException(env, "handleReceiveCallback"); return status == OK || status == NO_MEMORY ? 1 : 0; } -status_t NativeInputEventReceiver::consumeEvents(bool consumeBatches) { +status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env, bool consumeBatches) { #if DEBUG_DISPATCH_CYCLE ALOGD("channel '%s' ~ Consuming input events, consumeBatches=%s.", getInputChannelName(), consumeBatches ? "true" : "false"); @@ -142,7 +145,7 @@ status_t NativeInputEventReceiver::consumeEvents(bool consumeBatches) { mBatchedInputEventPending = false; } - JNIEnv* env = AndroidRuntime::getJNIEnv(); + bool skipCallbacks = false; for (;;) { uint32_t seq; InputEvent* inputEvent; @@ -150,7 +153,8 @@ status_t NativeInputEventReceiver::consumeEvents(bool consumeBatches) { consumeBatches, &seq, &inputEvent); if (status) { if (status == WOULD_BLOCK) { - if (mInputConsumer.hasPendingBatch() && !mBatchedInputEventPending) { + if (!skipCallbacks && !mBatchedInputEventPending + && mInputConsumer.hasPendingBatch()) { // There is a pending batch. Come back later. mBatchedInputEventPending = true; #if DEBUG_DISPATCH_CYCLE @@ -159,8 +163,8 @@ status_t NativeInputEventReceiver::consumeEvents(bool consumeBatches) { #endif env->CallVoidMethod(mReceiverObjGlobal, gInputEventReceiverClassInfo.dispatchBatchedInputEventPending); - if (mMessageQueue->raiseAndClearException( - env, "dispatchBatchedInputEventPending")) { + if (env->ExceptionCheck()) { + ALOGE("Exception dispatching batched input events."); mBatchedInputEventPending = false; // try again later } } @@ -172,46 +176,47 @@ status_t NativeInputEventReceiver::consumeEvents(bool consumeBatches) { } assert(inputEvent); - jobject inputEventObj; - switch (inputEvent->getType()) { - case AINPUT_EVENT_TYPE_KEY: + if (!skipCallbacks) { + jobject inputEventObj; + switch (inputEvent->getType()) { + case AINPUT_EVENT_TYPE_KEY: #if DEBUG_DISPATCH_CYCLE - ALOGD("channel '%s' ~ Received key event.", getInputChannelName()); + ALOGD("channel '%s' ~ Received key event.", getInputChannelName()); #endif - inputEventObj = android_view_KeyEvent_fromNative(env, - static_cast(inputEvent)); - mMessageQueue->raiseAndClearException(env, "new KeyEvent"); - break; + inputEventObj = android_view_KeyEvent_fromNative(env, + static_cast(inputEvent)); + break; - case AINPUT_EVENT_TYPE_MOTION: + case AINPUT_EVENT_TYPE_MOTION: #if DEBUG_DISPATCH_CYCLE - ALOGD("channel '%s' ~ Received motion event.", getInputChannelName()); + ALOGD("channel '%s' ~ Received motion event.", getInputChannelName()); #endif - inputEventObj = android_view_MotionEvent_obtainAsCopy(env, - static_cast(inputEvent)); - mMessageQueue->raiseAndClearException(env, "new MotionEvent"); - break; + inputEventObj = android_view_MotionEvent_obtainAsCopy(env, + static_cast(inputEvent)); + break; - default: - assert(false); // InputConsumer should prevent this from ever happening - inputEventObj = NULL; + default: + assert(false); // InputConsumer should prevent this from ever happening + inputEventObj = NULL; + } + + if (inputEventObj) { +#if DEBUG_DISPATCH_CYCLE + ALOGD("channel '%s' ~ Dispatching input event.", getInputChannelName()); +#endif + env->CallVoidMethod(mReceiverObjGlobal, + gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj); + if (env->ExceptionCheck()) { + ALOGE("Exception dispatching input event."); + skipCallbacks = true; + } + } else { + ALOGW("channel '%s' ~ Failed to obtain event object.", getInputChannelName()); + skipCallbacks = true; + } } - if (!inputEventObj) { - ALOGW("channel '%s' ~ Failed to obtain event object.", getInputChannelName()); - mInputConsumer.sendFinishedSignal(seq, false); - continue; - } - -#if DEBUG_DISPATCH_CYCLE - ALOGD("channel '%s' ~ Dispatching input event.", getInputChannelName()); -#endif - env->CallVoidMethod(mReceiverObjGlobal, - gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj); - - env->DeleteLocalRef(inputEventObj); - - if (mMessageQueue->raiseAndClearException(env, "dispatchInputEvent")) { + if (skipCallbacks) { mInputConsumer.sendFinishedSignal(seq, false); } } @@ -268,8 +273,8 @@ static void nativeFinishInputEvent(JNIEnv* env, jclass clazz, jint receiverPtr, static void nativeConsumeBatchedInputEvents(JNIEnv* env, jclass clazz, jint receiverPtr) { sp receiver = reinterpret_cast(receiverPtr); - status_t status = receiver->consumeEvents(true /*consumeBatches*/); - if (status && status != DEAD_OBJECT) { + status_t status = receiver->consumeEvents(env, true /*consumeBatches*/); + if (status && status != DEAD_OBJECT && !env->ExceptionCheck()) { String8 message; message.appendFormat("Failed to consume batched input event. status=%d", status); jniThrowRuntimeException(env, message.string()); From 7d32012c566e321cca7bb578aa5564e7cafc9720 Mon Sep 17 00:00:00 2001 From: James Dong Date: Wed, 11 Apr 2012 13:09:03 -0700 Subject: [PATCH 046/132] Fix thumbnail generation failure o Change the impl of MediaMetadataRetriever.setDataSource(String). It opens and passes an fd to the media framework rather than pass the file path directly to the media server. The change is needed since media server does not have read permission to sdcard o Remove the unnecessary jni method Change-Id: I5a2f47dde804523d264b588f855ba2575a99c179 --- .../android/media/MediaMetadataRetriever.java | 20 ++++++++++++++++++- .../android_media_MediaMetadataRetriever.cpp | 9 --------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java index 11ecd1f98e4e4..aef631f6c22bf 100644 --- a/media/java/android/media/MediaMetadataRetriever.java +++ b/media/java/android/media/MediaMetadataRetriever.java @@ -23,6 +23,7 @@ import android.graphics.Bitmap; import android.net.Uri; import java.io.FileDescriptor; +import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; @@ -57,7 +58,24 @@ public class MediaMetadataRetriever * @param path The path of the input media file. * @throws IllegalArgumentException If the path is invalid. */ - public native void setDataSource(String path) throws IllegalArgumentException; + public void setDataSource(String path) throws IllegalArgumentException { + FileInputStream is = null; + try { + is = new FileInputStream(path); + FileDescriptor fd = is.getFD(); + setDataSource(fd, 0, 0x7ffffffffffffffL); + } catch (FileNotFoundException fileEx) { + throw new IllegalArgumentException(); + } catch (IOException ioEx) { + throw new IllegalArgumentException(); + } + + try { + if (is != null) { + is.close(); + } + } catch (Exception e) {} + } /** * Sets the data source (URI) to use. Call this diff --git a/media/jni/android_media_MediaMetadataRetriever.cpp b/media/jni/android_media_MediaMetadataRetriever.cpp index 0dc3b65f7137f..297dadfe3dd44 100644 --- a/media/jni/android_media_MediaMetadataRetriever.cpp +++ b/media/jni/android_media_MediaMetadataRetriever.cpp @@ -131,13 +131,6 @@ android_media_MediaMetadataRetriever_setDataSourceAndHeaders( "setDataSource failed"); } - -static void android_media_MediaMetadataRetriever_setDataSource( - JNIEnv *env, jobject thiz, jstring path) { - android_media_MediaMetadataRetriever_setDataSourceAndHeaders( - env, thiz, path, NULL, NULL); -} - static void android_media_MediaMetadataRetriever_setDataSourceFD(JNIEnv *env, jobject thiz, jobject fileDescriptor, jlong offset, jlong length) { ALOGV("setDataSource"); @@ -447,8 +440,6 @@ static void android_media_MediaMetadataRetriever_native_setup(JNIEnv *env, jobje // JNI mapping between Java methods and native methods static JNINativeMethod nativeMethods[] = { - {"setDataSource", "(Ljava/lang/String;)V", (void *)android_media_MediaMetadataRetriever_setDataSource}, - { "_setDataSource", "(Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)V", From f715e0fdbf2638c90d91f882cef8b7c9c25b49be Mon Sep 17 00:00:00 2001 From: Amith Yamasani Date: Wed, 11 Apr 2012 15:02:39 -0700 Subject: [PATCH 047/132] Make dumpsys activity services work again. Due to the step to query the users, dumpsys was crashing when run as non-root. Clearing the calling identity after checking perms fixes this. Bug: 6311443 Change-Id: I0b0bca5c7305cea19adc772b3bfec34c16bb24c4 --- .../server/am/ActivityManagerService.java | 25 ++++++++----------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 78b441a5abc77..0c2e6acd7ee09 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -8309,7 +8309,7 @@ public final class ActivityManagerService extends ActivityManagerNative + android.Manifest.permission.DUMP); return; } - + boolean dumpAll = false; boolean dumpClient = false; String dumpPackage = null; @@ -8352,7 +8352,9 @@ public final class ActivityManagerService extends ActivityManagerNative pw.println("Unknown argument: " + opt + "; use -h for help"); } } - + + long origId = Binder.clearCallingIdentity(); + boolean more = false; // Is the caller requesting to dump a particular piece of data? if (opti < args.length) { String cmd = args[opti]; @@ -8361,7 +8363,6 @@ public final class ActivityManagerService extends ActivityManagerNative synchronized (this) { dumpActivitiesLocked(fd, pw, args, opti, true, dumpClient, null); } - return; } else if ("broadcasts".equals(cmd) || "b".equals(cmd)) { String[] newArgs; String name; @@ -8378,7 +8379,6 @@ public final class ActivityManagerService extends ActivityManagerNative synchronized (this) { dumpBroadcastsLocked(fd, pw, args, opti, true, name); } - return; } else if ("intents".equals(cmd) || "i".equals(cmd)) { String[] newArgs; String name; @@ -8395,7 +8395,6 @@ public final class ActivityManagerService extends ActivityManagerNative synchronized (this) { dumpPendingIntentsLocked(fd, pw, args, opti, true, name); } - return; } else if ("processes".equals(cmd) || "p".equals(cmd)) { String[] newArgs; String name; @@ -8412,12 +8411,10 @@ public final class ActivityManagerService extends ActivityManagerNative synchronized (this) { dumpProcessesLocked(fd, pw, args, opti, true, name); } - return; } else if ("oom".equals(cmd) || "o".equals(cmd)) { synchronized (this) { dumpOomLocked(fd, pw, args, opti, true); } - return; } else if ("provider".equals(cmd)) { String[] newArgs; String name; @@ -8434,12 +8431,10 @@ public final class ActivityManagerService extends ActivityManagerNative pw.println("No providers match: " + name); pw.println("Use -h for help."); } - return; } else if ("providers".equals(cmd) || "prov".equals(cmd)) { synchronized (this) { dumpProvidersLocked(fd, pw, args, opti, true, null); } - return; } else if ("service".equals(cmd)) { String[] newArgs; String name; @@ -8457,13 +8452,11 @@ public final class ActivityManagerService extends ActivityManagerNative pw.println("No services match: " + name); pw.println("Use -h for help."); } - return; } else if ("package".equals(cmd)) { String[] newArgs; if (opti >= args.length) { pw.println("package: no package name specified"); pw.println("Use -h for help."); - return; } else { dumpPackage = args[opti]; opti++; @@ -8472,22 +8465,25 @@ public final class ActivityManagerService extends ActivityManagerNative args.length - opti); args = newArgs; opti = 0; + more = true; } } else if ("services".equals(cmd) || "s".equals(cmd)) { synchronized (this) { dumpServicesLocked(fd, pw, args, opti, true, dumpClient, null); } - return; } else { // Dumping a single activity? if (!dumpActivity(fd, pw, cmd, args, opti, dumpAll)) { pw.println("Bad activity command, or no activities match: " + cmd); pw.println("Use -h for help."); } + } + if (!more) { + Binder.restoreCallingIdentity(origId); return; } } - + // No piece of data specified, dump everything. synchronized (this) { boolean needSep; @@ -8528,8 +8524,9 @@ public final class ActivityManagerService extends ActivityManagerNative } dumpProcessesLocked(fd, pw, args, opti, dumpAll, dumpPackage); } + Binder.restoreCallingIdentity(origId); } - + boolean dumpActivitiesLocked(FileDescriptor fd, PrintWriter pw, String[] args, int opti, boolean dumpAll, boolean dumpClient, String dumpPackage) { pw.println("ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)"); From 7420a7cd59ecc2b441902bfdd192fbaa6cee6527 Mon Sep 17 00:00:00 2001 From: James Dong Date: Wed, 11 Apr 2012 21:18:43 -0700 Subject: [PATCH 048/132] Fix failure from setDataSource(String path) when path is a local file o the failure was because the mediaserver does not have read permission to sdcard o related-to-bug: 6325960,6322913 Change-Id: I4feec01b8165c78563eee8aab69cb24df3244d03 --- media/java/android/media/MediaPlayer.java | 23 ++++++++++++++++++++--- media/jni/android_media_MediaPlayer.cpp | 8 -------- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java index c38f8f35a2bf8..dd01db6fd29bc 100644 --- a/media/java/android/media/MediaPlayer.java +++ b/media/java/android/media/MediaPlayer.java @@ -34,7 +34,9 @@ import android.graphics.Bitmap; import android.graphics.SurfaceTexture; import android.media.AudioManager; +import java.io.File; import java.io.FileDescriptor; +import java.io.FileInputStream; import java.io.IOException; import java.net.InetSocketAddress; import java.util.Map; @@ -847,8 +849,10 @@ public class MediaPlayer * As an alternative, the application could first open the file for reading, * and then use the file descriptor form {@link #setDataSource(FileDescriptor)}. */ - public native void setDataSource(String path) - throws IOException, IllegalArgumentException, SecurityException, IllegalStateException; + public void setDataSource(String path) + throws IOException, IllegalArgumentException, SecurityException, IllegalStateException { + setDataSource(path, null, null); + } /** * Sets the data source (file-path or http/rtsp URL) to use. @@ -875,7 +879,20 @@ public class MediaPlayer ++i; } } - _setDataSource(path, keys, values); + setDataSource(path, keys, values); + } + + private void setDataSource(String path, String[] keys, String[] values) + throws IOException, IllegalArgumentException, SecurityException, IllegalStateException { + File file = new File(path); + if (file.exists()) { + FileInputStream is = new FileInputStream(file); + FileDescriptor fd = is.getFD(); + setDataSource(fd); + is.close(); + } else { + _setDataSource(path, keys, values); + } } private native void _setDataSource( diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp index 2e74ffd8b3d5f..5eadb3a9c1d42 100644 --- a/media/jni/android_media_MediaPlayer.cpp +++ b/media/jni/android_media_MediaPlayer.cpp @@ -215,12 +215,6 @@ android_media_MediaPlayer_setDataSourceAndHeaders( "setDataSource failed." ); } -static void -android_media_MediaPlayer_setDataSource(JNIEnv *env, jobject thiz, jstring path) -{ - android_media_MediaPlayer_setDataSourceAndHeaders(env, thiz, path, NULL, NULL); -} - static void android_media_MediaPlayer_setDataSourceFD(JNIEnv *env, jobject thiz, jobject fileDescriptor, jlong offset, jlong length) { @@ -825,8 +819,6 @@ android_media_MediaPlayer_setNextMediaPlayer(JNIEnv *env, jobject thiz, jobject // ---------------------------------------------------------------------------- static JNINativeMethod gMethods[] = { - {"setDataSource", "(Ljava/lang/String;)V", (void *)android_media_MediaPlayer_setDataSource}, - { "_setDataSource", "(Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)V", From 11b5c3098f4818c375c85d9ab13e0df1f6caf5b4 Mon Sep 17 00:00:00 2001 From: Svetoslav Ganov Date: Mon, 9 Apr 2012 17:39:00 -0700 Subject: [PATCH 049/132] Some view not shown on the screen are reported for accessibility. 1. Some applications are keeping around visible views off screen to improve responsiveness by drawing them in layers, etc. While such a view is not visible on the screen the accessibility layer was reporting it since it was visible. Now the check is improved to verify whether the view is attached, is in visible window, is visible, and has a rectangle that is not clipped by its predecessors. 2. AccessibilityNodeInfo bounds in screen were not properly set since only the top left point was offset appropriately to take into account any predecessor's transformation matrix and the not transformed width and height were used. Now the bounds are properly offset. bug:6291855 Change-Id: I244d1d9af81391676c1c9e0fe86cf4574ff37225 --- core/java/android/view/View.java | 6 ++---- core/java/android/view/ViewRootImpl.java | 27 ++++++++++++++++++------ 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 0be7a871832d7..f877df17fbbb7 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -4483,10 +4483,8 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal getDrawingRect(bounds); info.setBoundsInParent(bounds); - int[] locationOnScreen = mAttachInfo.mInvalidateChildLocation; - getLocationOnScreen(locationOnScreen); - bounds.offsetTo(0, 0); - bounds.offset(locationOnScreen[0], locationOnScreen[1]); + getGlobalVisibleRect(bounds); + bounds.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop); info.setBoundsInScreen(bounds); if ((mPrivateFlags & IS_ROOT_NAMESPACE) == 0) { diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 899fb322db082..2e3ff38414161 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -5064,6 +5064,19 @@ public final class ViewRootImpl implements ViewParent, } } + /** + * Computes whether a view is visible on the screen. + * + * @param view The view to check. + * @return Whether the view is visible on the screen. + */ + private boolean isDisplayedOnScreen(View view) { + return (view.mAttachInfo != null + && view.mAttachInfo.mWindowVisibility == View.VISIBLE + && view.getVisibility() == View.VISIBLE + && view.getGlobalVisibleRect(mTempRect)); + } + /** * Class for managing accessibility interactions initiated from the system * and targeting the view hierarchy. A *ClientThread method is to be @@ -5175,7 +5188,7 @@ public final class ViewRootImpl implements ViewParent, } else { target = findViewByAccessibilityId(accessibilityViewId); } - if (target != null && target.getVisibility() == View.VISIBLE) { + if (target != null && isDisplayedOnScreen(target)) { getAccessibilityNodePrefetcher().prefetchAccessibilityNodeInfos(target, virtualDescendantId, prefetchFlags, infos); } @@ -5231,7 +5244,7 @@ public final class ViewRootImpl implements ViewParent, } if (root != null) { View target = root.findViewById(viewId); - if (target != null && target.getVisibility() == View.VISIBLE) { + if (target != null && isDisplayedOnScreen(target)) { info = target.createAccessibilityNodeInfo(); } } @@ -5287,7 +5300,7 @@ public final class ViewRootImpl implements ViewParent, } else { target = ViewRootImpl.this.mView; } - if (target != null && target.getVisibility() == View.VISIBLE) { + if (target != null && isDisplayedOnScreen(target)) { AccessibilityNodeProvider provider = target.getAccessibilityNodeProvider(); if (provider != null) { infos = provider.findAccessibilityNodeInfosByText(text, @@ -5304,7 +5317,7 @@ public final class ViewRootImpl implements ViewParent, final int viewCount = foundViews.size(); for (int i = 0; i < viewCount; i++) { View foundView = foundViews.get(i); - if (foundView.getVisibility() == View.VISIBLE) { + if (isDisplayedOnScreen(foundView)) { provider = foundView.getAccessibilityNodeProvider(); if (provider != null) { List infosFromProvider = @@ -5367,7 +5380,7 @@ public final class ViewRootImpl implements ViewParent, boolean succeeded = false; try { View target = findViewByAccessibilityId(accessibilityViewId); - if (target != null && target.getVisibility() == View.VISIBLE) { + if (target != null && isDisplayedOnScreen(target)) { AccessibilityNodeProvider provider = target.getAccessibilityNodeProvider(); if (provider != null) { succeeded = provider.performAccessibilityAction(action, @@ -5505,7 +5518,7 @@ public final class ViewRootImpl implements ViewParent, View child = parentGroup.getChildAt(i); if (outInfos.size() < MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE && child.getAccessibilityViewId() != current.getAccessibilityViewId() - && child.getVisibility() == View.VISIBLE) { + && isDisplayedOnScreen(child)) { final long childNodeId = AccessibilityNodeInfo.makeNodeId( child.getAccessibilityViewId(), AccessibilityNodeInfo.UNDEFINED); AccessibilityNodeInfo info = null; @@ -5533,7 +5546,7 @@ public final class ViewRootImpl implements ViewParent, final int childCount = rootGroup.getChildCount(); for (int i = 0; i < childCount; i++) { View child = rootGroup.getChildAt(i); - if (child.getVisibility() == View.VISIBLE + if (isDisplayedOnScreen(child) && outInfos.size() < MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) { final long childNodeId = AccessibilityNodeInfo.makeNodeId( child.getAccessibilityViewId(), AccessibilityNodeInfo.UNDEFINED); From 8a053db228829f4520daf63a2edad5e722974d63 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Thu, 12 Apr 2012 16:02:56 -0700 Subject: [PATCH 050/132] Bump the interpreter stack size for the main thread. Bug: 6315322 Change-Id: I8d84e7c2e0eeb5314530b8a8b141f44014b8c646 --- core/jni/AndroidRuntime.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 879b9d2973ea7..b877071ceafe4 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -549,6 +549,10 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv) opt.optionString = heapsizeOptsBuf; mOptions.add(opt); + // Increase the main thread's interpreter stack size for bug 6315322. + opt.optionString = "-XX:mainThreadStackSize=24K"; + mOptions.add(opt); + strcpy(heapgrowthlimitOptsBuf, "-XX:HeapGrowthLimit="); property_get("dalvik.vm.heapgrowthlimit", heapgrowthlimitOptsBuf+20, ""); if (heapgrowthlimitOptsBuf[20] != '\0') { From c016672b302e26d4bf03aa8beb6fd5c4ec2bd3ab Mon Sep 17 00:00:00 2001 From: Svetoslav Ganov Date: Fri, 13 Apr 2012 12:05:51 -0700 Subject: [PATCH 051/132] Accessibility query APIs report invisible views. 1. The accessibility querying APIs failed to check whether all predecessors of a view are visible before reporting it. bug:6291855 Change-Id: I364a6f08e8d02c7105c00c9fdff0fec033829554 --- core/java/android/view/ViewRootImpl.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 2e3ff38414161..7a43cf11e8865 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -5071,9 +5071,13 @@ public final class ViewRootImpl implements ViewParent, * @return Whether the view is visible on the screen. */ private boolean isDisplayedOnScreen(View view) { + // The first two checks are made also made by isShown() which + // however traverses the tree up to the parent to catch that. + // Therefore, we do some fail fast check to minimize the up + // tree traversal. return (view.mAttachInfo != null && view.mAttachInfo.mWindowVisibility == View.VISIBLE - && view.getVisibility() == View.VISIBLE + && view.isShown() && view.getGlobalVisibleRect(mTempRect)); } From 382fa051ab1bc1d4f9ed2a914e442bd6aed026de Mon Sep 17 00:00:00 2001 From: Mindy Pereira Date: Mon, 16 Apr 2012 08:58:53 -0700 Subject: [PATCH 052/132] Perform null check on empty view before doing accessibility check. Fixes b/6341858 AdapterView does not properly check for null before checking empty view accessibility info Change-Id: Ia19fdef2c7c5f3e6c3053ebc754efe6a664f9d66 --- core/java/android/widget/AdapterView.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java index 1a2231ef38671..abfc57763d0fd 100644 --- a/core/java/android/widget/AdapterView.java +++ b/core/java/android/widget/AdapterView.java @@ -650,7 +650,8 @@ public abstract class AdapterView extends ViewGroup { mEmptyView = emptyView; // If not explicitly specified this view is important for accessibility. - if (emptyView.getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { + if (emptyView != null + && emptyView.getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { emptyView.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); } From 130f9a1438b9c7d9512d9f17189256fd0279499a Mon Sep 17 00:00:00 2001 From: Bjorn Bringert Date: Mon, 16 Apr 2012 18:16:37 +0100 Subject: [PATCH 053/132] Find new recognizer if old one is gone Before, RecognitionManagerService just cleared the recognizer setting, which the Settings app really doesn't like. Bug: 6332933 Change-Id: If4f9b583c304c5ea99021dddda50fca55e3ac541 --- .../java/com/android/server/RecognitionManagerService.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/services/java/com/android/server/RecognitionManagerService.java b/services/java/com/android/server/RecognitionManagerService.java index 8e55512981d1d..85224d89eb6ce 100644 --- a/services/java/com/android/server/RecognitionManagerService.java +++ b/services/java/com/android/server/RecognitionManagerService.java @@ -75,7 +75,10 @@ public class RecognitionManagerService extends Binder { try { mContext.getPackageManager().getServiceInfo(comp, 0); } catch (NameNotFoundException e) { - setCurRecognizer(null); + comp = findAvailRecognizer(null); + if (comp != null) { + setCurRecognizer(comp); + } } } else { comp = findAvailRecognizer(null); From 424731d1f3477639bfacbd76193bbb102408f2f0 Mon Sep 17 00:00:00 2001 From: Craig Mautner Date: Tue, 17 Apr 2012 11:45:25 -0700 Subject: [PATCH 054/132] Move Surface operations into existing transaction. Several Surface operations - notably setPosition, setSize, and show - had been moved outside of a Surface.openTransaction/closeTransaction window. This corrects that problem. In addition, before animations were separated from layout the Surface frame was computed prior to returning from relayoutWindow(). After separation the frame was being computed during animation. This checkin restores the frame calculation in layout. Fixes bug 6343291. Change-Id: I4752bdf1fed0f2b46c5eb9508825c9b1b0fd702f --- .../server/wm/WindowManagerService.java | 134 +++++++++--------- .../server/wm/WindowStateAnimator.java | 45 ++++-- 2 files changed, 96 insertions(+), 83 deletions(-) diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index 0458a67305857..2904eacd9831a 100644 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -8022,7 +8022,7 @@ public class WindowManagerService extends IWindowManager.Stub Slog.v(TAG, "Resize reasons: " + " contentInsetsChanged=" + w.mContentInsetsChanged + " visibleInsetsChanged=" + w.mVisibleInsetsChanged - + " surfaceResized=" + w.mWinAnimator.mSurfaceResized + + " surfaceResized=" + winAnimator.mSurfaceResized + " configChanged=" + configChanged); } @@ -8037,7 +8037,7 @@ public class WindowManagerService extends IWindowManager.Stub if (w.mOrientationChanging) { if (DEBUG_ORIENTATION) Slog.v(TAG, "Orientation start waiting for draw in " - + w + ", surface " + w.mWinAnimator.mSurface); + + w + ", surface " + winAnimator.mSurface); winAnimator.mDrawState = WindowStateAnimator.DRAW_PENDING; if (w.mAppToken != null) { w.mAppToken.allDrawn = false; @@ -8045,15 +8045,15 @@ public class WindowManagerService extends IWindowManager.Stub } if (!mResizingWindows.contains(w)) { if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG, - "Resizing window " + w + " to " + w.mWinAnimator.mSurfaceW - + "x" + w.mWinAnimator.mSurfaceH); + "Resizing window " + w + " to " + winAnimator.mSurfaceW + + "x" + winAnimator.mSurfaceH); mResizingWindows.add(w); } } else if (w.mOrientationChanging) { if (w.isDrawnLw()) { if (DEBUG_ORIENTATION) Slog.v(TAG, "Orientation not waiting for draw in " - + w + ", surface " + w.mWinAnimator.mSurface); + + w + ", surface " + winAnimator.mSurface); w.mOrientationChanging = false; } } @@ -8145,7 +8145,7 @@ public class WindowManagerService extends IWindowManager.Stub updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES, false /*updateInputWindows*/); } - + // Initialize state of exiting tokens. for (i=mExitingTokens.size()-1; i>=0; i--) { mExitingTokens.get(i).hasVisible = false; @@ -8174,7 +8174,7 @@ public class WindowManagerService extends IWindowManager.Stub try { int repeats = 0; - + do { repeats++; if (repeats > 6) { @@ -8234,7 +8234,7 @@ public class WindowManagerService extends IWindowManager.Stub mInnerFields.mObscured = false; mInnerFields.mDimming = false; mInnerFields.mSyswin = false; - + boolean focusDisplayed = false; final int N = mWindows.size(); for (i=N-1; i>=0; i--) { @@ -8258,7 +8258,52 @@ public class WindowManagerService extends IWindowManager.Stub // has been updated accordingly. updateWallpaperVisibilityLocked(); } + + final WindowStateAnimator winAnimator = w.mWinAnimator; + + // If the window has moved due to its containing + // content frame changing, then we'd like to animate + // it. + if (w.mHasSurface && w.shouldAnimateMove()) { + // Frame has moved, containing content frame + // has also moved, and we're not currently animating... + // let's do something. + Animation a = AnimationUtils.loadAnimation(mContext, + com.android.internal.R.anim.window_move_from_decor); + winAnimator.setAnimation(a); + winAnimator.mAnimDw = w.mLastFrame.left - w.mFrame.left; + winAnimator.mAnimDh = w.mLastFrame.top - w.mFrame.top; + } else { + winAnimator.mAnimDw = innerDw; + winAnimator.mAnimDh = innerDh; + } + + //Slog.i(TAG, "Window " + this + " clearing mContentChanged - done placing"); + w.mContentChanged = false; + + // Moved from updateWindowsAndWallpaperLocked(). + if (w.mHasSurface) { + // Take care of the window being ready to display. + if (winAnimator.commitFinishDrawingLocked(currentTime)) { + if ((w.mAttrs.flags + & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) { + if (WindowManagerService.DEBUG_WALLPAPER) Slog.v(TAG, + "First draw done in potential wallpaper target " + w); + mInnerFields.mWallpaperMayChange = true; + mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; + if (WindowManagerService.DEBUG_LAYOUT_REPEATS) { + debugLayoutRepeats("updateWindowsAndWallpaperLocked 1", + mPendingLayoutChanges); + } + } + } + + winAnimator.setSurfaceBoundaries(recoveringMemory); + } + + updateResizingWindows(w); } + if (focusDisplayed) { mH.sendEmptyMessage(H.REPORT_LOSING_FOCUS); } @@ -8340,68 +8385,10 @@ public class WindowManagerService extends IWindowManager.Stub if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("mLayoutNeeded", mPendingLayoutChanges); } - final int N = mWindows.size(); - for (i=N-1; i>=0; i--) { - final WindowState w = mWindows.get(i); - final WindowStateAnimator winAnimator = w.mWinAnimator; - - // If the window has moved due to its containing - // content frame changing, then we'd like to animate - // it. - if (w.mHasSurface && w.shouldAnimateMove()) { - // Frame has moved, containing content frame - // has also moved, and we're not currently animating... - // let's do something. - Animation a = AnimationUtils.loadAnimation(mContext, - com.android.internal.R.anim.window_move_from_decor); - winAnimator.setAnimation(a); - winAnimator.mAnimDw = w.mLastFrame.left - w.mFrame.left; - winAnimator.mAnimDh = w.mLastFrame.top - w.mFrame.top; - } else { - winAnimator.mAnimDw = innerDw; - winAnimator.mAnimDh = innerDh; - } - - //Slog.i(TAG, "Window " + this + " clearing mContentChanged - done placing"); - w.mContentChanged = false; - - // TODO(cmautner): Can this move up to the loop at the end of try/catch above? - updateResizingWindows(w); - - // Moved from updateWindowsAndWallpaperLocked(). - if (w.mHasSurface) { - // Take care of the window being ready to display. - if (winAnimator.commitFinishDrawingLocked(currentTime)) { - if ((w.mAttrs.flags - & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) { - if (WindowManagerService.DEBUG_WALLPAPER) Slog.v(TAG, - "First draw done in potential wallpaper target " + w); - mInnerFields.mWallpaperMayChange = true; - mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; - if (WindowManagerService.DEBUG_LAYOUT_REPEATS) { - debugLayoutRepeats("updateWindowsAndWallpaperLocked 1", - mPendingLayoutChanges); - } - } - } - } - } - - if (DEBUG_ORIENTATION && mDisplayFrozen) Slog.v(TAG, - "With display frozen, orientationChangeComplete=" - + mInnerFields.mOrientationChangeComplete); - if (mInnerFields.mOrientationChangeComplete) { - if (mWindowsFreezingScreen) { - mWindowsFreezingScreen = false; - mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT); - } - stopFreezingDisplayLocked(); - } - if (!mResizingWindows.isEmpty()) { for (i = mResizingWindows.size() - 1; i >= 0; i--) { WindowState win = mResizingWindows.get(i); - final WindowStateAnimator winAnimator = win.mWinAnimator; + final WindowStateAnimator winAnimator = win.mWinAnimator; try { if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG, "Reporting new frame to " + win + ": " + win.mCompatFrame); @@ -8420,7 +8407,7 @@ public class WindowManagerService extends IWindowManager.Stub win.mConfiguration = mCurConfiguration; if (DEBUG_ORIENTATION && winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING) Slog.i( - TAG, "Resizing " + win + " WITH DRAW PENDING"); + TAG, "Resizing " + win + " WITH DRAW PENDING"); win.mClient.resized((int)winAnimator.mSurfaceW, (int)winAnimator.mSurfaceH, win.mLastContentInsets, win.mLastVisibleInsets, @@ -8436,6 +8423,17 @@ public class WindowManagerService extends IWindowManager.Stub mResizingWindows.clear(); } + if (DEBUG_ORIENTATION && mDisplayFrozen) Slog.v(TAG, + "With display frozen, orientationChangeComplete=" + + mInnerFields.mOrientationChangeComplete); + if (mInnerFields.mOrientationChangeComplete) { + if (mWindowsFreezingScreen) { + mWindowsFreezingScreen = false; + mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT); + } + stopFreezingDisplayLocked(); + } + // Destroy the surface of any windows that are no longer visible. boolean wallpaperDestroyed = false; i = mDestroySurface.size(); diff --git a/services/java/com/android/server/wm/WindowStateAnimator.java b/services/java/com/android/server/wm/WindowStateAnimator.java index 90b63a6a3c297..b61ccbfabf404 100644 --- a/services/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/java/com/android/server/wm/WindowStateAnimator.java @@ -499,6 +499,14 @@ class WindowStateAnimator { sSurfaces.remove(this); } + @Override + public void release() { + super.release(); + Slog.v(SURFACE_TAG, "release: " + this + ". Called by " + + WindowManagerService.getCallers(3)); + sSurfaces.remove(this); + } + static void dumpAllSurfaces() { final int N = sSurfaces.size(); for (int i = 0; i < N; i++) { @@ -886,22 +894,8 @@ class WindowStateAnimator { mDtDy = mWin.mGlobalScale; } - public void prepareSurfaceLocked(final boolean recoveringMemory) { + void setSurfaceBoundaries(final boolean recoveringMemory) { final WindowState w = mWin; - if (mSurface == null) { - if (w.mOrientationChanging) { - if (DEBUG_ORIENTATION) { - Slog.v(TAG, "Orientation change skips hidden " + w); - } - w.mOrientationChanging = false; - } - return; - } - - boolean displayed = false; - - computeShownFrameLocked(); - int width, height; if ((w.mAttrs.flags & LayoutParams.FLAG_SCALED) != 0) { // for a scaled surface, we just want to use @@ -950,6 +944,8 @@ class WindowStateAnimator { "SIZE " + width + "x" + height, null); mSurfaceResized = true; mSurface.setSize(width, height); + mAnimator.mPendingLayoutChanges |= + WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; } catch (RuntimeException e) { // If something goes wrong with the surface (such // as running out of memory), don't take down the @@ -961,6 +957,25 @@ class WindowStateAnimator { } } } + } + + public void prepareSurfaceLocked(final boolean recoveringMemory) { + final WindowState w = mWin; + if (mSurface == null) { + if (w.mOrientationChanging) { + if (DEBUG_ORIENTATION) { + Slog.v(TAG, "Orientation change skips hidden " + w); + } + w.mOrientationChanging = false; + } + return; + } + + boolean displayed = false; + + computeShownFrameLocked(); + + setSurfaceBoundaries(recoveringMemory); if (w.mAttachedHidden || !w.isReadyForDisplay()) { if (!mLastHidden) { From 6246629991ce987b8918987db11bc79e89d94a7a Mon Sep 17 00:00:00 2001 From: Craig Mautner Date: Mon, 16 Apr 2012 15:42:47 -0700 Subject: [PATCH 055/132] Clear orientation variable until rotation is done. In the old code orientationChangeComplete was set to true on each pass through perfomLayout. If any window was rotating the variable was set to false on the way through the performLayout. Since we can now make passes through performLayout before any animation step occurs we were seeing mOrientationChangeComplete true prior to rotation completing. This change sets mOrientationChangeComplete false at the start of a rotation and sets it to true if we ever get through an animation step without encountering any rotating windows. Change-Id: I37690cf20868dfbaac94a81640bc4d9cb9fb8f00 --- .../java/com/android/server/wm/ScreenRotationAnimation.java | 5 +++++ .../java/com/android/server/wm/WindowManagerService.java | 6 +++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/services/java/com/android/server/wm/ScreenRotationAnimation.java b/services/java/com/android/server/wm/ScreenRotationAnimation.java index 11af6ea1ab795..13013a8d776ef 100644 --- a/services/java/com/android/server/wm/ScreenRotationAnimation.java +++ b/services/java/com/android/server/wm/ScreenRotationAnimation.java @@ -121,6 +121,7 @@ class ScreenRotationAnimation { private boolean mMoreStartEnter; private boolean mMoreStartExit; private boolean mMoreStartFrame; + long mHalfwayPoint; public void printTo(String prefix, PrintWriter pw) { pw.print(prefix); pw.print("mSurface="); pw.print(mSurface); @@ -655,6 +656,9 @@ class ScreenRotationAnimation { } private boolean stepAnimation(long now) { + if (now > mHalfwayPoint) { + mHalfwayPoint = Long.MAX_VALUE; + } if (mFinishAnimReady && mFinishAnimStartTime < 0) { if (DEBUG_STATE) Slog.v(TAG, "Step: finish anim now ready"); mFinishAnimStartTime = now; @@ -915,6 +919,7 @@ class ScreenRotationAnimation { mRotateExitAnimation.setStartTime(now); } mAnimRunning = true; + mHalfwayPoint = now + mRotateEnterAnimation.getDuration() / 2; } return stepAnimation(now); diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index 2904eacd9831a..72aab7b62feb3 100644 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -4245,6 +4245,7 @@ public class WindowManagerService extends IWindowManager.Stub if (w.mHasSurface && !w.mOrientationChanging) { if (DEBUG_ORIENTATION) Slog.v(TAG, "set mOrientationChanging of " + w); w.mOrientationChanging = true; + mInnerFields.mOrientationChangeComplete = false; } unfrozeWindows = true; } @@ -5550,6 +5551,7 @@ public class WindowManagerService extends IWindowManager.Stub if (w.mHasSurface) { if (DEBUG_ORIENTATION) Slog.v(TAG, "Set mOrientationChanging of " + w); w.mOrientationChanging = true; + mInnerFields.mOrientationChangeComplete = false; } } for (int i=mRotationWatchers.size()-1; i>=0; i--) { @@ -7654,6 +7656,7 @@ public class WindowManagerService extends IWindowManager.Stub if (DEBUG_ORIENTATION) Slog.v(TAG, "Changing surface while display frozen: " + w); w.mOrientationChanging = true; + mInnerFields.mOrientationChangeComplete = false; if (!mWindowsFreezingScreen) { mWindowsFreezingScreen = true; // XXX should probably keep timeout from @@ -8125,7 +8128,8 @@ public class WindowManagerService extends IWindowManager.Stub private final void performLayoutAndPlaceSurfacesLockedInner( boolean recoveringMemory) { if (DEBUG_WINDOW_TRACE) { - Slog.v(TAG, "performLayoutAndPlaceSurfacesLockedInner: entry"); + Slog.v(TAG, "performLayoutAndPlaceSurfacesLockedInner: entry. Called by " + + getCallers(3)); } if (mDisplay == null) { Slog.i(TAG, "skipping performLayoutAndPlaceSurfacesLockedInner with no mDisplay"); From e94eb4e575c4d17653208176a0fb23784374f38f Mon Sep 17 00:00:00 2001 From: Amith Yamasani Date: Wed, 18 Apr 2012 09:54:43 -0700 Subject: [PATCH 056/132] Fix an NPE when launching an activity that's not found. Bug: 6356194 Change-Id: I66aeeda3ecab36a4aa32fb78c1d0559a73cd9a7a --- services/java/com/android/server/am/ActivityStack.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java index 2c53186bbd8d9..9085cea7c47ca 100644 --- a/services/java/com/android/server/am/ActivityStack.java +++ b/services/java/com/android/server/am/ActivityStack.java @@ -2944,7 +2944,7 @@ final class ActivityStack { // Collect information about the target of the Intent. ActivityInfo aInfo = resolveActivity(intent, resolvedType, startFlags, profileFile, profileFd, userId); - if (mService.isSingleton(aInfo.processName, aInfo.applicationInfo)) { + if (aInfo != null && mService.isSingleton(aInfo.processName, aInfo.applicationInfo)) { userId = 0; } aInfo = mService.getActivityInfoForUser(aInfo, userId); From f9c55bf9472eac922c7b62792c5af7dfd6f96f98 Mon Sep 17 00:00:00 2001 From: Svetoslav Ganov Date: Mon, 16 Apr 2012 18:17:17 -0700 Subject: [PATCH 057/132] Adding some more gestures and actions for accessibility. 1. Added more gesture for accessibility. After a meeting with the access-eng team we have decided that the current set of gestures may be smaller than needed considering that we will use four gestures for home, back, recents, and notifications. 2. Adding actions for going back, home, opening the recents, and opening the notifications. 3. Added preliminary mapping from some of the new gestures to the new actions. 4. Fixed a bug in the accessibility interaction controller which was trying to create a handled on the main looper thread which may be null if the queried UI is in the system process. Now the context looper of the root view is used. 5. Fixed a bug of using an incorrect constant. 6. Added a missing locking in a couple of places. 7. Fixed view comparison for accessibilityt since it was not anisymmetric. bug:5932640 bug:5605641 Change-Id: Icc983bf4eafefa42b65920b3782ed8a25518e94f --- api/current.txt | 20 +++- .../AccessibilityService.java | 111 +++++++++++++++++- .../IAccessibilityServiceConnection.aidl | 8 ++ .../AccessibilityInteractionController.java | 9 +- core/java/android/view/View.java | 18 ++- core/java/android/view/ViewGroup.java | 30 +++-- core/java/android/view/ViewRootImpl.java | 8 +- .../accessibility/AccessibilityNodeInfo.java | 25 ++-- core/res/res/raw/accessibility_gestures.bin | Bin 9261 -> 13005 bytes .../AccessibilityManagerService.java | 53 ++++++++- 10 files changed, 236 insertions(+), 46 deletions(-) diff --git a/api/current.txt b/api/current.txt index 8d12a566a6b97..5ef44f2d91918 100644 --- a/api/current.txt +++ b/api/current.txt @@ -1999,17 +1999,30 @@ package android.accessibilityservice { method protected void onGesture(int); method public abstract void onInterrupt(); method protected void onServiceConnected(); + method public final boolean performGlobalAction(int); method public final void setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo); field public static final int GESTURE_CLOCKWISE_CIRCLE = 9; // 0x9 field public static final int GESTURE_COUNTER_CLOCKWISE_CIRCLE = 10; // 0xa field public static final int GESTURE_SWIPE_DOWN = 2; // 0x2 + field public static final int GESTURE_SWIPE_DOWN_AND_LEFT = 17; // 0x11 + field public static final int GESTURE_SWIPE_DOWN_AND_RIGHT = 18; // 0x12 field public static final int GESTURE_SWIPE_DOWN_AND_UP = 8; // 0x8 field public static final int GESTURE_SWIPE_LEFT = 3; // 0x3 + field public static final int GESTURE_SWIPE_LEFT_AND_DOWN = 12; // 0xc field public static final int GESTURE_SWIPE_LEFT_AND_RIGHT = 5; // 0x5 + field public static final int GESTURE_SWIPE_LEFT_AND_UP = 11; // 0xb field public static final int GESTURE_SWIPE_RIGHT = 4; // 0x4 + field public static final int GESTURE_SWIPE_RIGHT_AND_DOWN = 14; // 0xe field public static final int GESTURE_SWIPE_RIGHT_AND_LEFT = 6; // 0x6 + field public static final int GESTURE_SWIPE_RIGHT_AND_UP = 13; // 0xd field public static final int GESTURE_SWIPE_UP = 1; // 0x1 field public static final int GESTURE_SWIPE_UP_AND_DOWN = 7; // 0x7 + field public static final int GESTURE_SWIPE_UP_AND_LEFT = 15; // 0xf + field public static final int GESTURE_SWIPE_UP_AND_RIGHT = 16; // 0x10 + field public static final int GLOBAL_ACTION_BACK = 1; // 0x1 + field public static final int GLOBAL_ACTION_HOME = 2; // 0x2 + field public static final int GLOBAL_ACTION_NOTIFICATIONS = 4; // 0x4 + field public static final int GLOBAL_ACTION_RECENTS = 3; // 0x3 field public static final java.lang.String SERVICE_INTERFACE = "android.accessibilityservice.AccessibilityService"; field public static final java.lang.String SERVICE_META_DATA = "android.accessibilityservice"; } @@ -24994,12 +25007,13 @@ package android.view.accessibility { method public void setSource(android.view.View, int); method public void setText(java.lang.CharSequence); method public void writeToParcel(android.os.Parcel, int); - field public static final int ACTION_ACCESSIBILITY_FOCUS = 16; // 0x10 - field public static final int ACTION_CLEAR_ACCESSIBILITY_FOCUS = 32; // 0x20 + field public static final int ACTION_ACCESSIBILITY_FOCUS = 64; // 0x40 + field public static final int ACTION_CLEAR_ACCESSIBILITY_FOCUS = 128; // 0x80 field public static final int ACTION_CLEAR_FOCUS = 2; // 0x2 field public static final int ACTION_CLEAR_SELECTION = 8; // 0x8 - field public static final int ACTION_CLICK = 64; // 0x40 + field public static final int ACTION_CLICK = 16; // 0x10 field public static final int ACTION_FOCUS = 1; // 0x1 + field public static final int ACTION_LONG_CLICK = 32; // 0x20 field public static final int ACTION_SELECT = 4; // 0x4 field public static final android.os.Parcelable.Creator CREATOR; field public static final int FOCUS_ACCESSIBILITY = 2; // 0x2 diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java index 3da35d3ef31ad..eed8aa66f61d3 100644 --- a/core/java/android/accessibilityservice/AccessibilityService.java +++ b/core/java/android/accessibilityservice/AccessibilityService.java @@ -258,14 +258,52 @@ public abstract class AccessibilityService extends Service { */ public static final int GESTURE_COUNTER_CLOCKWISE_CIRCLE = 10; + /** + * The user has performed a left and up gesture on the touch screen. + */ + public static final int GESTURE_SWIPE_LEFT_AND_UP = 11; + + /** + * The user has performed a left and down gesture on the touch screen. + */ + public static final int GESTURE_SWIPE_LEFT_AND_DOWN = 12; + + /** + * The user has performed a right and up gesture on the touch screen. + */ + public static final int GESTURE_SWIPE_RIGHT_AND_UP = 13; + + /** + * The user has performed a right and down gesture on the touch screen. + */ + public static final int GESTURE_SWIPE_RIGHT_AND_DOWN = 14; + + /** + * The user has performed an up and left gesture on the touch screen. + */ + public static final int GESTURE_SWIPE_UP_AND_LEFT = 15; + + /** + * The user has performed an up and right gesture on the touch screen. + */ + public static final int GESTURE_SWIPE_UP_AND_RIGHT = 16; + + /** + * The user has performed an down and left gesture on the touch screen. + */ + public static final int GESTURE_SWIPE_DOWN_AND_LEFT = 17; + + /** + * The user has performed an down and right gesture on the touch screen. + */ + public static final int GESTURE_SWIPE_DOWN_AND_RIGHT = 18; + /** * The {@link Intent} that must be declared as handled by the service. */ public static final String SERVICE_INTERFACE = "android.accessibilityservice.AccessibilityService"; - private static final int UNDEFINED = -1; - /** * Name under which an AccessibilityService component publishes information * about itself. This meta-data must reference an XML resource containing an @@ -284,6 +322,28 @@ public abstract class AccessibilityService extends Service { */ public static final String SERVICE_META_DATA = "android.accessibilityservice"; + /** + * Action to go back. + */ + public static final int GLOBAL_ACTION_BACK = 1; + + /** + * Action to go home. + */ + public static final int GLOBAL_ACTION_HOME = 2; + + /** + * Action to open the recents. + */ + public static final int GLOBAL_ACTION_RECENTS = 3; + + /** + * Action to open the notifications. + */ + public static final int GLOBAL_ACTION_NOTIFICATIONS = 4; + + private static final int UNDEFINED = -1; + private static final String LOG_TAG = "AccessibilityService"; interface Callbacks { @@ -344,6 +404,22 @@ public abstract class AccessibilityService extends Service { protected void onGesture(int gestureId) { // TODO: Describe the default gesture processing in the javaDoc once it is finalized. + // Global actions. + switch (gestureId) { + case GESTURE_SWIPE_DOWN_AND_LEFT: { + performGlobalAction(GLOBAL_ACTION_BACK); + } return; + case GESTURE_SWIPE_DOWN_AND_RIGHT: { + performGlobalAction(GLOBAL_ACTION_HOME); + } return; + case GESTURE_SWIPE_UP_AND_LEFT: { + performGlobalAction(GLOBAL_ACTION_RECENTS); + } return; + case GESTURE_SWIPE_UP_AND_RIGHT: { + performGlobalAction(GLOBAL_ACTION_NOTIFICATIONS); + } return; + } + // Cache the id to avoid locking final int connectionId = mConnectionId; if (connectionId == UNDEFINED) { @@ -357,10 +433,12 @@ public abstract class AccessibilityService extends Service { if (root == null) { return; } - AccessibilityNodeInfo current = root.findFocus(View.FOCUS_ACCESSIBILITY); + AccessibilityNodeInfo current = root.findFocus(AccessibilityNodeInfo.FOCUS_ACCESSIBILITY); if (current == null) { current = root; } + + // Local actions. AccessibilityNodeInfo next = null; switch (gestureId) { case GESTURE_SWIPE_UP: { @@ -401,6 +479,33 @@ public abstract class AccessibilityService extends Service { } } + /** + * Performs a global action. Such an action can be performed + * at any moment regardless of the current application or user + * location in that application. For example going back, going + * home, opening recents, etc. + * + * @param action The action to perform. + * @return Whether the action was successfully performed. + * + * @see #GLOBAL_ACTION_BACK + * @see #GLOBAL_ACTION_HOME + * @see #GLOBAL_ACTION_NOTIFICATIONS + * @see #GLOBAL_ACTION_RECENTS + */ + public final boolean performGlobalAction(int action) { + IAccessibilityServiceConnection connection = + AccessibilityInteractionClient.getInstance().getConnection(mConnectionId); + if (connection != null) { + try { + return connection.perfromGlobalAction(action); + } catch (RemoteException re) { + Log.w(LOG_TAG, "Error while calling performGlobalAction", re); + } + } + return false; + } + /** * Gets the an {@link AccessibilityServiceInfo} describing this * {@link AccessibilityService}. This method is useful if one wants diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl index 30da9db5a4968..1bd53877356b9 100644 --- a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl +++ b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl @@ -160,4 +160,12 @@ interface IAccessibilityServiceConnection { * @return The associated accessibility service info. */ AccessibilityServiceInfo getServiceInfo(); + + /** + * Performs a global action, such as going home, going back, etc. + * + * @param action The action to perform. + * @return Whether the action was performed. + */ + boolean perfromGlobalAction(int action); } diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java index 6c1a6bf1bdf9d..54c62ee83a125 100644 --- a/core/java/android/view/AccessibilityInteractionController.java +++ b/core/java/android/view/AccessibilityInteractionController.java @@ -52,13 +52,16 @@ final class AccessibilityInteractionController { private ArrayList mTempAccessibilityNodeInfoList = new ArrayList(); - private final Handler mHandler = new PrivateHandler(); + private final Handler mHandler; private final ViewRootImpl mViewRootImpl; private final AccessibilityNodePrefetcher mPrefetcher; public AccessibilityInteractionController(ViewRootImpl viewRootImpl) { + // mView is never null - the caller has already checked. + Looper looper = viewRootImpl.mView.mContext.getMainLooper(); + mHandler = new PrivateHandler(looper); mViewRootImpl = viewRootImpl; mPrefetcher = new AccessibilityNodePrefetcher(); } @@ -846,8 +849,8 @@ final class AccessibilityInteractionController { private final static int MSG_FIND_FOCUS = 5; private final static int MSG_FOCUS_SEARCH = 6; - public PrivateHandler() { - super(Looper.getMainLooper()); + public PrivateHandler(Looper looper) { + super(looper); } @Override diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 0ded5f926c7ab..2fea8ececa612 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -6359,16 +6359,14 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal public boolean performAccessibilityAction(int action) { switch (action) { case AccessibilityNodeInfo.ACTION_CLICK: { - final long now = SystemClock.uptimeMillis(); - // Send down. - MotionEvent event = MotionEvent.obtain(now, now, MotionEvent.ACTION_DOWN, - getWidth() / 2, getHeight() / 2, 0); - onTouchEvent(event); - // Send up. - event.setAction(MotionEvent.ACTION_UP); - onTouchEvent(event); - // Clean up. - event.recycle(); + if (isClickable()) { + performClick(); + } + } break; + case AccessibilityNodeInfo.ACTION_LONG_CLICK: { + if (isLongClickable()) { + performLongClick(); + } } break; case AccessibilityNodeInfo.ACTION_FOCUS: { if (!hasFocus()) { diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 6371963a84ff1..91e945b14e257 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -5792,11 +5792,13 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager throw new IllegalStateException("Instance already recycled."); } clear(); - if (sPoolSize < MAX_POOL_SIZE) { - mNext = sPool; - mIsPooled = true; - sPool = this; - sPoolSize++; + synchronized (sPoolLock) { + if (sPoolSize < MAX_POOL_SIZE) { + mNext = sPool; + mIsPooled = true; + sPool = this; + sPoolSize++; + } } } @@ -5889,11 +5891,13 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager throw new IllegalStateException("Instance already recycled."); } clear(); - if (sPoolSize < MAX_POOL_SIZE) { - mNext = sPool; - mIsPooled = true; - sPool = this; - sPoolSize++; + synchronized (sPoolLock) { + if (sPoolSize < MAX_POOL_SIZE) { + mNext = sPool; + mIsPooled = true; + sPool = this; + sPoolSize++; + } } } @@ -5943,9 +5947,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager if (widthDiference != 0) { return -widthDiference; } - // Return nondeterministically one of them since we do - // not want to ignore any views. - return 1; + // Just break the tie somehow. The accessibliity ids are unique + // and stable, hence this is deterministic tie breaking. + return mView.getAccessibilityViewId() - another.mView.getAccessibilityViewId(); } private void init(ViewGroup root, View view) { diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 147299307853c..3d40b2fcc2844 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -2665,6 +2665,7 @@ public final class ViewRootImpl implements ViewParent, private final static int MSG_PROCESS_INPUT_EVENTS = 19; private final static int MSG_DISPATCH_SCREEN_STATE = 20; private final static int MSG_INVALIDATE_DISPLAY_LIST = 21; + private final static int MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST = 22; final class ViewRootHandler extends Handler { @Override @@ -2712,6 +2713,8 @@ public final class ViewRootImpl implements ViewParent, return "MSG_DISPATCH_SCREEN_STATE"; case MSG_INVALIDATE_DISPLAY_LIST: return "MSG_INVALIDATE_DISPLAY_LIST"; + case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST: + return "MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST"; } return super.getMessageName(message); } @@ -2921,6 +2924,9 @@ public final class ViewRootImpl implements ViewParent, case MSG_INVALIDATE_DISPLAY_LIST: { invalidateDisplayLists(); } break; + case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST: { + setAccessibilityFocusedHost(null); + } break; } } } @@ -5066,7 +5072,7 @@ public final class ViewRootImpl implements ViewParent, } } else { ensureNoConnection(); - setAccessibilityFocusedHost(null); + mHandler.obtainMessage(MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST).sendToTarget(); } } diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java index 1071c657b983e..c5f2062daff48 100644 --- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java +++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java @@ -84,7 +84,7 @@ public class AccessibilityNodeInfo implements Parcelable { /** * Action that gives input focus to the node. */ - public static final int ACTION_FOCUS = 0x00000001; + public static final int ACTION_FOCUS = 0x00000001; /** * Action that clears input focus of the node. @@ -101,20 +101,25 @@ public class AccessibilityNodeInfo implements Parcelable { */ public static final int ACTION_CLEAR_SELECTION = 0x00000008; + /** + * Action that clicks on the node info. + */ + public static final int ACTION_CLICK = 0x00000010; + + /** + * Action that clicks on the node. + */ + public static final int ACTION_LONG_CLICK = 0x00000020; + /** * Action that gives accessibility focus to the node. */ - public static final int ACTION_ACCESSIBILITY_FOCUS = 0x00000010; + public static final int ACTION_ACCESSIBILITY_FOCUS = 0x00000040; /** * Action that clears accessibility focus of the node. */ - public static final int ACTION_CLEAR_ACCESSIBILITY_FOCUS = 0x00000020; - - /** - * Action that clicks on the node info./AccessibilityNodeInfoCache.java - */ - public static final int ACTION_CLICK = 0x00000040; + public static final int ACTION_CLEAR_ACCESSIBILITY_FOCUS = 0x00000080; /** * The input focus. @@ -278,9 +283,9 @@ public class AccessibilityNodeInfo implements Parcelable { (root != null) ? root.getAccessibilityViewId() : UNDEFINED; mSourceNodeId = makeNodeId(rootAccessibilityViewId, virtualDescendantId); } - + /** - * Find the view that has the input focus. The search starts from + * Find the view that has the specified focus type. The search starts from * the view represented by this node info. * * @param focus The focus to find. One of {@link #FOCUS_INPUT} or diff --git a/core/res/res/raw/accessibility_gestures.bin b/core/res/res/raw/accessibility_gestures.bin index 1f95e5665e4e05f5918b16b55a738436df4bf0c7..f7e661549c42972bc6e187fcfdbb653d8e952369 100644 GIT binary patch literal 13005 zcmZ9S37i$hwZ>}{L=-NIzzo~aGsDP^!+?N5Of%=8L0m8dw;)~>gCfc*M&nZ80?~(w zZ@}CEqIVefMF9~36`N&E%lop^uNFFobIl!rMvo? zJY!5#b6Sr+_#fMOy*G?39#gw*dU9Y)#ZC}PqN?*d!UsKf3AkNksIGFkaK4otiK;Fa z2zO8(#O*SME>Qmv;lZj8clqfa<#8MYhMrKKDqI~JSCD_U_*V!zo-4dgd5QS-{JX3Z zeoOU;gV4}>R(2qMCkIJGnaJ}l;e*QWbC5Q4*m`|02a%!wDu2dB#?TKUyYu;mi_(Vc zc)e?VE)EUX_j=bBTpSs0kdYmUs;-^6Brx14@;rb`tl=hU&zA`|O?n>AC5S&K^gLR) znIMke^>TAu z!N%&V+f>56=SFF-KSpbuZar7ha}hY{c^<8B9C}_rOG0qqc^xfu@ya`?<|n+H=7STN ztiStN=tq44dD(t+d+oOA&c$g{@q*ZJ9p}vve&2IhUE$A^6I_gTSjWnaL{(XH;pVCr za#6;R>#-=%dvFo_S1VUYyS&@V4(P+ApFI(JzJ&|ZhO{4*P2skPe?Id140qq@6+xH( zNp2Gu+OB#Px3-41N~`xJSe!1>@t zY0rzeWdP22Udyf0v3A$v6>b}WL$B|Ue%Lta`AzO_p)2p@K8^#gAK`)EMp2f_>+q0F z?D*x)`Ra6>JMfJ`tX-8~z+)nC(#K!I<1APZ*IRxKPlVnu^7;tA%W>NCEqrehob-GT z-=7ADo@cOa47Q%B^h9gEe%w@|)Z-G<37_ zUhWA0Fy$lMF=OZ=&n@e4r@&BuBPCJQvW0L@ra_8|~DearcLckQ@d1zuyy;pbE^hyB15Ih zh4iIkD?1WZt;%UP80X*$nCVS$N9*~Qw8I+eEa>#BXdSqV@+evX?yCMNw7?kZruuYB zM~1Y%TFs)Tp?6n*70vkxuc4GRbe_iVI)y(*yY3Cux9i(#w@okC&bUb^fr+ZNFEZ*p zH;=d7&jIv$_y-00f4N=S(8(~%g=YvKQEttsb2=b0{DobmUGGu7zwmp?7jipX$7{-$ zaUpoU#*gH-INqvAb|BwqZX2TAThHTNzjSk#E70$e@qLz{JDI}pE*3(~Q6QTVN}wzGDI3#=jJbR|*M?hH2{P($T_ z^CLs`tn7eZ?&b$NUGm0A+ zLilt17uU}#a`|?1xiJ;rX#64WADD`7mA~gfh*u60e0e4o9|U|2bUmM-j7Na=ctJl- zhNj|6pD!T3)tHJel!x){@aK3W-BpPUF$)f}@yFZn>CUfQ%x9(J z++EsXP9MnU!jCb@l|<_JmE1eP`6(xvpl=AB?DUCzCHQ6Q`C-1*8j3>Ci+L>cR|TDa z6_1Dhs`dJMo|G}PCGxz@-6z_r`kQ=T($Kch>!0w0L7b1edZ(>XR{yR(Pc>lg|E@Jp zMf?_#as2PP@ige0l`rOLWq1x$|4^Q04Q*7umLCcXtyaF19|qSb-^ULhHuRK{g8Vc2 zkyVCfsQwH;Iu!G#>Z|!t=x&rnfqxTEZ;Wxqdfv*@#~Zp#(CM%9^t7RYs=v+CGlqJr z{vpr6`S|%G_1yuUku;R={U?lY1LelTb$$GaV#gKVEB9ucyY~Cki9y1jseU!jC^How zE8oU5&@c8X*Pz|^0_EY)y=RZE-8SX4$)H}X7!#=<-k~=lv@=0m=Z_ufeH&}XKb8^t z9zC!6AUXm6nlKyx;}G{OO>0!Y%DqFmzT^t>-6HeBbCKt}xjpn}t>@|7*@6X~|My%T z8uzZ`3V0Uxb!n>t@HNKJ67}!k8D}TUaLqm%+{t!=w zzA%y<$ajM8wcs$zCmXu)h!zUscqiMs@hHZHY=by=X8Ts0%XsQgLkl9G??P$!Ile;L zd5%Z$LuiMKLhql-4~4iML3jKog_lKMuaSPC^>uOuKV&c;Td%L>X*i!3)F1J*Kcb&0 z@8D@T-cGT*{Qq#z+w@K-JHVgt)G|Z+l#j5@82T!z)vL@IY^|XaS-r|MclF`MI#&`^ zrUO5S=an-vp8L9SBlmt_F5w3e+;-l1S~nkH_M= zwVm&MmTyMAXuIAU@ih@R^!{CZ`A>KsUkv|qBD;KFaQ_hbtoQ%G-2xoX^S(yhAq|eQ z`o01#0bYLgE6PMl1S~liav*bi=gAt^nQr&y|rF;QxZwL*MTG z`y09SmfZZbzrc-Ix%q8>5xs0;^|8MbZGx`-Xn%h~YWkDUzyDHtH8k}5P!5nt?H}o` zoqlUQk9Tt)VeD`P`cyZU(E#O2H}_Gol^xI*(l*2wsJ>FzKS!qazbJgV>YE)`>{s69 z@>giT+y9BMj-&gJ3D`@Nnqb4-V|%D-Gs{Py*mT$U`E`2a)H){PO_q z-1DcWaWAm;lTVv*r_j(!vEz83mU3IfFIVov%`C=ujUUYQlNb*}F~ENv*GXf1SA7(n zG+>ckzB}j}@Iuw^rhQSYoqRfj{t2!LB>?_E({^yR#xJ9n5dXC5FVpkT=PAG8`Z&#r zBmnVyYux7aqohzKtDo@;n(|kuz{OvC>3S(gN0NR#kq{C!J7ZzaJQC5e-6EW zlsi|q&y_^#;1sI1vFkhdAkBw=xplJBXSi$4&F2UI=;|i-oOW;_EdlRR|MRrM7}^`U za2LOmo`wEZ|@b& zwc942Z^mUJ)Rjc)_K$c(I@T@5cI9C<)-A^Vj4u!HIPU#p2lFK%x=AEE5~;CQ@F2&b z=WBQ%_yyH(;sJ=y@fhx%iSs1)nny2KAOAZp{fYhuZtXbqdbJGyIsX#3gcdvgDtY}t zRl9=odzHSkxIX3A=xY;uEFAj|?S}q}>YvbCk)chY>_GfiZkr3aBZOH2zc3{1rb5{1*86mg+76~~po=faGkW}YWEVBsf1;|k)3a$#iX8SD8*VI6HIj}cy@`Xu3(Bk#XY z&hJe@mv5%Lhk8@FExJ{7dyG}cWTVhrygXo(-8okteA0B{uO4@APmO}0q7#c2!<7^qqy-_cN zRlkADlDXBy)Rqa{8U9}CpT-@GA=lAR5dS!rWa4_ItTLUi`aHMFP6Mp$fPWP?iE^tv zsVy&Z-L#?WRo_KFT0@h??(%;uqx@saN9i-@DevD}&wc%IBeN@s)Yg1AqPdYN%K`0) zV%>jhC)$Jft)bV;gYyZC|-`7)kAWDf8Y zZasg_mqxkO@6^^GcvzVGnwZ+wgs%+@9ged8Z2_b1X`djjcUw=s0sOWyaWaXoG@gI9#tRCN%&uhyq@G_5Uc-fzu^%EZ||y4<*PzNk67=2l7~VcE9j12!xv`^VV^7D zwH#V}?X{kFaNl%pwK}!!UG5R!ZCqsMKP2t7k@5*Hjtn*MyuASzBEEr@9f{QT=G+?b zjaA22p^PEzhub^I@Y`DbJ-8|Il_>xG6#k{j>w#o>_;WAkxOnM?&D@I#pB(_*Wlg|G zg{0v#(w?8;Vw3xrm71{Hb$>c6vh#0s!v*aNWe50Q96;CGG~oaTAr@^SuOCILh|Mw+ z>vOvd9>#1|pV(A*QREqm$5HHIXkvTenX31dd{%j|9B;Dq@mILvjYbRNd?#Kb=X-_f zW4H*%|GDZ9xa-d?vP_)m>PHvhQxoT(!kbK99|ZeqP1bIkK3sxo)w`emv+y|$ya9qk1>T^qt5qz89BRLplpo|4jJH z$j4vACAjPZ%2x>Q35_d=znV)zLpsY;-^L|@p_d}B<6Au9ms`*OBgdZ;dama72H%z< z&(Cpt_$OG;uX1~v`^KB9{wKGOVxxcc2f_o?|A}y!guCJh z%%wr>ovCJkoXG$(c8*5$oU@-8TC^$iA!)k{|UW+s%t;)dzdTGE4d_z_82;J zJkPZkw;qt?=Y;i{yk@=l&sIGWJ(2PLe@OnOf#-eFzMHB3pP%xA1{l@g&C8B%H`H#M z-jp(imRX=XtyEfGU6w|kzm;dmr8dh|XV6v~d)2GTr#BG4L}bKQ1@ul7TiUDYN(UXQ z-d~m`7eqeaa6UU7do`*W$xV@OLFjdSxzRmen|ANQEUlV%&k30qb8n4f3%J;&*P-MiB$cuev#_zmbz$B==EzwU#$Ez-*02}HD>|en*m4Ozkw$r-%>$$yq$b&I<~YrXSYn^ z%T)iIe~oy(e{;U&t0UZB)lbShlk(j9d^z$j3&oH~%}wy&BslV%&lkFQ<&NCf#D=lC zJ-8?0by%C*k2_dA)P+9&Qf>uZXRo=}b0g@_YQAxNdNQ^YG52BmH~gzKzLGw5Y>g{8 zzq#}g;#WnU7s-;?YC)&3q}NPr32^Q@ir`;uy?--pK)%(X=biMt)0N+Hbw#TqukUkh ziPi|Z{NK1`2KPGcN+LC{F8vAqwStcGPvPDs?|g{9+l{Q<#_V@XGM2V-psa}NWmMk9 zH{dWip60#?<}SN(24922YPD28$(Kc_Ml0u$NL5zzFEX)}%*ti%SuI???M=+&_?ZJHN(X;%3?y52L??V2vN)zGB6WKZ@2w(5=ruMQ*cp zt67iAZO-vr_r96ycC)H!9^#j1{7R~FEa}|!y(GhEj^CiC5U<^M)?uoO=bPP_(umjk zncc=cDdg&Vb`RPG*84NNf)1KkH<|rQIvK|KX7`?vYag>G^EpAR{miyp0M>3Z`%&(a zf$pzob~Tqfe=+E-vs~KFzbKn93F*yYpv%t{F@{=@?6TdMzM$Dr~2?1=<7nS|AKE1z}EAXr||72 zuNO4m4S!v`ZJJAOeLl*D-Fd64l3cai`J#*_&#AtHJ_=(CrFXu^28Uf~ef$wV1A2~6 z$Zc6EGOBId>3k0I>*zSHfm;-#6{(dFS$PXw3ryLpQ44jR%|D?^{wEF65!mA5ncMUj_ZiNOmMr z8*buXN3n;D4U_l==&RNLh)l|x)jwO_#Q&oDGn|AUBbY15w}eM#a=&9sZCK6Mg~qLx zWc985EATNv=l>U9mc|N|>IZlbo-OOCevAj;+43x}Z>-Pd@Hb3~A(7hHn!5#9xlnG; zB~kA8hpCO{%L-Vd$ontkR!+B`FXk35UiD#IKZzBxjMvAw)ibUWcz%G6T6~X;JkO-B zz+YO=Pt(E3(4Nrqb94aL`*%TH@5Wc@Ap9F6um8iv=DN+s59lcTDb>H`(~`O0FQqn~ zq=I!5xurfaR97SBDDyQ_~3?uj(2fMfS=!4*#X|q#ToqELG^FB#26ak z^~Glh|JLh^3%EEk^mrsY5~;hI6R$hTOTxhNBRh**3X<6LOH z#^dLfAwEAw5`g@pIe>q6==mNF()dhaJx}8R@rP7@f`cS}KCe8_ac<#t@w3jKTOeD! zSvV2+eE4}jnpxw>^GCwxgr4`i^W&CD&p){H=QimqFG+9_;@b(LzL&If*ULfR^&VUt z7%o!1f{R0NQ7KTWtW^gK(rAn?3ESkHgS2H`pxukUpCgN^cgT#WiU9(nyk zF3!a2Z^`Gb;%5TZ`+pGro9CrI9tA~^tDwaT?V_kHiZ{@zC?0QLK?MXcA|}#zCYd)I_Q~^PfBXNxvoo{r z%Ho_@<#DLKJ`W~oAKkmrgK$>If0_J0V6A!!v`>1D_WzQ`P))ll#B9c%wm6w zJ`pop`6pvWD?Sf(KKnyg-YlG-j`BR5Yy6_m#}pMUe*q@7;+v2P6s;D27UO(HtAtlz zbecI(=I}D#K8q0?|G0MiDu(5v{5FOJ%%RgiLP;3a55m_`{V0lz-<4NifVg4~n&ay` zqbKVtL&r&+;InR#>r+1*9gSb~(P$fTeML{v4;;Tr+Y9VJpAP6K|BUvqf3^58r%x2K z_!rPl_OB8B|L8T=<$2ZLMq5~4EB>XliS>2j-$?5NX3<|Vb*J^hZ_{HO|3qK|xPG4= z$48Vmk~NoRUpJkr0Z8OjYL<;sUbg*jknmM1E4;_DYgV@XK_rw)Z4><{;-R7r+FtOo z9Zs-3NVv#yrSo?<1@WAsl<4J_>qH-8`4ZujjlV{?%Idd=_5$DUrfua}1e+S}eMXv?UpRxRo@G{Gv32(6crL}Yab=YG0py)5!`_&7- zX88wg1K9sB!%%6*dCLWX#Z^ZKoozqS) zG0zVtSmgS49Alm@P6(Y|jf7U{>O20mDj0DpgUg%xrgJqNCv!gq*2d+We-Q>MMHRxE zQO0aCjt|yf!T_ykn0EX=`uU26STy=xB$)>b|9}|BpX~foyP_}ar#O9TA$q5|JmF$= zW&i2oABQf?fp7|)IR0$$*PvZa(KO+U(T4pOi~kCEp`v-BUt^vTT_O7Ks6i|Gt?-@n zeW2(T@h_z#%(n&hf|s4Tit0l}_lAx)Q$5EovB>S8`Z95j(8Jp4uUr3`(DBD~g#FKm zeuy}S=talV+S0L5(VIcDe_A0_UXkSOw0od8K^E*Pt-1P>^$cv(3vk!hb>$>ut5u?}zUzwDTP= z#ek4G=Xezc=9xpse*@$@IavP~6?p|OaQp>M z_Z9IJZw}TQFhMIi6gG3+i3qs8UkUd`iuFC(>HR=?MV|(a2jeW(cMFfeB<8n;301zL zS3~EoLsd@EKeXf7s8)(z5Pcr1(~ABkd?l*c|FrNms16lv)XE%QwoY4KY0>aqsMd;> zh4upT{kHtS2rokwmw%t|YE0(x@6yiy6wYS8IdJ?kz<$a9y7!P`{c7=lf-`+Z^R3<7 z|4U3{|0SY-gYki)*`hb#^ia`s$J5(k4ExV<{^=)TH2bSW?~4jw(OJSiM&uNoDSR@@ zS)U+00z>nP#tWa0LF_+6cnbRKsDHMZR|(o0yzKNVQRpk0EPSnAF?VG*`J=2Qn zM85^yLq!*f{wJK2SM)RC`;X%d%H#JTnPv|(ovVR}rxkkmHqOg>YY@vRoTwfDKMFaG zy9AEwQK&fW!)7k%h`yTBJmy1+`Zh zFSTi?LdWY6<7WOCINoHML0@Ud+ibJn6@9mD_RFI0H)%_oMgPt;n>K{X9A0*qvTtP% zXvf_VXaAiRjh;Xvt?2iG(@T)#_=Vc>P$adYUkX>6)rO`D6Znx4S-UB35{lVhA$l$P zJX&BsUTJJA=y&#TnGg>OQC?)F{6x1&FI`wroIEz7VN_8|HPD)pl1 z>(M{0QhyhI-m*OA;hpXM-f;Txp72AJdS5sRKc`argiGzmQaj;c@YDQuB|HJX;fqq)iqrw^V^IJY{v%?=o zaZb@DDerLS>1Ka_q_9$Tke^2-1L^+S391J zgs;pPFo%~dud~cUvzcdE<}#c4GRsMe#y`J_^G?6bEdOPyYFEj?>Ev=_W=$s*dy{$;{9+i%$A;=h~T){2&E=f9smXa9=8 z@mi|q@?>@|`8(ROf0cIno9LKh4jjLauFR_~a(zoaMGy9`7X2&q4VXjcKWrcC8sSFt z_akXm+8$+L%Qtnlv=@dLcK*^rl&ATdTDU*P=Av8)3iumaD|2|+QeX!qfXmq5!uQ};=_oJ3m4*Ws|0os& z(ej?fb$*mz#r1h+?fh?nr_4xwcHu^&OL?Dxtu51X={_tn%oq9K`u&JS9KRuG=CW>B z#PJ&}vR*a-zYALSB(h}_t-fAc1M6ul@+19Ub`@?6`FVv-|6eTN^5l7!{TcI_C4b76 z<8s9uIR9E)n&W(v_)VCbX121a&lb!I6+I^Y9hi}4*4DuK2bjvdJaqgSs(qfe0>|}8 zF+bw;ft@j){Vm)bV?t)M~G>0{#$Ot^_(Pj9u-U!ZNw4~I^Fm9_>^|4!Q6 z%DoT7VDy6?LOaBcTO-sTkU!c57j`jG@ysaE; zI#<=WJgw-tu({aSDEuPeZ{@)8^|+MvXDo6vV~a75^`}L@6?6T_>Jz&Mvsr&Cbnz=O zLq&#J>^ao3UxrES6-;Ko42#%@IE($<73SdkeSvX0GHt|;V2t6QS&w_Dyjpl8y{wt7o!cMZYW6K?RcJ3TzfDiFzlC?3y3i`|@1;kX z9~Xb4Nl|)STZ5NP6wrg3IdI&W9%#iqDP!WT%=b?u>0T2rTt;`b;<0o`D}NQ;){1A- zttuM7fNs-Keu(Z4BK1!^M-Q=Ima)WklS?iAk@$#0_RF-E*hBwdzw}q)AiZH&+IN)R zjq1rZw1?wYY1<$#o9snjhmrdyi|BjSrT>zH!6T-n|B~fs-%1~YZic12YV>B7=aHOh zryXfea<+Y&ljoP5iy=Pehpi6xck)^c*O7cm{uZNHUoZMCI3v&bDxASY!-2iP@sEMR z$TE_A9Fua9d{1sfjgBlk$;~)7%^bS;mvDX%8K245QRhdN&E&h75k@(W3pxHt?c(>^ zW%()LA23HL`fJdv7j?zY*}usmx3{R+E;F07(}x_#6O~uN8b1U(ZS8M5R|CuoG_7b3 z%QOr#+bOb|Wg0Zy#J623`t9@w)?FHB8t$XJS$B^u)9?r_30fXoreUQ?5qXT6h8N5f zC~1*tc%8Pe-=#^W;a{|k{cc!g8a|>OMi02UT=PuB9{SMe77c$*U#m#{8rz{D9jSj~ zA9M{P@r`BX+qC6=ji=d{ewSvM#xw0NJ}#{@jni-{`&YaBHU0#Zh68)S%QVilTX1Vd zzZNxlPCM=Nn{k2SvOz{ z8ClFu9)sRo%sIj<(3kaU;U`cSDw<^6*8hxMJp%1`JAC#}uxQHr5G8p<<3!(&LCoWw zUZpT37x7o|YQ^z^=)F*`c_&WW3tqM=j*&rRC#|X!r*Zr_;;+Q%%u~fb9uvdJPJC6Z zoek!T{&P&qD{4ZnZ`A@j8{85ob1*N)IUIktc6<-c)rvC0In)M`my)XWsAc`J(D|RS zyvCv_?|Gb?=eGrk-+^;{-ogs4f%Si*iuIj=Q}Pqfo3Ex&8g#7{sm_s4e8t1WL5o{8dshjpOL z!Tw)bzC-v1%hzcm8~rxRk`ER4+55?`tXN@rthF0|)0X5gVcwGD_VChc4%S~qQJ(Wv eIB()p-v}SD{JG;wW$K^WE!+deJU-qNp7fQ1H diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java index ed2a6c04677b6..66758164a5f60 100644 --- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -36,6 +36,7 @@ import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.database.ContentObserver; import android.graphics.Rect; +import android.hardware.input.InputManager; import android.net.Uri; import android.os.Binder; import android.os.Build; @@ -44,12 +45,16 @@ import android.os.IBinder; import android.os.Message; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.SystemClock; import android.provider.Settings; import android.text.TextUtils; import android.text.TextUtils.SimpleStringSplitter; import android.util.Slog; import android.util.SparseArray; import android.view.IWindow; +import android.view.InputDevice; +import android.view.KeyCharacterMap; +import android.view.KeyEvent; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityNodeInfo; @@ -1301,11 +1306,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } } } - final int flags = (mIncludeNotImportantViews) ? - AccessibilityNodeInfo.INCLUDE_NOT_IMPORTANT_VIEWS : 0; - final int interrogatingPid = Binder.getCallingPid(); final long identityToken = Binder.clearCallingIdentity(); try { + final int flags = (mIncludeNotImportantViews) ? + AccessibilityNodeInfo.INCLUDE_NOT_IMPORTANT_VIEWS : 0; + final int interrogatingPid = Binder.getCallingPid(); connection.performAccessibilityAction(accessibilityNodeId, action, interactionId, callback, flags, interrogatingPid, interrogatingTid); } catch (RemoteException re) { @@ -1318,6 +1323,24 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub return true; } + public boolean perfromGlobalAction(int action) { + switch (action) { + case AccessibilityService.GLOBAL_ACTION_BACK: { + sendDownAndUpKeyEvents(KeyEvent.KEYCODE_BACK); + } return true; + case AccessibilityService.GLOBAL_ACTION_HOME: { + sendDownAndUpKeyEvents(KeyEvent.KEYCODE_HOME); + } return true; + case AccessibilityService.GLOBAL_ACTION_RECENTS: { + sendDownAndUpKeyEvents(KeyEvent.KEYCODE_APP_SWITCH); + } return true; + case AccessibilityService.GLOBAL_ACTION_NOTIFICATIONS: { + // TODO: Implement when 6346026 is fixed. + } return true; + } + return false; + } + public void onServiceDisconnected(ComponentName componentName) { /* do nothing - #binderDied takes care */ } @@ -1358,6 +1381,30 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } } + private void sendDownAndUpKeyEvents(int keyCode) { + final long token = Binder.clearCallingIdentity(); + + // Inject down. + final long downTime = SystemClock.uptimeMillis(); + KeyEvent down = KeyEvent.obtain(downTime, downTime, KeyEvent.ACTION_DOWN, keyCode, 0, 0, + KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FROM_SYSTEM, + InputDevice.SOURCE_KEYBOARD, null); + InputManager.getInstance().injectInputEvent(down, + InputManager.INJECT_INPUT_EVENT_MODE_ASYNC); + down.recycle(); + + // Inject up. + final long upTime = SystemClock.uptimeMillis(); + KeyEvent up = KeyEvent.obtain(downTime, upTime, KeyEvent.ACTION_UP, keyCode, 0, 0, + KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FROM_SYSTEM, + InputDevice.SOURCE_KEYBOARD, null); + InputManager.getInstance().injectInputEvent(up, + InputManager.INJECT_INPUT_EVENT_MODE_ASYNC); + up.recycle(); + + Binder.restoreCallingIdentity(token); + } + private IAccessibilityInteractionConnection getConnectionLocked(int windowId) { if (DEBUG) { Slog.i(LOG_TAG, "Trying to get interaction connection to windowId: " + windowId); From ced57dfa93e81cf06f7c5165f4af88f638360b23 Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Wed, 18 Apr 2012 15:37:21 -0700 Subject: [PATCH 058/132] Revert "Telephony: Dynamically instantiate IccCard" This reverts commit fe37acae729529b8bf3a3140fa397bddce42b1e0 There are two bugs that are weekend release blockers: b/6357558 b/6357880 6357558 is easily fixed with: https://android-git.corp.google.com/g/#/c/182228/ But there are still questions. Bug 6357880 has unknown causes at the moment but this change is the most likely candidate. So for today's pre-weekend build we are reverting this change. --- .../telephony/DataConnectionTracker.java | 13 -- .../android/internal/telephony/IccCard.java | 122 ++++++++-------- .../IccPhoneBookInterfaceManager.java | 12 -- .../internal/telephony/IccRecords.java | 18 +-- .../android/internal/telephony/PhoneBase.java | 38 ++--- .../telephony/ServiceStateTracker.java | 33 +---- .../internal/telephony/cdma/CDMALTEPhone.java | 41 ++---- .../internal/telephony/cdma/CDMAPhone.java | 67 ++------- .../cdma/CdmaDataConnectionTracker.java | 38 +---- .../cdma/CdmaLteServiceStateTracker.java | 12 +- .../cdma/CdmaServiceStateTracker.java | 71 ++++------ .../cdma/RuimPhoneBookInterfaceManager.java | 10 +- .../internal/telephony/cdma/RuimRecords.java | 19 ++- .../internal/telephony/gsm/GSMPhone.java | 131 +++++------------ .../gsm/GsmDataConnectionTracker.java | 54 ++----- .../internal/telephony/gsm/GsmMmiCode.java | 15 +- .../telephony/gsm/GsmServiceStateTracker.java | 64 ++++----- .../internal/telephony/gsm/SIMRecords.java | 8 +- .../gsm/SimPhoneBookInterfaceManager.java | 9 +- .../internal/telephony/sip/SipPhoneBase.java | 4 - .../telephony/uicc/UiccController.java | 132 ++++-------------- 21 files changed, 275 insertions(+), 636 deletions(-) diff --git a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java index 214627d4dd20c..55f2ca3c4541a 100644 --- a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java +++ b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java @@ -46,7 +46,6 @@ import android.util.Log; import com.android.internal.R; import com.android.internal.telephony.DataConnection.FailCause; -import com.android.internal.telephony.uicc.UiccController; import com.android.internal.util.AsyncChannel; import com.android.internal.util.Protocol; @@ -58,7 +57,6 @@ import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; /** * {@hide} @@ -140,7 +138,6 @@ public abstract class DataConnectionTracker extends Handler { public static final int EVENT_CLEAN_UP_ALL_CONNECTIONS = BASE + 30; public static final int CMD_SET_DEPENDENCY_MET = BASE + 31; public static final int CMD_SET_POLICY_DATA_ENABLE = BASE + 32; - protected static final int EVENT_ICC_CHANGED = BASE + 33; /***** Constants *****/ @@ -253,8 +250,6 @@ public abstract class DataConnectionTracker extends Handler { // member variables protected PhoneBase mPhone; - protected UiccController mUiccController; - protected AtomicReference mIccRecords = new AtomicReference(); protected Activity mActivity = Activity.NONE; protected State mState = State.IDLE; protected Handler mDataConnectionTracker = null; @@ -505,8 +500,6 @@ public abstract class DataConnectionTracker extends Handler { protected DataConnectionTracker(PhoneBase phone) { super(); mPhone = phone; - mUiccController = UiccController.getInstance(); - mUiccController.registerForIccChanged(this, EVENT_ICC_CHANGED, null); IntentFilter filter = new IntentFilter(); filter.addAction(getActionIntentReconnectAlarm()); @@ -548,7 +541,6 @@ public abstract class DataConnectionTracker extends Handler { mIsDisposed = true; mPhone.getContext().unregisterReceiver(this.mIntentReceiver); mDataRoamingSettingObserver.unregister(mPhone.getContext()); - mUiccController.unregisterForIccChanged(this); } protected void broadcastMessenger() { @@ -671,7 +663,6 @@ public abstract class DataConnectionTracker extends Handler { protected abstract void onCleanUpConnection(boolean tearDown, int apnId, String reason); protected abstract void onCleanUpAllConnections(String cause); protected abstract boolean isDataPossible(String apnType); - protected abstract void onUpdateIcc(); protected void onDataStallAlarm(int tag) { loge("onDataStallAlarm: not impleted tag=" + tag); @@ -782,10 +773,6 @@ public abstract class DataConnectionTracker extends Handler { onSetPolicyDataEnabled(enabled); break; } - case EVENT_ICC_CHANGED: - onUpdateIcc(); - break; - default: Log.e("DATA", "Unidentified event msg=" + msg); break; diff --git a/telephony/java/com/android/internal/telephony/IccCard.java b/telephony/java/com/android/internal/telephony/IccCard.java index 140b7c60555b6..92024cdd72edb 100644 --- a/telephony/java/com/android/internal/telephony/IccCard.java +++ b/telephony/java/com/android/internal/telephony/IccCard.java @@ -35,12 +35,10 @@ import android.view.WindowManager; import com.android.internal.telephony.PhoneBase; import com.android.internal.telephony.CommandsInterface.RadioState; -import com.android.internal.telephony.gsm.GSMPhone; import com.android.internal.telephony.gsm.SIMFileHandler; import com.android.internal.telephony.gsm.SIMRecords; import com.android.internal.telephony.cat.CatService; import com.android.internal.telephony.cdma.CDMALTEPhone; -import com.android.internal.telephony.cdma.CDMAPhone; import com.android.internal.telephony.cdma.CdmaLteUiccFileHandler; import com.android.internal.telephony.cdma.CdmaLteUiccRecords; import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager; @@ -116,6 +114,8 @@ public class IccCard { protected static final int EVENT_ICC_LOCKED = 1; private static final int EVENT_GET_ICC_STATUS_DONE = 2; protected static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 3; + private static final int EVENT_PINPUK_DONE = 4; + private static final int EVENT_REPOLL_STATUS_DONE = 5; protected static final int EVENT_ICC_READY = 6; private static final int EVENT_QUERY_FACILITY_LOCK_DONE = 7; private static final int EVENT_CHANGE_FACILITY_LOCK_DONE = 8; @@ -178,19 +178,34 @@ public class IccCard { return State.UNKNOWN; } - public IccCard(PhoneBase phone, IccCardStatus ics, String logTag, boolean dbg) { + public IccCard(PhoneBase phone, String logTag, Boolean is3gpp, Boolean dbg) { mLogTag = logTag; mDbg = dbg; - if (mDbg) log("Creating"); - update(phone, ics); + if (mDbg) log("[IccCard] Creating card type " + (is3gpp ? "3gpp" : "3gpp2")); + mPhone = phone; + this.is3gpp = is3gpp; mCdmaSSM = CdmaSubscriptionSourceManager.getInstance(mPhone.getContext(), mPhone.mCM, mHandler, EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED, null); + if (phone.mCM.getLteOnCdmaMode() == Phone.LTE_ON_CDMA_TRUE + && phone instanceof CDMALTEPhone) { + mIccFileHandler = new CdmaLteUiccFileHandler(this, "", mPhone.mCM); + mIccRecords = new CdmaLteUiccRecords(this, mPhone.mContext, mPhone.mCM); + } else { + // Correct aid will be set later (when GET_SIM_STATUS returns) + mIccFileHandler = is3gpp ? new SIMFileHandler(this, "", mPhone.mCM) : + new RuimFileHandler(this, "", mPhone.mCM); + mIccRecords = is3gpp ? new SIMRecords(this, mPhone.mContext, mPhone.mCM) : + new RuimRecords(this, mPhone.mContext, mPhone.mCM); + } + mCatService = CatService.getInstance(mPhone.mCM, mIccRecords, + mPhone.mContext, mIccFileHandler, this); mPhone.mCM.registerForOffOrNotAvailable(mHandler, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); mPhone.mCM.registerForOn(mHandler, EVENT_RADIO_ON, null); + mPhone.mCM.registerForIccStatusChanged(mHandler, EVENT_ICC_STATUS_CHANGED, null); } public void dispose() { - if (mDbg) log("Disposing card type " + (is3gpp ? "3gpp" : "3gpp2")); + if (mDbg) log("[IccCard] Disposing card type " + (is3gpp ? "3gpp" : "3gpp2")); mPhone.mCM.unregisterForIccStatusChanged(mHandler); mPhone.mCM.unregisterForOffOrNotAvailable(mHandler); mPhone.mCM.unregisterForOn(mHandler); @@ -200,40 +215,6 @@ public class IccCard { mIccFileHandler.dispose(); } - public void update(PhoneBase phone, IccCardStatus ics) { - if (phone != mPhone) { - PhoneBase oldPhone = mPhone; - mPhone = phone; - log("Update"); - if (phone instanceof GSMPhone) { - is3gpp = true; - } else if (phone instanceof CDMALTEPhone){ - is3gpp = true; - } else if (phone instanceof CDMAPhone){ - is3gpp = false; - } else { - throw new RuntimeException("Update: Unhandled phone type. Critical error!" + - phone.getPhoneName()); - } - - - if (phone.mCM.getLteOnCdmaMode() == Phone.LTE_ON_CDMA_TRUE - && phone instanceof CDMALTEPhone) { - mIccFileHandler = new CdmaLteUiccFileHandler(this, "", mPhone.mCM); - mIccRecords = new CdmaLteUiccRecords(this, mPhone.mContext, mPhone.mCM); - } else { - // Correct aid will be set later (when GET_SIM_STATUS returns) - mIccFileHandler = is3gpp ? new SIMFileHandler(this, "", mPhone.mCM) : - new RuimFileHandler(this, "", mPhone.mCM); - mIccRecords = is3gpp ? new SIMRecords(this, mPhone.mContext, mPhone.mCM) : - new RuimRecords(this, mPhone.mContext, mPhone.mCM); - } - mCatService = CatService.getInstance(mPhone.mCM, mIccRecords, mPhone.mContext, - mIccFileHandler, this); - } - mHandler.sendMessage(mHandler.obtainMessage(EVENT_GET_ICC_STATUS_DONE, ics)); - } - protected void finalize() { if (mDbg) log("[IccCard] Finalized card type " + (is3gpp ? "3gpp" : "3gpp2")); } @@ -363,23 +344,27 @@ public class IccCard { */ public void supplyPin (String pin, Message onComplete) { - mPhone.mCM.supplyIccPin(pin, onComplete); + mPhone.mCM.supplyIccPin(pin, mHandler.obtainMessage(EVENT_PINPUK_DONE, onComplete)); } public void supplyPuk (String puk, String newPin, Message onComplete) { - mPhone.mCM.supplyIccPuk(puk, newPin, onComplete); + mPhone.mCM.supplyIccPuk(puk, newPin, + mHandler.obtainMessage(EVENT_PINPUK_DONE, onComplete)); } public void supplyPin2 (String pin2, Message onComplete) { - mPhone.mCM.supplyIccPin2(pin2, onComplete); + mPhone.mCM.supplyIccPin2(pin2, + mHandler.obtainMessage(EVENT_PINPUK_DONE, onComplete)); } public void supplyPuk2 (String puk2, String newPin2, Message onComplete) { - mPhone.mCM.supplyIccPuk2(puk2, newPin2, onComplete); + mPhone.mCM.supplyIccPuk2(puk2, newPin2, + mHandler.obtainMessage(EVENT_PINPUK_DONE, onComplete)); } public void supplyNetworkDepersonalization (String pin, Message onComplete) { - mPhone.mCM.supplyNetworkDepersonalization(pin, onComplete); + mPhone.mCM.supplyNetworkDepersonalization(pin, + mHandler.obtainMessage(EVENT_PINPUK_DONE, onComplete)); } /** @@ -509,15 +494,21 @@ public class IccCard { * */ public String getServiceProviderName () { - return mIccRecords.getServiceProviderName(); + return mPhone.mIccRecords.getServiceProviderName(); } protected void updateStateProperty() { mPhone.setSystemProperty(TelephonyProperties.PROPERTY_SIM_STATE, getState().toString()); } - private void getIccCardStatusDone(IccCardStatus ics) { - handleIccCardStatus(ics); + private void getIccCardStatusDone(AsyncResult ar) { + if (ar.exception != null) { + Log.e(mLogTag,"Error getting ICC status. " + + "RIL_REQUEST_GET_ICC_STATUS should " + + "never return an error", ar.exception); + return; + } + handleIccCardStatus((IccCardStatus) ar.result); } private void handleIccCardStatus(IccCardStatus newCardStatus) { @@ -593,7 +584,6 @@ public class IccCard { if (oldState != State.READY && newState == State.READY && (is3gpp || isSubscriptionFromIccCard)) { mIccFileHandler.setAid(getAid()); - broadcastIccStateChangedIntent(INTENT_VALUE_ICC_READY, null); mIccRecords.onReady(); } } @@ -714,6 +704,7 @@ public class IccCard { if (!is3gpp) { handleCdmaSubscriptionSource(); } + mPhone.mCM.getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE)); break; case EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED: handleCdmaSubscriptionSource(); @@ -734,9 +725,30 @@ public class IccCard { obtainMessage(EVENT_QUERY_FACILITY_LOCK_DONE)); break; case EVENT_GET_ICC_STATUS_DONE: - IccCardStatus cs = (IccCardStatus)msg.obj; + ar = (AsyncResult)msg.obj; - getIccCardStatusDone(cs); + getIccCardStatusDone(ar); + break; + case EVENT_PINPUK_DONE: + // a PIN/PUK/PIN2/PUK2/Network Personalization + // request has completed. ar.userObj is the response Message + // Repoll before returning + ar = (AsyncResult)msg.obj; + // TODO should abstract these exceptions + AsyncResult.forMessage(((Message)ar.userObj)).exception + = ar.exception; + mPhone.mCM.getIccCardStatus( + obtainMessage(EVENT_REPOLL_STATUS_DONE, ar.userObj)); + break; + case EVENT_REPOLL_STATUS_DONE: + // Finished repolling status after PIN operation + // ar.userObj is the response messaeg + // ar.userObj.obj is already an AsyncResult with an + // appropriate exception filled in if applicable + + ar = (AsyncResult)msg.obj; + getIccCardStatusDone(ar); + ((Message)ar.userObj).sendToTarget(); break; case EVENT_QUERY_FACILITY_LOCK_DONE: ar = (AsyncResult)msg.obj; @@ -785,6 +797,10 @@ public class IccCard { = ar.exception; ((Message)ar.userObj).sendToTarget(); break; + case EVENT_ICC_STATUS_CHANGED: + Log.d(mLogTag, "Received Event EVENT_ICC_STATUS_CHANGED"); + mPhone.mCM.getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE)); + break; case EVENT_CARD_REMOVED: onIccSwap(false); break; @@ -951,10 +967,6 @@ public class IccCard { Log.d(mLogTag, "[IccCard] " + msg); } - private void loge(String msg) { - Log.e(mLogTag, "[IccCard] " + msg); - } - protected int getCurrentApplicationIndex() { if (is3gpp) { return mIccCardStatus.getGsmUmtsSubscriptionAppIndex(); diff --git a/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java b/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java index 0e5f2da1db03a..45562ca96e44b 100644 --- a/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java +++ b/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java @@ -103,23 +103,11 @@ public abstract class IccPhoneBookInterfaceManager extends IIccPhoneBook.Stub { public IccPhoneBookInterfaceManager(PhoneBase phone) { this.phone = phone; - IccRecords r = phone.mIccRecords.get(); - if (r != null) { - adnCache = r.getAdnCache(); - } } public void dispose() { } - public void updateIccRecords(IccRecords iccRecords) { - if (iccRecords != null) { - adnCache = iccRecords.getAdnCache(); - } else { - adnCache = null; - } - } - protected void publish() { //NOTE service "simphonebook" added by IccSmsInterfaceManagerProxy ServiceManager.addService("simphonebook", this); diff --git a/telephony/java/com/android/internal/telephony/IccRecords.java b/telephony/java/com/android/internal/telephony/IccRecords.java index 3c906471ac159..41c9d5ad1c2e8 100644 --- a/telephony/java/com/android/internal/telephony/IccRecords.java +++ b/telephony/java/com/android/internal/telephony/IccRecords.java @@ -26,8 +26,6 @@ import android.os.RegistrantList; import com.android.internal.telephony.gsm.UsimServiceTable; import com.android.internal.telephony.ims.IsimRecords; -import java.util.concurrent.atomic.AtomicBoolean; - /** * {@hide} */ @@ -35,7 +33,7 @@ public abstract class IccRecords extends Handler implements IccConstants { protected static final boolean DBG = true; // ***** Instance Variables - protected AtomicBoolean mDestroyed = new AtomicBoolean(false); + protected boolean mDestroyed = false; // set to true once this object needs to be disposed of protected Context mContext; protected CommandsInterface mCi; protected IccFileHandler mFh; @@ -81,9 +79,9 @@ public abstract class IccRecords extends Handler implements IccConstants { // ***** Event Constants protected static final int EVENT_SET_MSISDN_DONE = 30; - public static final int EVENT_MWI = 0; // Message Waiting indication - public static final int EVENT_CFI = 1; // Call Forwarding indication - public static final int EVENT_SPN = 2; // Service Provider Name + public static final int EVENT_MWI = 0; + public static final int EVENT_CFI = 1; + public static final int EVENT_SPN = 2; public static final int EVENT_GET_ICC_RECORD_DONE = 100; @@ -115,7 +113,7 @@ public abstract class IccRecords extends Handler implements IccConstants { * Call when the IccRecords object is no longer going to be used. */ public void dispose() { - mDestroyed.set(true); + mDestroyed = true; mParentCard = null; mFh = null; mCi = null; @@ -130,8 +128,12 @@ public abstract class IccRecords extends Handler implements IccConstants { return adnCache; } + public IccCard getIccCard() { + return mParentCard; + } + public void registerForRecordsLoaded(Handler h, int what, Object obj) { - if (mDestroyed.get()) { + if (mDestroyed) { return; } diff --git a/telephony/java/com/android/internal/telephony/PhoneBase.java b/telephony/java/com/android/internal/telephony/PhoneBase.java index 0c2f234d91ce6..2ac936593a429 100644 --- a/telephony/java/com/android/internal/telephony/PhoneBase.java +++ b/telephony/java/com/android/internal/telephony/PhoneBase.java @@ -40,7 +40,6 @@ import com.android.internal.R; import com.android.internal.telephony.gsm.UsimServiceTable; import com.android.internal.telephony.ims.IsimRecords; import com.android.internal.telephony.test.SimulatedRadioControl; -import com.android.internal.telephony.uicc.UiccController; import com.android.internal.telephony.gsm.SIMRecords; import java.io.FileDescriptor; @@ -111,7 +110,6 @@ public abstract class PhoneBase extends Handler implements Phone { protected static final int EVENT_SET_NETWORK_AUTOMATIC = 28; protected static final int EVENT_NEW_ICC_SMS = 29; protected static final int EVENT_ICC_RECORD_EVENTS = 30; - protected static final int EVENT_ICC_CHANGED = 31; // Key used to read/write current CLIR setting public static final String CLIR_KEY = "clir_key"; @@ -128,8 +126,7 @@ public abstract class PhoneBase extends Handler implements Phone { int mCallRingDelay; public boolean mIsTheCurrentActivePhone = true; boolean mIsVoiceCapable = true; - protected UiccController mUiccController = null; - public AtomicReference mIccRecords = new AtomicReference(); + public IccRecords mIccRecords; protected AtomicReference mIccCard = new AtomicReference(); public SmsStorageMonitor mSmsStorageMonitor; public SmsUsageMonitor mSmsUsageMonitor; @@ -254,8 +251,6 @@ public abstract class PhoneBase extends Handler implements Phone { // Initialize device storage and outgoing SMS usage monitors for SMSDispatchers. mSmsStorageMonitor = new SmsStorageMonitor(this); mSmsUsageMonitor = new SmsUsageMonitor(context); - mUiccController = UiccController.getInstance(this); - mUiccController.registerForIccChanged(this, EVENT_ICC_CHANGED, null); } public void dispose() { @@ -267,7 +262,6 @@ public abstract class PhoneBase extends Handler implements Phone { // Dispose the SMS usage and storage monitors mSmsStorageMonitor.dispose(); mSmsUsageMonitor.dispose(); - mUiccController.unregisterForIccChanged(this); } } @@ -275,10 +269,9 @@ public abstract class PhoneBase extends Handler implements Phone { mSmsStorageMonitor = null; mSmsUsageMonitor = null; mSMS = null; - mIccRecords.set(null); + mIccRecords = null; mIccCard.set(null); mDataConnectionTracker = null; - mUiccController = null; } /** @@ -315,10 +308,6 @@ public abstract class PhoneBase extends Handler implements Phone { } break; - case EVENT_ICC_CHANGED: - onUpdateIccAvailability(); - break; - default: throw new RuntimeException("unexpected event not handled"); } @@ -329,9 +318,6 @@ public abstract class PhoneBase extends Handler implements Phone { return mContext; } - // Will be called when icc changed - protected abstract void onUpdateIccAvailability(); - /** * Disables the DNS check (i.e., allows "0.0.0.0"). * Useful for lab testing environment. @@ -680,26 +666,22 @@ public abstract class PhoneBase extends Handler implements Phone { @Override public String getIccSerialNumber() { - IccRecords r = mIccRecords.get(); - return (r != null) ? r.iccid : ""; + return mIccRecords.iccid; } @Override public boolean getIccRecordsLoaded() { - IccRecords r = mIccRecords.get(); - return (r != null) ? r.getRecordsLoaded() : false; + return mIccRecords.getRecordsLoaded(); } @Override public boolean getMessageWaitingIndicator() { - IccRecords r = mIccRecords.get(); - return (r != null) ? r.getVoiceMessageWaiting() : false; + return mIccRecords.getVoiceMessageWaiting(); } @Override public boolean getCallForwardingIndicator() { - IccRecords r = mIccRecords.get(); - return (r != null) ? r.getVoiceCallForwardingFlag() : false; + return mIccRecords.getVoiceCallForwardingFlag(); } /** @@ -1153,10 +1135,7 @@ public abstract class PhoneBase extends Handler implements Phone { */ @Override public void setVoiceMessageWaiting(int line, int countWaiting) { - IccRecords r = mIccRecords.get(); - if (r != null) { - r.setVoiceMessageWaiting(line, countWaiting); - } + mIccRecords.setVoiceMessageWaiting(line, countWaiting); } /** @@ -1165,8 +1144,7 @@ public abstract class PhoneBase extends Handler implements Phone { */ @Override public UsimServiceTable getUsimServiceTable() { - IccRecords r = mIccRecords.get(); - return (r != null) ? r.getUsimServiceTable() : null; + return mIccRecords.getUsimServiceTable(); } public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { diff --git a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java index a86b68b929fdc..75eb226d4aa1e 100644 --- a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java +++ b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java @@ -18,15 +18,12 @@ package com.android.internal.telephony; import android.os.AsyncResult; import android.os.Handler; -import android.os.Looper; import android.os.Message; import android.os.Registrant; import android.os.RegistrantList; import android.telephony.ServiceState; import android.telephony.SignalStrength; -import com.android.internal.telephony.uicc.UiccController; - import java.io.FileDescriptor; import java.io.PrintWriter; @@ -36,9 +33,6 @@ import java.io.PrintWriter; public abstract class ServiceStateTracker extends Handler { protected CommandsInterface cm; - protected UiccController mUiccController = null; - protected IccCard mIccCard = null; - protected IccRecords mIccRecords = null; public ServiceState ss; protected ServiceState newSS; @@ -136,7 +130,7 @@ public abstract class ServiceStateTracker extends Handler { protected static final int EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED = 39; protected static final int EVENT_CDMA_PRL_VERSION_CHANGED = 40; protected static final int EVENT_RADIO_ON = 41; - protected static final int EVENT_ICC_CHANGED = 42; + protected static final String TIMEZONE_PROPERTY = "persist.sys.timezone"; @@ -173,10 +167,7 @@ public abstract class ServiceStateTracker extends Handler { protected static final String REGISTRATION_DENIED_GEN = "General"; protected static final String REGISTRATION_DENIED_AUTH = "Authentication Failure"; - public ServiceStateTracker(PhoneBase p, CommandsInterface ci) { - cm = ci; - mUiccController = UiccController.getInstance(); - mUiccController.registerForIccChanged(this, EVENT_ICC_CHANGED, null); + public ServiceStateTracker() { } public boolean getDesiredPowerState() { @@ -303,10 +294,6 @@ public abstract class ServiceStateTracker extends Handler { } break; - case EVENT_ICC_CHANGED: - onUpdateIccAvailability(); - break; - default: log("Unhandled message with number: " + msg.what); break; @@ -317,7 +304,6 @@ public abstract class ServiceStateTracker extends Handler { protected abstract void handlePollStateResult(int what, AsyncResult ar); protected abstract void updateSpnDisplay(); protected abstract void setPowerStateToDesired(); - protected abstract void onUpdateIccAvailability(); protected abstract void log(String s); protected abstract void loge(String s); @@ -477,21 +463,6 @@ public abstract class ServiceStateTracker extends Handler { pollingContext = new int[1]; } - /** - * Verifies the current thread is the same as the thread originally - * used in the initialization of this instance. Throws RuntimeException - * if not. - * - * @exception RuntimeException if the current thread is not - * the thread that originally obtained this PhoneBase instance. - */ - protected void checkCorrectThread() { - if (Thread.currentThread() != getLooper().getThread()) { - throw new RuntimeException( - "ServiceStateTracker must be used from within one thread"); - } - } - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println("ServiceStateTracker:"); pw.println(" ss=" + ss); diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java index 24bb814037852..d99a62595f5aa 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java +++ b/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java @@ -29,7 +29,6 @@ import android.util.Log; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.IccCard; -import com.android.internal.telephony.IccRecords; import com.android.internal.telephony.OperatorInfo; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneNotifier; @@ -67,6 +66,7 @@ public class CDMALTEPhone extends CDMAPhone { public CDMALTEPhone(Context context, CommandsInterface ci, PhoneNotifier notifier) { super(context, ci, notifier, false); m3gppSMS = new GsmSMSDispatcher(this, mSmsStorageMonitor, mSmsUsageMonitor); + mIccRecords.registerForNewSms(this, EVENT_NEW_ICC_SMS, null); } @Override @@ -88,6 +88,10 @@ public class CDMALTEPhone extends CDMAPhone { @Override protected void initSstIcc() { + mIccCard.set(UiccController.getInstance(this).getIccCard()); + mIccRecords = mIccCard.get().getIccRecords(); + // CdmaLteServiceStateTracker registers with IccCard to know + // when the card is ready. So create mIccCard before the ServiceStateTracker mSST = new CdmaLteServiceStateTracker(this); } @@ -96,6 +100,7 @@ public class CDMALTEPhone extends CDMAPhone { synchronized(PhoneProxy.lockForRadioTechnologyChange) { super.dispose(); m3gppSMS.dispose(); + mIccRecords.unregisterForNewSms(this); } } @@ -198,12 +203,11 @@ public class CDMALTEPhone extends CDMAPhone { @Override public boolean updateCurrentCarrierInProvider() { - IccRecords r = mIccRecords.get(); - if (r != null) { + if (mIccRecords != null) { try { Uri uri = Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "current"); ContentValues map = new ContentValues(); - String operatorNumeric = r.getOperatorNumeric(); + String operatorNumeric = mIccRecords.getOperatorNumeric(); map.put(Telephony.Carriers.NUMERIC, operatorNumeric); if (DBG) log("updateCurrentCarrierInProvider from UICC: numeric=" + operatorNumeric); @@ -221,8 +225,7 @@ public class CDMALTEPhone extends CDMAPhone { // return IMSI from USIM as subscriber ID. @Override public String getSubscriberId() { - IccRecords r = mIccRecords.get(); - return (r != null) ? r.getIMSI() : ""; + return mIccRecords.getIMSI(); } @Override @@ -237,14 +240,12 @@ public class CDMALTEPhone extends CDMAPhone { @Override public IsimRecords getIsimRecords() { - IccRecords r = mIccRecords.get(); - return (r != null) ? r.getIsimRecords() : null; + return mIccRecords.getIsimRecords(); } @Override public String getMsisdn() { - IccRecords r = mIccRecords.get(); - return (r != null) ? r.getMsisdnNumber() : null; + return mIccRecords.getMsisdnNumber(); } @Override @@ -257,26 +258,6 @@ public class CDMALTEPhone extends CDMAPhone { mCM.requestIsimAuthentication(nonce, result); } - @Override - protected void registerForRuimRecordEvents() { - IccRecords r = mIccRecords.get(); - if (r == null) { - return; - } - r.registerForNewSms(this, EVENT_NEW_ICC_SMS, null); - super.registerForRuimRecordEvents(); - } - - @Override - protected void unregisterForRuimRecordEvents() { - IccRecords r = mIccRecords.get(); - if (r == null) { - return; - } - r.unregisterForNewSms(this); - super.unregisterForRuimRecordEvents(); - } - @Override protected void log(String s) { Log.d(LOG_TAG, "[CDMALTEPhone] " + s); diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java index 7922b3c05c4f2..9f6ec712385e5 100755 --- a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java +++ b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java @@ -50,7 +50,6 @@ import com.android.internal.telephony.IccCard; import com.android.internal.telephony.IccException; import com.android.internal.telephony.IccFileHandler; import com.android.internal.telephony.IccPhoneBookInterfaceManager; -import com.android.internal.telephony.IccRecords; import com.android.internal.telephony.IccSmsInterfaceManager; import com.android.internal.telephony.MccTable; import com.android.internal.telephony.MmiCode; @@ -153,6 +152,10 @@ public class CDMAPhone extends PhoneBase { } protected void initSstIcc() { + mIccCard.set(UiccController.getInstance(this).getIccCard()); + mIccRecords = mIccCard.get().getIccRecords(); + // CdmaServiceStateTracker registers with IccCard to know + // when the Ruim card is ready. So create mIccCard before the ServiceStateTracker mSST = new CdmaServiceStateTracker(this); } @@ -169,6 +172,7 @@ public class CDMAPhone extends PhoneBase { mEriManager = new EriManager(this, context, EriManager.ERI_FROM_XML); mCM.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null); + registerForRuimRecordEvents(); mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); mCM.registerForOn(this, EVENT_RADIO_ON, null); mCM.setOnSuppServiceNotification(this, EVENT_SSN, null); @@ -723,10 +727,7 @@ public class CDMAPhone extends PhoneBase { Message resp; mVmNumber = voiceMailNumber; resp = obtainMessage(EVENT_SET_VM_NUMBER_DONE, 0, 0, onComplete); - IccRecords r = mIccRecords.get(); - if (r != null) { - r.setVoiceMailNumber(alphaTag, mVmNumber, resp); - } + mIccRecords.setVoiceMailNumber(alphaTag, mVmNumber, resp); } public String getVoiceMailNumber() { @@ -748,8 +749,7 @@ public class CDMAPhone extends PhoneBase { * @hide */ public int getVoiceMessageCount() { - IccRecords r = mIccRecords.get(); - int voicemailCount = (r != null) ? r.getVoiceMessageCount() : 0; + int voicemailCount = mIccRecords.getVoiceMessageCount(); // If mRuimRecords.getVoiceMessageCount returns zero, then there is possibility // that phone was power cycled and would have lost the voicemail count. // So get the count from preferences. @@ -1064,39 +1064,6 @@ public class CDMAPhone extends PhoneBase { } } - @Override - protected void onUpdateIccAvailability() { - if (mUiccController == null ) { - return; - } - - IccCard newIccCard = mUiccController.getIccCard(); - - IccCard c = mIccCard.get(); - if (c != newIccCard) { - if (c != null) { - log("Removing stale icc objects."); - if (mIccRecords.get() != null) { - unregisterForRuimRecordEvents(); - if (mRuimPhoneBookInterfaceManager != null) { - mRuimPhoneBookInterfaceManager.updateIccRecords(null); - } - } - mIccRecords.set(null); - mIccCard.set(null); - } - if (newIccCard != null) { - log("New card found"); - mIccCard.set(newIccCard); - mIccRecords.set(newIccCard.getIccRecords()); - registerForRuimRecordEvents(); - if (mRuimPhoneBookInterfaceManager != null) { - mRuimPhoneBookInterfaceManager.updateIccRecords(mIccRecords.get()); - } - } - } - } - private void processIccRecordEvents(int eventCode) { switch (eventCode) { case RuimRecords.EVENT_MWI: @@ -1495,22 +1462,14 @@ public class CDMAPhone extends PhoneBase { return mEriManager.isEriFileLoaded(); } - protected void registerForRuimRecordEvents() { - IccRecords r = mIccRecords.get(); - if (r == null) { - return; - } - r.registerForRecordsEvents(this, EVENT_ICC_RECORD_EVENTS, null); - r.registerForRecordsLoaded(this, EVENT_RUIM_RECORDS_LOADED, null); + private void registerForRuimRecordEvents() { + mIccRecords.registerForRecordsEvents(this, EVENT_ICC_RECORD_EVENTS, null); + mIccRecords.registerForRecordsLoaded(this, EVENT_RUIM_RECORDS_LOADED, null); } - protected void unregisterForRuimRecordEvents() { - IccRecords r = mIccRecords.get(); - if (r == null) { - return; - } - r.unregisterForRecordsEvents(this); - r.unregisterForRecordsLoaded(this); + private void unregisterForRuimRecordEvents() { + mIccRecords.unregisterForRecordsEvents(this); + mIccRecords.unregisterForRecordsLoaded(this); } protected void log(String s) { diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java index d05ed6242dcdf..7e5e7075e7be2 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java @@ -40,8 +40,6 @@ import com.android.internal.telephony.DataConnection; import com.android.internal.telephony.DataConnectionAc; import com.android.internal.telephony.DataConnectionTracker; import com.android.internal.telephony.EventLogTags; -import com.android.internal.telephony.IccCard; -import com.android.internal.telephony.IccRecords; import com.android.internal.telephony.RetryManager; import com.android.internal.telephony.RILConstants; import com.android.internal.telephony.Phone; @@ -112,6 +110,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { p.mCM.registerForAvailable (this, EVENT_RADIO_AVAILABLE, null); p.mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); + p.mIccRecords.registerForRecordsLoaded(this, EVENT_RECORDS_LOADED, null); p.mCM.registerForDataNetworkStateChanged (this, EVENT_DATA_STATE_CHANGED, null); p.mCT.registerForVoiceCallEnded (this, EVENT_VOICE_CALL_ENDED, null); p.mCT.registerForVoiceCallStarted (this, EVENT_VOICE_CALL_STARTED, null); @@ -153,8 +152,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { // Unregister from all events mPhone.mCM.unregisterForAvailable(this); mPhone.mCM.unregisterForOffOrNotAvailable(this); - IccRecords r = mIccRecords.get(); - if (r != null) { r.unregisterForRecordsLoaded(this);} + mCdmaPhone.mIccRecords.unregisterForRecordsLoaded(this); mPhone.mCM.unregisterForDataNetworkStateChanged(this); mCdmaPhone.mCT.unregisterForVoiceCallEnded(this); mCdmaPhone.mCT.unregisterForVoiceCallStarted(this); @@ -224,12 +222,11 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { boolean subscriptionFromNv = (mCdmaSSM.getCdmaSubscriptionSource() == CdmaSubscriptionSourceManager.SUBSCRIPTION_FROM_NV); - IccRecords r = mIccRecords.get(); boolean allowed = (psState == ServiceState.STATE_IN_SERVICE || mAutoAttachOnCreation) && (subscriptionFromNv || - (r != null && r.getRecordsLoaded())) && + mCdmaPhone.mIccRecords.getRecordsLoaded()) && (mCdmaPhone.mSST.isConcurrentVoiceAndDataAllowed() || mPhone.getState() == Phone.State.IDLE) && !roaming && @@ -244,7 +241,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { reason += " - psState= " + psState; } if (!subscriptionFromNv && - !(r != null && r.getRecordsLoaded())) { + !mCdmaPhone.mIccRecords.getRecordsLoaded()) { reason += " - RUIM not loaded"; } if (!(mCdmaPhone.mSST.isConcurrentVoiceAndDataAllowed() || @@ -1008,33 +1005,6 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { } } - @Override - protected void onUpdateIcc() { - if (mUiccController == null ) { - return; - } - - IccCard newIccCard = mUiccController.getIccCard(); - IccRecords newIccRecords = null; - if (newIccCard != null) { - newIccRecords = newIccCard.getIccRecords(); - } - - IccRecords r = mIccRecords.get(); - if (r != newIccRecords) { - if (r != null) { - log("Removing stale icc objects."); - r.unregisterForRecordsLoaded(this); - mIccRecords.set(null); - } - if (newIccCard != null) { - log("New card found"); - mIccRecords.set(newIccRecords); - newIccRecords.registerForRecordsLoaded(this, EVENT_RECORDS_LOADED, null); - } - } - } - @Override public boolean isDisconnected() { return ((mState == State.IDLE) || (mState == State.FAILED)); diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java index 9a82f57121261..ff7a0810a40f1 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java @@ -65,7 +65,7 @@ public class CdmaLteServiceStateTracker extends CdmaServiceStateTracker { handlePollStateResult(msg.what, ar); break; case EVENT_RUIM_RECORDS_LOADED: - CdmaLteUiccRecords sim = (CdmaLteUiccRecords)mIccRecords; + CdmaLteUiccRecords sim = (CdmaLteUiccRecords)phone.mIccRecords; if ((sim != null) && sim.isProvisioned()) { mMdn = sim.getMdn(); mMin = sim.getMin(); @@ -353,18 +353,16 @@ public class CdmaLteServiceStateTracker extends CdmaServiceStateTracker { ss.setOperatorAlphaLong(eriText); } - if (mIccCard != null && mIccCard.getState() == IccCard.State.READY && - mIccRecords != null) { + if (phone.getIccCard().getState() == IccCard.State.READY) { // SIM is found on the device. If ERI roaming is OFF, and SID/NID matches // one configfured in SIM, use operator name from CSIM record. boolean showSpn = - ((CdmaLteUiccRecords)mIccRecords).getCsimSpnDisplayCondition(); + ((CdmaLteUiccRecords)phone.mIccRecords).getCsimSpnDisplayCondition(); int iconIndex = ss.getCdmaEriIconIndex(); if (showSpn && (iconIndex == EriInfo.ROAMING_INDICATOR_OFF) && - isInHomeSidNid(ss.getSystemId(), ss.getNetworkId()) && - mIccRecords != null) { - ss.setOperatorAlphaLong(mIccRecords.getServiceProviderName()); + isInHomeSidNid(ss.getSystemId(), ss.getNetworkId())) { + ss.setOperatorAlphaLong(phone.mIccRecords.getServiceProviderName()); } } diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java index 16ff70ea4d83a..b694e0a4c62cb 100755 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java @@ -115,6 +115,12 @@ public class CdmaServiceStateTracker extends ServiceStateTracker { long mSavedTime; long mSavedAtTime; + /** + * We can't register for SIM_RECORDS_LOADED immediately because the + * SIMRecords object may not be instantiated yet. + */ + private boolean mNeedToRegForRuimLoaded = false; + /** Wake lock used while setting time of day. */ private PowerManager.WakeLock mWakeLock; private static final String WAKELOCK_TAG = "ServiceStateTracker"; @@ -156,10 +162,11 @@ public class CdmaServiceStateTracker extends ServiceStateTracker { }; public CdmaServiceStateTracker(CDMAPhone phone) { - super(phone, phone.mCM); + super(); this.phone = phone; cr = phone.getContext().getContentResolver(); + cm = phone.mCM; ss = new ServiceState(); newSS = new ServiceState(); cellLoc = new CdmaCellLocation(); @@ -196,17 +203,18 @@ public class CdmaServiceStateTracker extends ServiceStateTracker { Settings.System.getUriFor(Settings.System.AUTO_TIME_ZONE), true, mAutoTimeZoneObserver); setSignalStrengthDefaultValues(); + + mNeedToRegForRuimLoaded = true; } public void dispose() { - checkCorrectThread(); // Unregister for all events. cm.unregisterForRadioStateChanged(this); cm.unregisterForVoiceNetworkStateChanged(this); + phone.getIccCard().unregisterForReady(this); cm.unregisterForCdmaOtaProvision(this); phone.unregisterForEriFileLoaded(this); - if (mIccCard != null) {mIccCard.unregisterForReady(this);} - if (mIccRecords != null) {mIccRecords.unregisterForRecordsLoaded(this);} + phone.mIccRecords.unregisterForRecordsLoaded(this); cm.unSetOnSignalStrengthUpdate(this); cm.unSetOnNITZTime(this); cr.unregisterContentObserver(mAutoTimeObserver); @@ -277,6 +285,14 @@ public class CdmaServiceStateTracker extends ServiceStateTracker { case EVENT_RUIM_READY: // TODO: Consider calling setCurrentPreferredNetworkType as we do in GsmSST. // cm.setCurrentPreferredNetworkType(); + + // The RUIM is now ready i.e if it was locked it has been + // unlocked. At this stage, the radio is already powered on. + if (mNeedToRegForRuimLoaded) { + phone.mIccRecords.registerForRecordsLoaded(this, + EVENT_RUIM_RECORDS_LOADED, null); + mNeedToRegForRuimLoaded = false; + } if (DBG) log("Receive EVENT_RUIM_READY and Send Request getCDMASubscription."); getSubscriptionInfoAndStartPollingThreads(); phone.prepareEri(); @@ -389,16 +405,8 @@ public class CdmaServiceStateTracker extends ServiceStateTracker { mIsMinInfoReady = true; updateOtaspState(); - if (mIccCard != null) { - if (DBG) log("GET_CDMA_SUBSCRIPTION broadcast Icc state changed"); - mIccCard.broadcastIccStateChangedIntent(IccCard.INTENT_VALUE_ICC_IMSI, - null); - } else { - if (DBG) { - log("GET_CDMA_SUBSCRIPTION mIccCard is null (probably NV type device)" + - " can't broadcast Icc state changed"); - } - } + phone.getIccCard().broadcastIccStateChangedIntent(IccCard.INTENT_VALUE_ICC_IMSI, + null); } else { if (DBG) { log("GET_CDMA_SUBSCRIPTION: error parsing cdmaSubscription params num=" @@ -490,6 +498,8 @@ public class CdmaServiceStateTracker extends ServiceStateTracker { if (!isSubscriptionFromRuim) { // NV is ready when subscription source is NV sendMessage(obtainMessage(EVENT_NV_READY)); + } else { + phone.getIccCard().registerForReady(this, EVENT_RUIM_READY, null); } } @@ -1684,38 +1694,6 @@ public class CdmaServiceStateTracker extends ServiceStateTracker { } } - @Override - protected void onUpdateIccAvailability() { - if (mUiccController == null ) { - return; - } - - IccCard newIccCard = mUiccController.getIccCard(); - - if (mIccCard != newIccCard) { - if (mIccCard != null) { - log("Removing stale icc objects."); - mIccCard.unregisterForReady(this); - if (mIccRecords != null) { - mIccRecords.unregisterForRecordsLoaded(this); - } - mIccRecords = null; - mIccCard = null; - } - if (newIccCard != null) { - log("New card found"); - mIccCard = newIccCard; - mIccRecords = mIccCard.getIccRecords(); - if (isSubscriptionFromRuim) { - mIccCard.registerForReady(this, EVENT_RUIM_READY, null); - if (mIccRecords != null) { - mIccRecords.registerForRecordsLoaded(this, EVENT_RUIM_RECORDS_LOADED, null); - } - } - } - } - } - @Override protected void log(String s) { Log.d(LOG_TAG, "[CdmaSST] " + s); @@ -1749,6 +1727,7 @@ public class CdmaServiceStateTracker extends ServiceStateTracker { pw.println(" mSavedTimeZone=" + mSavedTimeZone); pw.println(" mSavedTime=" + mSavedTime); pw.println(" mSavedAtTime=" + mSavedAtTime); + pw.println(" mNeedToRegForRuimLoaded=" + mNeedToRegForRuimLoaded); pw.println(" mWakeLock=" + mWakeLock); pw.println(" mCurPlmn=" + mCurPlmn); pw.println(" mMdn=" + mMdn); diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimPhoneBookInterfaceManager.java b/telephony/java/com/android/internal/telephony/cdma/RuimPhoneBookInterfaceManager.java index e919245c780f8..04ee2dd83009d 100644 --- a/telephony/java/com/android/internal/telephony/cdma/RuimPhoneBookInterfaceManager.java +++ b/telephony/java/com/android/internal/telephony/cdma/RuimPhoneBookInterfaceManager.java @@ -21,7 +21,6 @@ import java.util.concurrent.atomic.AtomicBoolean; import android.os.Message; import android.util.Log; -import com.android.internal.telephony.IccFileHandler; import com.android.internal.telephony.IccPhoneBookInterfaceManager; /** @@ -35,6 +34,7 @@ public class RuimPhoneBookInterfaceManager extends IccPhoneBookInterfaceManager public RuimPhoneBookInterfaceManager(CDMAPhone phone) { super(phone); + adnCache = phone.mIccRecords.getAdnCache(); //NOTE service "simphonebook" added by IccSmsInterfaceManagerProxy } @@ -61,12 +61,8 @@ public class RuimPhoneBookInterfaceManager extends IccPhoneBookInterfaceManager AtomicBoolean status = new AtomicBoolean(false); Message response = mBaseHandler.obtainMessage(EVENT_GET_SIZE_DONE, status); - IccFileHandler fh = phone.getIccFileHandler(); - //IccFileHandler can be null if there is no icc card present. - if (fh != null) { - fh.getEFLinearRecordSize(efid, response); - waitForResult(status); - } + phone.getIccFileHandler().getEFLinearRecordSize(efid, response); + waitForResult(status); } return recordSize; diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java b/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java index 80183c6edd079..2fefa3f53e0a1 100755 --- a/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java +++ b/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java @@ -199,7 +199,7 @@ public final class RuimRecords extends IccRecords { boolean isRecordLoadResponse = false; - if (mDestroyed.get()) { + if (mDestroyed) { loge("Received message " + msg + "[" + msg.what + "] while being destroyed. Ignoring."); return; @@ -317,20 +317,18 @@ public final class RuimRecords extends IccRecords { // One record loaded successfully or failed, In either case // we need to update the recordsToLoad count recordsToLoad -= 1; - if (DBG) log("onRecordLoaded " + recordsToLoad + " requested: " + recordsRequested); + if (DBG) log("RuimRecords:onRecordLoaded " + recordsToLoad + " requested: " + recordsRequested); if (recordsToLoad == 0 && recordsRequested == true) { onAllRecordsLoaded(); } else if (recordsToLoad < 0) { - loge("recordsToLoad <0, programmer error suspected"); + loge("RuimRecords: recordsToLoad <0, programmer error suspected"); recordsToLoad = 0; } } @Override protected void onAllRecordsLoaded() { - if (DBG) log("record load complete"); - // Further records that can be inserted are Operator/OEM dependent String operator = getRUIMOperatorNumeric(); @@ -350,6 +348,13 @@ public final class RuimRecords extends IccRecords { @Override public void onReady() { + /* broadcast intent ICC_READY here so that we can make sure + READY is sent before IMSI ready + */ + + mParentCard.broadcastIccStateChangedIntent( + IccCard.INTENT_VALUE_ICC_READY, null); + fetchRuimRecords(); mCi.getCDMASubscription(obtainMessage(EVENT_GET_CDMA_SUBSCRIPTION_DONE)); @@ -359,7 +364,7 @@ public final class RuimRecords extends IccRecords { private void fetchRuimRecords() { recordsRequested = true; - if (DBG) log("fetchRuimRecords " + recordsToLoad); + Log.v(LOG_TAG, "RuimRecords:fetchRuimRecords " + recordsToLoad); mCi.getIMSI(obtainMessage(EVENT_GET_IMSI_DONE)); recordsToLoad++; @@ -368,7 +373,7 @@ public final class RuimRecords extends IccRecords { obtainMessage(EVENT_GET_ICCID_DONE)); recordsToLoad++; - if (DBG) log("fetchRuimRecords " + recordsToLoad + " requested: " + recordsRequested); + log("RuimRecords:fetchRuimRecords " + recordsToLoad + " requested: " + recordsRequested); // Further records that can be inserted are Operator/OEM dependent } diff --git a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java index 8dda74befc661..6e9cd51de5003 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java +++ b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java @@ -59,7 +59,6 @@ import com.android.internal.telephony.Connection; import com.android.internal.telephony.IccCard; import com.android.internal.telephony.IccFileHandler; import com.android.internal.telephony.IccPhoneBookInterfaceManager; -import com.android.internal.telephony.IccRecords; import com.android.internal.telephony.IccSmsInterfaceManager; import com.android.internal.telephony.MmiCode; import com.android.internal.telephony.OperatorInfo; @@ -138,11 +137,13 @@ public class GSMPhone extends PhoneBase { if (ci instanceof SimulatedRadioControl) { mSimulatedRadioControl = (SimulatedRadioControl) ci; } + mCM.setPhoneType(Phone.PHONE_TYPE_GSM); + mIccCard.set(UiccController.getInstance(this).getIccCard()); + mIccRecords = mIccCard.get().getIccRecords(); mCT = new GsmCallTracker(this); mSST = new GsmServiceStateTracker (this); mSMS = new GsmSMSDispatcher(this, mSmsStorageMonitor, mSmsUsageMonitor); - mDataConnectionTracker = new GsmDataConnectionTracker (this); if (!unitTestMode) { mSimPhoneBookIntManager = new SimPhoneBookInterfaceManager(this); @@ -151,6 +152,7 @@ public class GSMPhone extends PhoneBase { } mCM.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null); + registerForSimRecordEvents(); mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); mCM.registerForOn(this, EVENT_RADIO_ON, null); mCM.setOnUSSD(this, EVENT_USSD, null); @@ -794,8 +796,7 @@ public class GSMPhone extends PhoneBase { public String getVoiceMailNumber() { // Read from the SIM. If its null, try reading from the shared preference area. - IccRecords r = mIccRecords.get(); - String number = (r != null) ? r.getVoiceMailNumber() : ""; + String number = mIccRecords.getVoiceMailNumber(); if (TextUtils.isEmpty(number)) { SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); number = sp.getString(VM_NUMBER, null); @@ -817,9 +818,8 @@ public class GSMPhone extends PhoneBase { public String getVoiceMailAlphaTag() { String ret; - IccRecords r = mIccRecords.get(); - ret = (r != null) ? r.getVoiceMailAlphaTag() : ""; + ret = mIccRecords.getVoiceMailAlphaTag(); if (ret == null || ret.length() == 0) { return mContext.getText( @@ -852,31 +852,24 @@ public class GSMPhone extends PhoneBase { } public String getSubscriberId() { - IccRecords r = mIccRecords.get(); - return (r != null) ? r.getIMSI() : ""; + return mIccRecords.getIMSI(); } public String getLine1Number() { - IccRecords r = mIccRecords.get(); - return (r != null) ? r.getMsisdnNumber() : ""; + return mIccRecords.getMsisdnNumber(); } @Override public String getMsisdn() { - IccRecords r = mIccRecords.get(); - return (r != null) ? r.getMsisdnNumber() : ""; + return mIccRecords.getMsisdnNumber(); } public String getLine1AlphaTag() { - IccRecords r = mIccRecords.get(); - return (r != null) ? r.getMsisdnAlphaTag() : ""; + return mIccRecords.getMsisdnAlphaTag(); } public void setLine1Number(String alphaTag, String number, Message onComplete) { - IccRecords r = mIccRecords.get(); - if (r != null) { - r.setMsisdnNumber(alphaTag, number, onComplete); - } + mIccRecords.setMsisdnNumber(alphaTag, number, onComplete); } public void setVoiceMailNumber(String alphaTag, @@ -886,10 +879,7 @@ public class GSMPhone extends PhoneBase { Message resp; mVmNumber = voiceMailNumber; resp = obtainMessage(EVENT_SET_VM_NUMBER_DONE, 0, 0, onComplete); - IccRecords r = mIccRecords.get(); - if (r != null) { - r.setVoiceMailNumber(alphaTag, mVmNumber, resp); - } + mIccRecords.setVoiceMailNumber(alphaTag, mVmNumber, resp); } private boolean isValidCommandInterfaceCFReason (int commandInterfaceCFReason) { @@ -1257,9 +1247,8 @@ public class GSMPhone extends PhoneBase { case EVENT_SET_CALL_FORWARD_DONE: ar = (AsyncResult)msg.obj; - IccRecords r = mIccRecords.get(); - if (ar.exception == null && r != null) { - r.setVoiceCallForwardingFlag(1, msg.arg1 == 1); + if (ar.exception == null) { + mIccRecords.setVoiceCallForwardingFlag(1, msg.arg1 == 1); } onComplete = (Message) ar.userObj; if (onComplete != null) { @@ -1332,41 +1321,12 @@ public class GSMPhone extends PhoneBase { } } - @Override - protected void onUpdateIccAvailability() { - if (mUiccController == null ) { - return; - } - - IccCard newIccCard = mUiccController.getIccCard(); - - IccCard c = mIccCard.get(); - if (c != newIccCard) { - if (c != null) { - if (LOCAL_DEBUG) log("Removing stale icc objects."); - if (mIccRecords.get() != null) { - unregisterForSimRecordEvents(); - mSimPhoneBookIntManager.updateIccRecords(null); - } - mIccRecords.set(null); - mIccCard.set(null); - } - if (newIccCard != null) { - if (LOCAL_DEBUG) log("New card found"); - mIccCard.set(newIccCard); - mIccRecords.set(newIccCard.getIccRecords()); - registerForSimRecordEvents(); - mSimPhoneBookIntManager.updateIccRecords(mIccRecords.get()); - } - } - } - private void processIccRecordEvents(int eventCode) { switch (eventCode) { - case IccRecords.EVENT_CFI: + case SIMRecords.EVENT_CFI: notifyCallForwardingIndicator(); break; - case IccRecords.EVENT_MWI: + case SIMRecords.EVENT_MWI: notifyMessageWaitingIndicator(); break; } @@ -1378,12 +1338,11 @@ public class GSMPhone extends PhoneBase { * @return true for success; false otherwise. */ boolean updateCurrentCarrierInProvider() { - IccRecords r = mIccRecords.get(); - if (r != null) { + if (mIccRecords != null) { try { Uri uri = Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "current"); ContentValues map = new ContentValues(); - map.put(Telephony.Carriers.NUMERIC, r.getOperatorNumeric()); + map.put(Telephony.Carriers.NUMERIC, mIccRecords.getOperatorNumeric()); mContext.getContentResolver().insert(uri, map); return true; } catch (SQLException e) { @@ -1445,19 +1404,16 @@ public class GSMPhone extends PhoneBase { } private void handleCfuQueryResult(CallForwardInfo[] infos) { - IccRecords r = mIccRecords.get(); - if (r != null) { - if (infos == null || infos.length == 0) { - // Assume the default is not active - // Set unconditional CFF in SIM to false - r.setVoiceCallForwardingFlag(1, false); - } else { - for (int i = 0, s = infos.length; i < s; i++) { - if ((infos[i].serviceClass & SERVICE_CLASS_VOICE) != 0) { - r.setVoiceCallForwardingFlag(1, (infos[i].status == 1)); - // should only have the one - break; - } + if (infos == null || infos.length == 0) { + // Assume the default is not active + // Set unconditional CFF in SIM to false + mIccRecords.setVoiceCallForwardingFlag(1, false); + } else { + for (int i = 0, s = infos.length; i < s; i++) { + if ((infos[i].serviceClass & SERVICE_CLASS_VOICE) != 0) { + mIccRecords.setVoiceCallForwardingFlag(1, (infos[i].status == 1)); + // should only have the one + break; } } } @@ -1516,35 +1472,22 @@ public class GSMPhone extends PhoneBase { } public boolean isCspPlmnEnabled() { - IccRecords r = mIccRecords.get(); - return (r != null) ? r.isCspPlmnEnabled() : false; + return mIccRecords.isCspPlmnEnabled(); } private void registerForSimRecordEvents() { - IccRecords r = mIccRecords.get(); - if (r == null) { - return; - } - r.registerForNetworkSelectionModeAutomatic( + mIccRecords.registerForNetworkSelectionModeAutomatic( this, EVENT_SET_NETWORK_AUTOMATIC, null); - r.registerForNewSms(this, EVENT_NEW_ICC_SMS, null); - r.registerForRecordsEvents(this, EVENT_ICC_RECORD_EVENTS, null); - r.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null); + mIccRecords.registerForNewSms(this, EVENT_NEW_ICC_SMS, null); + mIccRecords.registerForRecordsEvents(this, EVENT_ICC_RECORD_EVENTS, null); + mIccRecords.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null); } private void unregisterForSimRecordEvents() { - IccRecords r = mIccRecords.get(); - if (r == null) { - return; - } - r.unregisterForNetworkSelectionModeAutomatic(this); - r.unregisterForNewSms(this); - r.unregisterForRecordsEvents(this); - r.unregisterForRecordsLoaded(this); - } - - protected void log(String s) { - Log.d(LOG_TAG, "[GSMPhone] " + s); + mIccRecords.unregisterForNetworkSelectionModeAutomatic(this); + mIccRecords.unregisterForNewSms(this); + mIccRecords.unregisterForRecordsEvents(this); + mIccRecords.unregisterForRecordsLoaded(this); } @Override diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java index b44ba0bb1e5cd..40ee58c078f78 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java @@ -59,8 +59,6 @@ import com.android.internal.telephony.DataConnection.UpdateLinkPropertyResult; import com.android.internal.telephony.DataConnectionAc; import com.android.internal.telephony.DataConnectionTracker; import com.android.internal.telephony.EventLogTags; -import com.android.internal.telephony.IccCard; -import com.android.internal.telephony.IccRecords; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneBase; import com.android.internal.telephony.RILConstants; @@ -180,6 +178,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { p.mCM.registerForAvailable (this, EVENT_RADIO_AVAILABLE, null); p.mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); + p.mIccRecords.registerForRecordsLoaded(this, EVENT_RECORDS_LOADED, null); p.mCM.registerForDataNetworkStateChanged (this, EVENT_DATA_STATE_CHANGED, null); p.getCallTracker().registerForVoiceCallEnded (this, EVENT_VOICE_CALL_ENDED, null); p.getCallTracker().registerForVoiceCallStarted (this, EVENT_VOICE_CALL_STARTED, null); @@ -220,8 +219,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { //Unregister for all events mPhone.mCM.unregisterForAvailable(this); mPhone.mCM.unregisterForOffOrNotAvailable(this); - IccRecords r = mIccRecords.get(); - if (r != null) { r.unregisterForRecordsLoaded(this);} + mPhone.mIccRecords.unregisterForRecordsLoaded(this); mPhone.mCM.unregisterForDataNetworkStateChanged(this); mPhone.getCallTracker().unregisterForVoiceCallEnded(this); mPhone.getCallTracker().unregisterForVoiceCallStarted(this); @@ -622,12 +620,10 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { int gprsState = mPhone.getServiceStateTracker().getCurrentDataConnectionState(); boolean desiredPowerState = mPhone.getServiceStateTracker().getDesiredPowerState(); - IccRecords r = mIccRecords.get(); - boolean recordsLoaded = (r != null) ? r.getRecordsLoaded() : false; boolean allowed = (gprsState == ServiceState.STATE_IN_SERVICE || mAutoAttachOnCreation) && - recordsLoaded && + mPhone.mIccRecords.getRecordsLoaded() && (mPhone.getState() == Phone.State.IDLE || mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) && internalDataEnabled && @@ -639,7 +635,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { if (!((gprsState == ServiceState.STATE_IN_SERVICE) || mAutoAttachOnCreation)) { reason += " - gprs= " + gprsState; } - if (!recordsLoaded) reason += " - SIM not loaded"; + if (!mPhone.mIccRecords.getRecordsLoaded()) reason += " - SIM not loaded"; if (mPhone.getState() != Phone.State.IDLE && !mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) { reason += " - PhoneState= " + mPhone.getState(); @@ -1900,8 +1896,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { log("onRadioAvailable: We're on the simulator; assuming data is connected"); } - IccRecords r = mIccRecords.get(); - if (r != null && r.getRecordsLoaded()) { + if (mPhone.mIccRecords.getRecordsLoaded()) { notifyOffApnsOfAvailability(null); } @@ -2213,8 +2208,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { */ private void createAllApnList() { mAllApns = new ArrayList(); - IccRecords r = mIccRecords.get(); - String operator = (r != null) ? r.getOperatorNumeric() : ""; + String operator = mPhone.mIccRecords.getOperatorNumeric(); if (operator != null) { String selection = "numeric = '" + operator + "'"; // query only enabled apn. @@ -2325,9 +2319,8 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } } - IccRecords r = mIccRecords.get(); - String operator = (r != null) ? r.getOperatorNumeric() : ""; - int radioTech = mPhone.getServiceState().getRadioTechnology(); + String operator = mPhone.mIccRecords.getOperatorNumeric(); + int networkType = mPhone.getServiceState().getNetworkType(); if (requestedApnType.equals(Phone.APN_TYPE_DEFAULT)) { if (canSetPreferApn && mPreferredApn != null) { @@ -2336,7 +2329,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { + mPreferredApn.numeric + ":" + mPreferredApn); } if (mPreferredApn.numeric.equals(operator)) { - if (mPreferredApn.bearer == 0 || mPreferredApn.bearer == radioTech) { + if (mPreferredApn.bearer == 0 || mPreferredApn.bearer == networkType) { apnList.add(mPreferredApn); if (DBG) log("buildWaitingApns: X added preferred apnList=" + apnList); return apnList; @@ -2355,7 +2348,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { if (mAllApns != null) { for (ApnSetting apn : mAllApns) { if (apn.canHandleType(requestedApnType)) { - if (apn.bearer == 0 || apn.bearer == radioTech) { + if (apn.bearer == 0 || apn.bearer == networkType) { if (DBG) log("apn info : " +apn.toString()); apnList.add(apn); } @@ -2562,33 +2555,6 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { return cid; } - @Override - protected void onUpdateIcc() { - if (mUiccController == null ) { - return; - } - - IccCard newIccCard = mUiccController.getIccCard(); - IccRecords newIccRecords = null; - if (newIccCard != null) { - newIccRecords = newIccCard.getIccRecords(); - } - - IccRecords r = mIccRecords.get(); - if (r != newIccRecords) { - if (r != null) { - log("Removing stale icc objects."); - r.unregisterForRecordsLoaded(this); - mIccRecords.set(null); - } - if (newIccCard != null) { - log("New card found"); - mIccRecords.set(newIccRecords); - newIccRecords.registerForRecordsLoaded(this, EVENT_RECORDS_LOADED, null); - } - } - } - @Override protected void log(String s) { Log.d(LOG_TAG, "[GsmDCT] "+ s); diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java b/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java index 9e34b6afa1575..9b3d5cdacfbf2 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java @@ -885,10 +885,7 @@ public final class GsmMmiCode extends Handler implements MmiCode { */ if ((ar.exception == null) && (msg.arg1 == 1)) { boolean cffEnabled = (msg.arg2 == 1); - IccRecords r = phone.mIccRecords.get(); - if (r != null) { - r.setVoiceCallForwardingFlag(1, cffEnabled); - } + phone.mIccRecords.setVoiceCallForwardingFlag(1, cffEnabled); } onSetComplete(ar); @@ -1206,10 +1203,7 @@ public final class GsmMmiCode extends Handler implements MmiCode { (info.serviceClass & serviceClassMask) == CommandsInterface.SERVICE_CLASS_VOICE) { boolean cffEnabled = (info.status == 1); - IccRecords r = phone.mIccRecords.get(); - if (r != null) { - r.setVoiceCallForwardingFlag(1, cffEnabled); - } + phone.mIccRecords.setVoiceCallForwardingFlag(1, cffEnabled); } return TextUtils.replace(template, sources, destinations); @@ -1234,10 +1228,7 @@ public final class GsmMmiCode extends Handler implements MmiCode { sb.append(context.getText(com.android.internal.R.string.serviceDisabled)); // Set unconditional CFF in SIM to false - IccRecords r = phone.mIccRecords.get(); - if (r != null) { - r.setVoiceCallForwardingFlag(1, false); - } + phone.mIccRecords.setVoiceCallForwardingFlag(1, false); } else { SpannableStringBuilder tb = new SpannableStringBuilder(); diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java index 7c03d039432e9..c0acf5b57e718 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java @@ -124,6 +124,12 @@ final class GsmServiceStateTracker extends ServiceStateTracker { long mSavedTime; long mSavedAtTime; + /** + * We can't register for SIM_RECORDS_LOADED immediately because the + * SIMRecords object may not be instantiated yet. + */ + private boolean mNeedToRegForSimLoaded; + /** Started the recheck process after finding gprs should registered but not. */ private boolean mStartedGprsRegCheck = false; @@ -186,9 +192,10 @@ final class GsmServiceStateTracker extends ServiceStateTracker { }; public GsmServiceStateTracker(GSMPhone phone) { - super(phone, phone.mCM); + super(); this.phone = phone; + cm = phone.mCM; ss = new ServiceState(); newSS = new ServiceState(); cellLoc = new GsmCellLocation(); @@ -206,6 +213,7 @@ final class GsmServiceStateTracker extends ServiceStateTracker { cm.setOnNITZTime(this, EVENT_NITZ_TIME, null); cm.setOnSignalStrengthUpdate(this, EVENT_SIGNAL_STRENGTH_UPDATE, null); cm.setOnRestrictedStateChanged(this, EVENT_RESTRICTED_STATE_CHANGED, null); + phone.getIccCard().registerForReady(this, EVENT_SIM_READY, null); // system setting property AIRPLANE_MODE_ON is set in Settings. int airplaneMode = Settings.System.getInt( @@ -222,6 +230,7 @@ final class GsmServiceStateTracker extends ServiceStateTracker { mAutoTimeZoneObserver); setSignalStrengthDefaultValues(); + mNeedToRegForSimLoaded = true; // Monitor locale change IntentFilter filter = new IntentFilter(); @@ -233,13 +242,12 @@ final class GsmServiceStateTracker extends ServiceStateTracker { } public void dispose() { - checkCorrectThread(); // Unregister for all events. cm.unregisterForAvailable(this); cm.unregisterForRadioStateChanged(this); cm.unregisterForVoiceNetworkStateChanged(this); - if (mIccCard != null) {mIccCard.unregisterForReady(this);} - if (mIccRecords != null) {mIccRecords.unregisterForRecordsLoaded(this);} + phone.getIccCard().unregisterForReady(this); + phone.mIccRecords.unregisterForRecordsLoaded(this); cm.unSetOnSignalStrengthUpdate(this); cm.unSetOnRestrictedStateChanged(this); cm.unSetOnNITZTime(this); @@ -277,6 +285,15 @@ final class GsmServiceStateTracker extends ServiceStateTracker { // Set the network type, in case the radio does not restore it. cm.setCurrentPreferredNetworkType(); + // The SIM is now ready i.e if it was locked + // it has been unlocked. At this stage, the radio is already + // powered on. + if (mNeedToRegForSimLoaded) { + phone.mIccRecords.registerForRecordsLoaded(this, + EVENT_SIM_RECORDS_LOADED, null); + mNeedToRegForSimLoaded = false; + } + boolean skipRestoringSelection = phone.getContext().getResources().getBoolean( com.android.internal.R.bool.skip_restoring_network_selection); @@ -478,11 +495,8 @@ final class GsmServiceStateTracker extends ServiceStateTracker { } protected void updateSpnDisplay() { - if (mIccRecords == null) { - return; - } - int rule = mIccRecords.getDisplayRule(ss.getOperatorNumeric()); - String spn = mIccRecords.getServiceProviderName(); + int rule = phone.mIccRecords.getDisplayRule(ss.getOperatorNumeric()); + String spn = phone.mIccRecords.getServiceProviderName(); String plmn = ss.getOperatorAlphaLong(); // For emergency calls only, pass the EmergencyCallsOnly string via EXTRA_PLMN @@ -1131,7 +1145,7 @@ final class GsmServiceStateTracker extends ServiceStateTracker { ((state & RILConstants.RIL_RESTRICTED_STATE_CS_EMERGENCY) != 0) || ((state & RILConstants.RIL_RESTRICTED_STATE_CS_ALL) != 0) ); //ignore the normal call and data restricted state before SIM READY - if (mIccCard.getState() == IccCard.State.READY) { + if (phone.getIccCard().getState() == IccCard.State.READY) { newRs.setCsNormalRestricted( ((state & RILConstants.RIL_RESTRICTED_STATE_CS_NORMAL) != 0) || ((state & RILConstants.RIL_RESTRICTED_STATE_CS_ALL) != 0) ); @@ -1657,35 +1671,6 @@ final class GsmServiceStateTracker extends ServiceStateTracker { } } - @Override - protected void onUpdateIccAvailability() { - if (mUiccController == null ) { - return; - } - - IccCard newIccCard = mUiccController.getIccCard(); - - if (mIccCard != newIccCard) { - if (mIccCard != null) { - log("Removing stale icc objects."); - mIccCard.unregisterForReady(this); - if (mIccRecords != null) { - mIccRecords.unregisterForRecordsLoaded(this); - } - mIccRecords = null; - mIccCard = null; - } - if (newIccCard != null) { - log("New card found"); - mIccCard = newIccCard; - mIccRecords = mIccCard.getIccRecords(); - mIccCard.registerForReady(this, EVENT_SIM_READY, null); - if (mIccRecords != null) { - mIccRecords.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null); - } - } - } - } @Override protected void log(String s) { Log.d(LOG_TAG, "[GsmSST] " + s); @@ -1726,6 +1711,7 @@ final class GsmServiceStateTracker extends ServiceStateTracker { pw.println(" mSavedTimeZone=" + mSavedTimeZone); pw.println(" mSavedTime=" + mSavedTime); pw.println(" mSavedAtTime=" + mSavedAtTime); + pw.println(" mNeedToRegForSimLoaded=" + mNeedToRegForSimLoaded); pw.println(" mStartedGprsRegCheck=" + mStartedGprsRegCheck); pw.println(" mReportedGprsNoReg=" + mReportedGprsNoReg); pw.println(" mNotification=" + mNotification); diff --git a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java index 30779958710fc..80988fd30050c 100755 --- a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java +++ b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java @@ -521,7 +521,7 @@ public class SIMRecords extends IccRecords { boolean isRecordLoadResponse = false; - if (mDestroyed.get()) { + if (mDestroyed) { loge("Received message " + msg + "[" + msg.what + "] " + " while being destroyed. Ignoring."); return; @@ -1299,6 +1299,12 @@ public class SIMRecords extends IccRecords { @Override public void onReady() { + /* broadcast intent SIM_READY here so that we can make sure + READY is sent before IMSI ready + */ + mParentCard.broadcastIccStateChangedIntent( + IccCard.INTENT_VALUE_ICC_READY, null); + fetchSimRecords(); } diff --git a/telephony/java/com/android/internal/telephony/gsm/SimPhoneBookInterfaceManager.java b/telephony/java/com/android/internal/telephony/gsm/SimPhoneBookInterfaceManager.java index 37f9a4f6d8f0b..35ba0d112e1e0 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SimPhoneBookInterfaceManager.java +++ b/telephony/java/com/android/internal/telephony/gsm/SimPhoneBookInterfaceManager.java @@ -21,7 +21,6 @@ import java.util.concurrent.atomic.AtomicBoolean; import android.os.Message; import android.util.Log; -import com.android.internal.telephony.IccFileHandler; import com.android.internal.telephony.IccPhoneBookInterfaceManager; /** @@ -35,6 +34,7 @@ public class SimPhoneBookInterfaceManager extends IccPhoneBookInterfaceManager { public SimPhoneBookInterfaceManager(GSMPhone phone) { super(phone); + adnCache = phone.mIccRecords.getAdnCache(); //NOTE service "simphonebook" added by IccSmsInterfaceManagerProxy } @@ -61,11 +61,8 @@ public class SimPhoneBookInterfaceManager extends IccPhoneBookInterfaceManager { AtomicBoolean status = new AtomicBoolean(false); Message response = mBaseHandler.obtainMessage(EVENT_GET_SIZE_DONE, status); - IccFileHandler fh = phone.getIccFileHandler(); - if (fh != null) { - fh.getEFLinearRecordSize(efid, response); - waitForResult(status); - } + phone.getIccFileHandler().getEFLinearRecordSize(efid, response); + waitForResult(status); } return recordSize; diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java b/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java index 0243522494ed5..5c4b446a78cf6 100755 --- a/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java +++ b/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java @@ -461,8 +461,4 @@ abstract class SipPhoneBase extends PhoneBase { notifyPhoneStateChanged(); } } - - @Override - protected void onUpdateIccAvailability() { - } } diff --git a/telephony/java/com/android/internal/telephony/uicc/UiccController.java b/telephony/java/com/android/internal/telephony/uicc/UiccController.java index 4e12d6da9e4ca..5961efd35b530 100644 --- a/telephony/java/com/android/internal/telephony/uicc/UiccController.java +++ b/telephony/java/com/android/internal/telephony/uicc/UiccController.java @@ -16,150 +16,78 @@ package com.android.internal.telephony.uicc; -import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.IccCard; -import com.android.internal.telephony.IccCardStatus; -import com.android.internal.telephony.IccCardStatus.CardState; import com.android.internal.telephony.PhoneBase; +import com.android.internal.telephony.cdma.CDMALTEPhone; +import com.android.internal.telephony.cdma.CDMAPhone; +import com.android.internal.telephony.gsm.GSMPhone; -import android.os.AsyncResult; -import android.os.Handler; -import android.os.Message; -import android.os.Registrant; -import android.os.RegistrantList; import android.util.Log; /* This class is responsible for keeping all knowledge about * ICCs in the system. It is also used as API to get appropriate * applications to pass them to phone and service trackers. */ -public class UiccController extends Handler { +public class UiccController { private static final boolean DBG = true; private static final String LOG_TAG = "RIL_UiccController"; - private static final int EVENT_ICC_STATUS_CHANGED = 1; - private static final int EVENT_GET_ICC_STATUS_DONE = 2; - private static UiccController mInstance; private PhoneBase mCurrentPhone; - private CommandsInterface mCi; + private boolean mIsCurrentCard3gpp; private IccCard mIccCard; - private boolean mRegisteredWithCi = false; - - private RegistrantList mIccChangedRegistrants = new RegistrantList(); public static synchronized UiccController getInstance(PhoneBase phone) { if (mInstance == null) { mInstance = new UiccController(phone); - } else if (phone != null) { + } else { mInstance.setNewPhone(phone); } return mInstance; } - // This method is not synchronized as getInstance(PhoneBase) is. - public static UiccController getInstance() { - return getInstance(null); - } - - public synchronized IccCard getIccCard() { + public IccCard getIccCard() { return mIccCard; } - //Notifies when card status changes - public void registerForIccChanged(Handler h, int what, Object obj) { - Registrant r = new Registrant (h, what, obj); - mIccChangedRegistrants.add(r); - //Notify registrant right after registering, so that it will get the latest ICC status, - //otherwise which may not happen until there is an actual change in ICC status. - r.notifyRegistrant(); - } - public void unregisterForIccChanged(Handler h) { - mIccChangedRegistrants.remove(h); - } - - @Override - public void handleMessage (Message msg) { - switch (msg.what) { - case EVENT_ICC_STATUS_CHANGED: - if (DBG) log("Received EVENT_ICC_STATUS_CHANGED, calling getIccCardStatus"); - mCi.getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE)); - break; - case EVENT_GET_ICC_STATUS_DONE: - if (DBG) log("Received EVENT_GET_ICC_STATUS_DONE"); - AsyncResult ar = (AsyncResult)msg.obj; - onGetIccCardStatusDone(ar); - break; - default: - Log.e(LOG_TAG, " Unknown Event " + msg.what); - } - } - private UiccController(PhoneBase phone) { if (DBG) log("Creating UiccController"); setNewPhone(phone); } - private synchronized void onGetIccCardStatusDone(AsyncResult ar) { - if (ar.exception != null) { - Log.e(LOG_TAG,"Error getting ICC status. " - + "RIL_REQUEST_GET_ICC_STATUS should " - + "never return an error", ar.exception); + private void setNewPhone(PhoneBase phone) { + mCurrentPhone = phone; + if (phone instanceof GSMPhone) { + if (DBG) log("New phone is GSMPhone"); + updateCurrentCard(IccCard.CARD_IS_3GPP); + } else if (phone instanceof CDMALTEPhone){ + if (DBG) log("New phone type is CDMALTEPhone"); + updateCurrentCard(IccCard.CARD_IS_3GPP); + } else if (phone instanceof CDMAPhone){ + if (DBG) log("New phone type is CDMAPhone"); + updateCurrentCard(IccCard.CARD_IS_NOT_3GPP); + } else { + Log.e(LOG_TAG, "Unhandled phone type. Critical error!"); + } + } + + private void updateCurrentCard(boolean isNewCard3gpp) { + if (mIsCurrentCard3gpp == isNewCard3gpp && mIccCard != null) { return; } - IccCardStatus status = (IccCardStatus)ar.result; - - //Update already existing card - if (mIccCard != null && status.getCardState() == CardState.CARDSTATE_PRESENT) { - mIccCard.update(mCurrentPhone, status); - } - - //Dispose of removed card - if (mIccCard != null && status.getCardState() != CardState.CARDSTATE_PRESENT) { + if (mIccCard != null) { mIccCard.dispose(); mIccCard = null; } - //Create new card - if (mIccCard == null && status.getCardState() == CardState.CARDSTATE_PRESENT) { - mIccCard = new IccCard(mCurrentPhone, status, mCurrentPhone.getPhoneName(), true); - } - - if (DBG) log("Notifying IccChangedRegistrants"); - mIccChangedRegistrants.notifyRegistrants(); - } - - private void setNewPhone(PhoneBase phone) { - if (phone == null) { - throw new RuntimeException("Phone can't be null in UiccController"); - } - - if (DBG) log("setNewPhone"); - if (mCurrentPhone != phone) { - if (mIccCard != null) { - // Refresh card if phone changed - // TODO: Remove once card is simplified - if (DBG) log("Disposing card since phone object changed"); - mIccCard.dispose(); - mIccCard = null; - } - sendMessage(obtainMessage(EVENT_ICC_STATUS_CHANGED)); - mCurrentPhone = phone; - - if (!mRegisteredWithCi) { - // This needs to be done only once after we have valid phone object - mCi = mCurrentPhone.mCM; - mCi.registerForIccStatusChanged(this, EVENT_ICC_STATUS_CHANGED, null); - // TODO remove this once modem correctly notifies the unsols - mCi.registerForOn(this, EVENT_ICC_STATUS_CHANGED, null); - mRegisteredWithCi = true; - } - } + mIsCurrentCard3gpp = isNewCard3gpp; + mIccCard = new IccCard(mCurrentPhone, mCurrentPhone.getPhoneName(), + isNewCard3gpp, DBG); } private void log(String string) { Log.d(LOG_TAG, string); } -} +} \ No newline at end of file From 52767e8534b4ea45b216246e1fd817fa6f453573 Mon Sep 17 00:00:00 2001 From: Craig Mautner Date: Thu, 19 Apr 2012 09:59:31 -0700 Subject: [PATCH 059/132] Defer the Surface.show until animation phase. This fixes a rotation bug introduced by delaying rendering animation into the Surface. Now instead of delaying the rendering we delay the show by eliminating a point where we were showing the Surface too soon. Change-Id: I63ad3b494963111ffc96569093c8d43517c5408b --- .../java/com/android/server/wm/WindowStateAnimator.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/services/java/com/android/server/wm/WindowStateAnimator.java b/services/java/com/android/server/wm/WindowStateAnimator.java index 3a51afe50f55f..0cebee76bf56e 100644 --- a/services/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/java/com/android/server/wm/WindowStateAnimator.java @@ -978,7 +978,7 @@ class WindowStateAnimator { setSurfaceBoundaries(recoveringMemory); - if (w.mAttachedHidden || !w.isReadyForDisplay() || !w.isDrawnLw()) { + if (w.mAttachedHidden || !w.isReadyForDisplay()) { if (!mLastHidden) { //dump(); mLastHidden = true; @@ -1136,17 +1136,15 @@ class WindowStateAnimator { + " animating=" + mAnimating + " tok animating=" + (mWin.mAppToken != null ? mWin.mAppToken.mAppAnimator.animating : false)); - if (!showSurfaceRobustlyLocked()) { - return false; - } mService.enableScreenIfNeededLocked(); applyEnterAnimationLocked(); + // Force the show in the next prepareSurfaceLocked() call. mLastAlpha = -1; - mLastHidden = false; mDrawState = HAS_DRAWN; + mService.scheduleAnimationLocked(); int i = mWin.mChildWindows.size(); while (i > 0) { From d1fb3c8889d79037c7cac817858f109ce5903338 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Thu, 19 Apr 2012 14:17:03 -0700 Subject: [PATCH 060/132] Log when /cache files are deleted. Bug: 6362988 Change-Id: Ib8497453c45612be5b83035eeaf3abe6d716ccbf --- .../server/DeviceStorageMonitorService.java | 16 ++++++++++++++++ .../java/com/android/server/EventLogTags.logtags | 4 +++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/services/java/com/android/server/DeviceStorageMonitorService.java b/services/java/com/android/server/DeviceStorageMonitorService.java index b943c0996c559..0ed5189dd0e96 100644 --- a/services/java/com/android/server/DeviceStorageMonitorService.java +++ b/services/java/com/android/server/DeviceStorageMonitorService.java @@ -26,6 +26,7 @@ import android.content.pm.IPackageDataObserver; import android.content.pm.IPackageManager; import android.os.Binder; import android.os.Environment; +import android.os.FileObserver; import android.os.Handler; import android.os.Message; import android.os.Process; @@ -91,6 +92,7 @@ public class DeviceStorageMonitorService extends Binder { private Intent mStorageFullIntent; private Intent mStorageNotFullIntent; private CachePackageDataObserver mClearCacheObserver; + private final CacheFileDeletedObserver mCacheFileDeletedObserver; private static final int _TRUE = 1; private static final int _FALSE = 0; private long mMemLowThreshold; @@ -324,6 +326,9 @@ public class DeviceStorageMonitorService extends Binder { mMemLowThreshold = getMemThreshold(); mMemFullThreshold = getMemFullThreshold(); checkMemory(true); + + mCacheFileDeletedObserver = new CacheFileDeletedObserver(); + mCacheFileDeletedObserver.startWatching(); } @@ -419,4 +424,15 @@ public class DeviceStorageMonitorService extends Binder { public boolean isMemoryLow() { return mLowMemFlag; } + + public static class CacheFileDeletedObserver extends FileObserver { + public CacheFileDeletedObserver() { + super(Environment.getDownloadCacheDirectory().getAbsolutePath(), FileObserver.DELETE); + } + + @Override + public void onEvent(int event, String path) { + EventLogTags.writeCacheFileDeleted(path); + } + } } diff --git a/services/java/com/android/server/EventLogTags.logtags b/services/java/com/android/server/EventLogTags.logtags index 0bcec2e3b3a54..249513f2f4edd 100644 --- a/services/java/com/android/server/EventLogTags.logtags +++ b/services/java/com/android/server/EventLogTags.logtags @@ -36,7 +36,7 @@ option java_package com.android.server # --------------------------- -# DeviceStorageMonitoryService.java +# DeviceStorageMonitorService.java # --------------------------- # The disk space free on the /data partition, in bytes 2744 free_storage_changed (data|2|2) @@ -44,6 +44,8 @@ option java_package com.android.server 2745 low_storage (data|2|2) # disk space free on the /data, /system, and /cache partitions in bytes 2746 free_storage_left (data|2|2),(system|2|2),(cache|2|2) +# file on cache partition was deleted +2748 cache_file_deleted (path|3) # --------------------------- From 15cc7677cfa06f77b7fb0ac1439247ca84968c85 Mon Sep 17 00:00:00 2001 From: Svetoslav Ganov Date: Thu, 19 Apr 2012 17:13:46 -0700 Subject: [PATCH 061/132] UI test automation cannot get the root node and gets null children. 1. The AccessibilityInteractionController was using an incorrect looper i.e. not the UI thread looper which was causing getting the root node to fail. 2. The AccessibilityNodeInfo was populated by a ViewGroup with the children for accessibility without checking whether these children are really displayed. bug:6362875 Change-Id: I7906d89571eb9d57d10f971639f88632926dd077 --- .../AccessibilityInteractionController.java | 67 +++++++------------ core/java/android/view/View.java | 21 +++++- 2 files changed, 43 insertions(+), 45 deletions(-) diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java index 54c62ee83a125..e3f5b968781f3 100644 --- a/core/java/android/view/AccessibilityInteractionController.java +++ b/core/java/android/view/AccessibilityInteractionController.java @@ -58,9 +58,14 @@ final class AccessibilityInteractionController { private final AccessibilityNodePrefetcher mPrefetcher; + private final long mMyLooperThreadId; + + private final int mMyProcessId; + public AccessibilityInteractionController(ViewRootImpl viewRootImpl) { - // mView is never null - the caller has already checked. - Looper looper = viewRootImpl.mView.mContext.getMainLooper(); + Looper looper = viewRootImpl.mHandler.getLooper(); + mMyLooperThreadId = looper.getThread().getId(); + mMyProcessId = Process.myPid(); mHandler = new PrivateHandler(looper); mViewRootImpl = viewRootImpl; mPrefetcher = new AccessibilityNodePrefetcher(); @@ -137,8 +142,7 @@ final class AccessibilityInteractionController { // thread in this process, set the message as a static reference so // after this call completes the same thread but in the interrogating // client can handle the message to generate the result. - if (interrogatingPid == Process.myPid() - && interrogatingTid == Looper.getMainLooper().getThread().getId()) { + if (interrogatingPid == mMyProcessId && interrogatingTid == mMyLooperThreadId) { AccessibilityInteractionClient.getInstanceForThread( interrogatingTid).setSameThreadMessage(message); } else { @@ -169,7 +173,7 @@ final class AccessibilityInteractionController { } else { root = findViewByAccessibilityId(accessibilityViewId); } - if (root != null && isDisplayedOnScreen(root)) { + if (root != null && root.isDisplayedOnScreen()) { mPrefetcher.prefetchAccessibilityNodeInfos(root, virtualDescendantId, flags, infos); } } finally { @@ -199,8 +203,7 @@ final class AccessibilityInteractionController { // thread in this process, set the message as a static reference so // after this call completes the same thread but in the interrogating // client can handle the message to generate the result. - if (interrogatingPid == Process.myPid() - && interrogatingTid == Looper.getMainLooper().getThread().getId()) { + if (interrogatingPid == mMyProcessId && interrogatingTid == mMyLooperThreadId) { AccessibilityInteractionClient.getInstanceForThread( interrogatingTid).setSameThreadMessage(message); } else { @@ -232,7 +235,7 @@ final class AccessibilityInteractionController { } if (root != null) { View target = root.findViewById(viewId); - if (target != null && isDisplayedOnScreen(target)) { + if (target != null && target.isDisplayedOnScreen()) { info = target.createAccessibilityNodeInfo(); } } @@ -263,8 +266,7 @@ final class AccessibilityInteractionController { // thread in this process, set the message as a static reference so // after this call completes the same thread but in the interrogating // client can handle the message to generate the result. - if (interrogatingPid == Process.myPid() - && interrogatingTid == Looper.getMainLooper().getThread().getId()) { + if (interrogatingPid == mMyProcessId && interrogatingTid == mMyLooperThreadId) { AccessibilityInteractionClient.getInstanceForThread( interrogatingTid).setSameThreadMessage(message); } else { @@ -295,7 +297,7 @@ final class AccessibilityInteractionController { } else { root = mViewRootImpl.mView; } - if (root != null && isDisplayedOnScreen(root)) { + if (root != null && root.isDisplayedOnScreen()) { AccessibilityNodeProvider provider = root.getAccessibilityNodeProvider(); if (provider != null) { infos = provider.findAccessibilityNodeInfosByText(text, @@ -312,7 +314,7 @@ final class AccessibilityInteractionController { final int viewCount = foundViews.size(); for (int i = 0; i < viewCount; i++) { View foundView = foundViews.get(i); - if (isDisplayedOnScreen(foundView)) { + if (foundView.isDisplayedOnScreen()) { provider = foundView.getAccessibilityNodeProvider(); if (provider != null) { List infosFromProvider = @@ -356,8 +358,7 @@ final class AccessibilityInteractionController { // thread in this process, set the message as a static reference so // after this call completes the same thread but in the interrogating // client can handle the message to generate the result. - if (interogatingPid == Process.myPid() - && interrogatingTid == Looper.getMainLooper().getThread().getId()) { + if (interogatingPid == mMyProcessId && interrogatingTid == mMyLooperThreadId) { AccessibilityInteractionClient.getInstanceForThread( interrogatingTid).setSameThreadMessage(message); } else { @@ -388,7 +389,7 @@ final class AccessibilityInteractionController { } else { root = mViewRootImpl.mView; } - if (root != null && isDisplayedOnScreen(root)) { + if (root != null && root.isDisplayedOnScreen()) { switch (focusType) { case AccessibilityNodeInfo.FOCUS_ACCESSIBILITY: { View host = mViewRootImpl.mAccessibilityFocusedHost; @@ -409,7 +410,7 @@ final class AccessibilityInteractionController { case AccessibilityNodeInfo.FOCUS_INPUT: { // Input focus cannot go to virtual views. View target = root.findFocus(); - if (target != null && isDisplayedOnScreen(target)) { + if (target != null && target.isDisplayedOnScreen()) { focused = target.createAccessibilityNodeInfo(); } } break; @@ -444,8 +445,7 @@ final class AccessibilityInteractionController { // thread in this process, set the message as a static reference so // after this call completes the same thread but in the interrogating // client can handle the message to generate the result. - if (interogatingPid == Process.myPid() - && interrogatingTid == Looper.getMainLooper().getThread().getId()) { + if (interogatingPid == mMyProcessId && interrogatingTid == mMyLooperThreadId) { AccessibilityInteractionClient.getInstanceForThread( interrogatingTid).setSameThreadMessage(message); } else { @@ -476,7 +476,7 @@ final class AccessibilityInteractionController { } else { root = mViewRootImpl.mView; } - if (root != null && isDisplayedOnScreen(root)) { + if (root != null && root.isDisplayedOnScreen()) { if ((direction & View.FOCUS_ACCESSIBILITY) == View.FOCUS_ACCESSIBILITY) { AccessibilityNodeProvider provider = root.getAccessibilityNodeProvider(); if (provider != null) { @@ -530,8 +530,7 @@ final class AccessibilityInteractionController { // thread in this process, set the message as a static reference so // after this call completes the same thread but in the interrogating // client can handle the message to generate the result. - if (interogatingPid == Process.myPid() - && interrogatingTid == Looper.getMainLooper().getThread().getId()) { + if (interogatingPid == mMyProcessId && interrogatingTid == mMyLooperThreadId) { AccessibilityInteractionClient.getInstanceForThread( interrogatingTid).setSameThreadMessage(message); } else { @@ -562,7 +561,7 @@ final class AccessibilityInteractionController { } else { target = mViewRootImpl.mView; } - if (target != null && isDisplayedOnScreen(target)) { + if (target != null && target.isDisplayedOnScreen()) { AccessibilityNodeProvider provider = target.getAccessibilityNodeProvider(); if (provider != null) { succeeded = provider.performAccessibilityAction(action, virtualDescendantId); @@ -586,30 +585,12 @@ final class AccessibilityInteractionController { return null; } View foundView = root.findViewByAccessibilityId(accessibilityId); - if (foundView != null && !isDisplayedOnScreen(foundView)) { + if (foundView != null && !foundView.isDisplayedOnScreen()) { return null; } return foundView; } - /** - * Computes whether a view is visible on the screen. - * - * @param view The view to check. - * @return Whether the view is visible on the screen. - */ - private boolean isDisplayedOnScreen(View view) { - // The first two checks are made also made by isShown() which - // however traverses the tree up to the parent to catch that. - // Therefore, we do some fail fast check to minimize the up - // tree traversal. - return (view.mAttachInfo != null - && view.mAttachInfo.mWindowVisibility == View.VISIBLE - && view.getAlpha() > 0 - && view.isShown() - && view.getGlobalVisibleRect(mViewRootImpl.mTempRect)); - } - /** * This class encapsulates a prefetching strategy for the accessibility APIs for * querying window content. It is responsible to prefetch a batch of @@ -684,7 +665,7 @@ final class AccessibilityInteractionController { } View child = children.getChildAt(i); if (child.getAccessibilityViewId() != current.getAccessibilityViewId() - && isDisplayedOnScreen(child)) { + && child.isDisplayedOnScreen()) { AccessibilityNodeInfo info = null; AccessibilityNodeProvider provider = child.getAccessibilityNodeProvider(); if (provider == null) { @@ -718,7 +699,7 @@ final class AccessibilityInteractionController { return; } View child = children.getChildAt(i); - if ( isDisplayedOnScreen(child)) { + if (child.isDisplayedOnScreen()) { AccessibilityNodeProvider provider = child.getAccessibilityNodeProvider(); if (provider == null) { AccessibilityNodeInfo info = child.createAccessibilityNodeInfo(); diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index bd054bc5ab277..9c931bcfbb2c7 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -4673,6 +4673,23 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal } } + /** + * Computes whether this view is visible on the screen. + * + * @return Whether the view is visible on the screen. + */ + boolean isDisplayedOnScreen() { + // The first two checks are made also made by isShown() which + // however traverses the tree up to the parent to catch that. + // Therefore, we do some fail fast check to minimize the up + // tree traversal. + return (mAttachInfo != null + && mAttachInfo.mWindowVisibility == View.VISIBLE + && getAlpha() > 0 + && isShown() + && getGlobalVisibleRect(mAttachInfo.mTmpInvalRect)); + } + /** * Sets a delegate for implementing accessibility support via compositon as * opposed to inheritance. The delegate's primary use is for implementing @@ -6284,9 +6301,9 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal boolean includeForAccessibility() { if (mAttachInfo != null) { if (!mAttachInfo.mIncludeNotImportantViews) { - return isImportantForAccessibility(); + return isImportantForAccessibility() && isDisplayedOnScreen(); } else { - return true; + return isDisplayedOnScreen(); } } return false; From 7a753a641af991394e1e84f18198a5a1a922272a Mon Sep 17 00:00:00 2001 From: George Mount Date: Thu, 19 Apr 2012 14:33:34 -0700 Subject: [PATCH 062/132] Fix stack overflow during animation of action bar. Bug 6366482 The animation engine now notifies onAnimationStart() and onAnimationEnd() even when it does no action. This CL prevents the setVisiblity call from causing an infinite loop of triggering animation notifications. Change-Id: I009217a42debf1a1495da222199ca8f599fa7bcf --- .../com/android/internal/widget/AbsActionBarView.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/core/java/com/android/internal/widget/AbsActionBarView.java b/core/java/com/android/internal/widget/AbsActionBarView.java index 06f5158f43e4a..25a9c54b88ff4 100644 --- a/core/java/com/android/internal/widget/AbsActionBarView.java +++ b/core/java/com/android/internal/widget/AbsActionBarView.java @@ -161,10 +161,12 @@ public abstract class AbsActionBarView extends ViewGroup { @Override public void setVisibility(int visibility) { - if (mVisibilityAnim != null) { - mVisibilityAnim.end(); + if (visibility != getVisibility()) { + if (mVisibilityAnim != null) { + mVisibilityAnim.end(); + } + super.setVisibility(visibility); } - super.setVisibility(visibility); } public boolean showOverflowMenu() { From 4881680508c23a47f12f24e70849912d44053b4c Mon Sep 17 00:00:00 2001 From: Jonathan Dixon Date: Mon, 23 Apr 2012 18:51:28 +0100 Subject: [PATCH 063/132] Fix dumprendertree crash This is a quick workaround to get tests running again, will follow up with full fix tomorrow. Bug: 6379925 Change-Id: I96d6e27bfb8f8cd41ec08845ab0fb1e584dbc9da --- core/java/android/webkit/CookieManager.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/java/android/webkit/CookieManager.java b/core/java/android/webkit/CookieManager.java index 825436fc63118..90dfc4ea5109f 100644 --- a/core/java/android/webkit/CookieManager.java +++ b/core/java/android/webkit/CookieManager.java @@ -167,7 +167,8 @@ public class CookieManager { * file scheme URLs */ public static boolean allowFileSchemeCookies() { - throw new MustOverrideException(); + // TODO: indirect this via the WebViewFactoryProvider.Statics interface. http://b/6379925 + return CookieManagerClassic.allowFileSchemeCookies(); } /** @@ -181,6 +182,7 @@ public class CookieManager { * {@link WebView} or CookieManager instance has been created. */ public static void setAcceptFileSchemeCookies(boolean accept) { - throw new MustOverrideException(); + // TODO: indirect this via the WebViewFactoryProvider.Statics interface. http://b/6379925 + CookieManagerClassic.setAcceptFileSchemeCookies(accept); } } From 56989fdb655b113e9d61274b09f5358fa821e10e Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Mon, 23 Apr 2012 13:32:00 -0700 Subject: [PATCH 064/132] Grant external storage permissions to SystemUI. Used for taking screenshots and playing notification ringtones. Bug: 6381589 Change-Id: Ib1a5ad17edbeab984bbab25168d81eb99deba952 --- packages/SystemUI/AndroidManifest.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index 39fb2b4b1bb64..f200f43bc9a43 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -3,6 +3,8 @@ coreApp="true"> + + From 2ad93e4549ba6bd1f821f9049cbd59269b5c2974 Mon Sep 17 00:00:00 2001 From: Chris Wren Date: Mon, 23 Apr 2012 16:05:42 -0400 Subject: [PATCH 065/132] let default notifications with actions get bigger that 64dp. Bug: 6377749 Change-Id: I8c92ef67b59f7a44b61926c32480cce6990a1375 --- core/java/android/app/Notification.java | 2 +- .../layout/notification_template_big_base.xml | 148 ++++++++++++++++++ core/res/res/values/public.xml | 1 + 3 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 core/res/res/layout/notification_template_big_base.xml diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index b581f99eef754..0a996dfaec9b0 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -1450,7 +1450,7 @@ public class Notification implements Parcelable private RemoteViews makeBigContentView() { if (mActions.size() == 0) return null; - return applyStandardTemplateWithActions(R.layout.notification_template_base); + return applyStandardTemplateWithActions(R.layout.notification_template_big_base); } private RemoteViews generateActionButton(Action action) { diff --git a/core/res/res/layout/notification_template_big_base.xml b/core/res/res/layout/notification_template_big_base.xml new file mode 100644 index 0000000000000..5de584df624db --- /dev/null +++ b/core/res/res/layout/notification_template_big_base.xml @@ -0,0 +1,148 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 05150fd528b4a..1a631efb0ff21 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -1097,6 +1097,7 @@ + From 8209c810272360df02c3007a27e0a3b49bff74ec Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 24 Apr 2012 13:09:13 -0700 Subject: [PATCH 066/132] Disable READ_EXTERNAL enforcement until API level cut. Bug: 6389556 Change-Id: I78238b9de24c1b8ebb4fdc35d8aafd2e85a4adfe --- core/java/android/content/pm/PackageManager.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 675f77e843593..c3ce1cfc8e3ad 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -1092,7 +1092,8 @@ public abstract class PackageManager { = "android.content.pm.extra.VERIFICATION_INSTALL_FLAGS"; /** {@hide} */ - public static final boolean DEFAULT_ENFORCE_READ_EXTERNAL_STORAGE = !"user".equals(Build.TYPE); + // TODO: enable this for userdebug and eng builds; see 6389556 + public static final boolean DEFAULT_ENFORCE_READ_EXTERNAL_STORAGE = false; /** * Retrieve overall information about an application package that is From 44f33b9761266c3d87436f3f33bb338a8b405e53 Mon Sep 17 00:00:00 2001 From: Yu Shan Emily Lau Date: Thu, 26 Apr 2012 17:10:29 -0700 Subject: [PATCH 067/132] Fix the test cases which fail to launch the camera in the device which only has one camera. Change-Id: Ia34087715e49f1aa3e86f3f85cb4e77168323321 --- .../android/mediaframeworktest/functional/CameraTest.java | 3 ++- .../functional/mediarecorder/MediaRecorderTest.java | 4 +++- .../performance/MediaPlayerPerformance.java | 3 ++- .../android/mediaframeworktest/stress/CameraStressTest.java | 5 +++-- .../mediaframeworktest/stress/MediaRecorderStressTest.java | 6 ++++-- 5 files changed, 14 insertions(+), 7 deletions(-) diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CameraTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CameraTest.java index bbd6bea6bf249..2f864d7fa906f 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CameraTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CameraTest.java @@ -47,6 +47,7 @@ public class CameraTest extends ActivityInstrumentationTestCase Date: Wed, 25 Apr 2012 21:07:57 -0700 Subject: [PATCH 068/132] Create a catch-all testcase to handle asynchronous crashes and ANRs Bug: 5913065 Change-Id: I391aff6919a9586159ec0898279e7254eed990f8 --- .../android/smoketest/ProcessErrorsTest.java | 180 ++++++++++++------ .../android/smoketest/SmokeTestRunner.java | 12 +- 2 files changed, 134 insertions(+), 58 deletions(-) diff --git a/tests/SmokeTest/tests/src/com/android/smoketest/ProcessErrorsTest.java b/tests/SmokeTest/tests/src/com/android/smoketest/ProcessErrorsTest.java index b3a260050a528..03c2923900f6e 100644 --- a/tests/SmokeTest/tests/src/com/android/smoketest/ProcessErrorsTest.java +++ b/tests/SmokeTest/tests/src/com/android/smoketest/ProcessErrorsTest.java @@ -28,17 +28,18 @@ import android.util.Log; import java.util.ArrayList; import java.util.Collection; -import java.util.HashSet; +import java.util.Collections; import java.util.Iterator; +import java.util.LinkedHashSet; import java.util.List; import java.util.Set; /** - * This smoke test is designed to quickly sniff for any error conditions - * encountered after initial startup. + * This smoke test is designed to check for crashes and ANRs in an attempt to quickly determine if + * all minimal functionality in the build is working properly. */ public class ProcessErrorsTest extends AndroidTestCase { - + private static final String TAG = "ProcessErrorsTest"; private final Intent mHomeIntent; @@ -46,15 +47,28 @@ public class ProcessErrorsTest extends AndroidTestCase { protected ActivityManager mActivityManager; protected PackageManager mPackageManager; + /** + * Used to buffer asynchronously-caused crashes and ANRs so that we can have a big fail-party + * in the catch-all testCase. + */ + private static final Collection mAsyncErrors = + Collections.synchronizedSet(new LinkedHashSet()); + public ProcessErrorsTest() { mHomeIntent = new Intent(Intent.ACTION_MAIN); mHomeIntent.addCategory(Intent.CATEGORY_HOME); mHomeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); } + /** + * {@inheritDoc} + */ @Override public void setUp() throws Exception { super.setUp(); + // First, make sure we have a Context + assertNotNull("getContext() returned null!", getContext()); + mActivityManager = (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE); mPackageManager = getContext().getPackageManager(); @@ -75,43 +89,48 @@ public class ProcessErrorsTest extends AndroidTestCase { assertNull(reportMsg, reportMsg); } - private String checkForProcessErrors() throws Exception { - List errList; - errList = mActivityManager.getProcessesInErrorState(); + /** + * A test that runs all Launcher-launchable activities and verifies that no ANRs or crashes + * happened while doing so. + */ + public void testRunAllActivities() throws Exception { + final Set errSet = new LinkedHashSet(); - // note: this contains information about each process that is currently in an error - // condition. if the list is empty (null) then "we're good". + for (ResolveInfo app : getLauncherActivities(mPackageManager)) { + final Collection errProcs = runOneActivity(app); + if (errProcs != null) { + errSet.addAll(errProcs); + } + } - // if the list is non-empty, then it's useful to report the contents of the list - final String reportMsg = reportListContents(errList); - return reportMsg; + if (!errSet.isEmpty()) { + fail(String.format("Got %d errors:\n%s", errSet.size(), + reportWrappedListContents(errSet))); + } } /** - * A helper function to query the provided {@link PackageManager} for a list of Activities that - * can be launched from Launcher. + * This test checks for asynchronously-caused errors (crashes or ANRs) and fails in case any + * were found. This prevents us from needing to fail unrelated testcases when, for instance + * a background thread causes a crash or ANR. + *

+ * Because this behavior depends on the contents of static member {@link mAsyncErrors}, we clear + * that state here as a side-effect so that if two successive runs happen in the same process, + * the asynchronous errors in the second test run won't include errors produced during the first + * run. */ - static List getLauncherActivities(PackageManager pm) { - final Intent launchable = new Intent(Intent.ACTION_MAIN); - launchable.addCategory(Intent.CATEGORY_LAUNCHER); - final List activities = pm.queryIntentActivities(launchable, 0); - return activities; + public void testZZReportAsyncErrors() throws Exception { + try { + if (!mAsyncErrors.isEmpty()) { + fail(String.format("Got %d asynchronous errors:\n%s", mAsyncErrors.size(), + reportWrappedListContents(mAsyncErrors))); + } + } finally { + // Reset state just in case we should get another set of runs in the same process + mAsyncErrors.clear(); + } } - /** - * A helper function to create an {@link Intent} to run, given a {@link ResolveInfo} specifying - * an activity to be launched. - */ - static Intent intentForActivity(ResolveInfo app) { - // build an Intent to launch the specified app - final ComponentName component = new ComponentName(app.activityInfo.packageName, - app.activityInfo.name); - final Intent intent = new Intent(Intent.ACTION_MAIN); - intent.setComponent(component); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - intent.addFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); - return intent; - } /** * A method to run the specified Activity and return a {@link Collection} of the Activities that @@ -129,8 +148,7 @@ public class ProcessErrorsTest extends AndroidTestCase { // We check for any Crash or ANR dialogs that are already up, and we ignore them. This is // so that we don't report crashes that were caused by prior apps (which those particular - // tests should have caught and reported already). Otherwise, test failures would cascade - // from the initial broken app to many/all of the tests following that app's launch. + // tests should have caught and reported already). final Collection preErrProcs = ProcessError.fromCollection(mActivityManager.getProcessesInErrorState()); @@ -155,8 +173,24 @@ public class ProcessErrorsTest extends AndroidTestCase { // possible to occur. final Collection errProcs = ProcessError.fromCollection(mActivityManager.getProcessesInErrorState()); - // Take the difference between the error processes we see now, and the ones that were - // present when we started + + // Distinguish the asynchronous crashes/ANRs from the synchronous ones by checking the + // crash package name against the package name for {@code app} + if (errProcs != null) { + Iterator errIter = errProcs.iterator(); + while (errIter.hasNext()) { + ProcessError err = errIter.next(); + if (!packageMatches(app, err)) { + // async! Drop into mAsyncErrors and don't report now + mAsyncErrors.add(err); + errIter.remove(); + } + } + } + // Take the difference between the remaining current error processes and the ones that were + // present when we started. The result is guaranteed to be: + // 1) Errors that are pertinent to this app's package + // 2) Errors that are pertinent to this particular app invocation if (errProcs != null && preErrProcs != null) { errProcs.removeAll(preErrProcs); } @@ -164,27 +198,63 @@ public class ProcessErrorsTest extends AndroidTestCase { return errProcs; } - /** - * A test that runs all Launcher-launchable activities and verifies that no ANRs or crashes - * happened while doing so. - */ - public void testRunAllActivities() throws Exception { - final Set errSet = new HashSet(); + private String checkForProcessErrors() throws Exception { + List errList; + errList = mActivityManager.getProcessesInErrorState(); - for (ResolveInfo app : getLauncherActivities(mPackageManager)) { - final Collection errProcs = runOneActivity(app); - if (errProcs != null) { - errSet.addAll(errProcs); - } - } + // note: this contains information about each process that is currently in an error + // condition. if the list is empty (null) then "we're good". - if (!errSet.isEmpty()) { - fail(String.format("Got %d errors:\n%s", errSet.size(), - reportWrappedListContents(errSet))); - } + // if the list is non-empty, then it's useful to report the contents of the list + final String reportMsg = reportListContents(errList); + return reportMsg; } - String reportWrappedListContents(Collection errList) { + /** + * A helper function that checks whether the specified error could have been caused by the + * specified app. + * + * @param app The app to check against + * @param err The error that we're considering + */ + private static boolean packageMatches(ResolveInfo app, ProcessError err) { + final String appPkg = app.activityInfo.packageName; + final String errPkg = err.info.processName; + Log.d(TAG, String.format("packageMatches(%s, %s)", appPkg, errPkg)); + return appPkg.equals(errPkg); + } + + /** + * A helper function to query the provided {@link PackageManager} for a list of Activities that + * can be launched from Launcher. + */ + static List getLauncherActivities(PackageManager pm) { + final Intent launchable = new Intent(Intent.ACTION_MAIN); + launchable.addCategory(Intent.CATEGORY_LAUNCHER); + final List activities = pm.queryIntentActivities(launchable, 0); + return activities; + } + + /** + * A helper function to create an {@link Intent} to run, given a {@link ResolveInfo} specifying + * an activity to be launched. + */ + static Intent intentForActivity(ResolveInfo app) { + final ComponentName component = new ComponentName(app.activityInfo.packageName, + app.activityInfo.name); + final Intent intent = new Intent(Intent.ACTION_MAIN); + intent.setComponent(component); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.addFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); + return intent; + } + + /** + * Report error reports for {@link ProcessErrorStateInfo} instances that are wrapped inside of + * {@link ProcessError} instances. Just unwraps and calls + * {@see reportListContents(Collection)}. + */ + static String reportWrappedListContents(Collection errList) { List newList = new ArrayList(errList.size()); for (ProcessError err : errList) { newList.add(err.info); @@ -198,7 +268,7 @@ public class ProcessErrorsTest extends AndroidTestCase { * @param errList The error report containing one or more error records. * @return Returns a string containing all of the errors. */ - private String reportListContents(Collection errList) { + private static String reportListContents(Collection errList) { if (errList == null) return null; StringBuilder builder = new StringBuilder(); diff --git a/tests/SmokeTest/tests/src/com/android/smoketest/SmokeTestRunner.java b/tests/SmokeTest/tests/src/com/android/smoketest/SmokeTestRunner.java index 51331fe84e827..db549a19dc0fd 100644 --- a/tests/SmokeTest/tests/src/com/android/smoketest/SmokeTestRunner.java +++ b/tests/SmokeTest/tests/src/com/android/smoketest/SmokeTestRunner.java @@ -47,9 +47,6 @@ public class SmokeTestRunner extends InstrumentationTestRunner { final PackageManager pm = getTargetContext().getPackageManager(); final List apps = ProcessErrorsTest.getLauncherActivities(pm); - // FIXME: figure out some way to control the reported class names for these anonymous - // FIXME: class instances. - final TestCase setupTest = new ProcessErrorsTest() { @Override public void runTest() throws Exception { @@ -88,6 +85,15 @@ public class SmokeTestRunner extends InstrumentationTestRunner { suite.addTest(appTest); } + final TestCase asyncErrorTest = new ProcessErrorsTest() { + @Override + public void runTest() throws Exception { + testZZReportAsyncErrors(); + } + }; + asyncErrorTest.setName("testAsynchronousErrors"); + suite.addTest(asyncErrorTest); + return suite; } } From bd2ebca98a181f7724e0cb1fa5c087773a0c3179 Mon Sep 17 00:00:00 2001 From: Daniel Sandler Date: Fri, 27 Apr 2012 16:11:22 -0400 Subject: [PATCH 069/132] resolved simple conflict with e03bc95f --- .../systemui/statusbar/phone/NavigationBarView.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java index 73c5d3a5c02be..90e2bbbeacdc3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java @@ -35,6 +35,7 @@ import android.view.VelocityTracker; import android.view.View; import android.view.ViewGroup; import android.view.Surface; +import android.view.Window; import android.view.WindowManager; import android.view.WindowManagerImpl; import android.widget.ImageView; @@ -71,6 +72,8 @@ public class NavigationBarView extends LinearLayout { int mDisabledFlags = 0; int mNavigationIconHints = 0; + private Drawable mBackIcon, mBackLandIcon, mBackAltIcon, mBackAltLandIcon; + private DelegateViewHelper mDelegateHelper; // workaround for LayoutTransitions leaving the nav buttons in a weird state (bug 5549288) @@ -304,7 +307,6 @@ public class NavigationBarView extends LinearLayout { } mCurrentView = mRotatedViews[rot]; mCurrentView.setVisibility(View.VISIBLE); - mVertical = (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270); // force the low profile & disabled states into compliance setLowProfile(mLowProfile, false, true /* force */); @@ -326,6 +328,14 @@ public class NavigationBarView extends LinearLayout { protected void onSizeChanged(int w, int h, int oldw, int oldh) { if (DEBUG) Slog.d(TAG, String.format( "onSizeChanged: (%dx%d) old: (%dx%d)", w, h, oldw, oldh)); + + final boolean newVertical = w > 0 && h > w; + if (newVertical != mVertical) { + mVertical = newVertical; + //Slog.v(TAG, String.format("onSizeChanged: h=%d, w=%d, vert=%s", h, w, mVertical?"y":"n")); + reorient(); + } + postCheckForInvalidLayout("sizeChanged"); super.onSizeChanged(w, h, oldw, oldh); } From e5ed1406a544eb3891af66ee30165e13a30efbad Mon Sep 17 00:00:00 2001 From: Daniel Sandler Date: Fri, 27 Apr 2012 00:14:54 -0400 Subject: [PATCH 070/132] Finally, fix the teensy back button in landscape. Bug: 5993561 (and friends) Change-Id: I0ccde54ea145e945f1a02d0480585c32cd129911 --- packages/SystemUI/res/layout/navigation_bar.xml | 2 ++ .../systemui/statusbar/phone/NavigationBarView.java | 12 +++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/SystemUI/res/layout/navigation_bar.xml b/packages/SystemUI/res/layout/navigation_bar.xml index 8fbab74413307..b905db3f2efe0 100644 --- a/packages/SystemUI/res/layout/navigation_bar.xml +++ b/packages/SystemUI/res/layout/navigation_bar.xml @@ -54,6 +54,7 @@ android:src="@drawable/ic_sysbar_back" systemui:keyCode="4" android:layout_weight="0" + android:scaleType="center" systemui:glowBackground="@drawable/ic_sysbar_highlight" android:contentDescription="@string/accessibility_back" /> @@ -214,6 +215,7 @@ android:layout_height="80dp" android:layout_width="match_parent" android:src="@drawable/ic_sysbar_back_land" + android:scaleType="center" systemui:keyCode="4" android:layout_weight="0" android:contentDescription="@string/accessibility_back" diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java index 90e2bbbeacdc3..08ac9bf5d0dcf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java @@ -23,6 +23,7 @@ import android.app.StatusBarManager; import android.content.Context; import android.content.res.Resources; import android.graphics.Rect; +import android.graphics.drawable.Drawable; import android.os.Handler; import android.os.Message; import android.os.ServiceManager; @@ -149,6 +150,11 @@ public class NavigationBarView extends LinearLayout { mVertical = false; mShowMenu = false; mDelegateHelper = new DelegateViewHelper(this); + + mBackIcon = res.getDrawable(R.drawable.ic_sysbar_back); + mBackLandIcon = res.getDrawable(R.drawable.ic_sysbar_back_land); + mBackAltIcon = res.getDrawable(R.drawable.ic_sysbar_back_ime); + mBackAltLandIcon = res.getDrawable(R.drawable.ic_sysbar_back_ime); } View.OnTouchListener mLightsOutListener = new View.OnTouchListener() { @@ -191,10 +197,10 @@ public class NavigationBarView extends LinearLayout { getRecentsButton().setAlpha( (0 != (hints & StatusBarManager.NAVIGATION_HINT_RECENT_NOP)) ? 0.5f : 1.0f); - ((ImageView)getBackButton()).setImageResource( + ((ImageView)getBackButton()).setImageDrawable( (0 != (hints & StatusBarManager.NAVIGATION_HINT_BACK_ALT)) - ? R.drawable.ic_sysbar_back_ime - : R.drawable.ic_sysbar_back); + ? (mVertical ? mBackAltLandIcon : mBackAltIcon) + : (mVertical ? mBackLandIcon : mBackIcon)); } public void setDisabledFlags(int disabledFlags) { From f0c5811feeae2a0db893b82001fcb56947e86088 Mon Sep 17 00:00:00 2001 From: Chris Craik Date: Mon, 30 Apr 2012 10:15:33 -0700 Subject: [PATCH 071/132] check for null ViewRootImpl bug:6412902 Change-Id: I36b5ee48fb94ed0f8222f9ec41ee9fc3730ceed0 --- core/java/android/webkit/WebViewClassic.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java index ca17d31b7b32a..cb160f9eff744 100644 --- a/core/java/android/webkit/WebViewClassic.java +++ b/core/java/android/webkit/WebViewClassic.java @@ -87,6 +87,7 @@ import android.view.View.MeasureSpec; import android.view.ViewConfiguration; import android.view.ViewGroup; import android.view.ViewParent; +import android.view.ViewRootImpl; import android.view.ViewTreeObserver; import android.view.WindowManager; import android.view.accessibility.AccessibilityEvent; @@ -5435,8 +5436,9 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc if (mWebView.isHardwareAccelerated()) { int drawGLFunction = nativeGetDrawGLFunction(mNativeClass); - if (drawGLFunction != 0) { - mWebView.getViewRootImpl().detachFunctor(drawGLFunction); + ViewRootImpl viewRoot = mWebView.getViewRootImpl(); + if (drawGLFunction != 0 && viewRoot != null) { + viewRoot.detachFunctor(drawGLFunction); } } } From 5c898286a9106d67a0e1e5f27d8cf6f326565c7c Mon Sep 17 00:00:00 2001 From: John Reck Date: Mon, 30 Apr 2012 10:50:04 -0700 Subject: [PATCH 072/132] Fix crash in setNewPicture Bug: 6412902 Change-Id: I65d8f65839c6e84440cb9d0393c35a8c488c9781 --- core/java/android/webkit/WebViewClassic.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java index cb160f9eff744..b6fe6d8de29ad 100644 --- a/core/java/android/webkit/WebViewClassic.java +++ b/core/java/android/webkit/WebViewClassic.java @@ -7887,14 +7887,14 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc mSendScrollEvent = true; int functor = 0; - if (mWebView.isHardwareAccelerated() - || mWebView.getLayerType() != View.LAYER_TYPE_HARDWARE) { + ViewRootImpl viewRoot = mWebView.getViewRootImpl(); + if (mWebView.isHardwareAccelerated() && viewRoot != null) { functor = nativeGetDrawGLFunction(mNativeClass); + viewRoot.attachFunctor(functor); } - if (functor != 0) { - mWebView.getViewRootImpl().attachFunctor(functor); - } else { + if (functor == 0 + || mWebView.getLayerType() != View.LAYER_TYPE_NONE) { // invalidate the screen so that the next repaint will show new content // TODO: partial invalidate mWebView.invalidate(); From 602688d06f8448074e02af9890c362cf5ccdd531 Mon Sep 17 00:00:00 2001 From: Svetoslav Ganov Date: Sat, 28 Apr 2012 15:23:47 -0700 Subject: [PATCH 073/132] Fixing crash in ViewGroup.dispatchPopulateAccessibilityEvent 1. There was a double call to recycle of a pooled instance which was causing an exception. Removed an unnecessary call. bug:6408689 Change-Id: Ic74b743c6be28ca95ab84b15f28edb5bc95f0a88 --- core/java/android/view/ViewGroup.java | 1 - 1 file changed, 1 deletion(-) diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 467e285d694ad..bb7b3f8512138 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -2438,7 +2438,6 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) { handled = child.dispatchPopulateAccessibilityEvent(event); if (handled) { - children.recycle(); return handled; } } From f933bd647da2d67dcc1d9a1cd417669bc623fcd5 Mon Sep 17 00:00:00 2001 From: Chris Craik Date: Mon, 30 Apr 2012 13:13:41 -0700 Subject: [PATCH 074/132] never attach null functor bug:6412902 Change-Id: I26a5f80ae13cc19df3daa4d4e7e5401778f76dbb --- core/java/android/webkit/WebViewClassic.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java index b6fe6d8de29ad..a9b32b887adc1 100644 --- a/core/java/android/webkit/WebViewClassic.java +++ b/core/java/android/webkit/WebViewClassic.java @@ -7890,7 +7890,9 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc ViewRootImpl viewRoot = mWebView.getViewRootImpl(); if (mWebView.isHardwareAccelerated() && viewRoot != null) { functor = nativeGetDrawGLFunction(mNativeClass); - viewRoot.attachFunctor(functor); + if (functor != 0) { + viewRoot.attachFunctor(functor); + } } if (functor == 0 From 01c7d030e06da94bfd90f3ace0b9000c95d40f52 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Mon, 30 Apr 2012 16:59:05 -0700 Subject: [PATCH 075/132] Clear ident in dismissKeyguardOnNextActivity(). BaseStatusBar uses this to launch activities over the insecure lockscreen, so clear identity. Bug: 6414983 Change-Id: Idf578923285ee1344e6e13e7f51e17a5f2005c75 --- .../android/server/am/ActivityManagerService.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 429c3c439ab94..cc9650185c486 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -4107,12 +4107,17 @@ public final class ActivityManagerService extends ActivityManagerNative public void dismissKeyguardOnNextActivity() { enforceNotIsolatedCaller("dismissKeyguardOnNextActivity"); - synchronized (this) { - if (mLockScreenShown) { - mLockScreenShown = false; - comeOutOfSleepIfNeededLocked(); + final long token = Binder.clearCallingIdentity(); + try { + synchronized (this) { + if (mLockScreenShown) { + mLockScreenShown = false; + comeOutOfSleepIfNeededLocked(); + } + mMainStack.dismissKeyguardOnNextActivityLocked(); } - mMainStack.dismissKeyguardOnNextActivityLocked(); + } finally { + Binder.restoreCallingIdentity(token); } } From 6e98c05cdce3fc3314709ac528db80ada41f1be0 Mon Sep 17 00:00:00 2001 From: James Dong Date: Sat, 28 Apr 2012 21:30:46 -0700 Subject: [PATCH 076/132] Fix a race condition in Camera API for handling focus In the case where a previous AF completion was outstanding but before the completion notification reached the application, the application cancelled this AF request, and then started a new AF request. Right after the new AF request, the AF completion notification for earlier AF request reached the application. The application could not tell the AF completion notification was meant for the cancelled AF, but thought the new AF was successfully completed. Subsequently, the application trid to take a picture, which failed as a result. The fix is to add an explicit lock in the Camera.java class to fix the race condition to synchornize autoFocus(), cancelAutoFocus() and the callback of the pending AF completion message. o related-to-bug: 6026480 Change-Id: I33d244d908ac066698e792f641ba88fe228b14a9 --- core/java/android/hardware/Camera.java | 40 ++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java index eb0a0c6f4732a..5ed8dd12cca05 100644 --- a/core/java/android/hardware/Camera.java +++ b/core/java/android/hardware/Camera.java @@ -35,6 +35,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.StringTokenizer; +import java.util.concurrent.locks.ReentrantLock; /** * The Camera class is used to set image capture settings, start/stop preview, @@ -154,6 +155,7 @@ public class Camera { private boolean mOneShot; private boolean mWithBuffer; private boolean mFaceDetectionRunning = false; + private ReentrantLock mFocusLock = new ReentrantLock(); /** * Broadcast Action: A new picture is taken by the camera, and the entry of @@ -746,8 +748,14 @@ public class Camera { return; case CAMERA_MSG_FOCUS: - if (mAutoFocusCallback != null) { - mAutoFocusCallback.onAutoFocus(msg.arg1 == 0 ? false : true, mCamera); + mFocusLock.lock(); + try { + if (mAutoFocusCallback != null) { + boolean success = msg.arg1 == 0 ? false : true; + mAutoFocusCallback.onAutoFocus(success, mCamera); + } + } finally { + mFocusLock.unlock(); } return; @@ -872,8 +880,13 @@ public class Camera { */ public final void autoFocus(AutoFocusCallback cb) { - mAutoFocusCallback = cb; - native_autoFocus(); + mFocusLock.lock(); + try { + mAutoFocusCallback = cb; + native_autoFocus(); + } finally { + mFocusLock.unlock(); + } } private native final void native_autoFocus(); @@ -887,8 +900,14 @@ public class Camera { */ public final void cancelAutoFocus() { - mAutoFocusCallback = null; - native_cancelAutoFocus(); + mFocusLock.lock(); + try { + mAutoFocusCallback = null; + native_cancelAutoFocus(); + removePendingAFCompletionMessages(); + } finally { + mFocusLock.unlock(); + } } private native final void native_cancelAutoFocus(); @@ -3577,4 +3596,13 @@ public class Camera { return false; } }; + + /* + * At any time, there should be at most one pending auto focus completion + * message, but we simply remove all pending AF completion messages in + * the looper's queue. + */ + private void removePendingAFCompletionMessages() { + mEventHandler.removeMessages(CAMERA_MSG_FOCUS); + } } From edfbb2fc77daea9c0d692268b134254576a79842 Mon Sep 17 00:00:00 2001 From: Jim Miller Date: Wed, 2 May 2012 15:45:23 -0700 Subject: [PATCH 077/132] Revert "Fix for layout parameter validation bug in GridLayout." This reverts commit 8a36e05443f13edde1eae0cf6ea01b3b2da6e637 which was causing keyguard_screen_tab_unlock.xml to have a bad layout. Change-Id: I50bdc6dbdf8d7b98ef77eae532860d375574213e --- core/java/android/widget/GridLayout.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java index 4d9ff0f56f268..cb10d0a8fc283 100644 --- a/core/java/android/widget/GridLayout.java +++ b/core/java/android/widget/GridLayout.java @@ -658,7 +658,7 @@ public class GridLayout extends ViewGroup { private void validateLayoutParams() { final boolean horizontal = (orientation == HORIZONTAL); final Axis axis = horizontal ? horizontalAxis : verticalAxis; - final int count = max(0, axis.getCount()); // Handle negative values, including UNDEFINED + final int count = (axis.definedCount != UNDEFINED) ? axis.definedCount : 0; int major = 0; int minor = 0; From b2555853409cf562bfc3666240871235e4207bd3 Mon Sep 17 00:00:00 2001 From: Chris Craik Date: Wed, 2 May 2012 13:34:22 -0700 Subject: [PATCH 078/132] Add temporary functor lifetime logging bug:6405861 Note: revert once the above bug is verified fixed Change-Id: Iae04ec6ffa73a2711f96e128d60011bcb5864b5c --- core/java/android/webkit/WebViewClassic.java | 11 +++++++++-- libs/hwui/OpenGLRenderer.cpp | 1 + 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java index 30229f18acf27..246ac8de899a8 100644 --- a/core/java/android/webkit/WebViewClassic.java +++ b/core/java/android/webkit/WebViewClassic.java @@ -2018,6 +2018,11 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc } private void destroyImpl() { + int drawGLFunction = nativeGetDrawGLFunction(mNativeClass); + ViewRootImpl viewRoot = mWebView.getViewRootImpl(); + Log.d(LOGTAG, String.format("destroyImpl, drawGLFunction %x, viewroot == null %b, isHWAccel %b", + drawGLFunction, (viewRoot == null), mWebView.isHardwareAccelerated())); + mCallbackProxy.blockMessages(); clearHelpers(); if (mListBoxDialog != null) { @@ -5434,9 +5439,11 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc removeAccessibilityApisFromJavaScript(); updateHwAccelerated(); + int drawGLFunction = nativeGetDrawGLFunction(mNativeClass); + ViewRootImpl viewRoot = mWebView.getViewRootImpl(); + Log.d(LOGTAG, String.format("onDetachedFromWindow, drawGLFunction %x, viewroot == null %b, isHWAccel %b", + drawGLFunction, (viewRoot == null), mWebView.isHardwareAccelerated())); if (mWebView.isHardwareAccelerated()) { - int drawGLFunction = nativeGetDrawGLFunction(mNativeClass); - ViewRootImpl viewRoot = mWebView.getViewRootImpl(); if (drawGLFunction != 0 && viewRoot != null) { viewRoot.detachFunctor(drawGLFunction); } diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index da2192f21cb26..80db6937dde9b 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -247,6 +247,7 @@ void OpenGLRenderer::resume() { } void OpenGLRenderer::detachFunctor(Functor* functor) { + ALOGD("OGLR %p detachFunctor %p", this, functor); mFunctors.remove(functor); } From f87a998918de9d8c9562e151bd881edf5fbb8e6b Mon Sep 17 00:00:00 2001 From: Daniel Sandler Date: Wed, 2 May 2012 15:07:51 -0400 Subject: [PATCH 079/132] Large-screen notification panel size + positioning. On sw600 devices we show the notification panel in a smaller rectangle, centered in portrait and left-aligned in landscape. Also remove a bunch of -large resources that shouldn't be used anymore. Bug: 6297838 Change-Id: I8ed3445ccb7df16e30870a4322d89786467c54df --- .../res/layout-sw600dp/super_status_bar.xml | 38 ++++ .../res/layout/status_bar_expanded.xml | 212 +++++++++--------- .../SystemUI/res/values-large-port/dimens.xml | 24 -- packages/SystemUI/res/values-large/colors.xml | 6 - packages/SystemUI/res/values-large/config.xml | 26 --- packages/SystemUI/res/values-large/dimens.xml | 27 --- .../SystemUI/res/values-large/strings.xml | 33 --- .../res/values-sw600dp-land/dimens.xml | 26 +++ .../res/values-sw600dp-port/config.xml | 25 --- .../res/values-sw600dp-port/dimens.xml | 28 --- .../SystemUI/res/values-sw600dp/dimens.xml | 29 +++ packages/SystemUI/res/values/dimens.xml | 8 + .../statusbar/phone/PhoneStatusBar.java | 150 ++++--------- 13 files changed, 252 insertions(+), 380 deletions(-) create mode 100644 packages/SystemUI/res/layout-sw600dp/super_status_bar.xml delete mode 100644 packages/SystemUI/res/values-large-port/dimens.xml delete mode 100644 packages/SystemUI/res/values-large/colors.xml delete mode 100644 packages/SystemUI/res/values-large/config.xml delete mode 100644 packages/SystemUI/res/values-large/dimens.xml delete mode 100644 packages/SystemUI/res/values-large/strings.xml create mode 100644 packages/SystemUI/res/values-sw600dp-land/dimens.xml delete mode 100644 packages/SystemUI/res/values-sw600dp-port/config.xml delete mode 100644 packages/SystemUI/res/values-sw600dp-port/dimens.xml create mode 100644 packages/SystemUI/res/values-sw600dp/dimens.xml diff --git a/packages/SystemUI/res/layout-sw600dp/super_status_bar.xml b/packages/SystemUI/res/layout-sw600dp/super_status_bar.xml new file mode 100644 index 0000000000000..8e862349e878f --- /dev/null +++ b/packages/SystemUI/res/layout-sw600dp/super_status_bar.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml index eb1e1c0000711..1de4ab8d9e393 100644 --- a/packages/SystemUI/res/layout/status_bar_expanded.xml +++ b/packages/SystemUI/res/layout/status_bar_expanded.xml @@ -21,120 +21,114 @@ - - - - - - - - - - - - - - - - - - + + + + + + + + + + + - - - - - - - + systemui:rowHeight="@dimen/notification_height" + /> + - \ No newline at end of file + + + + + + + + \ No newline at end of file diff --git a/packages/SystemUI/res/values-large-port/dimens.xml b/packages/SystemUI/res/values-large-port/dimens.xml deleted file mode 100644 index 56effa3cd32a5..0000000000000 --- a/packages/SystemUI/res/values-large-port/dimens.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - 2dp - - - - diff --git a/packages/SystemUI/res/values-large/colors.xml b/packages/SystemUI/res/values-large/colors.xml deleted file mode 100644 index a7a70c3f41e9e..0000000000000 --- a/packages/SystemUI/res/values-large/colors.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - #000000 - #aa000000 - - diff --git a/packages/SystemUI/res/values-large/config.xml b/packages/SystemUI/res/values-large/config.xml deleted file mode 100644 index 4014f8d64b94c..0000000000000 --- a/packages/SystemUI/res/values-large/config.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - false - - diff --git a/packages/SystemUI/res/values-large/dimens.xml b/packages/SystemUI/res/values-large/dimens.xml deleted file mode 100644 index 9d89e21761ab6..0000000000000 --- a/packages/SystemUI/res/values-large/dimens.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - 360dp - - 36dp - - 8dp - - - diff --git a/packages/SystemUI/res/values-large/strings.xml b/packages/SystemUI/res/values-large/strings.xml deleted file mode 100644 index f04dc04ed530f..0000000000000 --- a/packages/SystemUI/res/values-large/strings.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - - - Clear all - - - " – " - - - Notifications off - - - Tap here to turn notifications back on. - diff --git a/packages/SystemUI/res/values-sw600dp-land/dimens.xml b/packages/SystemUI/res/values-sw600dp-land/dimens.xml new file mode 100644 index 0000000000000..afa0b20785547 --- /dev/null +++ b/packages/SystemUI/res/values-sw600dp-land/dimens.xml @@ -0,0 +1,26 @@ + + + + + 0dp + 32dp + + + + 0x33 + diff --git a/packages/SystemUI/res/values-sw600dp-port/config.xml b/packages/SystemUI/res/values-sw600dp-port/config.xml deleted file mode 100644 index ab7661a4b6c45..0000000000000 --- a/packages/SystemUI/res/values-sw600dp-port/config.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - 3 - - diff --git a/packages/SystemUI/res/values-sw600dp-port/dimens.xml b/packages/SystemUI/res/values-sw600dp-port/dimens.xml deleted file mode 100644 index 39eade6104a64..0000000000000 --- a/packages/SystemUI/res/values-sw600dp-port/dimens.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - 0dp - - - 70dip - - - 40dip - - diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml new file mode 100644 index 0000000000000..43ae55766bbc3 --- /dev/null +++ b/packages/SystemUI/res/values-sw600dp/dimens.xml @@ -0,0 +1,29 @@ + + + + + 446dp + + + 192dp + 0dp + + + + 0x31 + diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index f7b8cc95cfc70..e92dbc55275bb 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -120,4 +120,12 @@ 34dp + + + 0dp + 0dp + + + + 0x37 diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index 0125b644fa4c5..48f5f27e358cd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -46,6 +46,7 @@ import android.text.TextUtils; import android.util.DisplayMetrics; import android.util.Log; import android.util.Slog; +import android.util.TypedValue; import android.view.Display; import android.view.Gravity; import android.view.IWindowManager; @@ -61,6 +62,7 @@ import android.view.WindowManagerImpl; import android.view.animation.AccelerateInterpolator; import android.view.animation.Animation; import android.view.animation.AnimationUtils; +import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.RemoteViews; @@ -158,6 +160,9 @@ public class PhoneStatusBar extends BaseStatusBar { View mNotificationPanel; // the sliding/resizing panel within the notification window ScrollView mScrollView; View mExpandedContents; + int mNotificationPanelMarginBottomPx, mNotificationPanelMarginLeftPx; + int mNotificationPanelGravity; + // top bar View mClearButton; View mSettingsButton; @@ -279,6 +284,17 @@ public class PhoneStatusBar extends BaseStatusBar { if (DEBUG) { mStatusBarWindow.setBackgroundColor(0x6000FF80); } + mStatusBarWindow.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + if (event.getAction() == MotionEvent.ACTION_DOWN) { + if (mExpanded && !mAnimating) { + animateCollapse(); + } + } + return true; + }}); + mStatusBarView = (PhoneStatusBarView) mStatusBarWindow.findViewById(R.id.status_bar); mNotificationPanel = mStatusBarWindow.findViewById(R.id.notification_panel); @@ -1111,7 +1127,7 @@ public class PhoneStatusBar extends BaseStatusBar { // Expand the window to encompass the full screen in anticipation of the drag. // This is only possible to do atomically because the status bar is at the top of the screen! WindowManager.LayoutParams lp = (WindowManager.LayoutParams) mStatusBarWindow.getLayoutParams(); - lp.height = mDisplayMetrics.heightPixels; + lp.height = ViewGroup.LayoutParams.MATCH_PARENT; final WindowManager wm = WindowManagerImpl.getDefault(); wm.updateViewLayout(mStatusBarWindow, lp); @@ -1162,7 +1178,7 @@ public class PhoneStatusBar extends BaseStatusBar { if (mAnimating) { y = (int)mAnimY; } else { - y = mDisplayMetrics.heightPixels-1; + y = getExpandedViewMaxHeight()-1; } // Let the fling think that we're open so it goes in the right direction // and doesn't try to re-open the windowshade. @@ -1224,7 +1240,7 @@ public class PhoneStatusBar extends BaseStatusBar { if (SPEW) Slog.d(TAG, "doAnimation before mAnimY=" + mAnimY); incrementAnim(); if (SPEW) Slog.d(TAG, "doAnimation after mAnimY=" + mAnimY); - if (mAnimY >= mDisplayMetrics.heightPixels-1) { + if (mAnimY >= getExpandedViewMaxHeight()-1) { if (SPEW) Slog.d(TAG, "Animation completed to expanded state."); mAnimating = false; updateExpandedViewPos(EXPANDED_FULL_OPEN); @@ -1329,7 +1345,7 @@ public class PhoneStatusBar extends BaseStatusBar { if (mExpanded) { if (!always && ( vel > mFlingCollapseMinVelocityPx - || (y > (mDisplayMetrics.heightPixels*(1f-mCollapseMinDisplayFraction)) && + || (y > (getExpandedViewMaxHeight()*(1f-mCollapseMinDisplayFraction)) && vel > -mFlingExpandMinVelocityPx))) { // We are expanded, but they didn't move sufficiently to cause // us to retract. Animate back to the expanded position. @@ -1348,7 +1364,7 @@ public class PhoneStatusBar extends BaseStatusBar { } else { if (always || ( vel > mFlingExpandMinVelocityPx - || (y > (mDisplayMetrics.heightPixels*(1f-mExpandMinDisplayFraction)) && + || (y > (getExpandedViewMaxHeight()*(1f-mExpandMinDisplayFraction)) && vel > -mFlingCollapseMinVelocityPx))) { // We are collapsed, and they moved enough to allow us to // expand. Animate in the notifications. @@ -1412,7 +1428,8 @@ public class PhoneStatusBar extends BaseStatusBar { // mViewDelta = mAbsPos[1] + mTrackingView.getHeight() - y; } if ((!mExpanded && y < hitSize) || - (mExpanded && y > (mDisplayMetrics.heightPixels-hitSize))) { + // @@ add taps outside the panel if it's not full-screen + (mExpanded && y > (getExpandedViewMaxHeight()-hitSize))) { // We drop events at the edge of the screen to make the windowshade come // down by accident less, especially when pushing open a device with a keyboard @@ -1864,15 +1881,22 @@ public class PhoneStatusBar extends BaseStatusBar { return a < 0f ? 0f : (a > 1f ? 1f : a); } + int getExpandedViewMaxHeight() { + return mDisplayMetrics.heightPixels - mNotificationPanelMarginBottomPx; + } + void updateExpandedViewPos(int expandedPosition) { if (SPEW) { Slog.d(TAG, "updateExpandedViewPos before expandedPosition=" + expandedPosition //+ " mTrackingParams.y=" + ((mTrackingParams == null) ? "?" : mTrackingParams.y) - + " mTrackingPosition=" + mTrackingPosition); + + " mTrackingPosition=" + mTrackingPosition + + " gravity=" + mNotificationPanelGravity); } int panelh = 0; - final int disph = mDisplayMetrics.heightPixels; + final boolean portrait = mDisplayMetrics.heightPixels > mDisplayMetrics.widthPixels; + + final int disph = getExpandedViewMaxHeight(); // If the expanded view is not visible, make sure they're still off screen. // Maybe the view was resized. @@ -1906,113 +1930,25 @@ public class PhoneStatusBar extends BaseStatusBar { mTrackingPosition = panelh; - final View cropView = mNotificationPanel; - ViewGroup.LayoutParams lp = cropView.getLayoutParams(); + FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mNotificationPanel.getLayoutParams(); lp.height = panelh; + lp.gravity = mNotificationPanelGravity; + lp.leftMargin = mNotificationPanelMarginLeftPx; if (SPEW) { - Slog.v(TAG, "updated cropView height=" + panelh); + Slog.v(TAG, "updated cropView height=" + panelh + " grav=" + lp.gravity); } - cropView.setLayoutParams(lp); + mNotificationPanel.setLayoutParams(lp); // woo, special effects final int barh = getCloseViewHeight() + getStatusBarHeight(); final float frac = saturate((float)(panelh - barh) / (disph - barh)); final int color = ((int)(0xB0 * Math.sin(frac * 1.57f))) << 24; mStatusBarWindow.setBackgroundColor(color); - -// Slog.d(TAG, String.format("updateExpanded: pos=%d frac=%.2f col=0x%08x", pos, frac, color)); - -// if (mExpandedParams != null) { -// if (mCloseView.getWindowVisibility() == View.VISIBLE) { -// mCloseView.getLocationInWindow(mPositionTmp); -// final int closePos = mPositionTmp[1]; -// -// mExpandedContents.getLocationInWindow(mPositionTmp); -// final int contentsBottom = mPositionTmp[1] + mExpandedContents.getHeight(); -// -// mExpandedParams.y = pos + mTrackingView.getHeight() -// - (mTrackingParams.height-closePos) - contentsBottom; -// -// if (SPEW) { -// Slog.d(PhoneStatusBar.TAG, -// "pos=" + pos + -// " trackingHeight=" + mTrackingView.getHeight() + -// " (trackingParams.height - closePos)=" + -// (mTrackingParams.height - closePos) + -// " contentsBottom=" + contentsBottom); -// } -// -// } else { -// // If the tracking view is not yet visible, then we can't have -// // a good value of the close view location. We need to wait for -// // it to be visible to do a layout. -// mExpandedParams.y = -mDisplayMetrics.heightPixels; -// } -// int max = h; -// if (mExpandedParams.y > max) { -// mExpandedParams.y = max; -// } -// int min = mTrackingPosition; -// if (mExpandedParams.y < min) { -// mExpandedParams.y = min; -// } -// -// boolean visible = (mTrackingPosition + mTrackingView.getHeight()) > h; -// if (!visible) { -// // if the contents aren't visible, move the expanded view way off screen -// // because the window itself extends below the content view. -// mExpandedParams.y = -disph; -// } -// mExpandedDialog.getWindow().setAttributes(mExpandedParams); -// -// // As long as this isn't just a repositioning that's not supposed to affect -// // the user's perception of what's showing, call to say that the visibility -// // has changed. (Otherwise, someone else will call to do that). -// if (expandedPosition != EXPANDED_LEAVE_ALONE) { -// if (SPEW) Slog.d(TAG, "updateExpandedViewPos visibilityChanged(" + visible + ")"); -// visibilityChanged(visible); -// } -// } -// -// if (SPEW) { -// Slog.d(TAG, "updateExpandedViewPos after expandedPosition=" + expandedPosition -// + " mTrackingParams.y=" + mTrackingParams.y -// + " mTrackingPosition=" + mTrackingPosition -// + " mExpandedParams.y=" + mExpandedParams.y -// + " mExpandedParams.height=" + mExpandedParams.height); -// } - } - - int getExpandedHeight() { - return mDisplayMetrics.heightPixels; } void updateDisplaySize() { mDisplay.getMetrics(mDisplayMetrics); -// if (DEBUG) { -// Slog.d(TAG, "updateDisplaySize: " + mDisplayMetrics); -// } -// updateExpandedSize(); } -// void updateExpandedSize() { -// if (DEBUG) { -// Slog.d(TAG, "updateExpandedSize()"); -// } -// if (mStatusBarWindow != null && mDisplayMetrics != null) { -// mExpandedParams.width = mDisplayMetrics.widthPixels; -// mExpandedParams.height = getExpandedHeight(); -// if (!mExpandedVisible) { -// updateExpandedInvisiblePosition(); -// } else { -// mExpandedDialog.getWindow().setAttributes(mExpandedParams); -// } -// if (DEBUG) { -// Slog.d(TAG, "updateExpandedSize: height=" + mExpandedParams.height + " " + -// (mExpandedVisible ? "VISIBLE":"INVISIBLE")); -// } -// } -// } - void performDisableActions(int net) { int old = mDisabled; int diff = net ^ old; @@ -2152,8 +2088,9 @@ public class PhoneStatusBar extends BaseStatusBar { animateCollapse(excludeRecents); } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) { - repositionNavigationBar(); updateResources(); + repositionNavigationBar(); + updateExpandedViewPos(EXPANDED_LEAVE_ALONE); } } }; @@ -2228,6 +2165,15 @@ public class PhoneStatusBar extends BaseStatusBar { mCollapseAccelPx = res.getDimension(R.dimen.collapse_accel); mFlingGestureMaxXVelocityPx = res.getDimension(R.dimen.fling_gesture_max_x_velocity); + + mNotificationPanelMarginBottomPx + = (int) res.getDimension(R.dimen.notification_panel_margin_bottom); + mNotificationPanelMarginLeftPx + = (int) res.getDimension(R.dimen.notification_panel_margin_left); + mNotificationPanelGravity = res.getInteger(R.integer.notification_panel_layout_gravity); + if (mNotificationPanelGravity <= 0) { + mNotificationPanelGravity = Gravity.CENTER_VERTICAL | Gravity.TOP; + } if (false) Slog.v(TAG, "updateResources"); } From 82c617a7422162f0e9b61f1a59be03f4598af6a8 Mon Sep 17 00:00:00 2001 From: Chris Wren Date: Tue, 1 May 2012 12:03:58 -0400 Subject: [PATCH 080/132] Allow the Notification.Builder to carry around a Style to apply at build Change-Id: I5e848504b6d0444ee349ecea893ceae571dda796 --- api/current.txt | 21 +++-- core/java/android/app/Notification.java | 111 ++++++++++++++++++++---- 2 files changed, 108 insertions(+), 24 deletions(-) diff --git a/api/current.txt b/api/current.txt index d12604b3e6199..ab1819677ae17 100644 --- a/api/current.txt +++ b/api/current.txt @@ -3748,23 +3748,24 @@ package android.app { field public long when; } - public static class Notification.BigPictureStyle { + public static class Notification.BigPictureStyle extends android.app.Notification.Style { + ctor public Notification.BigPictureStyle(); ctor public Notification.BigPictureStyle(android.app.Notification.Builder); method public android.app.Notification.BigPictureStyle bigPicture(android.graphics.Bitmap); - method public android.app.Notification build(); } - public static class Notification.BigTextStyle { + public static class Notification.BigTextStyle extends android.app.Notification.Style { + ctor public Notification.BigTextStyle(); ctor public Notification.BigTextStyle(android.app.Notification.Builder); method public android.app.Notification.BigTextStyle bigText(java.lang.CharSequence); - method public android.app.Notification build(); } public static class Notification.Builder { ctor public Notification.Builder(android.content.Context); method public android.app.Notification.Builder addAction(int, java.lang.CharSequence, android.app.PendingIntent); method public android.app.Notification.Builder addKind(java.lang.String); - method public android.app.Notification getNotification(); + method public android.app.Notification build(); + method public deprecated android.app.Notification getNotification(); method public android.app.Notification.Builder setAutoCancel(boolean); method public android.app.Notification.Builder setContent(android.widget.RemoteViews); method public android.app.Notification.Builder setContentInfo(java.lang.CharSequence); @@ -3785,6 +3786,7 @@ package android.app { method public android.app.Notification.Builder setSmallIcon(int, int); method public android.app.Notification.Builder setSound(android.net.Uri); method public android.app.Notification.Builder setSound(android.net.Uri, int); + method public android.app.Notification.Builder setStyle(android.app.Notification.Style); method public android.app.Notification.Builder setSubText(java.lang.CharSequence); method public android.app.Notification.Builder setTicker(java.lang.CharSequence); method public android.app.Notification.Builder setTicker(java.lang.CharSequence, android.widget.RemoteViews); @@ -3793,10 +3795,17 @@ package android.app { method public android.app.Notification.Builder setWhen(long); } - public static class Notification.InboxStyle { + public static class Notification.InboxStyle extends android.app.Notification.Style { + ctor public Notification.InboxStyle(); ctor public Notification.InboxStyle(android.app.Notification.Builder); method public android.app.Notification.InboxStyle addLine(java.lang.CharSequence); + } + + public static class Notification.Style { + ctor public Notification.Style(); method public android.app.Notification build(); + method public void setBuilder(android.app.Notification.Builder); + field protected android.app.Notification.Builder mBuilder; } public class NotificationManager { diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 69689c9657355..ecaaefc15015f 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -888,7 +888,7 @@ public class Notification implements Parcelable * .setContentText(subject) * .setSmallIcon(R.drawable.new_mail) * .setLargeIcon(aBitmap) - * .getNotification(); + * .build(); * */ public static class Builder { @@ -925,6 +925,7 @@ public class Notification implements Parcelable private int mPriority; private ArrayList mActions = new ArrayList(3); private boolean mUseChronometer; + private Style mStyle; /** * Constructs a new Builder with the defaults: @@ -1305,7 +1306,7 @@ public class Notification implements Parcelable * Add metadata to this notification. * * A reference to the Bundle is held for the lifetime of this Builder, and the Bundle's - * current contents are copied into the Notification each time {@link #getNotification()} is + * current contents are copied into the Notification each time {@link #build()} is * called. * * @see Notification#extras @@ -1329,6 +1330,19 @@ public class Notification implements Parcelable return this; } + /** + * Add a rich notification style to be applied at build time. + * + * @param style Object responsible for modifying the notification style. + */ + public Builder setStyle(Style style) { + if (mStyle != style) { + mStyle = style; + mStyle.setBuilder(this); + } + return this; + } + private void setFlag(int mask, boolean value) { if (value) { mFlags |= mask; @@ -1464,10 +1478,9 @@ public class Notification implements Parcelable } /** - * Combine all of the options that have been set and return a new {@link Notification} - * object. + * Apply the unstyled operations and return a new {@link Notification} object. */ - public Notification getNotification() { + private Notification buildUnstyled() { Notification n = new Notification(); n.when = mWhen; n.icon = mSmallIcon; @@ -1509,6 +1522,49 @@ public class Notification implements Parcelable } return n; } + + /** + * @deprecated Use {@link #build()} instead. + */ + @Deprecated + public Notification getNotification() { + return build(); + } + + /** + * Combine all of the options that have been set and return a new {@link Notification} + * object. + */ + public Notification build() { + if (mStyle != null) { + return mStyle.build(); + } else { + return buildUnstyled(); + } + } + } + + + /** + * An object that can apply a rich notification style to a {@link Notification.Builder} + * object. + */ + public static class Style { + protected Builder mBuilder; + + public void setBuilder(Builder builder) { + if (mBuilder != builder) { + mBuilder = builder; + mBuilder.setStyle(this); + } + } + + public Notification build() { + if (mBuilder == null) { + throw new IllegalArgumentException("Style requires a valid Builder object"); + } + return mBuilder.buildUnstyled(); + } } /** @@ -1528,12 +1584,14 @@ public class Notification implements Parcelable * * @see Notification#bigContentView */ - public static class BigPictureStyle { - private Builder mBuilder; + public static class BigPictureStyle extends Style { private Bitmap mPicture; + public BigPictureStyle() { + } + public BigPictureStyle(Builder builder) { - mBuilder = builder; + setBuilder(builder); } public BigPictureStyle bigPicture(Bitmap b) { @@ -1549,8 +1607,12 @@ public class Notification implements Parcelable return contentView; } + @Override public Notification build() { - Notification wip = mBuilder.getNotification(); + if (mBuilder == null) { + throw new IllegalArgumentException("Style requires a valid Builder object"); + } + Notification wip = mBuilder.buildUnstyled(); wip.bigContentView = makeBigContentView(); return wip; } @@ -1573,12 +1635,14 @@ public class Notification implements Parcelable * * @see Notification#bigContentView */ - public static class BigTextStyle { - private Builder mBuilder; + public static class BigTextStyle extends Style { private CharSequence mBigText; + public BigTextStyle() { + } + public BigTextStyle(Builder builder) { - mBuilder = builder; + setBuilder(builder); } public BigTextStyle bigText(CharSequence cs) { @@ -1596,8 +1660,13 @@ public class Notification implements Parcelable return contentView; } + @Override public Notification build() { - Notification wip = mBuilder.getNotification(); + if (mBuilder == null) { + throw new IllegalArgumentException("Style requires a valid Builder object"); + } + mBuilder.mSubText = null; + Notification wip = mBuilder.buildUnstyled(); wip.bigContentView = makeBigContentView(); return wip; } @@ -1608,7 +1677,7 @@ public class Notification implements Parcelable * * This class is a "rebuilder": It consumes a Builder object and modifies its behavior, like so: *

-     * Notification noti = new Notification.DigestStyle(
+     * Notification noti = new Notification.InboxStyle(
      *      new Notification.Builder()
      *         .setContentTitle("New mail from " + sender.toString())
      *         .setContentText(subject)
@@ -1621,12 +1690,14 @@ public class Notification implements Parcelable
      * 
      * @see Notification#bigContentView
      */
-    public static class InboxStyle {
-        private Builder mBuilder;
+    public static class InboxStyle extends Style {
         private ArrayList mTexts = new ArrayList(5);
 
+        public InboxStyle() {
+        }
+
         public InboxStyle(Builder builder) {
-            mBuilder = builder;
+            setBuilder(builder);
         }
 
         public InboxStyle addLine(CharSequence cs) {
@@ -1652,8 +1723,12 @@ public class Notification implements Parcelable
             return contentView;
         }
 
+        @Override
         public Notification build() {
-            Notification wip = mBuilder.getNotification();
+            if (mBuilder == null) {
+                throw new IllegalArgumentException("Style requires a valid Builder object");
+            }
+            Notification wip = mBuilder.buildUnstyled();
             wip.bigContentView = makeBigContentView();
             return wip;
         }

From a8d58567b64913cbbda3b7d6362c7179d3d1fa21 Mon Sep 17 00:00:00 2001
From: Chris Wren 
Date: Tue, 1 May 2012 18:08:49 -0400
Subject: [PATCH 081/132] rework big text to handle gmail use case

Change-Id: I3175e198bd6f39025f4257454b43c459ed1e38f5
---
 core/java/android/app/Notification.java       |  7 +-
 .../res/layout/notification_template_base.xml |  7 --
 .../layout/notification_template_big_text.xml | 95 ++++++++++---------
 3 files changed, 55 insertions(+), 54 deletions(-)

diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index ecaaefc15015f..8f4efab5a099e 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1651,11 +1651,11 @@ public class Notification implements Parcelable
         }
 
         private RemoteViews makeBigContentView() {
-            RemoteViews contentView = mBuilder.applyStandardTemplateWithActions(R.layout.notification_template_big_text);
-
+            int bigTextId = R.layout.notification_template_big_text;
+            RemoteViews contentView = mBuilder.applyStandardTemplateWithActions(bigTextId);
             contentView.setTextViewText(R.id.big_text, mBigText);
             contentView.setViewVisibility(R.id.big_text, View.VISIBLE);
-            contentView.setTextViewText(R.id.text, ""); // XXX: what do do with this spot?
+            contentView.setViewVisibility(R.id.text2, View.GONE);
 
             return contentView;
         }
@@ -1665,7 +1665,6 @@ public class Notification implements Parcelable
             if (mBuilder == null) {
                 throw new IllegalArgumentException("Style requires a valid Builder object");
             }
-            mBuilder.mSubText = null;
             Notification wip = mBuilder.buildUnstyled();
             wip.bigContentView = makeBigContentView();
             return wip;
diff --git a/core/res/res/layout/notification_template_base.xml b/core/res/res/layout/notification_template_base.xml
index 1dc6275a72cee..ae2953797b190 100644
--- a/core/res/res/layout/notification_template_base.xml
+++ b/core/res/res/layout/notification_template_base.xml
@@ -85,13 +85,6 @@
             android:ellipsize="marquee"
             android:visibility="gone"
             />
-        
         
         
-            
+            
+                
+                
+                
+            
+            
-            
-            
         
-        
-        
+                >
+                
+        
         
-        
-                
-        
     
 

From 3355656c3a4b83eb77aaa3eacd6145791be512a6 Mon Sep 17 00:00:00 2001
From: Daniel Sandler 
Date: Thu, 3 May 2012 10:53:10 -0400
Subject: [PATCH 082/132] Move bar panels above the system bar window layer.

We use the new TYPE_NAVIGATION_BAR_PANEL for this instead of
TYPE_STATUS_BAR_PANEL (which is indeed above the status bar,
but far below the navigation bar, which is the window type
used for the system bar now.)

Bug: 6319161 (ticker underneath system bar)
Bug: 6437342 (missing clear all button on system bar)
Change-Id: Ib58c0003c4c81db64edca2c1bbc2d764c3237ed0
---
 .../android/systemui/statusbar/tablet/TabletStatusBar.java    | 4 ++--
 .../com/android/systemui/statusbar/tablet/TabletTicker.java   | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

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 f3a10e9889dd9..49e5a61cadcfc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -268,7 +268,7 @@ public class TabletStatusBar extends BaseStatusBar implements
         WindowManager.LayoutParams lp = mNotificationPanelParams = new WindowManager.LayoutParams(
                 res.getDimensionPixelSize(R.dimen.notification_panel_width),
                 getNotificationPanelHeight(),
-                WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
+                WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
                 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
                     | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
                     | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
@@ -636,7 +636,7 @@ public class TabletStatusBar extends BaseStatusBar implements
         WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
                 (int) mContext.getResources().getDimension(R.dimen.status_bar_recents_width),
                 ViewGroup.LayoutParams.MATCH_PARENT,
-                WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
+                WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
                 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
                 | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
                 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java
index 754441c56b491..d4ebe6d1f2a64 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java
@@ -223,7 +223,7 @@ public class TabletTicker
             windowFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
         }
         WindowManager.LayoutParams lp = new WindowManager.LayoutParams(width, mLargeIconHeight,
-                WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL, windowFlags,
+                WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL, windowFlags,
                 PixelFormat.TRANSLUCENT);
         lp.gravity = Gravity.BOTTOM | Gravity.RIGHT;
 //        lp.windowAnimations = com.android.internal.R.style.Animation_Toast;

From e03d73f9312b4f2203e555746bdb9e7050f27ad3 Mon Sep 17 00:00:00 2001
From: Daniel Sandler 
Date: Thu, 3 May 2012 11:25:29 -0400
Subject: [PATCH 083/132] Hide icons for low-priority notifications.

Anything below PRIORITY_LOW will usually be hidden (unless
the NotificationManagerService has a compelling reason to
adjust the priority).

Bug: 6357857
Change-Id: Ic8a806a6db87b0473014a5d006279991272a44ea
---
 .../systemui/statusbar/phone/PhoneStatusBar.java |  9 ++++++++-
 .../statusbar/tablet/TabletStatusBar.java        | 16 ++++++++++++----
 2 files changed, 20 insertions(+), 5 deletions(-)

diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 48f5f27e358cd..db8316f7e4bd6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -75,6 +75,7 @@ import com.android.systemui.R;
 import com.android.systemui.recent.RecentTasksLoader;
 import com.android.systemui.statusbar.BaseStatusBar;
 import com.android.systemui.statusbar.NotificationData;
+import com.android.systemui.statusbar.NotificationData.Entry;
 import com.android.systemui.statusbar.SignalClusterView;
 import com.android.systemui.statusbar.StatusBarIconView;
 import com.android.systemui.statusbar.policy.BatteryController;
@@ -118,6 +119,9 @@ public class PhoneStatusBar extends BaseStatusBar {
 
     private static final boolean CLOSE_PANEL_WHEN_EMPTIED = true;
 
+    private static final int NOTIFICATION_PRIORITY_MULTIPLIER = 10; // see NotificationManagerService
+    private static final int HIDE_ICONS_BELOW_SCORE = Notification.PRIORITY_LOW * NOTIFICATION_PRIORITY_MULTIPLIER;
+
     // fling gesture tuning parameters, scaled to display density
     private float mSelfExpandVelocityPx; // classic value: 2000px/s
     private float mSelfCollapseVelocityPx; // classic value: 2000px/s (will be negated to collapse "up")
@@ -905,7 +909,10 @@ public class PhoneStatusBar extends BaseStatusBar {
         ArrayList toShow = new ArrayList();
 
         for (int i=0; i= HIDE_ICONS_BELOW_SCORE) {
+                toShow.add(ent.icon);
+            }
         }
 
         ArrayList toRemove = new ArrayList();
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 49e5a61cadcfc..6e87dd76b34bf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -70,6 +70,7 @@ import com.android.systemui.statusbar.BaseStatusBar;
 import com.android.systemui.statusbar.NotificationData;
 import com.android.systemui.statusbar.SignalClusterView;
 import com.android.systemui.statusbar.StatusBarIconView;
+import com.android.systemui.statusbar.NotificationData.Entry;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.BluetoothController;
 import com.android.systemui.statusbar.policy.CompatModeButton;
@@ -111,6 +112,9 @@ public class TabletStatusBar extends BaseStatusBar implements
     final static int NOTIFICATION_PEEK_HOLD_THRESH = 200; // ms
     final static int NOTIFICATION_PEEK_FADE_DELAY = 3000; // ms
 
+    private static final int NOTIFICATION_PRIORITY_MULTIPLIER = 10; // see NotificationManagerService
+    private static final int HIDE_ICONS_BELOW_SCORE = Notification.PRIORITY_LOW * NOTIFICATION_PRIORITY_MULTIPLIER;
+
     // The height of the bar, as definied by the build.  It may be taller if we're plugged
     // into hdmi.
     int mNaturalBarHeight = -1;
@@ -1713,9 +1717,12 @@ public class TabletStatusBar extends BaseStatusBar implements
         if (mInputMethodSwitchButton.getVisibility() != View.GONE) maxNotificationIconsCount --;
         if (mCompatModeButton.getVisibility()        != View.GONE) maxNotificationIconsCount --;
 
-        for (int i=0; i< maxNotificationIconsCount; i++) {
-            if (i>=N) break;
-            toShow.add(mNotificationData.get(N-i-1).icon);
+        for (int i=0; toShow.size()< maxNotificationIconsCount; i++) {
+            if (i >= N) break;
+            Entry ent = mNotificationData.get(N-i-1);
+            if (ent.notification.score >= HIDE_ICONS_BELOW_SCORE) {
+                toShow.add(ent.icon);
+            }
         }
 
         ArrayList toRemove = new ArrayList();
@@ -1764,7 +1771,8 @@ public class TabletStatusBar extends BaseStatusBar implements
         for (int i=0; i
Date: Wed, 2 May 2012 18:23:13 -0700
Subject: [PATCH 084/132] Fix accessibility drawing

 Bug: 6407623
 If script injection is disabled, the accessibility injector works
 by modifying the text selection. However, this would cause WebView
 to go into text selection mode, showing the CAB and such, which
 we don't want. Add a flag saying WHY text selection is being changed
 so that we can respond accordingly in WebViewClassic.

Change-Id: Ia509def3fcdb022b93fbbc7ed89bc9558663afd3
---
 core/java/android/webkit/WebViewClassic.java | 16 ++++++++++++----
 core/java/android/webkit/WebViewCore.java    | 18 ++++++++++++++++--
 2 files changed, 28 insertions(+), 6 deletions(-)

diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java
index 99a321219f4c8..51c91055a9ac7 100644
--- a/core/java/android/webkit/WebViewClassic.java
+++ b/core/java/android/webkit/WebViewClassic.java
@@ -102,6 +102,7 @@ import android.webkit.WebView.PictureListener;
 import android.webkit.WebViewCore.DrawData;
 import android.webkit.WebViewCore.EventHub;
 import android.webkit.WebViewCore.TextFieldInitData;
+import android.webkit.WebViewCore.TextSelectionData;
 import android.webkit.WebViewCore.TouchHighlightData;
 import android.webkit.WebViewCore.WebKitHitTest;
 import android.widget.AbsoluteLayout;
@@ -4211,7 +4212,7 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
 
         // decide which adornments to draw
         int extras = DRAW_EXTRAS_NONE;
-        if (!mFindIsUp && mSelectingText) {
+        if (!mFindIsUp && mShowTextSelectionExtra) {
             extras = DRAW_EXTRAS_SELECTION;
         }
 
@@ -4535,11 +4536,13 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
 
     private void startSelectingText() {
         mSelectingText = true;
+        mShowTextSelectionExtra = true;
         mHandleAlphaAnimator.setIntValues(255);
         mHandleAlphaAnimator.start();
     }
     private void endSelectingText() {
         mSelectingText = false;
+        mShowTextSelectionExtra = false;
         mHandleAlphaAnimator.setIntValues(0);
         mHandleAlphaAnimator.start();
     }
@@ -5312,9 +5315,6 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
                 mSelectCallback.finish();
                 mSelectCallback = null;
             }
-            if (!mIsCaretSelection) {
-                updateWebkitSelection();
-            }
             invalidate(); // redraw without selection
             mAutoScrollX = 0;
             mAutoScrollY = 0;
@@ -6442,6 +6442,7 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
     private int mTrackballXMove = 0;
     private int mTrackballYMove = 0;
     private boolean mSelectingText = false;
+    private boolean mShowTextSelectionExtra = false;
     private boolean mSelectionStarted = false;
     private static final int TRACKBALL_KEY_TIMEOUT = 1000;
     private static final int TRACKBALL_TIMEOUT = 200;
@@ -7942,6 +7943,13 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
         }
         nativeSetTextSelection(mNativeClass, data.mSelectTextPtr);
 
+        if (data.mSelectionReason == TextSelectionData.REASON_ACCESSIBILITY_INJECTOR) {
+            selectionDone();
+            mShowTextSelectionExtra = true;
+            invalidate();
+            return;
+        }
+
         if (data.mSelectTextPtr != 0 &&
                 (data.mStart != data.mEnd ||
                 (mFieldPointer == nodePointer && mFieldPointer != 0))) {
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 7a757a81e4cf4..661bbf8eff38a 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -143,6 +143,7 @@ public final class WebViewCore {
     private int mHighUsageDeltaMb;
 
     private int mChromeCanFocusDirection;
+    private int mTextSelectionChangeReason = TextSelectionData.REASON_UNKNOWN;
 
     // The thread name used to identify the WebCore thread and for use in
     // debugging other classes that require operation within the WebCore thread.
@@ -861,6 +862,8 @@ public final class WebViewCore {
     }
 
     static class TextSelectionData {
+        static final int REASON_UNKNOWN = 0;
+        static final int REASON_ACCESSIBILITY_INJECTOR = 1;
         public TextSelectionData(int start, int end, int selectTextPtr) {
             mStart = start;
             mEnd = end;
@@ -869,6 +872,7 @@ public final class WebViewCore {
         int mStart;
         int mEnd;
         int mSelectTextPtr;
+        int mSelectionReason = TextSelectionData.REASON_UNKNOWN;
     }
 
     static class TouchUpData {
@@ -1544,12 +1548,16 @@ public final class WebViewCore {
                             break;
 
                         case MODIFY_SELECTION:
+                            mTextSelectionChangeReason
+                                    = TextSelectionData.REASON_ACCESSIBILITY_INJECTOR;
                             String modifiedSelectionString =
                                 nativeModifySelection(mNativeClass, msg.arg1,
                                         msg.arg2);
                             mWebViewClassic.mPrivateHandler.obtainMessage(
                                     WebViewClassic.SELECTION_STRING_CHANGED,
                                     modifiedSelectionString).sendToTarget();
+                            mTextSelectionChangeReason
+                                    = TextSelectionData.REASON_UNKNOWN;
                             break;
 
                         case LISTBOX_CHOICES:
@@ -2763,13 +2771,19 @@ public final class WebViewCore {
         }
     }
 
+    private TextSelectionData createTextSelection(int start, int end, int selPtr) {
+        TextSelectionData data = new TextSelectionData(start, end, selPtr);
+        data.mSelectionReason = mTextSelectionChangeReason;
+        return data;
+    }
+
     // called by JNI
     private void updateTextSelection(int pointer, int start, int end,
             int textGeneration, int selectionPtr) {
         if (mWebViewClassic != null) {
             Message.obtain(mWebViewClassic.mPrivateHandler,
                 WebViewClassic.UPDATE_TEXT_SELECTION_MSG_ID, pointer, textGeneration,
-                new TextSelectionData(start, end, selectionPtr)).sendToTarget();
+                createTextSelection(start, end, selectionPtr)).sendToTarget();
         }
     }
 
@@ -2803,7 +2817,7 @@ public final class WebViewCore {
         Message.obtain(mWebViewClassic.mPrivateHandler,
                 WebViewClassic.UPDATE_TEXT_SELECTION_MSG_ID,
                 initData.mFieldPointer, 0,
-                new TextSelectionData(start, end, selectionPtr))
+                createTextSelection(start, end, selectionPtr))
                 .sendToTarget();
     }
 

From 7e0fe5d25b74344681263cf1e4b3c08fa0b610eb Mon Sep 17 00:00:00 2001
From: Jeff Sharkey 
Date: Fri, 4 May 2012 14:49:37 -0700
Subject: [PATCH 085/132] Disable policy when bandwidth module missing.

Bug: 6447017
Change-Id: I705a223dac15fc41e231bb9c81a96a287caaf094
---
 .../server/net/NetworkPolicyManagerService.java | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java
index 8ebe224f15fd4..9119dd1516e51 100644
--- a/services/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -318,6 +318,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
     }
 
     public void systemReady() {
+        if (!isBandwidthControlEnabled()) {
+            Slog.w(TAG, "bandwidth controls disabled, unable to enforce policy");
+            return;
+        }
+
         synchronized (mRulesLock) {
             // read policy from disk
             readPolicyLocked();
@@ -1897,6 +1902,18 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
         }
     }
 
+    private boolean isBandwidthControlEnabled() {
+        final long token = Binder.clearCallingIdentity();
+        try {
+            return mNetworkManager.isBandwidthControlEnabled();
+        } catch (RemoteException e) {
+            // ignored; service lives in system_server
+            return false;
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
     /**
      * Try refreshing {@link #mTime} when stale.
      */

From 324acbf6234ff4a5f4a513f600daec2a7de9a390 Mon Sep 17 00:00:00 2001
From: Daniel Sandler 
Date: Wed, 9 May 2012 02:06:29 -0400
Subject: [PATCH 086/132] Fix situations where the shade wouldn't close.

It appears sometimes the Choreographer will call you with an
old frame (i.e. an animation time in the past).

Bug: 6457615
Change-Id: I7135e2f4f524c14fe4f58f9a367f764b66d68edc
---
 .../statusbar/phone/PhoneStatusBar.java       | 31 ++++++++++++++-----
 1 file changed, 24 insertions(+), 7 deletions(-)

diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 96f08b11ac383..1d281c50311a6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -212,6 +212,7 @@ public class PhoneStatusBar extends BaseStatusBar {
 
     Choreographer mChoreographer;
     boolean mAnimating;
+    boolean mClosing; // only valid when mAnimating; indicates the initial acceleration
     float mAnimY;
     float mAnimVel;
     float mAnimAccel;
@@ -1276,14 +1277,26 @@ public class PhoneStatusBar extends BaseStatusBar {
         }
     }
 
+    void resetLastAnimTime() {
+        mAnimLastTimeNanos = System.nanoTime();
+        if (SPEW) {
+            Throwable t = new Throwable();
+            t.fillInStackTrace();
+            Slog.d(TAG, "resetting last anim time=" + mAnimLastTimeNanos, t);
+        }
+    }
+
     void doAnimation(long frameTimeNanos) {
         if (mAnimating) {
-            if (SPEW) Slog.d(TAG, "doAnimation");
+            if (SPEW) Slog.d(TAG, "doAnimation dt=" + (frameTimeNanos - mAnimLastTimeNanos));
             if (SPEW) Slog.d(TAG, "doAnimation before mAnimY=" + mAnimY);
             incrementAnim(frameTimeNanos);
-            if (SPEW) Slog.d(TAG, "doAnimation after  mAnimY=" + mAnimY);
+            if (SPEW) {
+                Slog.d(TAG, "doAnimation after  mAnimY=" + mAnimY);
+                Slog.d(TAG, "doAnimation expandedViewMax=" + getExpandedViewMaxHeight());
+            }
 
-            if (mAnimY >= getExpandedViewMaxHeight()-1) {
+            if (mAnimY >= getExpandedViewMaxHeight()-1 && !mClosing) {
                 if (SPEW) Slog.d(TAG, "Animation completed to expanded state.");
                 mAnimating = false;
                 updateExpandedViewPos(EXPANDED_FULL_OPEN);
@@ -1291,14 +1304,14 @@ public class PhoneStatusBar extends BaseStatusBar {
                 return;
             }
 
-            if (mAnimY == 0 && mAnimAccel == 0 && mAnimVel == 0) {
+            if (mAnimY == 0 && mAnimAccel == 0 && mClosing) {
                 if (SPEW) Slog.d(TAG, "Animation completed to collapsed state.");
                 mAnimating = false;
                 performCollapse();
                 return;
             }
 
-            if (mAnimY < getStatusBarHeight()) {
+            if (mAnimY < getStatusBarHeight() && mClosing) {
                 // Draw one more frame with the bar positioned at the top of the screen
                 // before ending the animation so that the user sees the bar in
                 // its final position.  The call to performCollapse() causes a window
@@ -1336,6 +1349,9 @@ public class PhoneStatusBar extends BaseStatusBar {
     }
     
     void doRevealAnimation(long frameTimeNanos) {
+        if (SPEW) {
+            Slog.d(TAG, "doRevealAnimation: dt=" + (frameTimeNanos - mAnimLastTimeNanos));
+        }
         final int h = getCloseViewHeight() + getStatusBarHeight();
         if (mAnimatingReveal && mAnimating && mAnimY < h) {
             incrementAnim(frameTimeNanos);
@@ -1365,7 +1381,7 @@ public class PhoneStatusBar extends BaseStatusBar {
             updateExpandedViewPos((int)mAnimY);
             mAnimating = true;
             mAnimatingReveal = true;
-            mAnimLastTimeNanos = System.nanoTime();
+            resetLastAnimTime();
             mChoreographer.removeCallbacks(Choreographer.CALLBACK_ANIMATION,
                     mAnimationCallback, null);
             mChoreographer.removeCallbacks(Choreographer.CALLBACK_ANIMATION,
@@ -1439,8 +1455,9 @@ public class PhoneStatusBar extends BaseStatusBar {
         //Slog.d(TAG, "mAnimY=" + mAnimY + " mAnimVel=" + mAnimVel
         //        + " mAnimAccel=" + mAnimAccel);
 
-        mAnimLastTimeNanos = System.nanoTime();
+        resetLastAnimTime();
         mAnimating = true;
+        mClosing = mAnimAccel < 0;
 
         mChoreographer.removeCallbacks(Choreographer.CALLBACK_ANIMATION,
                 mAnimationCallback, null);

From 5f77adfd281d890706d1d0d27c71196361cfe437 Mon Sep 17 00:00:00 2001
From: Guang Zhu 
Date: Tue, 8 May 2012 23:09:24 -0700
Subject: [PATCH 087/132] Make UiTestAutomationBridge see non-important views
 again

This problem was introduced in I74df9c24. The intention of the
change was still let UiTestAutomationBridge see the
non-important views, but there were bugs in the implementation:

1. AccessibilityManagerService was not really updating
   mIncludeNotImportantViews when mIsAutomation is true

2. Wrong constant is used to set the flag

Change-Id: Ia0a2e9ed9720bd0ea3a563e0b492e870a6ec1586
---
 .../UiTestAutomationBridge.java               |  6 +++---
 .../AccessibilityManagerService.java          | 19 ++++++++-----------
 2 files changed, 11 insertions(+), 14 deletions(-)

diff --git a/core/java/android/accessibilityservice/UiTestAutomationBridge.java b/core/java/android/accessibilityservice/UiTestAutomationBridge.java
index 69195c1e34632..30be374372d51 100644
--- a/core/java/android/accessibilityservice/UiTestAutomationBridge.java
+++ b/core/java/android/accessibilityservice/UiTestAutomationBridge.java
@@ -83,7 +83,7 @@ public class UiTestAutomationBridge {
      * @return The event.
      */
     public AccessibilityEvent getLastAccessibilityEvent() {
-        return mLastEvent; 
+        return mLastEvent;
     }
 
     /**
@@ -142,7 +142,7 @@ public class UiTestAutomationBridge {
 
             @Override
             public void onInterrupt() {
-                UiTestAutomationBridge.this.onInterrupt();  
+                UiTestAutomationBridge.this.onInterrupt();
             }
 
             @Override
@@ -189,7 +189,7 @@ public class UiTestAutomationBridge {
         final AccessibilityServiceInfo info = new AccessibilityServiceInfo();
         info.eventTypes = AccessibilityEvent.TYPES_ALL_MASK;
         info.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC;
-        info.flags |= AccessibilityNodeInfo.INCLUDE_NOT_IMPORTANT_VIEWS;
+        info.flags |= AccessibilityServiceInfo.INCLUDE_NOT_IMPORTANT_VIEWS;
 
         try {
             manager.registerUiTestAutomationService(mListener, info);
diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
index e447218b4c846..1cb2092300471 100644
--- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -259,7 +259,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
                         updateInputFilterLocked();
                         sendStateToClientsLocked();
                     }
-                    
+
                     return;
                 }
 
@@ -1266,16 +1266,13 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
             mNotificationTimeout = info.notificationTimeout;
             mIsDefault = (info.flags & DEFAULT) != 0;
 
-            if (!mIsAutomation) {
-                final int targetSdkVersion =
-                    info.getResolveInfo().serviceInfo.applicationInfo.targetSdkVersion;
-                // TODO: Uncomment this line and remove the line below when JellyBean
-                // SDK version is finalized.
-                // if (targetSdkVersion >= Build.VERSION_CODES.JELLY_BEAN) {
-                if (targetSdkVersion > Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
-                    mIncludeNotImportantViews =
-                        (info.flags & INCLUDE_NOT_IMPORTANT_VIEWS) != 0;
-                }
+            if (mIsAutomation || info.getResolveInfo().serviceInfo.applicationInfo.targetSdkVersion
+                    // TODO: Uncomment this line and remove the line below when JellyBean
+                    // SDK version is finalized.
+                    // >= Build.VERSION_CODES.JELLY_BEAN) {
+                    > Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
+                mIncludeNotImportantViews =
+                    (info.flags & INCLUDE_NOT_IMPORTANT_VIEWS) != 0;
             }
 
             synchronized (mLock) {

From d36b4b1f05e82d571a2acc5896a046e913d976b5 Mon Sep 17 00:00:00 2001
From: Michael Jurka 
Date: Thu, 3 May 2012 10:57:31 -0700
Subject: [PATCH 088/132] Making transition out of recents look better

- Fading out recents first, then scaling up app
thumbnail
- Fade Recents out over 130ms
- Delay the window animation for 200ms first,
then animate for 200ms (previously we didn't delay
and then animated for 300ms)

Bug: 6390075

Change-Id: Ia8c753bf7ee03d2acef6eb2772b28d88fe10a682
---
 core/java/android/app/ActivityOptions.java    | 38 ++++++++++-
 core/java/android/view/IWindowManager.aidl    |  2 +-
 .../layout-land/status_bar_recent_panel.xml   |  6 ++
 .../layout-port/status_bar_recent_panel.xml   |  6 ++
 .../res/layout/system_bar_recent_panel.xml    |  6 ++
 .../systemui/recent/Choreographer.java        | 21 ++++---
 .../systemui/recent/RecentsPanelView.java     | 44 +++++++++++--
 .../com/android/server/am/ActivityRecord.java |  8 ++-
 .../server/wm/WindowManagerService.java       | 63 ++++++++++++++-----
 .../bridge/android/BridgeWindowManager.java   |  2 +-
 10 files changed, 161 insertions(+), 35 deletions(-)

diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 3d0b7d8e17a87..523a78d8dd6cc 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -98,6 +98,8 @@ public class ActivityOptions {
     public static final int ANIM_SCALE_UP = 2;
     /** @hide */
     public static final int ANIM_THUMBNAIL = 3;
+    /** @hide */
+    public static final int ANIM_THUMBNAIL_DELAYED = 4;
 
     private String mPackageName;
     private int mAnimationType = ANIM_NONE;
@@ -219,9 +221,38 @@ public class ActivityOptions {
      */
     public static ActivityOptions makeThumbnailScaleUpAnimation(View source,
             Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener) {
+        return makeThumbnailScaleUpAnimation(source, thumbnail, startX, startY, listener, false);
+    }
+
+    /**
+     * Create an ActivityOptions specifying an animation where a thumbnail
+     * is scaled from a given position to the new activity window that is
+     * being started. Before the animation, there is a short delay.
+     *
+     * @param source The View that this thumbnail is animating from.  This
+     * defines the coordinate space for startX and startY.
+     * @param thumbnail The bitmap that will be shown as the initial thumbnail
+     * of the animation.
+     * @param startX The x starting location of the bitmap, relative to source.
+     * @param startY The y starting location of the bitmap, relative to source.
+     * @param listener Optional OnAnimationStartedListener to find out when the
+     * requested animation has started running.  If for some reason the animation
+     * is not executed, the callback will happen immediately.
+     * @return Returns a new ActivityOptions object that you can use to
+     * supply these options as the options Bundle when starting an activity.
+     * @hide
+     */
+    public static ActivityOptions makeDelayedThumbnailScaleUpAnimation(View source,
+            Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener) {
+        return makeThumbnailScaleUpAnimation(source, thumbnail, startX, startY, listener, true);
+    }
+
+    private static ActivityOptions makeThumbnailScaleUpAnimation(View source,
+            Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener,
+            boolean delayed) {
         ActivityOptions opts = new ActivityOptions();
         opts.mPackageName = source.getContext().getPackageName();
-        opts.mAnimationType = ANIM_THUMBNAIL;
+        opts.mAnimationType = delayed ? ANIM_THUMBNAIL_DELAYED : ANIM_THUMBNAIL;
         opts.mThumbnail = thumbnail;
         int[] pts = new int[2];
         source.getLocationOnScreen(pts);
@@ -258,7 +289,8 @@ public class ActivityOptions {
             mStartY = opts.getInt(KEY_ANIM_START_Y, 0);
             mStartWidth = opts.getInt(KEY_ANIM_START_WIDTH, 0);
             mStartHeight = opts.getInt(KEY_ANIM_START_HEIGHT, 0);
-        } else if (mAnimationType == ANIM_THUMBNAIL) {
+        } else if (mAnimationType == ANIM_THUMBNAIL ||
+                mAnimationType == ANIM_THUMBNAIL_DELAYED) {
             mThumbnail = (Bitmap)opts.getParcelable(KEY_ANIM_THUMBNAIL);
             mStartX = opts.getInt(KEY_ANIM_START_X, 0);
             mStartY = opts.getInt(KEY_ANIM_START_Y, 0);
@@ -359,6 +391,7 @@ public class ActivityOptions {
                 mStartHeight = otherOptions.mStartHeight;
                 break;
             case ANIM_THUMBNAIL:
+            case ANIM_THUMBNAIL_DELAYED:
                 mAnimationType = otherOptions.mAnimationType;
                 mThumbnail = otherOptions.mThumbnail;
                 mStartX = otherOptions.mStartX;
@@ -401,6 +434,7 @@ public class ActivityOptions {
                 b.putInt(KEY_ANIM_START_HEIGHT, mStartHeight);
                 break;
             case ANIM_THUMBNAIL:
+            case ANIM_THUMBNAIL_DELAYED:
                 b.putInt(KEY_ANIM_TYPE, mAnimationType);
                 b.putParcelable(KEY_ANIM_THUMBNAIL, mThumbnail);
                 b.putInt(KEY_ANIM_START_X, mStartX);
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index e1f01dbc0056d..c5a687acef484 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -84,7 +84,7 @@ interface IWindowManager
     void overridePendingAppTransitionScaleUp(int startX, int startY, int startWidth,
             int startHeight);
     void overridePendingAppTransitionThumb(in Bitmap srcThumb, int startX, int startY,
-            IRemoteCallback startedCallback);
+            IRemoteCallback startedCallback, boolean delayed);
     void executeAppTransition();
     void setAppStartingWindow(IBinder token, String pkg, int theme,
             in CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes,
diff --git a/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml b/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
index ec2abe07c7f35..869b16446aaf5 100644
--- a/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
+++ b/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
@@ -27,6 +27,12 @@
     systemui:recentItemLayout="@layout/status_bar_recent_item"
     >
 
+    
+
     
 
+    
+
     
 
+        
+
          mRecentTaskDescriptions;
     private Runnable mPreloadTasksRunnable;
@@ -283,7 +286,9 @@ public class RecentsPanelView extends FrameLayout implements OnItemClickListener
     public void show(boolean show, boolean animate,
             ArrayList recentTaskDescriptions, boolean firstScreenful) {
         // For now, disable animations. We may want to re-enable in the future
-        animate = false;
+        if (show) {
+            animate = false;
+        }
         if (show) {
             // Need to update list of recent apps before we set visibility so this view's
             // content description is updated before it gets focus for TalkBack mode
@@ -687,11 +692,31 @@ public class RecentsPanelView extends FrameLayout implements OnItemClickListener
                 context.getSystemService(Context.ACTIVITY_SERVICE);
         holder.thumbnailViewImage.setDrawingCacheEnabled(true);
         Bitmap bm = holder.thumbnailViewImage.getDrawingCache();
-        ActivityOptions opts = ActivityOptions.makeThumbnailScaleUpAnimation(
+        mPlaceholderThumbnail = (ImageView) findViewById(R.id.recents_transition_placeholder_icon);
+
+        final ImageView placeholderThumbnail = mPlaceholderThumbnail;
+        mHideWindowAfterPlaceholderThumbnailIsHidden = false;
+        placeholderThumbnail.setVisibility(VISIBLE);
+        Bitmap b2 = bm.copy(bm.getConfig(), true);
+        placeholderThumbnail.setImageBitmap(b2);
+
+        Rect r = new Rect();
+        holder.thumbnailViewImage.getGlobalVisibleRect(r);
+
+        placeholderThumbnail.setTranslationX(r.left);
+        placeholderThumbnail.setTranslationY(r.top);
+
+        show(false, true);
+
+        ActivityOptions opts = ActivityOptions.makeDelayedThumbnailScaleUpAnimation(
                 holder.thumbnailViewImage, bm, 0, 0,
                 new ActivityOptions.OnAnimationStartedListener() {
                     @Override public void onAnimationStarted() {
-                        hide(true);
+                        mPlaceholderThumbnail = null;
+                        placeholderThumbnail.setVisibility(INVISIBLE);
+                        if (mHideWindowAfterPlaceholderThumbnailIsHidden) {
+                            hideWindow();
+                        }
                     }
                 });
         if (ad.taskId >= 0) {
@@ -709,6 +734,15 @@ public class RecentsPanelView extends FrameLayout implements OnItemClickListener
         holder.thumbnailViewImage.setDrawingCacheEnabled(false);
     }
 
+    public void hideWindow() {
+        if (mPlaceholderThumbnail != null) {
+            mHideWindowAfterPlaceholderThumbnailIsHidden = true;
+        } else {
+            setVisibility(GONE);
+            mHideWindowAfterPlaceholderThumbnailIsHidden = false;
+        }
+    }
+
     public void onItemClick(AdapterView parent, View view, int position, long id) {
         handleOnClick(view);
     }
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index 97bfd6f4af0bb..ad80273bc02bb 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -552,7 +552,8 @@ final class ActivityRecord {
 
     void applyOptionsLocked() {
         if (pendingOptions != null) {
-            switch (pendingOptions.getAnimationType()) {
+            final int animationType = pendingOptions.getAnimationType();
+            switch (animationType) {
                 case ActivityOptions.ANIM_CUSTOM:
                     service.mWindowManager.overridePendingAppTransition(
                             pendingOptions.getPackageName(),
@@ -571,10 +572,13 @@ final class ActivityRecord {
                     }
                     break;
                 case ActivityOptions.ANIM_THUMBNAIL:
+                case ActivityOptions.ANIM_THUMBNAIL_DELAYED:
+                    boolean delayed = (animationType == ActivityOptions.ANIM_THUMBNAIL_DELAYED);
                     service.mWindowManager.overridePendingAppTransitionThumb(
                             pendingOptions.getThumbnail(),
                             pendingOptions.getStartX(), pendingOptions.getStartY(),
-                            pendingOptions.getOnAnimationStartListener());
+                            pendingOptions.getOnAnimationStartListener(),
+                            delayed);
                     if (intent.getSourceBounds() == null) {
                         intent.setSourceBounds(new Rect(pendingOptions.getStartX(),
                                 pendingOptions.getStartY(),
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 8957edfd6af7a..575496fa16bc8 100755
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -512,6 +512,7 @@ public class WindowManagerService extends IWindowManager.Stub
     int mNextAppTransitionType = ActivityOptions.ANIM_NONE;
     String mNextAppTransitionPackage;
     Bitmap mNextAppTransitionThumbnail;
+    boolean mNextAppTransitionDelayed;
     IRemoteCallback mNextAppTransitionCallback;
     int mNextAppTransitionEnter;
     int mNextAppTransitionExit;
@@ -3176,7 +3177,7 @@ public class WindowManagerService extends IWindowManager.Stub
     }
 
     private Animation createThumbnailAnimationLocked(int transit,
-            boolean enter, boolean thumb) {
+            boolean enter, boolean thumb, boolean delayed) {
         Animation a;
         final int thumbWidthI = mNextAppTransitionThumbnail.getWidth();
         final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
@@ -3186,6 +3187,7 @@ public class WindowManagerService extends IWindowManager.Stub
         // it  is the standard duration for that.  Otherwise we use the longer
         // task transition duration.
         int duration;
+        int delayDuration = delayed ? 200 : 0;
         switch (transit) {
             case WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN:
             case WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE:
@@ -3193,7 +3195,7 @@ public class WindowManagerService extends IWindowManager.Stub
                         com.android.internal.R.integer.config_shortAnimTime);
                 break;
             default:
-                duration = 300;
+                duration = delayed ? 200 : 300;
                 break;
         }
         if (thumb) {
@@ -3201,6 +3203,7 @@ public class WindowManagerService extends IWindowManager.Stub
             // filling the screen.
             float scaleW = mAppDisplayWidth/thumbWidth;
             float scaleH = mAppDisplayHeight/thumbHeight;
+
             Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH,
                     computePivot(mNextAppTransitionStartX, 1/scaleW),
                     computePivot(mNextAppTransitionStartY, 1/scaleH));
@@ -3210,17 +3213,38 @@ public class WindowManagerService extends IWindowManager.Stub
             set.addAnimation(scale);
             alpha.setDuration(duration);
             set.addAnimation(alpha);
+            set.setFillBefore(true);
+            if (delayDuration > 0) {
+                set.setStartOffset(delayDuration);
+            }
             a = set;
         } else if (enter) {
             // Entering app zooms out from the center of the thumbnail.
-            float scaleW = thumbWidth/mAppDisplayWidth;
-            float scaleH = thumbHeight/mAppDisplayHeight;
-            a = new ScaleAnimation(scaleW, 1, scaleH, 1,
+            float scaleW = thumbWidth / mAppDisplayWidth;
+            float scaleH = thumbHeight / mAppDisplayHeight;
+            AnimationSet set = new AnimationSet(true);
+            Animation scale = new ScaleAnimation(scaleW, 1, scaleH, 1,
                     computePivot(mNextAppTransitionStartX, scaleW),
                     computePivot(mNextAppTransitionStartY, scaleH));
-            a.setDuration(duration);
+            scale.setDuration(duration);
+            scale.setFillBefore(true);
+            set.addAnimation(scale);
+            // Need to set an alpha animation on the entering app window
+            // in case it appears one frame before the thumbnail window
+            // (this solves flicker)
+            Animation alpha = new AlphaAnimation(0, 1);
+            alpha.setDuration(1);
+            alpha.setFillAfter(true);
+            set.addAnimation(alpha);
+            a = set;
+            if (delayDuration > 0) {
+                a.setStartOffset(delayDuration);
+            }
         } else {
             a = createExitAnimationLocked(transit, duration);
+            if (delayDuration > 0) {
+                a.setStartOffset(delayDuration);
+            }
         }
         a.setFillAfter(true);
         final Interpolator interpolator = AnimationUtils.loadInterpolator(mContext,
@@ -3252,12 +3276,18 @@ public class WindowManagerService extends IWindowManager.Stub
                 if (DEBUG_ANIM) Slog.v(TAG, "applyAnimation: wtoken=" + wtoken
                         + " anim=" + a + " nextAppTransition=ANIM_SCALE_UP"
                         + " transit=" + transit + " Callers " + Debug.getCallers(3));
-            } else if (mNextAppTransitionType == ActivityOptions.ANIM_THUMBNAIL) {
-                a = createThumbnailAnimationLocked(transit, enter, false);
+            } else if (mNextAppTransitionType == ActivityOptions.ANIM_THUMBNAIL ||
+                    mNextAppTransitionType == ActivityOptions.ANIM_THUMBNAIL_DELAYED) {
+                boolean delayed = (mNextAppTransitionType == ActivityOptions.ANIM_THUMBNAIL_DELAYED);
+                a = createThumbnailAnimationLocked(transit, enter, false, delayed);
                 initialized = true;
-                if (DEBUG_ANIM) Slog.v(TAG, "applyAnimation: wtoken=" + wtoken
-                        + " anim=" + a + " nextAppTransition=ANIM_THUMBNAIL"
-                        + " transit=" + transit + " Callers " + Debug.getCallers(3));
+
+                if (DEBUG_ANIM) {
+                    String animName = delayed ? "ANIM_THUMBNAIL_DELAYED" : "ANIM_THUMBNAIL";
+                    Slog.v(TAG, "applyAnimation: wtoken=" + wtoken
+                            + " anim=" + a + " nextAppTransition=" + animName
+                            + " transit=" + transit + " Callers " + Debug.getCallers(3));
+                }
             } else {
                 int animAttr = 0;
                 switch (transit) {
@@ -3879,11 +3909,13 @@ public class WindowManagerService extends IWindowManager.Stub
     }
 
     public void overridePendingAppTransitionThumb(Bitmap srcThumb, int startX,
-            int startY, IRemoteCallback startedCallback) {
+            int startY, IRemoteCallback startedCallback, boolean delayed) {
         if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
-            mNextAppTransitionType = ActivityOptions.ANIM_THUMBNAIL;
+            mNextAppTransitionType =
+                    delayed ? ActivityOptions.ANIM_THUMBNAIL_DELAYED : ActivityOptions.ANIM_THUMBNAIL;
             mNextAppTransitionPackage = null;
             mNextAppTransitionThumbnail = srcThumb;
+            mNextAppTransitionDelayed = delayed;
             mNextAppTransitionStartX = startX;
             mNextAppTransitionStartY = startY;
             mNextAppTransitionCallback = startedCallback;
@@ -8024,7 +8056,8 @@ public class WindowManagerService extends IWindowManager.Stub
                     drawSurface.unlockCanvasAndPost(c);
                     drawSurface.release();
                     topOpeningApp.mAppAnimator.thumbnailLayer = topOpeningLayer;
-                    Animation anim = createThumbnailAnimationLocked(transit, true, true);
+                    Animation anim = createThumbnailAnimationLocked(
+                            transit, true, true, mNextAppTransitionDelayed);
                     topOpeningApp.mAppAnimator.thumbnailAnimation = anim;
                     anim.restrictDuration(MAX_ANIMATION_DURATION);
                     anim.scaleCurrentDuration(mTransitionAnimationScale);
@@ -9602,10 +9635,12 @@ public class WindowManagerService extends IWindowManager.Stub
                             pw.println(mNextAppTransitionStartHeight);
                     break;
                 case ActivityOptions.ANIM_THUMBNAIL:
+                case ActivityOptions.ANIM_THUMBNAIL_DELAYED:
                     pw.print("  mNextAppTransitionThumbnail=");
                             pw.print(mNextAppTransitionThumbnail);
                             pw.print(" mNextAppTransitionStartX="); pw.print(mNextAppTransitionStartX);
                             pw.print(" mNextAppTransitionStartY="); pw.println(mNextAppTransitionStartY);
+                            pw.print(" mNextAppTransitionDelayed="); pw.println(mNextAppTransitionDelayed);
                     break;
             }
             pw.print("  mStartingIconInTransition="); pw.print(mStartingIconInTransition);
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java
index 85b67d51d13e8..a4b2125549cff 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java
@@ -240,7 +240,7 @@ public class BridgeWindowManager implements IWindowManager {
 
     @Override
     public void overridePendingAppTransitionThumb(Bitmap srcThumb, int startX, int startY,
-            IRemoteCallback startedCallback) throws RemoteException {
+            IRemoteCallback startedCallback, boolean delayed) throws RemoteException {
         // TODO Auto-generated method stub
     }
 

From 901dd93da9400a2c15b2fa4c4916ac19822bc744 Mon Sep 17 00:00:00 2001
From: Chris Wren 
Date: Tue, 8 May 2012 13:36:48 -0400
Subject: [PATCH 089/132] Pull up updateNotification to BaseStatusBar in
 preparation for modifying update behvior.

Bug: 6455789
Change-Id: I09fbf4d31643813cb4dfecaa496327d9625a15af
---
 .../systemui/statusbar/BaseStatusBar.java     | 202 ++++++++++++++
 .../statusbar/phone/PhoneStatusBar.java       | 210 +-------------
 .../statusbar/phone/PhoneStatusBarView.java   |   3 +-
 .../statusbar/tablet/TabletStatusBar.java     | 262 ++----------------
 4 files changed, 239 insertions(+), 438 deletions(-)

diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 37fb53d3472b7..50472b884baa6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -35,6 +35,7 @@ import android.os.Message;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.provider.Settings;
+import android.text.TextUtils;
 import android.util.Log;
 import android.util.Slog;
 import android.view.Display;
@@ -47,6 +48,7 @@ import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
 import android.view.WindowManager;
 import android.view.WindowManagerImpl;
+import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.RemoteViews;
 import android.widget.PopupMenu;
@@ -62,6 +64,7 @@ import com.android.systemui.recent.RecentsPanelView;
 import com.android.systemui.recent.RecentTasksLoader;
 import com.android.systemui.recent.TaskDescription;
 import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.policy.NotificationRowLayout;
 import com.android.systemui.statusbar.tablet.StatusBarPanel;
 
 import com.android.systemui.R;
@@ -77,11 +80,24 @@ public abstract class BaseStatusBar extends SystemUI implements
     protected static final int MSG_CANCEL_PRELOAD_RECENT_APPS = 1023;
     protected static final int MSG_OPEN_SEARCH_PANEL = 1024;
     protected static final int MSG_CLOSE_SEARCH_PANEL = 1025;
+    protected static final int MSG_SHOW_INTRUDER = 1026;
+    protected static final int MSG_HIDE_INTRUDER = 1027;
+
+    protected static final boolean ENABLE_INTRUDERS = false;
+
+    public static final int EXPANDED_LEAVE_ALONE = -10000;
+    public static final int EXPANDED_FULL_OPEN = -10001;
 
     protected CommandQueue mCommandQueue;
     protected IStatusBarService mBarService;
     protected H mHandler = createHandler();
 
+    // all notifications
+    protected NotificationData mNotificationData = new NotificationData();
+    protected NotificationRowLayout mPile;
+
+    protected StatusBarNotification mCurrentlyIntrudingNotification;
+
     // used to notify status bar for suppressing notification LED
     protected boolean mPanelSlightlyVisible;
 
@@ -634,4 +650,190 @@ public abstract class BaseStatusBar extends SystemUI implements
         }
     }
 
+    /**
+     * Cancel this notification and tell the StatusBarManagerService / NotificationManagerService
+     * about the failure.
+     *
+     * WARNING: this will call back into us.  Don't hold any locks.
+     */
+    void handleNotificationError(IBinder key, StatusBarNotification n, String message) {
+        removeNotification(key);
+        try {
+            mBarService.onNotificationError(n.pkg, n.tag, n.id, n.uid, n.initialPid, message);
+        } catch (RemoteException ex) {
+            // The end is nigh.
+        }
+    }
+
+    protected StatusBarNotification removeNotificationViews(IBinder key) {
+        NotificationData.Entry entry = mNotificationData.remove(key);
+        if (entry == null) {
+            Slog.w(TAG, "removeNotification for unknown key: " + key);
+            return null;
+        }
+        // Remove the expanded view.
+        ViewGroup rowParent = (ViewGroup)entry.row.getParent();
+        if (rowParent != null) rowParent.removeView(entry.row);
+        updateNotificationIcons();
+
+        return entry.notification;
+    }
+
+    protected StatusBarIconView addNotificationViews(IBinder key,
+            StatusBarNotification notification) {
+        if (DEBUG) {
+            Slog.d(TAG, "addNotificationViews(key=" + key + ", notification=" + notification);
+        }
+        // Construct the icon.
+        final StatusBarIconView iconView = new StatusBarIconView(mContext,
+                notification.pkg + "/0x" + Integer.toHexString(notification.id),
+                notification.notification);
+        iconView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
+
+        final StatusBarIcon ic = new StatusBarIcon(notification.pkg,
+                    notification.notification.icon,
+                    notification.notification.iconLevel,
+                    notification.notification.number,
+                    notification.notification.tickerText);
+        if (!iconView.set(ic)) {
+            handleNotificationError(key, notification, "Couldn't create icon: " + ic);
+            return null;
+        }
+        // Construct the expanded view.
+        NotificationData.Entry entry = new NotificationData.Entry(key, notification, iconView);
+        if (!inflateViews(entry, mPile)) {
+            handleNotificationError(key, notification, "Couldn't expand RemoteViews for: "
+                    + notification);
+            return null;
+        }
+
+        // Add the expanded view and icon.
+        int pos = mNotificationData.add(entry);
+        if (DEBUG) {
+            Slog.d(TAG, "addNotificationViews: added at " + pos);
+        }
+        updateNotificationIcons();
+
+        return iconView;
+    }
+
+    protected abstract void haltTicker();
+    protected abstract void setAreThereNotifications();
+    protected abstract void updateNotificationIcons();
+    protected abstract void tick(IBinder key, StatusBarNotification n, boolean firstTime);
+    protected abstract void updateExpandedViewPos(int expandedPosition);
+
+    protected boolean isTopNotification(ViewGroup parent, NotificationData.Entry entry) {
+        return parent.indexOfChild(entry.row) == 0;
+    }
+
+    public void updateNotification(IBinder key, StatusBarNotification notification) {
+        if (DEBUG) Slog.d(TAG, "updateNotification(" + key + " -> " + notification + ")");
+
+        final NotificationData.Entry oldEntry = mNotificationData.findByKey(key);
+        if (oldEntry == null) {
+            Slog.w(TAG, "updateNotification for unknown key: " + key);
+            return;
+        }
+
+        final StatusBarNotification oldNotification = oldEntry.notification;
+
+        // XXX: modify when we do something more intelligent with the two content views
+        final RemoteViews oldContentView = (oldNotification.notification.bigContentView != null)
+                ? oldNotification.notification.bigContentView
+                : oldNotification.notification.contentView;
+        final RemoteViews contentView = (notification.notification.bigContentView != null)
+                ? notification.notification.bigContentView
+                : notification.notification.contentView;
+
+        if (DEBUG) {
+            Slog.d(TAG, "old notification: when=" + oldNotification.notification.when
+                    + " ongoing=" + oldNotification.isOngoing()
+                    + " expanded=" + oldEntry.expanded
+                    + " contentView=" + oldContentView
+                    + " rowParent=" + oldEntry.row.getParent());
+            Slog.d(TAG, "new notification: when=" + notification.notification.when
+                    + " ongoing=" + oldNotification.isOngoing()
+                    + " contentView=" + contentView);
+        }
+
+        // Can we just reapply the RemoteViews in place?  If when didn't change, the order
+        // didn't change.
+        boolean contentsUnchanged = oldEntry.expanded != null
+                && contentView != null && oldContentView != null
+                && contentView.getPackage() != null
+                && oldContentView.getPackage() != null
+                && oldContentView.getPackage().equals(contentView.getPackage())
+                && oldContentView.getLayoutId() == contentView.getLayoutId();
+        ViewGroup rowParent = (ViewGroup) oldEntry.row.getParent();
+        boolean orderUnchanged = notification.notification.when==oldNotification.notification.when
+                && notification.score == oldNotification.score;
+                // score now encompasses/supersedes isOngoing()
+
+        boolean updateTicker = notification.notification.tickerText != null
+                && !TextUtils.equals(notification.notification.tickerText,
+                        oldEntry.notification.notification.tickerText);
+        boolean isTopAnyway = isTopNotification(rowParent, oldEntry);
+        if (contentsUnchanged && (orderUnchanged || isTopAnyway)) {
+            if (DEBUG) Slog.d(TAG, "reusing notification for key: " + key);
+            oldEntry.notification = notification;
+            try {
+                // Reapply the RemoteViews
+                contentView.reapply(mContext, oldEntry.content);
+                // update the contentIntent
+                final PendingIntent contentIntent = notification.notification.contentIntent;
+                if (contentIntent != null) {
+                    final View.OnClickListener listener = makeClicker(contentIntent,
+                            notification.pkg, notification.tag, notification.id);
+                    oldEntry.content.setOnClickListener(listener);
+                } else {
+                    oldEntry.content.setOnClickListener(null);
+                }
+                // Update the icon.
+                final StatusBarIcon ic = new StatusBarIcon(notification.pkg,
+                        notification.notification.icon, notification.notification.iconLevel,
+                        notification.notification.number,
+                        notification.notification.tickerText);
+                if (!oldEntry.icon.set(ic)) {
+                    handleNotificationError(key, notification, "Couldn't update icon: " + ic);
+                    return;
+                }
+            }
+            catch (RuntimeException e) {
+                // It failed to add cleanly.  Log, and remove the view from the panel.
+                Slog.w(TAG, "Couldn't reapply views for package " + contentView.getPackage(), e);
+                removeNotificationViews(key);
+                addNotificationViews(key, notification);
+            }
+        } else {
+            if (DEBUG) Slog.d(TAG, "not reusing notification for key: " + key);
+            removeNotificationViews(key);
+            addNotificationViews(key, notification);
+        }
+
+        // Update the veto button accordingly (and as a result, whether this row is
+        // swipe-dismissable)
+        updateNotificationVetoButton(oldEntry.row, notification);
+
+        // Restart the ticker if it's still running
+        if (updateTicker) {
+            haltTicker();
+            tick(key, notification, false);
+        }
+
+        // Recalculate the position of the sliding windows and the titles.
+        setAreThereNotifications();
+        updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
+
+        // See if we need to update the intruder.
+        if (ENABLE_INTRUDERS && oldNotification == mCurrentlyIntrudingNotification) {
+            if (DEBUG) Slog.d(TAG, "updating the current intruder:" + notification);
+            // XXX: this is a hack for Alarms. The real implementation will need to *update*
+            // the intruder.
+            if (notification.notification.fullScreenIntent == null) { // TODO(dsandler): consistent logic with add()
+                if (DEBUG) Slog.d(TAG, "no longer intrudes!");
+                mHandler.sendEmptyMessage(MSG_HIDE_INTRUDER);
+            }
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index f5f2e28c80174..f1dd183295018 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -42,7 +42,6 @@ import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.provider.Settings;
-import android.text.TextUtils;
 import android.util.DisplayMetrics;
 import android.util.Log;
 import android.util.Slog;
@@ -105,16 +104,10 @@ public class PhoneStatusBar extends BaseStatusBar {
     public static final String ACTION_STATUSBAR_START
             = "com.android.internal.policy.statusbar.START";
 
-    private static final boolean ENABLE_INTRUDERS = false;
     private static final boolean DIM_BEHIND_EXPANDED_PANEL = false;
 
-    static final int EXPANDED_LEAVE_ALONE = -10000;
-    static final int EXPANDED_FULL_OPEN = -10001;
-
     private static final int MSG_OPEN_NOTIFICATION_PANEL = 1000;
     private static final int MSG_CLOSE_NOTIFICATION_PANEL = 1001;
-    private static final int MSG_SHOW_INTRUDER = 1002;
-    private static final int MSG_HIDE_INTRUDER = 1003;
     // 1020-1030 reserved for BaseStatusBar
 
     // will likely move to a resource or other tunable param at some point
@@ -179,10 +172,6 @@ public class PhoneStatusBar extends BaseStatusBar {
     CloseDragHandle mCloseView;
     private int mCloseViewHeight;
 
-    // all notifications
-    NotificationData mNotificationData = new NotificationData();
-    NotificationRowLayout mPile;
-
     // position
     int[] mPositionTmp = new int[2];
     boolean mExpanded;
@@ -519,7 +508,7 @@ public class PhoneStatusBar extends BaseStatusBar {
             toggleRecentApps();
         }
     };
-    private StatusBarNotification mCurrentlyIntrudingNotification;
+
     View.OnTouchListener mHomeSearchActionListener = new View.OnTouchListener() {
         public boolean onTouch(View v, MotionEvent event) {
             switch(event.getAction()) {
@@ -693,7 +682,7 @@ public class PhoneStatusBar extends BaseStatusBar {
 
             // show the ticker if there isn't an intruder too
             if (mCurrentlyIntrudingNotification == null) {
-                tick(notification);
+                tick(null, notification, true);
             }
         }
 
@@ -702,117 +691,6 @@ public class PhoneStatusBar extends BaseStatusBar {
         updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
     }
 
-    public void updateNotification(IBinder key, StatusBarNotification notification) {
-        if (DEBUG) Slog.d(TAG, "updateNotification(" + key + " -> " + notification + ")");
-
-        final NotificationData.Entry oldEntry = mNotificationData.findByKey(key);
-        if (oldEntry == null) {
-            Slog.w(TAG, "updateNotification for unknown key: " + key);
-            return;
-        }
-
-        final StatusBarNotification oldNotification = oldEntry.notification;
-
-        // XXX: modify when we do something more intelligent with the two content views
-        final RemoteViews oldContentView = (oldNotification.notification.bigContentView != null) 
-                ? oldNotification.notification.bigContentView
-                : oldNotification.notification.contentView;
-        final RemoteViews contentView = (notification.notification.bigContentView != null) 
-                ? notification.notification.bigContentView
-                : notification.notification.contentView;
-
-        if (DEBUG) {
-            Slog.d(TAG, "old notification: when=" + oldNotification.notification.when
-                    + " ongoing=" + oldNotification.isOngoing()
-                    + " expanded=" + oldEntry.expanded
-                    + " contentView=" + oldContentView
-                    + " rowParent=" + oldEntry.row.getParent());
-            Slog.d(TAG, "new notification: when=" + notification.notification.when
-                    + " ongoing=" + oldNotification.isOngoing()
-                    + " contentView=" + contentView);
-        }
-
-
-        // Can we just reapply the RemoteViews in place?  If when didn't change, the order
-        // didn't change.
-        boolean contentsUnchanged = oldEntry.expanded != null
-                && contentView != null && oldContentView != null
-                && contentView.getPackage() != null
-                && oldContentView.getPackage() != null
-                && oldContentView.getPackage().equals(contentView.getPackage())
-                && oldContentView.getLayoutId() == contentView.getLayoutId();
-        ViewGroup rowParent = (ViewGroup) oldEntry.row.getParent();
-        boolean orderUnchanged = notification.notification.when==oldNotification.notification.when
-                && notification.score == oldNotification.score;
-                // score now encompasses/supersedes isOngoing()
-
-        boolean updateTicker = notification.notification.tickerText != null
-                && !TextUtils.equals(notification.notification.tickerText,
-                        oldEntry.notification.notification.tickerText);
-        boolean isFirstAnyway = rowParent.indexOfChild(oldEntry.row) == 0;
-        if (contentsUnchanged && (orderUnchanged || isFirstAnyway)) {
-            if (DEBUG) Slog.d(TAG, "reusing notification for key: " + key);
-            oldEntry.notification = notification;
-            try {
-                // Reapply the RemoteViews
-                contentView.reapply(mContext, oldEntry.content);
-                // update the contentIntent
-                final PendingIntent contentIntent = notification.notification.contentIntent;
-                if (contentIntent != null) {
-                    final View.OnClickListener listener = new NotificationClicker(contentIntent,
-                            notification.pkg, notification.tag, notification.id);
-                    oldEntry.content.setOnClickListener(listener);
-                } else {
-                    oldEntry.content.setOnClickListener(null);
-                }
-                // Update the icon.
-                final StatusBarIcon ic = new StatusBarIcon(notification.pkg,
-                        notification.notification.icon, notification.notification.iconLevel,
-                        notification.notification.number,
-                        notification.notification.tickerText);
-                if (!oldEntry.icon.set(ic)) {
-                    handleNotificationError(key, notification, "Couldn't update icon: " + ic);
-                    return;
-                }
-            }
-            catch (RuntimeException e) {
-                // It failed to add cleanly.  Log, and remove the view from the panel.
-                Slog.w(TAG, "Couldn't reapply views for package " + contentView.getPackage(), e);
-                removeNotificationViews(key);
-                addNotificationViews(key, notification);
-            }
-        } else {
-            if (SPEW) Slog.d(TAG, "not reusing notification");
-            removeNotificationViews(key);
-            addNotificationViews(key, notification);
-        }
-
-        // Update the veto button accordingly (and as a result, whether this row is
-        // swipe-dismissable)
-        updateNotificationVetoButton(oldEntry.row, notification);
-
-        // Restart the ticker if it's still running
-        if (updateTicker) {
-            mTicker.halt();
-            tick(notification);
-        }
-
-        // Recalculate the position of the sliding windows and the titles.
-        setAreThereNotifications();
-        updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
-
-        // See if we need to update the intruder.
-        if (ENABLE_INTRUDERS && oldNotification == mCurrentlyIntrudingNotification) {
-            if (DEBUG) Slog.d(TAG, "updating the current intruder:" + notification);
-            // XXX: this is a hack for Alarms. The real implementation will need to *update* 
-            // the intruder.
-            if (notification.notification.fullScreenIntent == null) { // TODO(dsandler): consistent logic with add()
-                if (DEBUG) Slog.d(TAG, "no longer intrudes!");
-                mHandler.sendEmptyMessage(MSG_HIDE_INTRUDER);
-            }
-        }
-    }
-
     public void removeNotification(IBinder key) {
         StatusBarNotification old = removeNotificationViews(key);
         if (SPEW) Slog.d(TAG, "removeNotification key=" + key + " old=" + old);
@@ -841,44 +719,6 @@ public class PhoneStatusBar extends BaseStatusBar {
         updateRecentsPanel();
     }
 
-
-    StatusBarIconView addNotificationViews(IBinder key, StatusBarNotification notification) {
-        if (DEBUG) {
-            Slog.d(TAG, "addNotificationViews(key=" + key + ", notification=" + notification);
-        }
-        // Construct the icon.
-        final StatusBarIconView iconView = new StatusBarIconView(mContext,
-                notification.pkg + "/0x" + Integer.toHexString(notification.id),
-                notification.notification);
-        iconView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
-
-        final StatusBarIcon ic = new StatusBarIcon(notification.pkg,
-                    notification.notification.icon,
-                    notification.notification.iconLevel,
-                    notification.notification.number,
-                    notification.notification.tickerText);
-        if (!iconView.set(ic)) {
-            handleNotificationError(key, notification, "Couldn't create icon: " + ic);
-            return null;
-        }
-        // Construct the expanded view.
-        NotificationData.Entry entry = new NotificationData.Entry(key, notification, iconView);
-        if (!inflateViews(entry, mPile)) {
-            handleNotificationError(key, notification, "Couldn't expand RemoteViews for: "
-                    + notification);
-            return null;
-        }
-
-        // Add the expanded view and icon.
-        int pos = mNotificationData.add(entry);
-        if (DEBUG) {
-            Slog.d(TAG, "addNotificationViews: added at " + pos);
-        }
-        updateNotificationIcons();
-
-        return iconView;
-    }
-
     private void loadNotificationShade() {
         int N = mNotificationData.size();
 
@@ -915,7 +755,8 @@ public class PhoneStatusBar extends BaseStatusBar {
         updateNotificationIcons();
     }
 
-    private void updateNotificationIcons() {
+    @Override
+    protected void updateNotificationIcons() {
         loadNotificationShade();
 
         final LinearLayout.LayoutParams params
@@ -956,21 +797,8 @@ public class PhoneStatusBar extends BaseStatusBar {
         }
     }
 
-    StatusBarNotification removeNotificationViews(IBinder key) {
-        NotificationData.Entry entry = mNotificationData.remove(key);
-        if (entry == null) {
-            Slog.w(TAG, "removeNotification for unknown key: " + key);
-            return null;
-        }
-        // Remove the expanded view.
-        ViewGroup rowParent = (ViewGroup)entry.row.getParent();
-        if (rowParent != null) rowParent.removeView(entry.row);
-        updateNotificationIcons();
-
-        return entry.notification;
-    }
-
-    private void setAreThereNotifications() {
+    @Override
+    protected void setAreThereNotifications() {
         final boolean any = mNotificationData.size() > 0;
 
         final boolean clearable = any && mNotificationData.hasClearableItems();
@@ -1754,7 +1582,8 @@ public class PhoneStatusBar extends BaseStatusBar {
         }
     }
 
-    private void tick(StatusBarNotification n) {
+    @Override
+    protected void tick(IBinder key, StatusBarNotification n, boolean firstTime) {
         // no ticking in lights-out mode
         if (!areLightsOn()) return;
         
@@ -1770,21 +1599,6 @@ public class PhoneStatusBar extends BaseStatusBar {
         }
     }
 
-    /**
-     * Cancel this notification and tell the StatusBarManagerService / NotificationManagerService
-     * about the failure.
-     *
-     * WARNING: this will call back into us.  Don't hold any locks.
-     */
-    void handleNotificationError(IBinder key, StatusBarNotification n, String message) {
-        removeNotification(key);
-        try {
-            mBarService.onNotificationError(n.pkg, n.tag, n.id, n.uid, n.initialPid, message);
-        } catch (RemoteException ex) {
-            // The end is nigh.
-        }
-    }
-
     private class MyTicker extends Ticker {
         MyTicker(Context context, View sb) {
             super(context, sb);
@@ -1961,7 +1775,8 @@ public class PhoneStatusBar extends BaseStatusBar {
         return mDisplayMetrics.heightPixels - mNotificationPanelMarginBottomPx;
     }
 
-    void updateExpandedViewPos(int expandedPosition) {
+    @Override
+    protected void updateExpandedViewPos(int expandedPosition) {
         if (SPEW) {
             Slog.d(TAG, "updateExpandedViewPos before expandedPosition=" + expandedPosition
                     //+ " mTrackingParams.y=" + ((mTrackingParams == null) ? "?" : mTrackingParams.y)
@@ -2288,5 +2103,10 @@ public class PhoneStatusBar extends BaseStatusBar {
             vibrate();
         }
     };
+
+    @Override
+    protected void haltTicker() {
+        mTicker.halt();
+    }
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index a8f5c6463c218..a9cc62a4d6157 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -31,6 +31,7 @@ import android.view.accessibility.AccessibilityEvent;
 import android.widget.FrameLayout;
 
 import com.android.systemui.R;
+import com.android.systemui.statusbar.BaseStatusBar;
 import com.android.systemui.statusbar.policy.FixedSizeDrawable;
 
 public class PhoneStatusBarView extends FrameLayout {
@@ -95,7 +96,7 @@ public class PhoneStatusBarView extends FrameLayout {
     @Override
     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
         super.onSizeChanged(w, h, oldw, oldh);
-        mService.updateExpandedViewPos(PhoneStatusBar.EXPANDED_LEAVE_ALONE);
+        mService.updateExpandedViewPos(BaseStatusBar.EXPANDED_LEAVE_ALONE);
     }
 
     @Override
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 b0830eea6d209..9c48f06d15e25 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -109,7 +109,6 @@ public class TabletStatusBar extends BaseStatusBar implements
     private static final boolean FAKE_SPACE_BAR = true;
 
     // Notification "peeking" (flyover preview of individual notifications)
-    final static boolean NOTIFICATION_PEEK_ENABLED = false;
     final static int NOTIFICATION_PEEK_HOLD_THRESH = 200; // ms
     final static int NOTIFICATION_PEEK_FADE_DELAY = 3000; // ms
 
@@ -127,9 +126,6 @@ public class TabletStatusBar extends BaseStatusBar implements
 
     IWindowManager mWindowManager;
 
-    // tracking all current notifications
-    private NotificationData mNotificationData = new NotificationData();
-
     TabletStatusBarView mStatusBarView;
     View mNotificationArea;
     View mNotificationTrigger;
@@ -160,8 +156,6 @@ public class TabletStatusBar extends BaseStatusBar implements
     int mNotificationPeekTapDuration;
     int mNotificationFlingVelocity;
 
-    NotificationRowLayout mPile;
-
     BatteryController mBatteryController;
     BluetoothController mBluetoothController;
     LocationController mLocationController;
@@ -290,47 +284,6 @@ public class TabletStatusBar extends BaseStatusBar implements
 
         WindowManagerImpl.getDefault().addView(mNotificationPanel, lp);
 
-        // Notification preview window
-        if (NOTIFICATION_PEEK_ENABLED) {
-            mNotificationPeekWindow = (NotificationPeekPanel) View.inflate(context,
-                    R.layout.system_bar_notification_peek, null);
-            mNotificationPeekWindow.setBar(this);
-
-            mNotificationPeekRow = (ViewGroup) mNotificationPeekWindow.findViewById(R.id.content);
-            mNotificationPeekWindow.setVisibility(View.GONE);
-            mNotificationPeekWindow.setOnTouchListener(
-                    new TouchOutsideListener(MSG_CLOSE_NOTIFICATION_PEEK, mNotificationPeekWindow));
-            mNotificationPeekScrubRight = new LayoutTransition();
-            mNotificationPeekScrubRight.setAnimator(LayoutTransition.APPEARING,
-                    ObjectAnimator.ofInt(null, "left", -512, 0));
-            mNotificationPeekScrubRight.setAnimator(LayoutTransition.DISAPPEARING,
-                    ObjectAnimator.ofInt(null, "left", -512, 0));
-            mNotificationPeekScrubRight.setDuration(500);
-
-            mNotificationPeekScrubLeft = new LayoutTransition();
-            mNotificationPeekScrubLeft.setAnimator(LayoutTransition.APPEARING,
-                    ObjectAnimator.ofInt(null, "left", 512, 0));
-            mNotificationPeekScrubLeft.setAnimator(LayoutTransition.DISAPPEARING,
-                    ObjectAnimator.ofInt(null, "left", 512, 0));
-            mNotificationPeekScrubLeft.setDuration(500);
-
-            // XXX: setIgnoreChildren?
-            lp = new WindowManager.LayoutParams(
-                    512, // ViewGroup.LayoutParams.WRAP_CONTENT,
-                    ViewGroup.LayoutParams.WRAP_CONTENT,
-                    WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
-                    WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
-                        | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
-                        | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
-                    PixelFormat.TRANSLUCENT);
-            lp.gravity = Gravity.BOTTOM | Gravity.RIGHT;
-            lp.y = res.getDimensionPixelOffset(R.dimen.peek_window_y_offset);
-            lp.setTitle("NotificationPeekWindow");
-            lp.windowAnimations = com.android.internal.R.style.Animation_Toast;
-
-            WindowManagerImpl.getDefault().addView(mNotificationPeekWindow, lp);
-        }
-
         // Recents Panel
         mRecentTasksLoader = new RecentTasksLoader(context);
         updateRecentsPanel();
@@ -494,24 +447,16 @@ public class TabletStatusBar extends BaseStatusBar implements
 
         // the whole right-hand side of the bar
         mNotificationArea = sb.findViewById(R.id.notificationArea);
-        if (!NOTIFICATION_PEEK_ENABLED) {
-            mNotificationArea.setOnTouchListener(new NotificationTriggerTouchListener());
-        }
+        mNotificationArea.setOnTouchListener(new NotificationTriggerTouchListener());
 
         // the button to open the notification area
         mNotificationTrigger = sb.findViewById(R.id.notificationTrigger);
-        if (NOTIFICATION_PEEK_ENABLED) {
-            mNotificationTrigger.setOnTouchListener(new NotificationTriggerTouchListener());
-        }
 
         // the more notifications icon
         mNotificationIconArea = (NotificationIconArea)sb.findViewById(R.id.notificationIcons);
 
         // where the icons go
         mIconLayout = (NotificationIconArea.IconLayout) sb.findViewById(R.id.icons);
-        if (NOTIFICATION_PEEK_ENABLED) {
-            mIconLayout.setOnTouchListener(new NotificationIconTouchListener());
-        }
 
         ViewConfiguration vc = ViewConfiguration.get(context);
         mNotificationPeekTapDuration = vc.getTapTimeout();
@@ -827,9 +772,6 @@ public class TabletStatusBar extends BaseStatusBar implements
                 case MSG_OPEN_NOTIFICATION_PANEL:
                     if (DEBUG) Slog.d(TAG, "opening notifications panel");
                     if (!mNotificationPanel.isShowing()) {
-                        if (NOTIFICATION_PEEK_ENABLED) {
-                            mNotificationPeekWindow.setVisibility(View.GONE);
-                        }
                         mNotificationPanel.show(true, true);
                         mNotificationArea.setVisibility(View.INVISIBLE);
                         mTicker.halt();
@@ -916,106 +858,6 @@ public class TabletStatusBar extends BaseStatusBar implements
         setAreThereNotifications();
     }
 
-    public void updateNotification(IBinder key, StatusBarNotification notification) {
-        if (DEBUG) Slog.d(TAG, "updateNotification(" + key + " -> " + notification + ")");
-
-        final NotificationData.Entry oldEntry = mNotificationData.findByKey(key);
-        if (oldEntry == null) {
-            Slog.w(TAG, "updateNotification for unknown key: " + key);
-            return;
-        }
-
-        final StatusBarNotification oldNotification = oldEntry.notification;
-
-        // XXX: modify when we do something more intelligent with the two content views
-        final RemoteViews oldContentView = (oldNotification.notification.bigContentView != null) 
-                ? oldNotification.notification.bigContentView
-                : oldNotification.notification.contentView;
-        final RemoteViews contentView = (notification.notification.bigContentView != null) 
-                ? notification.notification.bigContentView
-                : notification.notification.contentView;
-
-        if (DEBUG) {
-            Slog.d(TAG, "old notification: when=" + oldNotification.notification.when
-                    + " ongoing=" + oldNotification.isOngoing()
-                    + " expanded=" + oldEntry.expanded
-                    + " contentView=" + oldContentView
-                    + " rowParent=" + oldEntry.row.getParent());
-            Slog.d(TAG, "new notification: when=" + notification.notification.when
-                    + " ongoing=" + oldNotification.isOngoing()
-                    + " contentView=" + contentView);
-        }
-
-        // Can we just reapply the RemoteViews in place?  If when didn't change, the order
-        // didn't change.
-        boolean contentsUnchanged = oldEntry.expanded != null
-                && contentView != null && oldContentView != null
-                && contentView.getPackage() != null
-                && oldContentView.getPackage() != null
-                && oldContentView.getPackage().equals(contentView.getPackage())
-                && oldContentView.getLayoutId() == contentView.getLayoutId();
-        ViewGroup rowParent = (ViewGroup) oldEntry.row.getParent();
-        boolean orderUnchanged = notification.notification.when==oldNotification.notification.when
-                && notification.score == oldNotification.score;
-                // score now encompasses/supersedes isOngoing()
-        boolean updateTicker = notification.notification.tickerText != null
-                && !TextUtils.equals(notification.notification.tickerText,
-                        oldEntry.notification.notification.tickerText);
-        boolean isLastAnyway = rowParent.indexOfChild(oldEntry.row) == rowParent.getChildCount()-1;
-        if (contentsUnchanged && (orderUnchanged || isLastAnyway)) {
-            if (DEBUG) Slog.d(TAG, "reusing notification for key: " + key);
-            oldEntry.notification = notification;
-            try {
-                // Reapply the RemoteViews
-                contentView.reapply(mContext, oldEntry.content);
-                // update the contentIntent
-                final PendingIntent contentIntent = notification.notification.contentIntent;
-                if (contentIntent != null) {
-                    final View.OnClickListener listener = makeClicker(contentIntent,
-                            notification.pkg, notification.tag, notification.id);
-                    oldEntry.content.setOnClickListener(listener);
-                } else {
-                    oldEntry.content.setOnClickListener(null);
-                }
-                // Update the icon.
-                final StatusBarIcon ic = new StatusBarIcon(notification.pkg,
-                        notification.notification.icon, notification.notification.iconLevel,
-                        notification.notification.number,
-                        notification.notification.tickerText);
-                if (!oldEntry.icon.set(ic)) {
-                    handleNotificationError(key, notification, "Couldn't update icon: " + ic);
-                    return;
-                }
-
-                if (NOTIFICATION_PEEK_ENABLED && key == mNotificationPeekKey) {
-                    // must update the peek window
-                    Message peekMsg = mHandler.obtainMessage(MSG_OPEN_NOTIFICATION_PEEK);
-                    peekMsg.arg1 = mNotificationPeekIndex;
-                    mHandler.removeMessages(MSG_OPEN_NOTIFICATION_PEEK);
-                    mHandler.sendMessage(peekMsg);
-                }
-            }
-            catch (RuntimeException e) {
-                // It failed to add cleanly.  Log, and remove the view from the panel.
-                Slog.w(TAG, "Couldn't reapply views for package " + contentView.getPackage(), e);
-                removeNotificationViews(key);
-                addNotificationViews(key, notification);
-            }
-        } else {
-            if (DEBUG) Slog.d(TAG, "not reusing notification for key: " + key);
-            removeNotificationViews(key);
-            addNotificationViews(key, notification);
-        }
-
-        // Restart the ticker if it's still running
-        if (updateTicker) {
-            mTicker.halt();
-            tick(key, notification, false);
-        }
-
-        setAreThereNotifications();
-    }
-
     public void removeNotification(IBinder key) {
         if (DEBUG) Slog.d(TAG, "removeNotification(" + key + ")");
         removeNotificationViews(key);
@@ -1105,7 +947,8 @@ public class TabletStatusBar extends BaseStatusBar implements
         return n.tickerView != null || !TextUtils.isEmpty(n.tickerText);
     }
 
-    private void tick(IBinder key, StatusBarNotification n, boolean firstTime) {
+    @Override
+    protected void tick(IBinder key, StatusBarNotification n, boolean firstTime) {
         // Don't show the ticker when the windowshade is open.
         if (mNotificationPanel.isShowing()) {
             return;
@@ -1134,11 +977,6 @@ public class TabletStatusBar extends BaseStatusBar implements
     }
 
     public void animateExpand() {
-        if (NOTIFICATION_PEEK_ENABLED) {
-            mHandler.removeMessages(MSG_CLOSE_NOTIFICATION_PEEK);
-            mHandler.removeMessages(MSG_OPEN_NOTIFICATION_PEEK);
-            mHandler.sendEmptyMessage(MSG_CLOSE_NOTIFICATION_PEEK);
-        }
         mHandler.removeMessages(MSG_OPEN_NOTIFICATION_PANEL);
         mHandler.sendEmptyMessage(MSG_OPEN_NOTIFICATION_PANEL);
     }
@@ -1158,10 +996,6 @@ public class TabletStatusBar extends BaseStatusBar implements
         mHandler.sendEmptyMessage(MSG_CLOSE_INPUT_METHODS_PANEL);
         mHandler.removeMessages(MSG_CLOSE_COMPAT_MODE_PANEL);
         mHandler.sendEmptyMessage(MSG_CLOSE_COMPAT_MODE_PANEL);
-        if (NOTIFICATION_PEEK_ENABLED) {
-            mHandler.removeMessages(MSG_CLOSE_NOTIFICATION_PEEK);
-            mHandler.sendEmptyMessage(MSG_CLOSE_NOTIFICATION_PEEK);
-        }
     }
 
     @Override // CommandQueue
@@ -1350,24 +1184,13 @@ public class TabletStatusBar extends BaseStatusBar implements
         }
     }
 
-    private void setAreThereNotifications() {
+    @Override
+    protected void setAreThereNotifications() {
         if (mNotificationPanel != null) {
             mNotificationPanel.setClearable(mNotificationData.hasClearableItems());
         }
     }
 
-    /**
-     * Cancel this notification and tell the status bar service about the failure. Hold no locks.
-     */
-    void handleNotificationError(IBinder key, StatusBarNotification n, String message) {
-        removeNotification(key);
-        try {
-            mBarService.onNotificationError(n.pkg, n.tag, n.id, n.uid, n.initialPid, message);
-        } catch (RemoteException ex) {
-            // The end is nigh.
-        }
-    }
-
     private View.OnClickListener mOnClickListener = new View.OnClickListener() {
         public void onClick(View v) {
             if (v == mRecentButton) {
@@ -1405,28 +1228,6 @@ public class TabletStatusBar extends BaseStatusBar implements
         mHandler.sendEmptyMessage(msg);
     }
 
-    StatusBarNotification removeNotificationViews(IBinder key) {
-        NotificationData.Entry entry = mNotificationData.remove(key);
-        if (entry == null) {
-            Slog.w(TAG, "removeNotification for unknown key: " + key);
-            return null;
-        }
-        // Remove the expanded view.
-        ViewGroup rowParent = (ViewGroup)entry.row.getParent();
-        if (rowParent != null) rowParent.removeView(entry.row);
-
-        if (NOTIFICATION_PEEK_ENABLED && key == mNotificationPeekKey) {
-            // must close the peek as well, since it's gone
-            mHandler.sendEmptyMessage(MSG_CLOSE_NOTIFICATION_PEEK);
-        }
-        // Remove the icon.
-//        ViewGroup iconParent = (ViewGroup)entry.icon.getParent();
-//        if (iconParent != null) iconParent.removeView(entry.icon);
-        updateNotificationIcons();
-
-        return entry.notification;
-    }
-
     private class NotificationTriggerTouchListener implements View.OnTouchListener {
         VelocityTracker mVT;
         float mInitialTouchX, mInitialTouchY;
@@ -1619,50 +1420,14 @@ public class TabletStatusBar extends BaseStatusBar implements
         }
     }
 
-    StatusBarIconView addNotificationViews(IBinder key, StatusBarNotification notification) {
-        if (DEBUG) {
-            Slog.d(TAG, "addNotificationViews(key=" + key + ", notification=" + notification);
-        }
-        // Construct the icon.
-        final StatusBarIconView iconView = new StatusBarIconView(mContext,
-                notification.pkg + "/0x" + Integer.toHexString(notification.id),
-                notification.notification);
-        iconView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
-
-        final StatusBarIcon ic = new StatusBarIcon(notification.pkg,
-                    notification.notification.icon,
-                    notification.notification.iconLevel,
-                    notification.notification.number,
-                    notification.notification.tickerText);
-        if (!iconView.set(ic)) {
-            handleNotificationError(key, notification, "Couldn't attach StatusBarIcon: " + ic);
-            return null;
-        }
-        // Construct the expanded view.
-        NotificationData.Entry entry = new NotificationData.Entry(key, notification, iconView);
-        if (!inflateViews(entry, mPile)) {
-            handleNotificationError(key, notification, "Couldn't expand RemoteViews for: "
-                    + notification);
-            return null;
-        }
-
-        // Add the icon.
-        int pos = mNotificationData.add(entry);
-        if (DEBUG) {
-            Slog.d(TAG, "addNotificationViews: added at " + pos);
-        }
-        updateNotificationIcons();
-
-        return iconView;
-    }
-
     private void reloadAllNotificationIcons() {
         if (mIconLayout == null) return;
         mIconLayout.removeAllViews();
         updateNotificationIcons();
     }
 
-    private void updateNotificationIcons() {
+    @Override
+    protected void updateNotificationIcons() {
         // XXX: need to implement a new limited linear layout class
         // to avoid removing & readding everything
 
@@ -1835,6 +1600,19 @@ public class TabletStatusBar extends BaseStatusBar implements
         mNetworkController.dump(fd, pw, args);
     }
 
+    @Override
+    protected boolean isTopNotification(ViewGroup parent, NotificationData.Entry entry) {
+        return parent.indexOfChild(entry.row) == parent.getChildCount()-1;
+    }
+
+    @Override
+    protected void haltTicker() {
+        mTicker.halt();
+    }
+
+    @Override
+    protected void updateExpandedViewPos(int expandedPosition) {
+    }
 }
 
 

From 0d30be293a5e40e140cc360c130ec7d44ae8725b Mon Sep 17 00:00:00 2001
From: Chris Wren 
Date: Wed, 9 May 2012 21:25:57 -0400
Subject: [PATCH 090/132] Auto-expand the top notification.

Bug: 6455789
Change-Id: Ia455f204544ad0c41ace77ea3ece6e0d3d3110d9
---
 packages/SystemUI/res/values/ids.xml          |  1 +
 .../com/android/systemui/ExpandHelper.java    |  2 +
 .../systemui/statusbar/BaseStatusBar.java     | 55 +++++++++++++----
 .../systemui/statusbar/NotificationData.java  | 59 ++++++++++++++++++-
 .../statusbar/phone/PhoneStatusBar.java       |  3 +-
 .../policy/NotificationRowLayout.java         |  9 ++-
 .../statusbar/tablet/TabletStatusBar.java     |  5 ++
 7 files changed, 118 insertions(+), 16 deletions(-)

diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index 2a4c5fd0b23f1..8ebbc520197dd 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -17,4 +17,5 @@
 
 
     
+    
 
diff --git a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
index c5928f1ace73a..7a7afa726f55b 100644
--- a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
@@ -34,6 +34,7 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
         View getChildAtPosition(MotionEvent ev);
         View getChildAtPosition(float x, float y);
         boolean canChildBeExpanded(View v);
+        boolean setUserExpandedChild(View v, boolean userxpanded);
     }
 
     private static final String TAG = "ExpandHelper";
@@ -272,6 +273,7 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
         mScaleAnimation.start();
         mStretching = false;
         setGlow(0f);
+        mCallback.setUserExpandedChild(mCurrView, h == mNaturalHeight);
         if (DEBUG) Log.d(TAG, "scale was finished on view: " + mCurrView);
         clearView();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 50472b884baa6..a310b1deaa77f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -486,17 +486,7 @@ public abstract class BaseStatusBar extends SystemUI implements
         // for blaming (see SwipeHelper.setLongPressListener)
         row.setTag(sbn.pkg);
 
-        // XXX: temporary: while testing big notifications, auto-expand all of them
         ViewGroup.LayoutParams lp = row.getLayoutParams();
-        Boolean expandable = Boolean.FALSE;
-        if (large != null) {
-            lp.height = ViewGroup.LayoutParams.WRAP_CONTENT;
-            expandable = Boolean.TRUE;
-        } else {
-            lp.height = rowHeight;
-        }
-        row.setLayoutParams(lp);
-        row.setTag(R.id.expandable_tag, expandable);
         workAroundBadLayerDrawableOpacity(row);
         View vetoButton = updateNotificationVetoButton(row, sbn);
         vetoButton.setContentDescription(mContext.getString(
@@ -562,10 +552,11 @@ public abstract class BaseStatusBar extends SystemUI implements
 
         applyLegacyRowBackground(sbn, content);
 
+        row.setTag(R.id.expandable_tag, Boolean.valueOf(large != null));
         entry.row = row;
         entry.content = content;
         entry.expanded = expandedOneU;
-        entry.expandedLarge = expandedOneU;
+        entry.setLargeView(expandedLarge);
 
         return true;
     }
@@ -674,6 +665,7 @@ public abstract class BaseStatusBar extends SystemUI implements
         // Remove the expanded view.
         ViewGroup rowParent = (ViewGroup)entry.row.getParent();
         if (rowParent != null) rowParent.removeView(entry.row);
+        updateExpansionStates();
         updateNotificationIcons();
 
         return entry.notification;
@@ -712,16 +704,53 @@ public abstract class BaseStatusBar extends SystemUI implements
         if (DEBUG) {
             Slog.d(TAG, "addNotificationViews: added at " + pos);
         }
+        updateExpansionStates();
         updateNotificationIcons();
 
         return iconView;
     }
 
+    protected boolean expandView(NotificationData.Entry entry, boolean expand) {
+        if (entry.expandable()) {
+            int rowHeight =
+                    mContext.getResources().getDimensionPixelSize(R.dimen.notification_height);
+            ViewGroup.LayoutParams lp = entry.row.getLayoutParams();
+            if (expand) {
+                lp.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+            } else {
+                lp.height = rowHeight;
+            }
+            entry.row.setLayoutParams(lp);
+            return expand;
+        } else {
+            return false;
+        }
+    }
+
+    protected void updateExpansionStates() {
+        int N = mNotificationData.size();
+        for (int i = 0; i < N; i++) {
+            NotificationData.Entry entry = mNotificationData.get(i);
+            if (i == (N-1)) {
+                if (DEBUG) Slog.d(TAG, "expanding top notification at " + i);
+                expandView(entry, true);
+            } else {
+                if (!entry.userExpanded()) {
+                    if (DEBUG) Slog.d(TAG, "collapsing notification at " + i);
+                    expandView(entry, false);
+                } else {
+                    if (DEBUG) Slog.d(TAG, "ignoring user-modified notification at " + i);
+                }
+            }
+        }
+    }
+
     protected abstract void haltTicker();
     protected abstract void setAreThereNotifications();
     protected abstract void updateNotificationIcons();
     protected abstract void tick(IBinder key, StatusBarNotification n, boolean firstTime);
     protected abstract void updateExpandedViewPos(int expandedPosition);
+    protected abstract int getExpandedViewMaxHeight();
 
     protected boolean isTopNotification(ViewGroup parent, NotificationData.Entry entry) {
         return parent.indexOfChild(entry.row) == 0;
@@ -798,6 +827,7 @@ public abstract class BaseStatusBar extends SystemUI implements
                     handleNotificationError(key, notification, "Couldn't update icon: " + ic);
                     return;
                 }
+                updateExpansionStates();
             }
             catch (RuntimeException e) {
                 // It failed to add cleanly.  Log, and remove the view from the panel.
@@ -807,6 +837,9 @@ public abstract class BaseStatusBar extends SystemUI implements
             }
         } else {
             if (DEBUG) Slog.d(TAG, "not reusing notification for key: " + key);
+            if (DEBUG) Slog.d(TAG, "contents was " + (contentsUnchanged ? "unchanged" : "changed"));
+            if (DEBUG) Slog.d(TAG, "order was " + (orderUnchanged ? "unchanged" : "changed"));
+            if (DEBUG) Slog.d(TAG, "notification is " + (isTopAnyway ? "top" : "not top"));
             removeNotificationViews(key);
             addNotificationViews(key, notification);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index 3ff85d9bff007..1a07ed3775727 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -22,6 +22,7 @@ import android.view.View;
 import android.widget.ImageView;
 
 import com.android.internal.statusbar.StatusBarNotification;
+import com.android.systemui.R;
 
 import java.util.Comparator;
 import java.util.ArrayList;
@@ -38,13 +39,32 @@ public class NotificationData {
         public View content; // takes the click events and sends the PendingIntent
         public View expanded; // the inflated RemoteViews
         public ImageView largeIcon;
-        public View expandedLarge;
+        protected View expandedLarge;
         public Entry() {}
         public Entry(IBinder key, StatusBarNotification n, StatusBarIconView ic) {
             this.key = key;
             this.notification = n;
             this.icon = ic;
         }
+        public void setLargeView(View expandedLarge) {
+            this.expandedLarge = expandedLarge;
+            writeBooleanTag(row, R.id.expandable_tag, expandedLarge != null);
+        }
+        public View getLargeView() {
+            return expandedLarge;
+        }
+        /**
+         * Return whether the entry can be expanded.
+         */
+        public boolean expandable() {
+            return NotificationData.getIsExpandable(row);
+        }
+        /**
+         * Return whether the entry has been manually expanded by the user.
+         */
+        public boolean userExpanded() {
+            return NotificationData.getUserExpanded(row);
+        }
     }
     private final ArrayList mEntries = new ArrayList();
     private final Comparator mEntryCmp = new Comparator() {
@@ -134,4 +154,41 @@ public class NotificationData {
         }
         return false;
     }
+
+    protected static boolean readBooleanTag(View view, int id)  {
+        if (view != null) {
+            Object value = view.getTag(id);
+            return value != null && value instanceof Boolean && ((Boolean) value).booleanValue();
+        }
+        return false;
+    }
+
+    protected static boolean writeBooleanTag(View view, int id, boolean value)  {
+        if (view != null) {
+            view.setTag(id, Boolean.valueOf(value));
+            return value;
+        }
+        return false;
+    }
+
+    /**
+     * Return whether the entry can be expanded.
+     */
+    public static boolean getIsExpandable(View row) {
+        return readBooleanTag(row, R.id.expandable_tag);
+    }
+
+    /**
+     * Return whether the entry has been manually expanded by the user.
+     */
+    public static boolean getUserExpanded(View row) {
+        return readBooleanTag(row, R.id.user_expanded_tag);
+    }
+
+    /**
+     * Set whether the entry has been manually expanded by the user.
+     */
+    public static boolean setUserExpanded(View row, boolean userExpanded) {
+        return writeBooleanTag(row, R.id.user_expanded_tag, userExpanded);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index f1dd183295018..d3fbdabd340f0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -1771,7 +1771,8 @@ public class PhoneStatusBar extends BaseStatusBar {
         return a < 0f ? 0f : (a > 1f ? 1f : a);
     }
 
-    int getExpandedViewMaxHeight() {
+    @Override
+    protected int getExpandedViewMaxHeight() {
         return mDisplayMetrics.heightPixels - mNotificationPanelMarginBottomPx;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
index 03dfd1c19a24d..0fe7a0a1b2126 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
@@ -39,6 +39,7 @@ import com.android.systemui.ExpandHelper;
 import com.android.systemui.Gefingerpoken;
 import com.android.systemui.R;
 import com.android.systemui.SwipeHelper;
+import com.android.systemui.statusbar.NotificationData;
 
 import java.util.HashMap;
 
@@ -175,9 +176,11 @@ public class NotificationRowLayout
     }
 
     public boolean canChildBeExpanded(View v) {
-        Object isExpandable = v.getTag(R.id.expandable_tag);
-        return isExpandable != null && isExpandable instanceof Boolean &&
-                ((Boolean)isExpandable).booleanValue();
+        return NotificationData.getIsExpandable(v);
+    }
+
+    public boolean setUserExpandedChild(View v, boolean userExpanded) {
+        return NotificationData.setUserExpanded(v, userExpanded);
     }
 
     public void onChildDismissed(View v) {
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 9c48f06d15e25..906d1aae696c6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -348,6 +348,11 @@ public class TabletStatusBar extends BaseStatusBar implements
         scroller.setFillViewport(true);
     }
 
+    @Override
+    protected int getExpandedViewMaxHeight() {
+        return getNotificationPanelHeight();
+    }
+
     private int getNotificationPanelHeight() {
         final Resources res = mContext.getResources();
         final Display d = WindowManagerImpl.getDefault().getDefaultDisplay();

From 621b800c78a0b274fa0b2c34eb30cf8c1d48b04d Mon Sep 17 00:00:00 2001
From: Kenny Root 
Date: Thu, 10 May 2012 10:21:06 -0700
Subject: [PATCH 091/132] Use long instead of int for file offsets

Use long instead of int so we don't run into a 2GB file limit.

Fix possible overflows in offset and length.

Change-Id: Idb3a34f5600f9c2372b9c89256f21757049fa43b
---
 .../content/pm/ContainerEncryptionParams.java | 28 ++++++++++---------
 .../content/pm/LimitedLengthInputStream.java  | 26 ++++++++++++-----
 .../pm/LimitedLengthInputStreamTest.java      | 12 +++++++-
 .../defcontainer/DefaultContainerService.java | 25 ++++++++++++-----
 4 files changed, 63 insertions(+), 28 deletions(-)

diff --git a/core/java/android/content/pm/ContainerEncryptionParams.java b/core/java/android/content/pm/ContainerEncryptionParams.java
index 5b1440d907d5c..88112a751b352 100644
--- a/core/java/android/content/pm/ContainerEncryptionParams.java
+++ b/core/java/android/content/pm/ContainerEncryptionParams.java
@@ -70,16 +70,16 @@ public class ContainerEncryptionParams implements Parcelable {
     private final byte[] mMacTag;
 
     /** Offset into file where authenticated (e.g., MAC protected) data begins. */
-    private final int mAuthenticatedDataStart;
+    private final long mAuthenticatedDataStart;
 
     /** Offset into file where encrypted data begins. */
-    private final int mEncryptedDataStart;
+    private final long mEncryptedDataStart;
 
     /**
      * Offset into file for the end of encrypted data (and, by extension,
      * authenticated data) in file.
      */
-    private final int mDataEnd;
+    private final long mDataEnd;
 
     public ContainerEncryptionParams(String encryptionAlgorithm,
             AlgorithmParameterSpec encryptionSpec, SecretKey encryptionKey)
@@ -99,6 +99,8 @@ public class ContainerEncryptionParams implements Parcelable {
      * @param macAlgorithm MAC algorithm to use; format matches JCE
      * @param macSpec algorithm parameters specification, may be {@code null}
      * @param macKey key used for authentication (i.e., for the MAC tag)
+     * @param macTag message authentication code (MAC) tag for the authenticated
+     *            data
      * @param authenticatedDataStart offset of start of authenticated data in
      *            stream
      * @param encryptedDataStart offset of start of encrypted data in stream
@@ -109,7 +111,7 @@ public class ContainerEncryptionParams implements Parcelable {
     public ContainerEncryptionParams(String encryptionAlgorithm,
             AlgorithmParameterSpec encryptionSpec, SecretKey encryptionKey, String macAlgorithm,
             AlgorithmParameterSpec macSpec, SecretKey macKey, byte[] macTag,
-            int authenticatedDataStart, int encryptedDataStart, int dataEnd)
+            long authenticatedDataStart, long encryptedDataStart, long dataEnd)
             throws InvalidAlgorithmParameterException {
         if (TextUtils.isEmpty(encryptionAlgorithm)) {
             throw new NullPointerException("algorithm == null");
@@ -172,15 +174,15 @@ public class ContainerEncryptionParams implements Parcelable {
         return mMacTag;
     }
 
-    public int getAuthenticatedDataStart() {
+    public long getAuthenticatedDataStart() {
         return mAuthenticatedDataStart;
     }
 
-    public int getEncryptedDataStart() {
+    public long getEncryptedDataStart() {
         return mEncryptedDataStart;
     }
 
-    public int getDataEnd() {
+    public long getDataEnd() {
         return mDataEnd;
     }
 
@@ -315,9 +317,9 @@ public class ContainerEncryptionParams implements Parcelable {
 
         dest.writeByteArray(mMacTag);
 
-        dest.writeInt(mAuthenticatedDataStart);
-        dest.writeInt(mEncryptedDataStart);
-        dest.writeInt(mDataEnd);
+        dest.writeLong(mAuthenticatedDataStart);
+        dest.writeLong(mEncryptedDataStart);
+        dest.writeLong(mDataEnd);
     }
 
     private ContainerEncryptionParams(Parcel source) throws InvalidAlgorithmParameterException {
@@ -333,9 +335,9 @@ public class ContainerEncryptionParams implements Parcelable {
 
         mMacTag = source.createByteArray();
 
-        mAuthenticatedDataStart = source.readInt();
-        mEncryptedDataStart = source.readInt();
-        mDataEnd = source.readInt();
+        mAuthenticatedDataStart = source.readLong();
+        mEncryptedDataStart = source.readLong();
+        mDataEnd = source.readLong();
 
         switch (encParamType) {
             case ENC_PARAMS_IV_PARAMETERS:
diff --git a/core/java/android/content/pm/LimitedLengthInputStream.java b/core/java/android/content/pm/LimitedLengthInputStream.java
index 25a490f66f686..e78727718cbd0 100644
--- a/core/java/android/content/pm/LimitedLengthInputStream.java
+++ b/core/java/android/content/pm/LimitedLengthInputStream.java
@@ -3,6 +3,7 @@ package android.content.pm;
 import java.io.FilterInputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.Arrays;
 
 /**
  * A class that limits the amount of data that is read from an InputStream. When
@@ -15,20 +16,20 @@ public class LimitedLengthInputStream extends FilterInputStream {
     /**
      * The end of the stream where we don't want to allow more data to be read.
      */
-    private final int mEnd;
+    private final long mEnd;
 
     /**
      * Current offset in the stream.
      */
-    private int mOffset;
+    private long mOffset;
 
     /**
      * @param in underlying stream to wrap
      * @param offset offset into stream where data starts
      * @param length length of data at offset
-     * @throws IOException if an error occured with the underlying stream
+     * @throws IOException if an error occurred with the underlying stream
      */
-    public LimitedLengthInputStream(InputStream in, int offset, int length) throws IOException {
+    public LimitedLengthInputStream(InputStream in, long offset, long length) throws IOException {
         super(in);
 
         if (in == null) {
@@ -36,11 +37,15 @@ public class LimitedLengthInputStream extends FilterInputStream {
         }
 
         if (offset < 0) {
-            throw new IOException("offset == " + offset);
+            throw new IOException("offset < 0");
         }
 
         if (length < 0) {
-            throw new IOException("length must be non-negative; is " + length);
+            throw new IOException("length < 0");
+        }
+
+        if (length > Long.MAX_VALUE - offset) {
+            throw new IOException("offset + length > Long.MAX_VALUE");
         }
 
         mEnd = offset + length;
@@ -65,8 +70,15 @@ public class LimitedLengthInputStream extends FilterInputStream {
             return -1;
         }
 
+        final int arrayLength = buffer.length;
+        Arrays.checkOffsetAndCount(arrayLength, offset, byteCount);
+
+        if (mOffset > Long.MAX_VALUE - byteCount) {
+            throw new IOException("offset out of bounds: " + mOffset + " + " + byteCount);
+        }
+
         if (mOffset + byteCount > mEnd) {
-            byteCount = mEnd - mOffset;
+            byteCount = (int) (mEnd - mOffset);
         }
 
         final int numRead = super.read(buffer, offset, byteCount);
diff --git a/core/tests/coretests/src/android/content/pm/LimitedLengthInputStreamTest.java b/core/tests/coretests/src/android/content/pm/LimitedLengthInputStreamTest.java
index 0a0152b83b62a..1f762fdc49f4e 100644
--- a/core/tests/coretests/src/android/content/pm/LimitedLengthInputStreamTest.java
+++ b/core/tests/coretests/src/android/content/pm/LimitedLengthInputStreamTest.java
@@ -66,6 +66,17 @@ public class LimitedLengthInputStreamTest extends AndroidTestCase {
         }
     }
 
+    @MediumTest
+    public void testConstructor_OffsetLengthOverflow_Fail() throws Exception {
+        try {
+        InputStream is = new LimitedLengthInputStream(mTestStream1, Long.MAX_VALUE - 1,
+                Long.MAX_VALUE - 1);
+            fail("Should fail when offset + length is > Long.MAX_VALUE");
+        } catch (IOException e) {
+            // success
+        }
+    }
+
     private void checkReadBytesWithOffsetAndLength_WithString1(int offset, int length)
             throws Exception {
         byte[] temp = new byte[TEST_STRING1.length];
@@ -182,5 +193,4 @@ public class LimitedLengthInputStreamTest extends AndroidTestCase {
     public void testSingleByteRead_NonZeroOffset_FullLength_Success() throws Exception {
         checkSingleByteRead_WithString1(3, TEST_STRING1.length - 3);
     }
-
 }
diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
index 17e5f4ee97085..3b87b963be39a 100644
--- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
+++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
@@ -473,6 +473,8 @@ public class DefaultContainerService extends IntentService {
     }
 
     private static class ApkContainer {
+        private static final int MAX_AUTHENTICATED_DATA_SIZE = 16384;
+
         private final InputStream mInStream;
 
         private MacAuthenticatedInputStream mAuthenticatedStream;
@@ -540,26 +542,35 @@ public class DefaultContainerService extends IntentService {
                 throw new IOException(e);
             }
 
-            final int encStart = encryptionParams.getEncryptedDataStart();
-            final int end = encryptionParams.getDataEnd();
+            final long encStart = encryptionParams.getEncryptedDataStart();
+            final long end = encryptionParams.getDataEnd();
             if (end < encStart) {
                 throw new IOException("end <= encStart");
             }
 
             final Mac mac = getMacInstance(encryptionParams);
             if (mac != null) {
-                final int macStart = encryptionParams.getAuthenticatedDataStart();
+                final long macStart = encryptionParams.getAuthenticatedDataStart();
+                if (macStart >= Integer.MAX_VALUE) {
+                    throw new IOException("macStart >= Integer.MAX_VALUE");
+                }
 
-                final int furtherOffset;
+                final long furtherOffset;
                 if (macStart >= 0 && encStart >= 0 && macStart < encStart) {
                     /*
                      * If there is authenticated data at the beginning, read
                      * that into our MAC first.
                      */
-                    final int authenticatedLength = encStart - macStart;
-                    final byte[] authenticatedData = new byte[authenticatedLength];
+                    final long authenticatedLengthLong = encStart - macStart;
+                    if (authenticatedLengthLong > MAX_AUTHENTICATED_DATA_SIZE) {
+                        throw new IOException("authenticated data is too long");
+                    }
+                    final int authenticatedLength = (int) authenticatedLengthLong;
 
-                    Streams.readFully(inStream, authenticatedData, macStart, authenticatedLength);
+                    final byte[] authenticatedData = new byte[(int) authenticatedLength];
+
+                    Streams.readFully(inStream, authenticatedData, (int) macStart,
+                            authenticatedLength);
                     mac.update(authenticatedData, 0, authenticatedLength);
 
                     furtherOffset = 0;

From 38d32d7ee1cceea763c862cda1e167237f146eca Mon Sep 17 00:00:00 2001
From: Daniel Sandler 
Date: Thu, 10 May 2012 16:20:40 -0400
Subject: [PATCH 092/132] Restyling action buttons.

Bug: 6418617
Change-Id: I843352fbd167aeb6cc7beb0172b7416aabd5856a
---
 core/java/android/app/Notification.java     | 11 ++++++++++-
 core/res/res/layout/notification_action.xml |  1 +
 2 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index edeeee263d8ca..09d24e38f452c 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1490,7 +1490,16 @@ public class Notification implements Parcelable
             RemoteViews button = new RemoteViews(mContext.getPackageName(), R.layout.notification_action);
             button.setTextViewCompoundDrawables(R.id.action0, action.icon, 0, 0, 0);
             button.setTextViewText(R.id.action0, action.title);
-            button.setOnClickPendingIntent(R.id.action0, action.actionIntent);
+            if (action.actionIntent != null) {
+                button.setOnClickPendingIntent(R.id.action0, action.actionIntent);
+                //button.setBoolean(R.id.action0, "setEnabled", true);
+                button.setFloat(R.id.button0, "setAlpha", 1.0f);
+                button.setBoolean(R.id.button0, "setClickable", true);
+            } else {
+                //button.setBoolean(R.id.action0, "setEnabled", false);
+                button.setFloat(R.id.button0, "setAlpha", 0.5f);
+                button.setBoolean(R.id.button0, "setClickable", false);
+            }
             button.setContentDescription(R.id.action0, action.title);
             return button;
         }
diff --git a/core/res/res/layout/notification_action.xml b/core/res/res/layout/notification_action.xml
index 36982caae1fea..28812a9dd413b 100644
--- a/core/res/res/layout/notification_action.xml
+++ b/core/res/res/layout/notification_action.xml
@@ -15,6 +15,7 @@
 -->