From 6cdde8311edab1d2f4eabc8f20a7bc45647bcb16 Mon Sep 17 00:00:00 2001 From: Chris Craik Date: Tue, 17 Dec 2013 15:07:47 -0800 Subject: [PATCH 001/119] Check mDisplayListData before deref bug:12191897 Change-Id: I72ed3801e72c657b9d7736b0efb33c5e7cfd5b57 --- libs/hwui/DisplayList.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp index de2106c0d2c5c..d2aa061949cf4 100644 --- a/libs/hwui/DisplayList.cpp +++ b/libs/hwui/DisplayList.cpp @@ -494,7 +494,8 @@ void DisplayList::applyViewPropertyTransforms(mat4& matrix) { */ void DisplayList::computeOrdering() { ATRACE_CALL(); - mat4::identity(); + if (mDisplayListData == NULL) return; + for (unsigned int i = 0; i < mDisplayListData->children.size(); i++) { DrawDisplayListOp* childOp = mDisplayListData->children[i]; childOp->mDisplayList->computeOrderingImpl(childOp, &m3dNodes, &mat4::identity()); @@ -505,6 +506,7 @@ void DisplayList::computeOrderingImpl( DrawDisplayListOp* opState, KeyedVector >* compositedChildrenOf3dRoot, const mat4* transformFrom3dRoot) { + // TODO: should avoid this calculation in most cases opState->mTransformFrom3dRoot.load(*transformFrom3dRoot); opState->mTransformFrom3dRoot.multiply(opState->mTransformFromParent); @@ -537,7 +539,7 @@ void DisplayList::computeOrderingImpl( transformFrom3dRoot = &(opState->mTransformFrom3dRoot); } - if (mDisplayListData->children.size() > 0) { + if (mDisplayListData != NULL && mDisplayListData->children.size() > 0) { for (unsigned int i = 0; i < mDisplayListData->children.size(); i++) { DrawDisplayListOp* childOp = mDisplayListData->children[i]; childOp->mDisplayList->computeOrderingImpl(childOp, From 11e5f6ba29e3e351fe9c388bd79fce1829018885 Mon Sep 17 00:00:00 2001 From: Alan Viverette Date: Tue, 7 Jan 2014 20:28:56 +0000 Subject: [PATCH 002/119] Revert "Allow Views to specify a theme override" Inheriting the parent view's Context breaks RemoteView inflation. This reverts commit dd9233253b88d86473403d5b63c72e223b5e40bd. Change-Id: I1c9a940a31169cd42b7356ad58548597a2efbb24 --- core/java/android/view/LayoutInflater.java | 41 +++++----------------- 1 file changed, 9 insertions(+), 32 deletions(-) diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java index 32c98855f9ac4..aa43bad85a36a 100644 --- a/core/java/android/view/LayoutInflater.java +++ b/core/java/android/view/LayoutInflater.java @@ -91,8 +91,6 @@ public abstract class LayoutInflater { private static final String TAG_1995 = "blink"; private static final String TAG_REQUEST_FOCUS = "requestFocus"; - private static final String ATTR_THEME = "theme"; - /** * Hook to allow clients of the LayoutInflater to restrict the set of Views that are allowed * to be inflated. @@ -679,44 +677,23 @@ public abstract class LayoutInflater { name = attrs.getAttributeValue(null, "class"); } - // Apply a theme override, if necessary. - final Context viewContext; - final int themeResId = attrs.getAttributeResourceValue(null, ATTR_THEME, 0); - if (themeResId != 0) { - viewContext = new ContextThemeWrapper(mContext, themeResId); - } else if (parent != null) { - viewContext = parent.getContext(); - } else { - viewContext = mContext; - } - if (DEBUG) System.out.println("******** Creating view: " + name); try { View view; - if (mFactory2 != null) { - view = mFactory2.onCreateView(parent, name, viewContext, attrs); - } else if (mFactory != null) { - view = mFactory.onCreateView(name, viewContext, attrs); - } else { - view = null; - } + if (mFactory2 != null) view = mFactory2.onCreateView(parent, name, mContext, attrs); + else if (mFactory != null) view = mFactory.onCreateView(name, mContext, attrs); + else view = null; if (view == null && mPrivateFactory != null) { - view = mPrivateFactory.onCreateView(parent, name, viewContext, attrs); + view = mPrivateFactory.onCreateView(parent, name, mContext, attrs); } - + if (view == null) { - final Object lastContext = mConstructorArgs[0]; - mConstructorArgs[0] = viewContext; - try { - if (-1 == name.indexOf('.')) { - view = onCreateView(parent, name, attrs); - } else { - view = createView(name, null, attrs); - } - } finally { - mConstructorArgs[0] = lastContext; + if (-1 == name.indexOf('.')) { + view = onCreateView(parent, name, attrs); + } else { + view = createView(name, null, attrs); } } From 8682e6f57175db64c85a70c96cb4258191541e51 Mon Sep 17 00:00:00 2001 From: Craig Mautner Date: Fri, 10 Jan 2014 10:16:43 -0800 Subject: [PATCH 003/119] Allow for the possibility of null ActivityContainer When BinderProxy is passed in as the IBinder for getEnclosingActivityContainer the activity manager cannot turn it into an ActivityRecord. This causes NPE in ActivityThread which is Not Good (tm). Allowing null to be returned when requesting an ActivityContainer and handling it appropriately fixes this bug. Fixes bug 12473669. Change-Id: I6937636042f8853b3ddc2df40be010e7391e41a5 --- .../android/app/ActivityManagerNative.java | 32 +++++++++++++++---- core/java/android/app/ActivityThread.java | 3 +- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index 3bc2ee60c10ad..7b81713c0fccc 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -2027,7 +2027,12 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM IActivityContainer activityContainer = createActivityContainer(parentActivityToken, callback); reply.writeNoException(); - reply.writeStrongBinder(activityContainer.asBinder()); + if (activityContainer != null) { + reply.writeInt(1); + reply.writeStrongBinder(activityContainer.asBinder()); + } else { + reply.writeInt(0); + } return true; } @@ -2036,7 +2041,12 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM IBinder activityToken = data.readStrongBinder(); IActivityContainer activityContainer = getEnclosingActivityContainer(activityToken); reply.writeNoException(); - reply.writeStrongBinder(activityContainer.asBinder()); + if (activityContainer != null) { + reply.writeInt(1); + reply.writeStrongBinder(activityContainer.asBinder()); + } else { + reply.writeInt(0); + } return true; } @@ -4670,8 +4680,13 @@ class ActivityManagerProxy implements IActivityManager data.writeStrongBinder((IBinder)callback); mRemote.transact(CREATE_ACTIVITY_CONTAINER_TRANSACTION, data, reply, 0); reply.readException(); - IActivityContainer res = - IActivityContainer.Stub.asInterface(reply.readStrongBinder()); + final int result = reply.readInt(); + final IActivityContainer res; + if (result == 1) { + res = IActivityContainer.Stub.asInterface(reply.readStrongBinder()); + } else { + res = null; + } data.recycle(); reply.recycle(); return res; @@ -4685,8 +4700,13 @@ class ActivityManagerProxy implements IActivityManager data.writeStrongBinder(activityToken); mRemote.transact(GET_ACTIVITY_CONTAINER_TRANSACTION, data, reply, 0); reply.readException(); - IActivityContainer res = - IActivityContainer.Stub.asInterface(reply.readStrongBinder()); + final int result = reply.readInt(); + final IActivityContainer res; + if (result == 1) { + res = IActivityContainer.Stub.asInterface(reply.readStrongBinder()); + } else { + res = null; + } data.recycle(); reply.recycle(); return res; diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 94ebff97d496e..5239cc6d3af45 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -2235,7 +2235,8 @@ public final class ActivityThread { try { IActivityContainer container = ActivityManagerNative.getDefault().getEnclosingActivityContainer(r.token); - final int displayId = container.getDisplayId(); + final int displayId = + container == null ? Display.DEFAULT_DISPLAY : container.getDisplayId(); if (displayId > Display.DEFAULT_DISPLAY) { Display display = dm.getRealDisplay(displayId, r.token); baseContext = appContext.createDisplayContext(display); From bfb577e58a373243bf584a3c8703a3ce56b241b2 Mon Sep 17 00:00:00 2001 From: Craig Mautner Date: Fri, 10 Jan 2014 08:40:23 -0800 Subject: [PATCH 004/119] Call moveHomeStack before moving any stack. Order matters, otherwise mFocusedStack and mLastStack aren't updated correctly. Fixes bug 12478856. Change-Id: I12e4334678bb3af49d1ff26c4003def3e8d987c2 --- services/core/java/com/android/server/am/ActivityStack.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 125621a20a9cc..6078611f69834 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -458,11 +458,11 @@ final class ActivityStack { final void moveToFront() { if (isAttached()) { - mStacks.remove(this); - mStacks.add(this); if (isOnHomeDisplay()) { mStackSupervisor.moveHomeStack(isHomeStack()); } + mStacks.remove(this); + mStacks.add(this); } } From 86b846213a8ee456494a09e72d6a13881e8632da Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Mon, 13 Jan 2014 10:19:17 -0800 Subject: [PATCH 005/119] libjhead_jni is still needed protip: do not remove things from makefiles just because it builds without them b/12528751 Change-Id: I3ef8dcdf638e8b59d309922bb972c893fc75a712 --- media/jni/Android.mk | 3 +++ 1 file changed, 3 insertions(+) diff --git a/media/jni/Android.mk b/media/jni/Android.mk index a45051c93df3b..dea971e4cfbcc 100644 --- a/media/jni/Android.mk +++ b/media/jni/Android.mk @@ -40,6 +40,9 @@ LOCAL_SHARED_LIBRARIES := \ libexif \ libstagefright_amrnb_common \ +LOCAL_REQUIRED_MODULES := \ + libjhead_jni + LOCAL_STATIC_LIBRARIES := \ libstagefright_amrnbenc From dae0ff1ec29203dda2d143794c3acbe647a52574 Mon Sep 17 00:00:00 2001 From: Alan Viverette Date: Thu, 16 Jan 2014 11:02:55 -0800 Subject: [PATCH 006/119] Revert changes to default styles and themes Partial revert of commit 65f31d4104a0b667b635abc78406d5159341ad95. BUG: 12571939 Change-Id: Ideea7b716d5a7b2082a244b9c5ffb02151ee8d67 --- .../res/res/values/styles_device_defaults.xml | 941 +++++++++++++----- .../res/res/values/themes_device_defaults.xml | 82 +- 2 files changed, 746 insertions(+), 277 deletions(-) diff --git a/core/res/res/values/styles_device_defaults.xml b/core/res/res/values/styles_device_defaults.xml index 4acafad582353..512c9b8bd8ae7 100644 --- a/core/res/res/values/styles_device_defaults.xml +++ b/core/res/res/values/styles_device_defaults.xml @@ -32,262 +32,731 @@ easier. --> - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + - + - + - + - + - + + + + + + + + + + + + + + + + + - - - - - - - - - - - - @@ -453,7 +453,7 @@ easier. - - - - @@ -496,65 +496,65 @@ easier. - - - - - - - - - - - - - - - - - From 735683271c89ba25aa15f90077e6697903ebef13 Mon Sep 17 00:00:00 2001 From: Adam Powell Date: Tue, 21 Jan 2014 18:39:53 +0000 Subject: [PATCH 007/119] Revert "Update smoothScrollToPosition to move faster for large offsets" This reverts commit 203af24e4c2975c0b95fb4cc85ea03865e3b0e5b. Change-Id: Ic56a9ded03eec188fb2834b42b60171f3cacb58b --- api/current.txt | 4 +- core/java/android/widget/AbsListView.java | 326 +--------------------- core/java/android/widget/GridView.java | 10 - core/java/android/widget/ListView.java | 117 +++----- 4 files changed, 48 insertions(+), 409 deletions(-) diff --git a/api/current.txt b/api/current.txt index a057cb216ea49..6169857425b24 100644 --- a/api/current.txt +++ b/api/current.txt @@ -31482,12 +31482,10 @@ package android.widget { method public int getCheckedItemPosition(); method public android.util.SparseBooleanArray getCheckedItemPositions(); method public int getChoiceMode(); - method public int getFirstPositionForRow(int); method public int getListPaddingBottom(); method public int getListPaddingLeft(); method public int getListPaddingRight(); method public int getListPaddingTop(); - method public int getRowForPosition(int); method public android.view.View getSelectedView(); method public android.graphics.drawable.Drawable getSelector(); method public java.lang.CharSequence getTextFilter(); @@ -31533,7 +31531,6 @@ package android.widget { method public void setRemoteViewsAdapter(android.content.Intent); method public void setScrollIndicators(android.view.View, android.view.View); method public void setScrollingCacheEnabled(boolean); - method public void setSelectionFromTop(int, int); method public void setSelector(int); method public void setSelector(android.graphics.drawable.Drawable); method public void setSmoothScrollbarEnabled(boolean); @@ -32649,6 +32646,7 @@ package android.widget { method public void setOverscrollHeader(android.graphics.drawable.Drawable); method public void setSelection(int); method public void setSelectionAfterHeaderView(); + method public void setSelectionFromTop(int, int); method public void smoothScrollByOffset(int); } diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index e9107d67597e8..4d8975cdcbede 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -36,7 +36,6 @@ import android.text.TextWatcher; import android.util.AttributeSet; import android.util.Log; import android.util.LongSparseArray; -import android.util.MathUtils; import android.util.SparseArray; import android.util.SparseBooleanArray; import android.util.StateSet; @@ -61,8 +60,6 @@ import android.view.ViewTreeObserver; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityNodeInfo; -import android.view.animation.AccelerateDecelerateInterpolator; -import android.view.animation.AnimationUtils; import android.view.animation.Interpolator; import android.view.animation.LinearInterpolator; import android.view.inputmethod.BaseInputConnection; @@ -421,7 +418,7 @@ public abstract class AbsListView extends AdapterView implements Te /** * Handles scrolling between positions within the list. */ - SubPositionScroller mPositionScroller; + PositionScroller mPositionScroller; /** * The offset in pixels form the top of the AdapterView to the top @@ -4843,14 +4840,14 @@ public abstract class AbsListView extends AdapterView implements Te */ public void smoothScrollToPosition(int position) { if (mPositionScroller == null) { - mPositionScroller = new SubPositionScroller(); + mPositionScroller = new PositionScroller(); } mPositionScroller.start(position); } /** * Smoothly scroll to the specified adapter position. The view will scroll - * such that the indicated position is displayed offset pixels below + * such that the indicated position is displayed offset pixels from * the top edge of the view. If this is impossible, (e.g. the offset would scroll * the first or last item beyond the boundaries of the list) it will get as close * as possible. The scroll will take duration milliseconds to complete. @@ -4862,14 +4859,14 @@ public abstract class AbsListView extends AdapterView implements Te */ public void smoothScrollToPositionFromTop(int position, int offset, int duration) { if (mPositionScroller == null) { - mPositionScroller = new SubPositionScroller(); + mPositionScroller = new PositionScroller(); } mPositionScroller.startWithOffset(position, offset, duration); } /** * Smoothly scroll to the specified adapter position. The view will scroll - * such that the indicated position is displayed offset pixels below + * such that the indicated position is displayed offset pixels from * the top edge of the view. If this is impossible, (e.g. the offset would scroll * the first or last item beyond the boundaries of the list) it will get as close * as possible. @@ -4880,9 +4877,9 @@ public abstract class AbsListView extends AdapterView implements Te */ public void smoothScrollToPositionFromTop(int position, int offset) { if (mPositionScroller == null) { - mPositionScroller = new SubPositionScroller(); + mPositionScroller = new PositionScroller(); } - mPositionScroller.startWithOffset(position, offset, offset); + mPositionScroller.startWithOffset(position, offset); } /** @@ -4896,7 +4893,7 @@ public abstract class AbsListView extends AdapterView implements Te */ public void smoothScrollToPosition(int position, int boundPosition) { if (mPositionScroller == null) { - mPositionScroller = new SubPositionScroller(); + mPositionScroller = new PositionScroller(); } mPositionScroller.start(position, boundPosition); } @@ -6995,311 +6992,4 @@ public abstract class AbsListView extends AdapterView implements Te return null; } } - - /** - * Returns the height of a row, which is computed as the maximum height of - * the items in the row. - * - * @param row the row index - * @return row height in pixels - */ - private int getHeightForRow(int row) { - final int firstRowPosition = getFirstPositionForRow(row); - final int lastRowPosition = getFirstPositionForRow(row + 1); - int maxHeight = 0; - for (int i = firstRowPosition; i < lastRowPosition; i++) { - final int height = getHeightForPosition(i); - if (height > maxHeight) { - maxHeight = height; - } - } - return maxHeight; - } - - /** - * Returns the height of the view for the specified position. - * - * @param position the item position - * @return view height in pixels - */ - int getHeightForPosition(int position) { - final int firstVisiblePosition = getFirstVisiblePosition(); - final int childCount = getChildCount(); - final int index = position - firstVisiblePosition; - if (position >= 0 && position < childCount) { - final View view = getChildAt(index); - return view.getHeight(); - } else { - final View view = obtainView(position, mIsScrap); - view.measure(mWidthMeasureSpec, MeasureSpec.UNSPECIFIED); - final int height = view.getMeasuredHeight(); - mRecycler.addScrapView(view, position); - return height; - } - } - - /** - * Returns the row for the specified item position. - * - * @param position the item position - * @return the row index - */ - public int getRowForPosition(int position) { - return position; - } - - /** - * Returns the first item position within the specified row. - * - * @param row the row - * @return the item position - */ - public int getFirstPositionForRow(int row) { - return row; - } - - /** - * Sets the selected item and positions the selection y pixels from the top edge - * of the ListView. (If in touch mode, the item will not be selected but it will - * still be positioned appropriately.) - * - * @param position Index (starting at 0) of the data item to be selected. - * @param y The distance from the top edge of the ListView (plus padding) that the - * item will be positioned. - */ - public void setSelectionFromTop(int position, int y) { - if (mAdapter == null) { - return; - } - - if (!isInTouchMode()) { - position = lookForSelectablePosition(position, true); - if (position >= 0) { - setNextSelectedPositionInt(position); - } - } else { - mResurrectToPosition = position; - } - - if (position >= 0) { - mLayoutMode = LAYOUT_SPECIFIC; - mSpecificTop = mListPadding.top + y; - - if (mNeedSync) { - mSyncPosition = position; - mSyncRowId = mAdapter.getItemId(position); - } - - if (mPositionScroller != null) { - mPositionScroller.stop(); - } - requestLayout(); - } - } - - class SubPositionScroller { - private static final int DEFAULT_SCROLL_DURATION = 200; - - private SubScroller mSubScroller; - private int mOffset; - - /** - * Scroll the minimum amount to get the target view entirely on-screen. - */ - private void scrollToPosition(final int targetPosition, final boolean useOffset, - final int offset, final int boundPosition, final int duration) { - stop(); - - if (mDataChanged) { - // Wait until we're back in a stable state to try this. - mPositionScrollAfterLayout = new Runnable() { - @Override - public void run() { - scrollToPosition( - targetPosition, useOffset, offset, boundPosition, duration); - } - }; - return; - } - - final int firstPosition = getFirstVisiblePosition(); - final int lastPosition = firstPosition + getChildCount(); - final int targetRow = getRowForPosition(targetPosition); - final int firstRow = getRowForPosition(firstPosition); - final int lastRow = getRowForPosition(lastPosition); - if (useOffset || targetRow <= firstRow) { - mOffset = offset; - } else if (targetRow >= lastRow - 1) { - final int listHeight = getHeight() - getPaddingTop() - getPaddingBottom(); - mOffset = listHeight - getHeightForPosition(targetPosition); - } else { - // Don't scroll, target is entirely on-screen. - return; - } - - float endSubRow = targetRow; - if (boundPosition != INVALID_POSITION) { - final int boundRow = getRowForPosition(boundPosition); - if (boundRow >= firstRow && boundRow < lastRow) { - endSubRow = computeBoundSubRow(targetRow, boundRow); - } - } - - final View firstChild = getChildAt(0); - final float startOffsetRatio = -firstChild.getTop() / (float) firstChild.getHeight(); - final float startSubRow = firstRow + startOffsetRatio; - if (startSubRow == endSubRow && mOffset == 0) { - // Don't scroll, target is already in position. - return; - } - - if (mSubScroller == null) { - mSubScroller = new SubScroller(); - } - mSubScroller.startScroll(startSubRow, endSubRow, duration); - - postOnAnimation(mAnimationFrame); - } - - private float computeBoundSubRow(int targetRow, int boundRow) { - // Compute the target and offset as a sub-position. - int remainingOffset = mOffset; - int targetHeight = getHeightForRow(targetRow - 1); - while (remainingOffset > 0) { - remainingOffset -= targetHeight; - targetRow--; - targetHeight = getHeightForRow(targetRow - 1); - } - final float targetSubRow = targetRow - remainingOffset / targetHeight; - mOffset = 0; - - if (targetSubRow >= boundRow) { - // End position would push the bound position above the list. - return boundRow; - } - - // Compute the closest possible sub-position that wouldn't push the - // bound position's view further below the list. - final int listHeight = getHeight() - getPaddingTop() - getPaddingBottom(); - final int boundHeight = getHeightForRow(boundRow); - int endRow = boundRow; - int totalHeight = boundHeight; - int endHeight; - do { - endRow--; - endHeight = getHeightForRow(endRow); - totalHeight += endHeight; - } while (totalHeight < listHeight && endRow > 0); - - final float endOffsetRatio = (totalHeight - listHeight) / (float) endHeight; - final float boundSubRow = endRow + endOffsetRatio; - return Math.max(boundSubRow, targetSubRow); - } - - /** - * @param position - * @param boundPosition - */ - public void start(int position, int boundPosition) { - scrollToPosition(position, false, 0, boundPosition, DEFAULT_SCROLL_DURATION); - } - - /** - * @param position - * @param offset - * @param duration - */ - public void startWithOffset(int position, int offset, int duration) { - scrollToPosition(position, true, offset, INVALID_POSITION, duration); - } - - /** - * @param position - */ - public void start(int position) { - scrollToPosition(position, false, 0, INVALID_POSITION, DEFAULT_SCROLL_DURATION); - } - - public void stop() { - removeCallbacks(mAnimationFrame); - } - - private void onAnimationFrame() { - final boolean shouldPost = mSubScroller.computePosition(); - final float subRow = mSubScroller.getPosition(); - - final int row = (int) subRow; - final int position = getFirstPositionForRow(row); - final int rowHeight = getHeightForRow(row); - final int offset = (int) (rowHeight * (subRow - row)); - final int addOffset = (int) (mOffset * mSubScroller.getInterpolatedValue()); - setSelectionFromTop(position, -offset + addOffset); - - if (shouldPost) { - postOnAnimation(mAnimationFrame); - } - } - - private Runnable mAnimationFrame = new Runnable() { - @Override - public void run() { - onAnimationFrame(); - } - }; - } - - /** - * Scroller capable of returning floating point positions. - */ - private static class SubScroller { - private final Interpolator mInterpolator; - - private float mStartPosition; - private float mEndPosition; - private long mStartTime; - private long mDuration; - - private float mPosition; - private float mInterpolatedValue; - - public SubScroller() { - this(null); - } - - public SubScroller(Interpolator interpolator) { - if (interpolator == null) { - mInterpolator = new AccelerateDecelerateInterpolator(); - } else { - mInterpolator = interpolator; - } - } - - public void startScroll(float startPosition, float endPosition, int duration) { - mStartPosition = startPosition; - mEndPosition = endPosition; - mDuration = duration; - - mStartTime = AnimationUtils.currentAnimationTimeMillis(); - mPosition = startPosition; - mInterpolatedValue = 0; - } - - public boolean computePosition() { - final long elapsed = AnimationUtils.currentAnimationTimeMillis() - mStartTime; - final float value = MathUtils.constrain(elapsed / (float) mDuration, 0, 1); - - mInterpolatedValue = mInterpolator.getInterpolation(value); - mPosition = (mEndPosition - mStartPosition) * mInterpolatedValue + mStartPosition; - - return elapsed < mDuration; - } - - public float getPosition() { - return mPosition; - } - - public float getInterpolatedValue() { - return mInterpolatedValue; - } - } } diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java index 0b424f72be21d..acd711d61e8c1 100644 --- a/core/java/android/widget/GridView.java +++ b/core/java/android/widget/GridView.java @@ -1026,16 +1026,6 @@ public class GridView extends AbsListView { return didNotInitiallyFit; } - @Override - public int getRowForPosition(int position) { - return position / mNumColumns; - } - - @Override - public int getFirstPositionForRow(int row) { - return row * mNumColumns; - } - @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // Sets up mListPadding diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java index f937cd629d906..c4617236d041a 100644 --- a/core/java/android/widget/ListView.java +++ b/core/java/android/widget/ListView.java @@ -1891,6 +1891,45 @@ public class ListView extends AbsListView { setSelectionFromTop(position, 0); } + /** + * Sets the selected item and positions the selection y pixels from the top edge + * of the ListView. (If in touch mode, the item will not be selected but it will + * still be positioned appropriately.) + * + * @param position Index (starting at 0) of the data item to be selected. + * @param y The distance from the top edge of the ListView (plus padding) that the + * item will be positioned. + */ + public void setSelectionFromTop(int position, int y) { + if (mAdapter == null) { + return; + } + + if (!isInTouchMode()) { + position = lookForSelectablePosition(position, true); + if (position >= 0) { + setNextSelectedPositionInt(position); + } + } else { + mResurrectToPosition = position; + } + + if (position >= 0) { + mLayoutMode = LAYOUT_SPECIFIC; + mSpecificTop = mListPadding.top + y; + + if (mNeedSync) { + mSyncPosition = position; + mSyncRowId = mAdapter.getItemId(position); + } + + if (mPositionScroller != null) { + mPositionScroller.stop(); + } + requestLayout(); + } + } + /** * Makes the item at the supplied position selected. * @@ -3706,84 +3745,6 @@ public class ListView extends AbsListView { return new long[0]; } - @Override - int getHeightForPosition(int position) { - final int height = super.getHeightForPosition(position); - if (shouldAdjustHeightForDivider(position)) { - return height + mDividerHeight; - } - return height; - } - - private boolean shouldAdjustHeightForDivider(int itemIndex) { - final int dividerHeight = mDividerHeight; - final Drawable overscrollHeader = mOverScrollHeader; - final Drawable overscrollFooter = mOverScrollFooter; - final boolean drawOverscrollHeader = overscrollHeader != null; - final boolean drawOverscrollFooter = overscrollFooter != null; - final boolean drawDividers = dividerHeight > 0 && mDivider != null; - - if (drawDividers) { - final boolean fillForMissingDividers = isOpaque() && !super.isOpaque(); - final int itemCount = mItemCount; - final int headerCount = mHeaderViewInfos.size(); - final int footerLimit = (itemCount - mFooterViewInfos.size()); - final boolean isHeader = (itemIndex < headerCount); - final boolean isFooter = (itemIndex >= footerLimit); - final boolean headerDividers = mHeaderDividersEnabled; - final boolean footerDividers = mFooterDividersEnabled; - if ((headerDividers || !isHeader) && (footerDividers || !isFooter)) { - final ListAdapter adapter = mAdapter; - if (!mStackFromBottom) { - final boolean isLastItem = (itemIndex == (itemCount - 1)); - if (!drawOverscrollFooter || !isLastItem) { - final int nextIndex = itemIndex + 1; - // Draw dividers between enabled items, headers - // and/or footers when enabled and requested, and - // after the last enabled item. - if (adapter.isEnabled(itemIndex) && (headerDividers || !isHeader - && (nextIndex >= headerCount)) && (isLastItem - || adapter.isEnabled(nextIndex) && (footerDividers || !isFooter - && (nextIndex < footerLimit)))) { - return true; - } else if (fillForMissingDividers) { - return true; - } - } - } else { - final int start = drawOverscrollHeader ? 1 : 0; - final boolean isFirstItem = (itemIndex == start); - if (!isFirstItem) { - final int previousIndex = (itemIndex - 1); - // Draw dividers between enabled items, headers - // and/or footers when enabled and requested, and - // before the first enabled item. - if (adapter.isEnabled(itemIndex) && (headerDividers || !isHeader - && (previousIndex >= headerCount)) && (isFirstItem || - adapter.isEnabled(previousIndex) && (footerDividers || !isFooter - && (previousIndex < footerLimit)))) { - return true; - } else if (fillForMissingDividers) { - return true; - } - } - } - } - } - - return false; - } - - @Override - public int getRowForPosition(int position) { - return position; - } - - @Override - public int getFirstPositionForRow(int row) { - return row; - } - @Override public void onInitializeAccessibilityEvent(AccessibilityEvent event) { super.onInitializeAccessibilityEvent(event); From a8a08ed9a79ef5e73e9acd960aed6e69314f17c6 Mon Sep 17 00:00:00 2001 From: Chris Craik Date: Fri, 24 Jan 2014 13:22:35 -0800 Subject: [PATCH 008/119] Clear root level reorder lists to prevent accessing stale DisplayLists bug:12581401 Adds temporary logging which should log/crash earlier on incorrectly reordering hierarchies. Change-Id: Iee00940718c3cc868161e754aff93cd3b2747094 --- libs/hwui/DisplayList.cpp | 45 +++++++++++++++++++++++++++++++----- libs/hwui/DisplayList.h | 22 ++++++++++++++---- libs/hwui/Layer.cpp | 1 + libs/hwui/OpenGLRenderer.cpp | 2 ++ 4 files changed, 59 insertions(+), 11 deletions(-) diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp index a1563418030b4..3c8495e759597 100644 --- a/libs/hwui/DisplayList.cpp +++ b/libs/hwui/DisplayList.cpp @@ -261,6 +261,7 @@ void DisplayList::init() { mHeight = 0; mPivotExplicitlySet = false; mCaching = false; + mOrderingId = 0; } size_t DisplayList::getSize() { @@ -501,13 +502,20 @@ void DisplayList::applyViewPropertyTransforms(mat4& matrix) { */ void DisplayList::computeOrdering() { ATRACE_CALL(); - if (mDisplayListData == NULL) return; + m3dNodes.clear(); + mProjectedNodes.clear(); + mRootDisplayList = this; + mOrderingId++; + // TODO: create temporary DDLOp and call computeOrderingImpl on top DisplayList so that + // transform properties are applied correctly to top level children + if (mDisplayListData == NULL) return; for (unsigned int i = 0; i < mDisplayListData->children.size(); i++) { DrawDisplayListOp* childOp = mDisplayListData->children[i]; childOp->mDisplayList->computeOrderingImpl(childOp, &m3dNodes, &mat4::identity(), - &mProjectedNodes, &mat4::identity()); + &mProjectedNodes, &mat4::identity(), + mRootDisplayList, mOrderingId); } } @@ -516,7 +524,14 @@ void DisplayList::computeOrderingImpl( Vector* compositedChildrenOf3dRoot, const mat4* transformFrom3dRoot, Vector* compositedChildrenOfProjectionSurface, - const mat4* transformFromProjectionSurface) { + const mat4* transformFromProjectionSurface, + const void* rootDisplayList, const int orderingId) { + m3dNodes.clear(); + mProjectedNodes.clear(); + + // Temporary, for logging + mRootDisplayList = rootDisplayList; + mOrderingId = orderingId; // TODO: should avoid this calculation in most cases // TODO: just calculate single matrix, down to all leaf composited elements @@ -546,7 +561,6 @@ void DisplayList::computeOrderingImpl( opState->mSkipInOrderDraw = false; } - m3dNodes.clear(); if (mIsContainedVolume) { // create a new 3d space for descendents by collecting them compositedChildrenOf3dRoot = &m3dNodes; @@ -556,7 +570,6 @@ void DisplayList::computeOrderingImpl( transformFrom3dRoot = &localTransformFrom3dRoot; } - mProjectedNodes.clear(); if (mDisplayListData != NULL && mDisplayListData->projectionIndex >= 0) { // create a new projection surface for descendents by collecting them compositedChildrenOfProjectionSurface = &mProjectedNodes; @@ -571,7 +584,8 @@ void DisplayList::computeOrderingImpl( DrawDisplayListOp* childOp = mDisplayListData->children[i]; childOp->mDisplayList->computeOrderingImpl(childOp, compositedChildrenOf3dRoot, transformFrom3dRoot, - compositedChildrenOfProjectionSurface, transformFromProjectionSurface); + compositedChildrenOfProjectionSurface, transformFromProjectionSurface, + rootDisplayList, orderingId); } } } @@ -585,6 +599,7 @@ public: } inline LinearAllocator& allocator() { return *(mDeferStruct.mAllocator); } + const DisplayList* getRoot() { return mDeferStruct.mRoot; } private: DeferStateStruct& mDeferStruct; const int mLevel; @@ -607,6 +622,7 @@ public: } inline LinearAllocator& allocator() { return *(mReplayStruct.mAllocator); } + const DisplayList* getRoot() { return mReplayStruct.mRoot; } private: ReplayStateStruct& mReplayStruct; const int mLevel; @@ -643,6 +659,14 @@ void DisplayList::iterate3dChildren(ChildrenSelectMode mode, OpenGLRenderer& ren const float zValue = m3dNodes[i].key; DrawDisplayListOp* childOp = m3dNodes[i].value; + if (CC_UNLIKELY(handler.getRoot()->mRootDisplayList != childOp->mDisplayList->mRootDisplayList || + handler.getRoot()->mOrderingId != childOp->mDisplayList->mOrderingId)) { + ALOGW("Error in 3d order computation: Root %p, order %d, expected %p %d", + childOp->mDisplayList->mRootDisplayList, childOp->mDisplayList->mOrderingId, + handler.getRoot()->mRootDisplayList, handler.getRoot()->mOrderingId); + CRASH(); + } + if (mode == kPositiveZChildren && zValue < 0.0f) continue; if (mode == kNegativeZChildren && zValue > 0.0f) break; @@ -704,6 +728,15 @@ void DisplayList::iterate(OpenGLRenderer& renderer, T& handler, const int level) ALOGW("Error: %s is drawing after destruction, size %d", getName(), mSize); CRASH(); } + + if (CC_UNLIKELY(handler.getRoot()->mRootDisplayList != mRootDisplayList || + handler.getRoot()->mOrderingId != mOrderingId)) { + ALOGW("Error in order computation: Root %p, order %d, expected %p %d", + mRootDisplayList, mOrderingId, + handler.getRoot()->mRootDisplayList, handler.getRoot()->mOrderingId); + CRASH(); + } + if (mSize == 0 || mAlpha <= 0) { DISPLAY_LIST_LOGD("%*sEmpty display list (%p, %s)", level * 2, "", this, mName.string()); return; diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h index 5399185e6e44c..8026c4afd10b3 100644 --- a/libs/hwui/DisplayList.h +++ b/libs/hwui/DisplayList.h @@ -76,7 +76,7 @@ class DrawDisplayListOp; class PlaybackStateStruct { protected: PlaybackStateStruct(OpenGLRenderer& renderer, int replayFlags, LinearAllocator* allocator) - : mRenderer(renderer), mReplayFlags(replayFlags), mAllocator(allocator){} + : mRenderer(renderer), mReplayFlags(replayFlags), mAllocator(allocator), mRoot(NULL) {} public: OpenGLRenderer& mRenderer; @@ -85,6 +85,7 @@ public: // Allocator with the lifetime of a single frame. // replay uses an Allocator owned by the struct, while defer shares the DeferredDisplayList's Allocator LinearAllocator * const mAllocator; + const DisplayList* mRoot; // TEMPORARY, for debug logging only }; class DeferStateStruct : public PlaybackStateStruct { @@ -195,6 +196,9 @@ public: } void setProjectToContainedVolume(bool shouldProject) { + if (!mProjectToContainedVolume && shouldProject) { + ALOGD("DL %s(%p) marked for projection", getName(), this); + } mProjectToContainedVolume = shouldProject; } @@ -260,6 +264,9 @@ public: void setTranslationZ(float translationZ) { if (translationZ != mTranslationZ) { + if (mTranslationZ == 0.0f) { + ALOGD("DL %s(%p) marked for 3d compositing", getName(), this); + } mTranslationZ = translationZ; onTranslationUpdate(); } @@ -527,10 +534,11 @@ private: void applyViewPropertyTransforms(mat4& matrix); void computeOrderingImpl(DrawDisplayListOp* opState, - Vector* compositedChildrenOf3dRoot, - const mat4* transformFrom3dRoot, - Vector* compositedChildrenOfProjectionSurface, - const mat4* transformFromProjectionSurface); + Vector* compositedChildrenOf3dRoot, + const mat4* transformFrom3dRoot, + Vector* compositedChildrenOfProjectionSurface, + const mat4* transformFromProjectionSurface, + const void* rootDisplayList, const int orderingId); template inline void setViewProperties(OpenGLRenderer& renderer, T& handler, const int level); @@ -623,6 +631,10 @@ private: // for projection surfaces, contains a list of all children items Vector mProjectedNodes; + + // TEMPORARY, for debug logging only + const void* mRootDisplayList; + int mOrderingId; }; // class DisplayList }; // namespace uirenderer diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp index 742ffd47fd8d4..ed571fa5b8c12 100644 --- a/libs/hwui/Layer.cpp +++ b/libs/hwui/Layer.cpp @@ -199,6 +199,7 @@ void Layer::defer() { DeferStateStruct deferredState(*deferredList, *renderer, DisplayList::kReplayFlag_ClipChildren); + deferredState.mRoot = displayList; renderer->initViewport(width, height); renderer->setupFrameState(dirtyRect.left, dirtyRect.top, diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 7ee803fa1a9b9..741e953e3eba6 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -1877,6 +1877,7 @@ status_t OpenGLRenderer::drawDisplayList(DisplayList* displayList, Rect& dirty, if (CC_UNLIKELY(mCaches.drawDeferDisabled)) { status = startFrame(); ReplayStateStruct replayStruct(*this, dirty, replayFlags); + replayStruct.mRoot = displayList; displayList->replay(replayStruct, 0); return status | replayStruct.mDrawGlStatus; } @@ -1884,6 +1885,7 @@ status_t OpenGLRenderer::drawDisplayList(DisplayList* displayList, Rect& dirty, bool avoidOverdraw = !mCaches.debugOverdraw && !mCountOverdraw; // shh, don't tell devs! DeferredDisplayList deferredList(*currentClipRect(), avoidOverdraw); DeferStateStruct deferStruct(deferredList, *this, replayFlags); + deferStruct.mRoot = displayList; displayList->defer(deferStruct, 0); flushLayers(); From 2f22b78081b482121afdf93c36d6b5ea83790403 Mon Sep 17 00:00:00 2001 From: Chris Craik Date: Mon, 27 Jan 2014 13:58:11 -0800 Subject: [PATCH 009/119] Disable Drawable DisplayLists bug:12581401 bug:12758460 DisplayLists of drawables aren't being cleared out correctly, and will incorrectly store state across configuration changes. Disable them temporarily until this is fixed. Change-Id: Ic09f0674d30476127316cfb4ffe45eb34cc15aa0 --- graphics/java/android/graphics/drawable/Drawable.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java index cfb1983b30250..2ec428419c9e0 100644 --- a/graphics/java/android/graphics/drawable/Drawable.java +++ b/graphics/java/android/graphics/drawable/Drawable.java @@ -156,7 +156,7 @@ public abstract class Drawable { * @param canvas The canvas to draw into */ public void draw(Canvas canvas) { - if (canvas != null && canvas.isHardwareAccelerated()) { + if (canvas != null && canvas.isHardwareAccelerated() && false) { // temporarily disabled final HardwareCanvas hardwareCanvas = (HardwareCanvas) canvas; final DisplayList displayList = getDisplayList(hardwareCanvas); if (displayList != null) { From 8868555639ca28f79be33b438301d28cddc0ab99 Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Wed, 29 Jan 2014 12:52:15 -0800 Subject: [PATCH 010/119] change Surface constructor arg to 64bit Bug: 12799017 Bug: 12799384 Change-Id: Ic16b4fa5394df38cee0378b6e00d1808b9c8cb94 --- core/jni/android_view_Surface.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp index 19ee8a69f032f..ab6c1e0c3d9a0 100644 --- a/core/jni/android_view_Surface.cpp +++ b/core/jni/android_view_Surface.cpp @@ -114,7 +114,8 @@ jobject android_view_Surface_createFromIGraphicBufferProducer(JNIEnv* env, return NULL; } - jobject surfaceObj = env->NewObject(gSurfaceClassInfo.clazz, gSurfaceClassInfo.ctor, surface.get()); + jobject surfaceObj = env->NewObject(gSurfaceClassInfo.clazz, + gSurfaceClassInfo.ctor, (jlong)surface.get()); if (surfaceObj == NULL) { if (env->ExceptionCheck()) { ALOGE("Could not create instance of Surface from IGraphicBufferProducer."); From c398c6e1c38482de80461562ac40e67c292bd731 Mon Sep 17 00:00:00 2001 From: Brian Carlstrom Date: Thu, 30 Jan 2014 13:14:01 -0800 Subject: [PATCH 011/119] frameworks/base: Rename persist.sys.dalvik.vm.lib to allow new default (cherry picked from commit c6c633608ad4cd77ed21227b0bdb11eb79797c31) Bug: 12798969 Change-Id: Ibb7ed86867e4dca53ad7fe33326b08e6f5e664c4 --- core/java/com/android/internal/app/ProcessStats.java | 2 +- services/core/java/com/android/server/SystemServer.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/java/com/android/internal/app/ProcessStats.java b/core/java/com/android/internal/app/ProcessStats.java index eda1db2a2bc63..4dd4a45fe21b8 100644 --- a/core/java/com/android/internal/app/ProcessStats.java +++ b/core/java/com/android/internal/app/ProcessStats.java @@ -1097,7 +1097,7 @@ public final class ProcessStats implements Parcelable { public boolean evaluateSystemProperties(boolean update) { boolean changed = false; - String runtime = SystemProperties.get("persist.sys.dalvik.vm.lib", + String runtime = SystemProperties.get("persist.sys.dalvik.vm.lib.1", VMRuntime.getRuntime().vmLibrary()); if (!Objects.equals(runtime, mRuntime)) { changed = true; diff --git a/services/core/java/com/android/server/SystemServer.java b/services/core/java/com/android/server/SystemServer.java index b04fc15983400..1f6235fe0be81 100644 --- a/services/core/java/com/android/server/SystemServer.java +++ b/services/core/java/com/android/server/SystemServer.java @@ -163,7 +163,7 @@ public final class SystemServer { // had to fallback to a different runtime because it is // running as root and we need to be the system user to set // the property. http://b/11463182 - SystemProperties.set("persist.sys.dalvik.vm.lib", VMRuntime.getRuntime().vmLibrary()); + SystemProperties.set("persist.sys.dalvik.vm.lib.1", VMRuntime.getRuntime().vmLibrary()); // Enable the sampling profiler. if (SamplingProfilerIntegration.isEnabled()) { From a07f727685882e3e1e6abb4e7fc2cc06a942a6a4 Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Wed, 5 Feb 2014 10:42:01 -0800 Subject: [PATCH 012/119] android_media_MediaMuxer_setLocation: amended signature. Change parameter `nativeObject` from type `jint` to `jlong` to match its JNI signature. Bug: 12890910 Change-Id: I7feb7fa5c3eccc07f2d1bc733b7d4b3a3b52e292 --- media/jni/android_media_MediaMuxer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/media/jni/android_media_MediaMuxer.cpp b/media/jni/android_media_MediaMuxer.cpp index 2c16a050f6b38..ea890c20968a0 100644 --- a/media/jni/android_media_MediaMuxer.cpp +++ b/media/jni/android_media_MediaMuxer.cpp @@ -164,7 +164,7 @@ static void android_media_MediaMuxer_setOrientationHint( } static void android_media_MediaMuxer_setLocation( - JNIEnv *env, jclass clazz, jint nativeObject, jint latitude, jint longitude) { + JNIEnv *env, jclass clazz, jlong nativeObject, jint latitude, jint longitude) { MediaMuxer* muxer = reinterpret_cast(nativeObject); status_t res = muxer->setLocation(latitude, longitude); From 3ed62ec2428eb1725ba56719fd07cf8dc88762ad Mon Sep 17 00:00:00 2001 From: Craig Mautner Date: Thu, 6 Feb 2014 10:31:41 -0800 Subject: [PATCH 013/119] Test for Configuration differences before changing. Changing Configuration first and then testing for changes yields a result indicating no change. Fixes bug 12904769. Change-Id: If7e39e843f15b1143d9877497d595511afabd020 --- .../server/wm/WindowManagerService.java | 16 -------------- .../com/android/server/wm/WindowState.java | 22 +++++++++++++++---- 2 files changed, 18 insertions(+), 20 deletions(-) diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index d7f3fa0a9f279..b76ec4bb67263 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -9300,22 +9300,6 @@ public class WindowManagerService extends IWindowManager.Stub // Don't remove this window until rotation has completed. continue; } - final WindowStateAnimator winAnimator = win.mWinAnimator; - if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG, - "Reporting new frame to " + win + ": " + win.mCompatFrame); - int diff = 0; - boolean configChanged = win.isConfigChanged(); - if ((DEBUG_RESIZE || DEBUG_ORIENTATION || DEBUG_CONFIGURATION) - && configChanged) { - Slog.i(TAG, "Sending new config to window " + win + ": " - + winAnimator.mSurfaceW + "x" + winAnimator.mSurfaceH - + " / " + mCurConfiguration + " / 0x" - + Integer.toHexString(diff)); - } - win.setConfiguration(mCurConfiguration); - if (DEBUG_ORIENTATION && - winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING) Slog.i( - TAG, "Resizing " + win + " WITH DRAW PENDING"); win.reportResized(); mResizingWindows.remove(i); } diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 2f778b1d844ed..a8e45c4e3323a 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -16,8 +16,11 @@ package com.android.server.wm; -import static com.android.server.wm.WindowManagerService.DEBUG_VISIBILITY; +import static com.android.server.wm.WindowManagerService.DEBUG_CONFIGURATION; import static com.android.server.wm.WindowManagerService.DEBUG_LAYOUT; +import static com.android.server.wm.WindowManagerService.DEBUG_ORIENTATION; +import static com.android.server.wm.WindowManagerService.DEBUG_RESIZE; +import static com.android.server.wm.WindowManagerService.DEBUG_VISIBILITY; import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW; @@ -1310,13 +1313,24 @@ final class WindowState implements WindowManagerPolicy.WindowState { void reportResized() { try { + if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG, "Reporting new frame to " + this + + ": " + mCompatFrame); + boolean configChanged = isConfigChanged(); + if ((DEBUG_RESIZE || DEBUG_ORIENTATION || DEBUG_CONFIGURATION) && configChanged) { + Slog.i(TAG, "Sending new config to window " + this + ": " + + mWinAnimator.mSurfaceW + "x" + mWinAnimator.mSurfaceH + + " / " + mService.mCurConfiguration); + } + setConfiguration(mService.mCurConfiguration); + if (DEBUG_ORIENTATION && mWinAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING) + Slog.i(TAG, "Resizing " + this + " WITH DRAW PENDING"); + final Rect frame = mFrame; final Rect overscanInsets = mLastOverscanInsets; final Rect contentInsets = mLastContentInsets; final Rect visibleInsets = mLastVisibleInsets; - final boolean reportDraw - = mWinAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING; - final Configuration newConfig = isConfigChanged() ? mConfiguration : null; + final boolean reportDraw = mWinAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING; + final Configuration newConfig = configChanged ? mConfiguration : null; if (mClient instanceof IWindow.Stub) { // To prevent deadlock simulate one-way call if win.mClient is a local object. mService.mH.post(new Runnable() { From 3a9cc28137c84a64b708edfd7bc5423e78ef9220 Mon Sep 17 00:00:00 2001 From: Narayan Kamath Date: Thu, 6 Feb 2014 11:50:31 +0000 Subject: [PATCH 014/119] Fix several bad function definitions. We claim these functions want jlong as input (8 bytes wide) but the definitions use pointer types or jints (4 bytes wide for 32 bit). bug: 12890271 Change-Id: I6a167a4f3aac1e22ddea33d067caaef6a11b418c --- core/jni/android/graphics/Canvas.cpp | 13 +++++++------ core/jni/android_view_GLES20Canvas.cpp | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp index 2cb28124f96ef..e98d45b1eebaf 100644 --- a/core/jni/android/graphics/Canvas.cpp +++ b/core/jni/android/graphics/Canvas.cpp @@ -327,9 +327,10 @@ public: } static jboolean clipPath(JNIEnv* env, jobject, jlong canvasHandle, - SkPath* path, jint op) { + jlong pathHandle, jint op) { SkCanvas* canvas = reinterpret_cast(canvasHandle); - bool result = canvas->clipPath(*path, static_cast(op)); + bool result = canvas->clipPath(*reinterpret_cast(pathHandle), + static_cast(op)); return result ? JNI_TRUE : JNI_FALSE; } @@ -342,9 +343,9 @@ public: } static void setDrawFilter(JNIEnv* env, jobject, jlong canvasHandle, - SkDrawFilter* filter) { + jlong filterHandle) { SkCanvas* canvas = reinterpret_cast(canvasHandle); - canvas->setDrawFilter(filter); + canvas->setDrawFilter(reinterpret_cast(filterHandle)); } static jboolean quickReject__RectF(JNIEnv* env, jobject, jlong canvasHandle, @@ -356,9 +357,9 @@ public: } static jboolean quickReject__Path(JNIEnv* env, jobject, jlong canvasHandle, - SkPath* path) { + jlong pathHandle) { SkCanvas* canvas = reinterpret_cast(canvasHandle); - bool result = canvas->quickReject(*path); + bool result = canvas->quickReject(*reinterpret_cast(pathHandle)); return result ? JNI_TRUE : JNI_FALSE; } diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp index 6cc94e359a898..f32c724aaf06d 100644 --- a/core/jni/android_view_GLES20Canvas.cpp +++ b/core/jni/android_view_GLES20Canvas.cpp @@ -222,7 +222,7 @@ static jint android_view_GLES20Canvas_callDrawGLFunction(JNIEnv* env, jobject cl } static void android_view_GLES20Canvas_detachFunctor(JNIEnv* env, - jobject clazz, jlong rendererPtr, jint functorPtr) { + jobject clazz, jlong rendererPtr, jlong functorPtr) { OpenGLRenderer* renderer = reinterpret_cast(rendererPtr); Functor* functor = reinterpret_cast(functorPtr); renderer->detachFunctor(functor); From 86fa01c536c849174001d059e6c9178a39a1d0a8 Mon Sep 17 00:00:00 2001 From: John Spurlock Date: Mon, 10 Feb 2014 15:36:24 -0500 Subject: [PATCH 015/119] Fix NPE in PolicyControl. Bug:12957738 Change-Id: I8051a7a0656f50ed63321f9a79faf0383d7c66b4 --- .../internal/policy/impl/PolicyControl.java | 46 ++++++++++--------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/policy/src/com/android/internal/policy/impl/PolicyControl.java b/policy/src/com/android/internal/policy/impl/PolicyControl.java index e6a7d76ccbc6a..4f355ddca65c4 100644 --- a/policy/src/com/android/internal/policy/impl/PolicyControl.java +++ b/policy/src/com/android/internal/policy/impl/PolicyControl.java @@ -140,30 +140,32 @@ public class PolicyControl { sImmersiveStatusFilter = null; sImmersiveNavigationFilter = null; sImmersivePreconfirmationsFilter = null; - String[] nvps = value.split(":"); - for (String nvp : nvps) { - int i = nvp.indexOf('='); - if (i == -1) continue; - String n = nvp.substring(0, i); - String v = nvp.substring(i + 1); - if (n.equals(NAME_IMMERSIVE_FULL)) { - Filter f = Filter.parse(v); - sImmersiveStatusFilter = sImmersiveNavigationFilter = f; - if (sImmersivePreconfirmationsFilter == null) { + if (value != null) { + String[] nvps = value.split(":"); + for (String nvp : nvps) { + int i = nvp.indexOf('='); + if (i == -1) continue; + String n = nvp.substring(0, i); + String v = nvp.substring(i + 1); + if (n.equals(NAME_IMMERSIVE_FULL)) { + Filter f = Filter.parse(v); + sImmersiveStatusFilter = sImmersiveNavigationFilter = f; + if (sImmersivePreconfirmationsFilter == null) { + sImmersivePreconfirmationsFilter = f; + } + } else if (n.equals(NAME_IMMERSIVE_STATUS)) { + Filter f = Filter.parse(v); + sImmersiveStatusFilter = f; + } else if (n.equals(NAME_IMMERSIVE_NAVIGATION)) { + Filter f = Filter.parse(v); + sImmersiveNavigationFilter = f; + if (sImmersivePreconfirmationsFilter == null) { + sImmersivePreconfirmationsFilter = f; + } + } else if (n.equals(NAME_IMMERSIVE_PRECONFIRMATIONS)) { + Filter f = Filter.parse(v); sImmersivePreconfirmationsFilter = f; } - } else if (n.equals(NAME_IMMERSIVE_STATUS)) { - Filter f = Filter.parse(v); - sImmersiveStatusFilter = f; - } else if (n.equals(NAME_IMMERSIVE_NAVIGATION)) { - Filter f = Filter.parse(v); - sImmersiveNavigationFilter = f; - if (sImmersivePreconfirmationsFilter == null) { - sImmersivePreconfirmationsFilter = f; - } - } else if (n.equals(NAME_IMMERSIVE_PRECONFIRMATIONS)) { - Filter f = Filter.parse(v); - sImmersivePreconfirmationsFilter = f; } } if (DEBUG) { From ea44ed5cfb78bbe9d9159573b3551766a7c20a13 Mon Sep 17 00:00:00 2001 From: Amith Yamasani Date: Mon, 10 Feb 2014 13:43:18 -0800 Subject: [PATCH 016/119] Fix NPE on removing a user Bug: 12957232 Check for null mDeviceOwner. Change-Id: I107dc24d1a8de121ebd2c1bb56e1af40bb1c55ac --- .../server/devicepolicy/DevicePolicyManagerService.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index a8f2df16c69b8..5a964ad0a32e7 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -599,9 +599,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { Slog.w(LOG_TAG, "Tried to remove device policy file for user 0! Ignoring."); return; } - - mDeviceOwner.removeProfileOwner(userHandle); - mDeviceOwner.writeOwnerFile(); + if (mDeviceOwner != null) { + mDeviceOwner.removeProfileOwner(userHandle); + mDeviceOwner.writeOwnerFile(); + } DevicePolicyData policy = mUserData.get(userHandle); if (policy != null) { From f855141b0fa784e872ece965fad63f11e9e34961 Mon Sep 17 00:00:00 2001 From: Chris Craik Date: Wed, 12 Feb 2014 13:44:47 -0800 Subject: [PATCH 017/119] Avoid crash if layer is destroyed after GLRenderer bug:12988766 Change-Id: I96961aeef0b1d42ae8c609f1607a100e61a3d593 --- core/java/android/view/GLRenderer.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/java/android/view/GLRenderer.java b/core/java/android/view/GLRenderer.java index 40ad72ca5bffd..c1eb6b771c093 100644 --- a/core/java/android/view/GLRenderer.java +++ b/core/java/android/view/GLRenderer.java @@ -497,7 +497,9 @@ public class GLRenderer extends HardwareRenderer { @Override void onLayerDestroyed(HardwareLayer layer) { - mGlCanvas.cancelLayerUpdate(layer); + if (mGlCanvas != null) { + mGlCanvas.cancelLayerUpdate(layer); + } mAttachedLayers.remove(layer); } From c790993fbc365e3fc540ac86b816ac2adf31e93b Mon Sep 17 00:00:00 2001 From: Alan Viverette Date: Thu, 13 Feb 2014 17:47:38 -0800 Subject: [PATCH 018/119] Refactor AbsListView position scrollers for better abstraction The AbsListView sub-scroller knows nothing about layout. That's now handled by ListView and GridView, with subclasses of AbsListView using the default PositionScroller. Removes unnecessary (unreleased) APIs. Also fixes a bounds check that was using the item position rather than the child view position. BUG: 13006641 Change-Id: I2adb0f15623e32295facf81f5ada974083ba03ce --- api/current.txt | 2 - core/java/android/widget/AbsListView.java | 1030 +++++++++++---------- core/java/android/widget/GridView.java | 40 +- core/java/android/widget/ListView.java | 29 +- 4 files changed, 584 insertions(+), 517 deletions(-) diff --git a/api/current.txt b/api/current.txt index 3ea1aad67a442..b93c0904d29ef 100644 --- a/api/current.txt +++ b/api/current.txt @@ -31628,12 +31628,10 @@ package android.widget { method public int getCheckedItemPosition(); method public android.util.SparseBooleanArray getCheckedItemPositions(); method public int getChoiceMode(); - method public int getFirstPositionForRow(int); method public int getListPaddingBottom(); method public int getListPaddingLeft(); method public int getListPaddingRight(); method public int getListPaddingTop(); - method public int getRowForPosition(int); method public android.view.View getSelectedView(); method public android.graphics.drawable.Drawable getSelector(); method public java.lang.CharSequence getTextFilter(); diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index 0a755ca8aef1b..146718d8e67e5 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -421,7 +421,7 @@ public abstract class AbsListView extends AdapterView implements Te /** * Handles scrolling between positions within the list. */ - SubPositionScroller mPositionScroller; + AbsPositionScroller mPositionScroller; /** * The offset in pixels form the top of the AdapterView to the top @@ -4374,447 +4374,6 @@ public abstract class AbsListView extends AdapterView implements Te } } - class PositionScroller implements Runnable { - private static final int SCROLL_DURATION = 200; - - private static final int MOVE_DOWN_POS = 1; - private static final int MOVE_UP_POS = 2; - private static final int MOVE_DOWN_BOUND = 3; - private static final int MOVE_UP_BOUND = 4; - private static final int MOVE_OFFSET = 5; - - private int mMode; - private int mTargetPos; - private int mBoundPos; - private int mLastSeenPos; - private int mScrollDuration; - private final int mExtraScroll; - - private int mOffsetFromTop; - - PositionScroller() { - mExtraScroll = ViewConfiguration.get(mContext).getScaledFadingEdgeLength(); - } - - void start(final int position) { - stop(); - - if (mDataChanged) { - // Wait until we're back in a stable state to try this. - mPositionScrollAfterLayout = new Runnable() { - @Override public void run() { - start(position); - } - }; - return; - } - - final int childCount = getChildCount(); - if (childCount == 0) { - // Can't scroll without children. - return; - } - - final int firstPos = mFirstPosition; - final int lastPos = firstPos + childCount - 1; - - int viewTravelCount; - int clampedPosition = Math.max(0, Math.min(getCount() - 1, position)); - if (clampedPosition < firstPos) { - viewTravelCount = firstPos - clampedPosition + 1; - mMode = MOVE_UP_POS; - } else if (clampedPosition > lastPos) { - viewTravelCount = clampedPosition - lastPos + 1; - mMode = MOVE_DOWN_POS; - } else { - scrollToVisible(clampedPosition, INVALID_POSITION, SCROLL_DURATION); - return; - } - - if (viewTravelCount > 0) { - mScrollDuration = SCROLL_DURATION / viewTravelCount; - } else { - mScrollDuration = SCROLL_DURATION; - } - mTargetPos = clampedPosition; - mBoundPos = INVALID_POSITION; - mLastSeenPos = INVALID_POSITION; - - postOnAnimation(this); - } - - void start(final int position, final int boundPosition) { - stop(); - - if (boundPosition == INVALID_POSITION) { - start(position); - return; - } - - if (mDataChanged) { - // Wait until we're back in a stable state to try this. - mPositionScrollAfterLayout = new Runnable() { - @Override public void run() { - start(position, boundPosition); - } - }; - return; - } - - final int childCount = getChildCount(); - if (childCount == 0) { - // Can't scroll without children. - return; - } - - final int firstPos = mFirstPosition; - final int lastPos = firstPos + childCount - 1; - - int viewTravelCount; - int clampedPosition = Math.max(0, Math.min(getCount() - 1, position)); - if (clampedPosition < firstPos) { - final int boundPosFromLast = lastPos - boundPosition; - if (boundPosFromLast < 1) { - // Moving would shift our bound position off the screen. Abort. - return; - } - - final int posTravel = firstPos - clampedPosition + 1; - final int boundTravel = boundPosFromLast - 1; - if (boundTravel < posTravel) { - viewTravelCount = boundTravel; - mMode = MOVE_UP_BOUND; - } else { - viewTravelCount = posTravel; - mMode = MOVE_UP_POS; - } - } else if (clampedPosition > lastPos) { - final int boundPosFromFirst = boundPosition - firstPos; - if (boundPosFromFirst < 1) { - // Moving would shift our bound position off the screen. Abort. - return; - } - - final int posTravel = clampedPosition - lastPos + 1; - final int boundTravel = boundPosFromFirst - 1; - if (boundTravel < posTravel) { - viewTravelCount = boundTravel; - mMode = MOVE_DOWN_BOUND; - } else { - viewTravelCount = posTravel; - mMode = MOVE_DOWN_POS; - } - } else { - scrollToVisible(clampedPosition, boundPosition, SCROLL_DURATION); - return; - } - - if (viewTravelCount > 0) { - mScrollDuration = SCROLL_DURATION / viewTravelCount; - } else { - mScrollDuration = SCROLL_DURATION; - } - mTargetPos = clampedPosition; - mBoundPos = boundPosition; - mLastSeenPos = INVALID_POSITION; - - postOnAnimation(this); - } - - void startWithOffset(int position, int offset) { - startWithOffset(position, offset, SCROLL_DURATION); - } - - void startWithOffset(final int position, int offset, final int duration) { - stop(); - - if (mDataChanged) { - // Wait until we're back in a stable state to try this. - final int postOffset = offset; - mPositionScrollAfterLayout = new Runnable() { - @Override public void run() { - startWithOffset(position, postOffset, duration); - } - }; - return; - } - - final int childCount = getChildCount(); - if (childCount == 0) { - // Can't scroll without children. - return; - } - - offset += getPaddingTop(); - - mTargetPos = Math.max(0, Math.min(getCount() - 1, position)); - mOffsetFromTop = offset; - mBoundPos = INVALID_POSITION; - mLastSeenPos = INVALID_POSITION; - mMode = MOVE_OFFSET; - - final int firstPos = mFirstPosition; - final int lastPos = firstPos + childCount - 1; - - int viewTravelCount; - if (mTargetPos < firstPos) { - viewTravelCount = firstPos - mTargetPos; - } else if (mTargetPos > lastPos) { - viewTravelCount = mTargetPos - lastPos; - } else { - // On-screen, just scroll. - final int targetTop = getChildAt(mTargetPos - firstPos).getTop(); - smoothScrollBy(targetTop - offset, duration, true); - return; - } - - // Estimate how many screens we should travel - final float screenTravelCount = (float) viewTravelCount / childCount; - mScrollDuration = screenTravelCount < 1 ? - duration : (int) (duration / screenTravelCount); - mLastSeenPos = INVALID_POSITION; - - postOnAnimation(this); - } - - /** - * Scroll such that targetPos is in the visible padded region without scrolling - * boundPos out of view. Assumes targetPos is onscreen. - */ - void scrollToVisible(int targetPos, int boundPos, int duration) { - final int firstPos = mFirstPosition; - final int childCount = getChildCount(); - final int lastPos = firstPos + childCount - 1; - final int paddedTop = mListPadding.top; - final int paddedBottom = getHeight() - mListPadding.bottom; - - if (targetPos < firstPos || targetPos > lastPos) { - Log.w(TAG, "scrollToVisible called with targetPos " + targetPos + - " not visible [" + firstPos + ", " + lastPos + "]"); - } - if (boundPos < firstPos || boundPos > lastPos) { - // boundPos doesn't matter, it's already offscreen. - boundPos = INVALID_POSITION; - } - - final View targetChild = getChildAt(targetPos - firstPos); - final int targetTop = targetChild.getTop(); - final int targetBottom = targetChild.getBottom(); - int scrollBy = 0; - - if (targetBottom > paddedBottom) { - scrollBy = targetBottom - paddedBottom; - } - if (targetTop < paddedTop) { - scrollBy = targetTop - paddedTop; - } - - if (scrollBy == 0) { - return; - } - - if (boundPos >= 0) { - final View boundChild = getChildAt(boundPos - firstPos); - final int boundTop = boundChild.getTop(); - final int boundBottom = boundChild.getBottom(); - final int absScroll = Math.abs(scrollBy); - - if (scrollBy < 0 && boundBottom + absScroll > paddedBottom) { - // Don't scroll the bound view off the bottom of the screen. - scrollBy = Math.max(0, boundBottom - paddedBottom); - } else if (scrollBy > 0 && boundTop - absScroll < paddedTop) { - // Don't scroll the bound view off the top of the screen. - scrollBy = Math.min(0, boundTop - paddedTop); - } - } - - smoothScrollBy(scrollBy, duration); - } - - void stop() { - removeCallbacks(this); - } - - @Override - public void run() { - final int listHeight = getHeight(); - final int firstPos = mFirstPosition; - - switch (mMode) { - case MOVE_DOWN_POS: { - final int lastViewIndex = getChildCount() - 1; - final int lastPos = firstPos + lastViewIndex; - - if (lastViewIndex < 0) { - return; - } - - if (lastPos == mLastSeenPos) { - // No new views, let things keep going. - postOnAnimation(this); - return; - } - - final View lastView = getChildAt(lastViewIndex); - final int lastViewHeight = lastView.getHeight(); - final int lastViewTop = lastView.getTop(); - final int lastViewPixelsShowing = listHeight - lastViewTop; - final int extraScroll = lastPos < mItemCount - 1 ? - Math.max(mListPadding.bottom, mExtraScroll) : mListPadding.bottom; - - final int scrollBy = lastViewHeight - lastViewPixelsShowing + extraScroll; - smoothScrollBy(scrollBy, mScrollDuration, true); - - mLastSeenPos = lastPos; - if (lastPos < mTargetPos) { - postOnAnimation(this); - } - break; - } - - case MOVE_DOWN_BOUND: { - final int nextViewIndex = 1; - final int childCount = getChildCount(); - - if (firstPos == mBoundPos || childCount <= nextViewIndex - || firstPos + childCount >= mItemCount) { - return; - } - final int nextPos = firstPos + nextViewIndex; - - if (nextPos == mLastSeenPos) { - // No new views, let things keep going. - postOnAnimation(this); - return; - } - - final View nextView = getChildAt(nextViewIndex); - final int nextViewHeight = nextView.getHeight(); - final int nextViewTop = nextView.getTop(); - final int extraScroll = Math.max(mListPadding.bottom, mExtraScroll); - if (nextPos < mBoundPos) { - smoothScrollBy(Math.max(0, nextViewHeight + nextViewTop - extraScroll), - mScrollDuration, true); - - mLastSeenPos = nextPos; - - postOnAnimation(this); - } else { - if (nextViewTop > extraScroll) { - smoothScrollBy(nextViewTop - extraScroll, mScrollDuration, true); - } - } - break; - } - - case MOVE_UP_POS: { - if (firstPos == mLastSeenPos) { - // No new views, let things keep going. - postOnAnimation(this); - return; - } - - final View firstView = getChildAt(0); - if (firstView == null) { - return; - } - final int firstViewTop = firstView.getTop(); - final int extraScroll = firstPos > 0 ? - Math.max(mExtraScroll, mListPadding.top) : mListPadding.top; - - smoothScrollBy(firstViewTop - extraScroll, mScrollDuration, true); - - mLastSeenPos = firstPos; - - if (firstPos > mTargetPos) { - postOnAnimation(this); - } - break; - } - - case MOVE_UP_BOUND: { - final int lastViewIndex = getChildCount() - 2; - if (lastViewIndex < 0) { - return; - } - final int lastPos = firstPos + lastViewIndex; - - if (lastPos == mLastSeenPos) { - // No new views, let things keep going. - postOnAnimation(this); - return; - } - - final View lastView = getChildAt(lastViewIndex); - final int lastViewHeight = lastView.getHeight(); - final int lastViewTop = lastView.getTop(); - final int lastViewPixelsShowing = listHeight - lastViewTop; - final int extraScroll = Math.max(mListPadding.top, mExtraScroll); - mLastSeenPos = lastPos; - if (lastPos > mBoundPos) { - smoothScrollBy(-(lastViewPixelsShowing - extraScroll), mScrollDuration, true); - postOnAnimation(this); - } else { - final int bottom = listHeight - extraScroll; - final int lastViewBottom = lastViewTop + lastViewHeight; - if (bottom > lastViewBottom) { - smoothScrollBy(-(bottom - lastViewBottom), mScrollDuration, true); - } - } - break; - } - - case MOVE_OFFSET: { - if (mLastSeenPos == firstPos) { - // No new views, let things keep going. - postOnAnimation(this); - return; - } - - mLastSeenPos = firstPos; - - final int childCount = getChildCount(); - final int position = mTargetPos; - final int lastPos = firstPos + childCount - 1; - - int viewTravelCount = 0; - if (position < firstPos) { - viewTravelCount = firstPos - position + 1; - } else if (position > lastPos) { - viewTravelCount = position - lastPos; - } - - // Estimate how many screens we should travel - final float screenTravelCount = (float) viewTravelCount / childCount; - - final float modifier = Math.min(Math.abs(screenTravelCount), 1.f); - if (position < firstPos) { - final int distance = (int) (-getHeight() * modifier); - final int duration = (int) (mScrollDuration * modifier); - smoothScrollBy(distance, duration, true); - postOnAnimation(this); - } else if (position > lastPos) { - final int distance = (int) (getHeight() * modifier); - final int duration = (int) (mScrollDuration * modifier); - smoothScrollBy(distance, duration, true); - postOnAnimation(this); - } else { - // On-screen, just scroll. - final int targetTop = getChildAt(position - firstPos).getTop(); - final int distance = targetTop - mOffsetFromTop; - final int duration = (int) (mScrollDuration * - ((float) Math.abs(distance) / getHeight())); - smoothScrollBy(distance, duration, true); - } - break; - } - - default: - break; - } - } - } - /** * The amount of friction applied to flings. The default value * is {@link ViewConfiguration#getScrollFriction}. @@ -4836,6 +4395,13 @@ public abstract class AbsListView extends AdapterView implements Te mVelocityScale = scale; } + /** + * Override this for better control over position scrolling. + */ + AbsPositionScroller createPositionScroller() { + return new PositionScroller(); + } + /** * Smoothly scroll to the specified adapter position. The view will * scroll such that the indicated position is displayed. @@ -4843,7 +4409,7 @@ public abstract class AbsListView extends AdapterView implements Te */ public void smoothScrollToPosition(int position) { if (mPositionScroller == null) { - mPositionScroller = new SubPositionScroller(); + mPositionScroller = createPositionScroller(); } mPositionScroller.start(position); } @@ -4862,7 +4428,7 @@ public abstract class AbsListView extends AdapterView implements Te */ public void smoothScrollToPositionFromTop(int position, int offset, int duration) { if (mPositionScroller == null) { - mPositionScroller = new SubPositionScroller(); + mPositionScroller = createPositionScroller(); } mPositionScroller.startWithOffset(position, offset, duration); } @@ -4880,7 +4446,7 @@ public abstract class AbsListView extends AdapterView implements Te */ public void smoothScrollToPositionFromTop(int position, int offset) { if (mPositionScroller == null) { - mPositionScroller = new SubPositionScroller(); + mPositionScroller = createPositionScroller(); } mPositionScroller.startWithOffset(position, offset, offset); } @@ -4896,7 +4462,7 @@ public abstract class AbsListView extends AdapterView implements Te */ public void smoothScrollToPosition(int position, int boundPosition) { if (mPositionScroller == null) { - mPositionScroller = new SubPositionScroller(); + mPositionScroller = createPositionScroller(); } mPositionScroller.start(position, boundPosition); } @@ -6996,26 +6562,6 @@ public abstract class AbsListView extends AdapterView implements Te } } - /** - * Returns the height of a row, which is computed as the maximum height of - * the items in the row. - * - * @param row the row index - * @return row height in pixels - */ - private int getHeightForRow(int row) { - final int firstRowPosition = getFirstPositionForRow(row); - final int lastRowPosition = getFirstPositionForRow(row + 1); - int maxHeight = 0; - for (int i = firstRowPosition; i < lastRowPosition; i++) { - final int height = getHeightForPosition(i); - if (height > maxHeight) { - maxHeight = height; - } - } - return maxHeight; - } - /** * Returns the height of the view for the specified position. * @@ -7026,10 +6572,12 @@ public abstract class AbsListView extends AdapterView implements Te final int firstVisiblePosition = getFirstVisiblePosition(); final int childCount = getChildCount(); final int index = position - firstVisiblePosition; - if (position >= 0 && position < childCount) { + if (index >= 0 && index < childCount) { + // Position is on-screen, use existing view. final View view = getChildAt(index); return view.getHeight(); } else { + // Position is off-screen, obtain & recycle view. final View view = obtainView(position, mIsScrap); view.measure(mWidthMeasureSpec, MeasureSpec.UNSPECIFIED); final int height = view.getMeasuredHeight(); @@ -7038,26 +6586,6 @@ public abstract class AbsListView extends AdapterView implements Te } } - /** - * Returns the row for the specified item position. - * - * @param position the item position - * @return the row index - */ - public int getRowForPosition(int position) { - return position; - } - - /** - * Returns the first item position within the specified row. - * - * @param row the row - * @return the item position - */ - public int getFirstPositionForRow(int row) { - return row; - } - /** * Sets the selected item and positions the selection y pixels from the top edge * of the ListView. (If in touch mode, the item will not be selected but it will @@ -7097,10 +6625,474 @@ public abstract class AbsListView extends AdapterView implements Te } } - class SubPositionScroller { + /** + * Abstract positon scroller used to handle smooth scrolling. + */ + static abstract class AbsPositionScroller { + public abstract void start(int position); + public abstract void start(int position, int boundPosition); + public abstract void startWithOffset(int position, int offset); + public abstract void startWithOffset(int position, int offset, int duration); + public abstract void stop(); + } + + /** + * Default position scroller that simulates a fling. + */ + class PositionScroller extends AbsPositionScroller implements Runnable { + private static final int SCROLL_DURATION = 200; + + private static final int MOVE_DOWN_POS = 1; + private static final int MOVE_UP_POS = 2; + private static final int MOVE_DOWN_BOUND = 3; + private static final int MOVE_UP_BOUND = 4; + private static final int MOVE_OFFSET = 5; + + private int mMode; + private int mTargetPos; + private int mBoundPos; + private int mLastSeenPos; + private int mScrollDuration; + private final int mExtraScroll; + + private int mOffsetFromTop; + + PositionScroller() { + mExtraScroll = ViewConfiguration.get(mContext).getScaledFadingEdgeLength(); + } + + @Override + public void start(final int position) { + stop(); + + if (mDataChanged) { + // Wait until we're back in a stable state to try this. + mPositionScrollAfterLayout = new Runnable() { + @Override public void run() { + start(position); + } + }; + return; + } + + final int childCount = getChildCount(); + if (childCount == 0) { + // Can't scroll without children. + return; + } + + final int firstPos = mFirstPosition; + final int lastPos = firstPos + childCount - 1; + + int viewTravelCount; + int clampedPosition = Math.max(0, Math.min(getCount() - 1, position)); + if (clampedPosition < firstPos) { + viewTravelCount = firstPos - clampedPosition + 1; + mMode = MOVE_UP_POS; + } else if (clampedPosition > lastPos) { + viewTravelCount = clampedPosition - lastPos + 1; + mMode = MOVE_DOWN_POS; + } else { + scrollToVisible(clampedPosition, INVALID_POSITION, SCROLL_DURATION); + return; + } + + if (viewTravelCount > 0) { + mScrollDuration = SCROLL_DURATION / viewTravelCount; + } else { + mScrollDuration = SCROLL_DURATION; + } + mTargetPos = clampedPosition; + mBoundPos = INVALID_POSITION; + mLastSeenPos = INVALID_POSITION; + + postOnAnimation(this); + } + + @Override + public void start(final int position, final int boundPosition) { + stop(); + + if (boundPosition == INVALID_POSITION) { + start(position); + return; + } + + if (mDataChanged) { + // Wait until we're back in a stable state to try this. + mPositionScrollAfterLayout = new Runnable() { + @Override public void run() { + start(position, boundPosition); + } + }; + return; + } + + final int childCount = getChildCount(); + if (childCount == 0) { + // Can't scroll without children. + return; + } + + final int firstPos = mFirstPosition; + final int lastPos = firstPos + childCount - 1; + + int viewTravelCount; + int clampedPosition = Math.max(0, Math.min(getCount() - 1, position)); + if (clampedPosition < firstPos) { + final int boundPosFromLast = lastPos - boundPosition; + if (boundPosFromLast < 1) { + // Moving would shift our bound position off the screen. Abort. + return; + } + + final int posTravel = firstPos - clampedPosition + 1; + final int boundTravel = boundPosFromLast - 1; + if (boundTravel < posTravel) { + viewTravelCount = boundTravel; + mMode = MOVE_UP_BOUND; + } else { + viewTravelCount = posTravel; + mMode = MOVE_UP_POS; + } + } else if (clampedPosition > lastPos) { + final int boundPosFromFirst = boundPosition - firstPos; + if (boundPosFromFirst < 1) { + // Moving would shift our bound position off the screen. Abort. + return; + } + + final int posTravel = clampedPosition - lastPos + 1; + final int boundTravel = boundPosFromFirst - 1; + if (boundTravel < posTravel) { + viewTravelCount = boundTravel; + mMode = MOVE_DOWN_BOUND; + } else { + viewTravelCount = posTravel; + mMode = MOVE_DOWN_POS; + } + } else { + scrollToVisible(clampedPosition, boundPosition, SCROLL_DURATION); + return; + } + + if (viewTravelCount > 0) { + mScrollDuration = SCROLL_DURATION / viewTravelCount; + } else { + mScrollDuration = SCROLL_DURATION; + } + mTargetPos = clampedPosition; + mBoundPos = boundPosition; + mLastSeenPos = INVALID_POSITION; + + postOnAnimation(this); + } + + @Override + public void startWithOffset(int position, int offset) { + startWithOffset(position, offset, SCROLL_DURATION); + } + + @Override + public void startWithOffset(final int position, int offset, final int duration) { + stop(); + + if (mDataChanged) { + // Wait until we're back in a stable state to try this. + final int postOffset = offset; + mPositionScrollAfterLayout = new Runnable() { + @Override public void run() { + startWithOffset(position, postOffset, duration); + } + }; + return; + } + + final int childCount = getChildCount(); + if (childCount == 0) { + // Can't scroll without children. + return; + } + + offset += getPaddingTop(); + + mTargetPos = Math.max(0, Math.min(getCount() - 1, position)); + mOffsetFromTop = offset; + mBoundPos = INVALID_POSITION; + mLastSeenPos = INVALID_POSITION; + mMode = MOVE_OFFSET; + + final int firstPos = mFirstPosition; + final int lastPos = firstPos + childCount - 1; + + int viewTravelCount; + if (mTargetPos < firstPos) { + viewTravelCount = firstPos - mTargetPos; + } else if (mTargetPos > lastPos) { + viewTravelCount = mTargetPos - lastPos; + } else { + // On-screen, just scroll. + final int targetTop = getChildAt(mTargetPos - firstPos).getTop(); + smoothScrollBy(targetTop - offset, duration, true); + return; + } + + // Estimate how many screens we should travel + final float screenTravelCount = (float) viewTravelCount / childCount; + mScrollDuration = screenTravelCount < 1 ? + duration : (int) (duration / screenTravelCount); + mLastSeenPos = INVALID_POSITION; + + postOnAnimation(this); + } + + /** + * Scroll such that targetPos is in the visible padded region without scrolling + * boundPos out of view. Assumes targetPos is onscreen. + */ + private void scrollToVisible(int targetPos, int boundPos, int duration) { + final int firstPos = mFirstPosition; + final int childCount = getChildCount(); + final int lastPos = firstPos + childCount - 1; + final int paddedTop = mListPadding.top; + final int paddedBottom = getHeight() - mListPadding.bottom; + + if (targetPos < firstPos || targetPos > lastPos) { + Log.w(TAG, "scrollToVisible called with targetPos " + targetPos + + " not visible [" + firstPos + ", " + lastPos + "]"); + } + if (boundPos < firstPos || boundPos > lastPos) { + // boundPos doesn't matter, it's already offscreen. + boundPos = INVALID_POSITION; + } + + final View targetChild = getChildAt(targetPos - firstPos); + final int targetTop = targetChild.getTop(); + final int targetBottom = targetChild.getBottom(); + int scrollBy = 0; + + if (targetBottom > paddedBottom) { + scrollBy = targetBottom - paddedBottom; + } + if (targetTop < paddedTop) { + scrollBy = targetTop - paddedTop; + } + + if (scrollBy == 0) { + return; + } + + if (boundPos >= 0) { + final View boundChild = getChildAt(boundPos - firstPos); + final int boundTop = boundChild.getTop(); + final int boundBottom = boundChild.getBottom(); + final int absScroll = Math.abs(scrollBy); + + if (scrollBy < 0 && boundBottom + absScroll > paddedBottom) { + // Don't scroll the bound view off the bottom of the screen. + scrollBy = Math.max(0, boundBottom - paddedBottom); + } else if (scrollBy > 0 && boundTop - absScroll < paddedTop) { + // Don't scroll the bound view off the top of the screen. + scrollBy = Math.min(0, boundTop - paddedTop); + } + } + + smoothScrollBy(scrollBy, duration); + } + + @Override + public void stop() { + removeCallbacks(this); + } + + @Override + public void run() { + final int listHeight = getHeight(); + final int firstPos = mFirstPosition; + + switch (mMode) { + case MOVE_DOWN_POS: { + final int lastViewIndex = getChildCount() - 1; + final int lastPos = firstPos + lastViewIndex; + + if (lastViewIndex < 0) { + return; + } + + if (lastPos == mLastSeenPos) { + // No new views, let things keep going. + postOnAnimation(this); + return; + } + + final View lastView = getChildAt(lastViewIndex); + final int lastViewHeight = lastView.getHeight(); + final int lastViewTop = lastView.getTop(); + final int lastViewPixelsShowing = listHeight - lastViewTop; + final int extraScroll = lastPos < mItemCount - 1 ? + Math.max(mListPadding.bottom, mExtraScroll) : mListPadding.bottom; + + final int scrollBy = lastViewHeight - lastViewPixelsShowing + extraScroll; + smoothScrollBy(scrollBy, mScrollDuration, true); + + mLastSeenPos = lastPos; + if (lastPos < mTargetPos) { + postOnAnimation(this); + } + break; + } + + case MOVE_DOWN_BOUND: { + final int nextViewIndex = 1; + final int childCount = getChildCount(); + + if (firstPos == mBoundPos || childCount <= nextViewIndex + || firstPos + childCount >= mItemCount) { + return; + } + final int nextPos = firstPos + nextViewIndex; + + if (nextPos == mLastSeenPos) { + // No new views, let things keep going. + postOnAnimation(this); + return; + } + + final View nextView = getChildAt(nextViewIndex); + final int nextViewHeight = nextView.getHeight(); + final int nextViewTop = nextView.getTop(); + final int extraScroll = Math.max(mListPadding.bottom, mExtraScroll); + if (nextPos < mBoundPos) { + smoothScrollBy(Math.max(0, nextViewHeight + nextViewTop - extraScroll), + mScrollDuration, true); + + mLastSeenPos = nextPos; + + postOnAnimation(this); + } else { + if (nextViewTop > extraScroll) { + smoothScrollBy(nextViewTop - extraScroll, mScrollDuration, true); + } + } + break; + } + + case MOVE_UP_POS: { + if (firstPos == mLastSeenPos) { + // No new views, let things keep going. + postOnAnimation(this); + return; + } + + final View firstView = getChildAt(0); + if (firstView == null) { + return; + } + final int firstViewTop = firstView.getTop(); + final int extraScroll = firstPos > 0 ? + Math.max(mExtraScroll, mListPadding.top) : mListPadding.top; + + smoothScrollBy(firstViewTop - extraScroll, mScrollDuration, true); + + mLastSeenPos = firstPos; + + if (firstPos > mTargetPos) { + postOnAnimation(this); + } + break; + } + + case MOVE_UP_BOUND: { + final int lastViewIndex = getChildCount() - 2; + if (lastViewIndex < 0) { + return; + } + final int lastPos = firstPos + lastViewIndex; + + if (lastPos == mLastSeenPos) { + // No new views, let things keep going. + postOnAnimation(this); + return; + } + + final View lastView = getChildAt(lastViewIndex); + final int lastViewHeight = lastView.getHeight(); + final int lastViewTop = lastView.getTop(); + final int lastViewPixelsShowing = listHeight - lastViewTop; + final int extraScroll = Math.max(mListPadding.top, mExtraScroll); + mLastSeenPos = lastPos; + if (lastPos > mBoundPos) { + smoothScrollBy(-(lastViewPixelsShowing - extraScroll), mScrollDuration, true); + postOnAnimation(this); + } else { + final int bottom = listHeight - extraScroll; + final int lastViewBottom = lastViewTop + lastViewHeight; + if (bottom > lastViewBottom) { + smoothScrollBy(-(bottom - lastViewBottom), mScrollDuration, true); + } + } + break; + } + + case MOVE_OFFSET: { + if (mLastSeenPos == firstPos) { + // No new views, let things keep going. + postOnAnimation(this); + return; + } + + mLastSeenPos = firstPos; + + final int childCount = getChildCount(); + final int position = mTargetPos; + final int lastPos = firstPos + childCount - 1; + + int viewTravelCount = 0; + if (position < firstPos) { + viewTravelCount = firstPos - position + 1; + } else if (position > lastPos) { + viewTravelCount = position - lastPos; + } + + // Estimate how many screens we should travel + final float screenTravelCount = (float) viewTravelCount / childCount; + + final float modifier = Math.min(Math.abs(screenTravelCount), 1.f); + if (position < firstPos) { + final int distance = (int) (-getHeight() * modifier); + final int duration = (int) (mScrollDuration * modifier); + smoothScrollBy(distance, duration, true); + postOnAnimation(this); + } else if (position > lastPos) { + final int distance = (int) (getHeight() * modifier); + final int duration = (int) (mScrollDuration * modifier); + smoothScrollBy(distance, duration, true); + postOnAnimation(this); + } else { + // On-screen, just scroll. + final int targetTop = getChildAt(position - firstPos).getTop(); + final int distance = targetTop - mOffsetFromTop; + final int duration = (int) (mScrollDuration * + ((float) Math.abs(distance) / getHeight())); + smoothScrollBy(distance, duration, true); + } + break; + } + + default: + break; + } + } + } + + /** + * Abstract position scroller that handles sub-position scrolling but has no + * understanding of layout. + */ + abstract class AbsSubPositionScroller extends AbsPositionScroller { private static final int DEFAULT_SCROLL_DURATION = 200; - private SubScroller mSubScroller; + private final SubScroller mSubScroller = new SubScroller(); /** * The target offset in pixels between the top of the list and the top @@ -7171,9 +7163,6 @@ public abstract class AbsListView extends AdapterView implements Te return; } - if (mSubScroller == null) { - mSubScroller = new SubScroller(); - } mSubScroller.startScroll(startSubRow, endSubRow, duration); postOnAnimation(mAnimationFrame); @@ -7228,28 +7217,67 @@ public abstract class AbsListView extends AdapterView implements Te return Math.max(boundSubRow, targetSubRow); } - public void start(int position, int boundPosition) { - scrollToPosition(position, false, 0, boundPosition, DEFAULT_SCROLL_DURATION); - } - - public void startWithOffset(int position, int offset, int duration) { - scrollToPosition(position, true, offset, INVALID_POSITION, duration); - } - + @Override public void start(int position) { scrollToPosition(position, false, 0, INVALID_POSITION, DEFAULT_SCROLL_DURATION); } + @Override + public void start(int position, int boundPosition) { + scrollToPosition(position, false, 0, boundPosition, DEFAULT_SCROLL_DURATION); + } + + @Override + public void startWithOffset(int position, int offset) { + scrollToPosition(position, true, offset, INVALID_POSITION, DEFAULT_SCROLL_DURATION); + } + + @Override + public void startWithOffset(int position, int offset, int duration) { + scrollToPosition(position, true, offset, INVALID_POSITION, duration); + } + + @Override public void stop() { removeCallbacks(mAnimationFrame); } + /** + * Returns the height of a row, which is computed as the maximum height of + * the items in the row. + * + * @param row the row index + * @return row height in pixels + */ + public abstract int getHeightForRow(int row); + + /** + * Returns the row for the specified item position. + * + * @param position the item position + * @return the row index + */ + public abstract int getRowForPosition(int position); + + /** + * Returns the first item position within the specified row. + * + * @param row the row + * @return the position of the first item in the row + */ + public abstract int getFirstPositionForRow(int row); + private void onAnimationFrame() { final boolean shouldPost = mSubScroller.computePosition(); final float subRow = mSubScroller.getPosition(); final int row = (int) subRow; final int position = getFirstPositionForRow(row); + if (position >= getCount()) { + // Invalid position, abort scrolling. + return; + } + final int rowHeight = getHeightForRow(row); final int offset = (int) (rowHeight * (subRow - row)); final int addOffset = (int) (mOffset * mSubScroller.getInterpolatedValue()); @@ -7271,7 +7299,7 @@ public abstract class AbsListView extends AdapterView implements Te /** * Scroller capable of returning floating point positions. */ - private static class SubScroller { + static class SubScroller { private final Interpolator mInterpolator; private float mStartPosition; diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java index 0b424f72be21d..24e4cb39ae326 100644 --- a/core/java/android/widget/GridView.java +++ b/core/java/android/widget/GridView.java @@ -35,6 +35,8 @@ import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.AccessibilityNodeInfo.CollectionInfo; import android.view.accessibility.AccessibilityNodeInfo.CollectionItemInfo; import android.view.animation.GridLayoutAnimationController; +import android.widget.AbsListView.AbsPositionScroller; +import android.widget.ListView.ListViewPositionScroller; import android.widget.RemoteViews.RemoteView; import java.lang.annotation.Retention; @@ -1027,13 +1029,8 @@ public class GridView extends AbsListView { } @Override - public int getRowForPosition(int position) { - return position / mNumColumns; - } - - @Override - public int getFirstPositionForRow(int row) { - return row * mNumColumns; + AbsPositionScroller createPositionScroller() { + return new GridViewPositionScroller(); } @Override @@ -2357,4 +2354,33 @@ public class GridView extends AbsListView { final CollectionItemInfo itemInfo = CollectionItemInfo.obtain(column, 1, row, 1, isHeading); info.setCollectionItemInfo(itemInfo); } + + /** + * Sub-position scroller that understands the layout of a GridView. + */ + class GridViewPositionScroller extends AbsSubPositionScroller { + @Override + public int getRowForPosition(int position) { + return position / mNumColumns; + } + + @Override + public int getFirstPositionForRow(int row) { + return row * mNumColumns; + } + + @Override + public int getHeightForRow(int row) { + final int firstRowPosition = row * mNumColumns; + final int lastRowPosition = Math.min(getCount(), firstRowPosition + mNumColumns); + int maxHeight = 0; + for (int i = firstRowPosition; i < lastRowPosition; i++) { + final int height = getHeightForPosition(i); + if (height > maxHeight) { + maxHeight = height; + } + } + return maxHeight; + } + } } diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java index f937cd629d906..ca139b3ac3331 100644 --- a/core/java/android/widget/ListView.java +++ b/core/java/android/widget/ListView.java @@ -3775,13 +3775,8 @@ public class ListView extends AbsListView { } @Override - public int getRowForPosition(int position) { - return position; - } - - @Override - public int getFirstPositionForRow(int row) { - return row; + AbsPositionScroller createPositionScroller() { + return new ListViewPositionScroller(); } @Override @@ -3810,4 +3805,24 @@ public class ListView extends AbsListView { final CollectionItemInfo itemInfo = CollectionItemInfo.obtain(0, 1, position, 1, isHeading); info.setCollectionItemInfo(itemInfo); } + + /** + * Sub-position scroller that understands the layout of a ListView. + */ + class ListViewPositionScroller extends AbsSubPositionScroller { + @Override + public int getRowForPosition(int position) { + return position; + } + + @Override + public int getFirstPositionForRow(int row) { + return row; + } + + @Override + public int getHeightForRow(int row) { + return getHeightForPosition(row); + } + } } From 4a78985e671f1f321a5db2b5ff41554814759fa1 Mon Sep 17 00:00:00 2001 From: Alan Viverette Date: Tue, 18 Feb 2014 14:07:35 -0800 Subject: [PATCH 019/119] Fix sub scroller bounds checking BUG: 13031919 Change-Id: I6b569b50034fbe70441e11e56706faa9f2acfcbd --- core/java/android/widget/AbsListView.java | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index 63ce5a3894900..93b95bf6efd9b 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -7155,7 +7155,7 @@ public abstract class AbsListView extends AdapterView implements Te float endSubRow = targetRow; if (boundPosition != INVALID_POSITION) { final int boundRow = getRowForPosition(boundPosition); - if (boundRow >= firstRow && boundRow < lastRow) { + if (boundRow >= firstRow && boundRow < lastRow && boundRow != targetRow) { endSubRow = computeBoundSubRow(targetRow, boundRow); } } @@ -7185,15 +7185,18 @@ public abstract class AbsListView extends AdapterView implements Te } private float computeBoundSubRow(int targetRow, int boundRow) { - // Compute the target and offset as a sub-position. + // If the final offset is greater than 0, we're aiming above the + // suggested target row. Compute the actual target row and offset + // within that row by subtracting the height of each preceeding row. int remainingOffset = mOffset; - int targetHeight = getHeightForRow(targetRow - 1); - while (remainingOffset > 0) { - remainingOffset -= targetHeight; + int targetHeight = getHeightForRow(targetRow); + while (targetRow > 0 && remainingOffset > targetHeight) { targetRow--; - targetHeight = getHeightForRow(targetRow - 1); + remainingOffset -= targetHeight; + targetHeight = getHeightForRow(targetRow); } + // Compute the offset within the actual target row. final float targetOffsetRatio; if (targetHeight == 0) { targetOffsetRatio = 1; @@ -7201,6 +7204,7 @@ public abstract class AbsListView extends AdapterView implements Te targetOffsetRatio = remainingOffset / (float) targetHeight; } + // The final offset has been accounted for, reset it. final float targetSubRow = targetRow - targetOffsetRatio; mOffset = 0; From 47698278cc7baf0c17c10286772f765f895a8e36 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Wed, 19 Feb 2014 10:49:24 -0800 Subject: [PATCH 020/119] Fix issue #13095629: Device is in restart mode for long time... ...during taking OTA Add some sanity checks. Change-Id: I6bec1b8d8443c4b3c2a706635acf89c8e5051428 --- core/java/com/android/internal/os/BatteryStatsImpl.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 155f062be9c63..274e26756506b 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -23,6 +23,7 @@ import android.bluetooth.BluetoothHeadset; import android.content.Context; import android.net.ConnectivityManager; import android.net.NetworkStats; +import android.os.BadParcelableException; import android.os.BatteryManager; import android.os.BatteryStats; import android.os.FileUtils; @@ -86,7 +87,7 @@ public final class BatteryStatsImpl extends BatteryStats { private static final int MAGIC = 0xBA757475; // 'BATSTATS' // Current on-disk Parcel version - private static final int VERSION = 84 + (USE_OLD_HISTORY ? 1000 : 0); + private static final int VERSION = 85 + (USE_OLD_HISTORY ? 1000 : 0); // Maximum number of items we will record in the history. private static final int MAX_HISTORY_ITEMS = 2000; @@ -6026,7 +6027,7 @@ public final class BatteryStatsImpl extends BatteryStats { stream.close(); readSummaryFromParcel(in); - } catch(java.io.IOException e) { + } catch(Exception e) { Slog.e("BatteryStats", "Error reading battery statistics", e); } @@ -6234,6 +6235,9 @@ public final class BatteryStatsImpl extends BatteryStats { } sNumSpeedSteps = in.readInt(); + if (sNumSpeedSteps < 0 || sNumSpeedSteps > 100) { + throw new BadParcelableException("Bad speed steps in data: " + sNumSpeedSteps); + } final int NU = in.readInt(); if (NU > 10000) { From 1329f3bf2945452758478a9e6b60d24ec5c5d0ea Mon Sep 17 00:00:00 2001 From: John Spurlock Date: Wed, 19 Feb 2014 09:49:25 -0500 Subject: [PATCH 021/119] Don't call back into AM to get current user. Bug:13079471 Change-Id: I733d6e3c41c91008406261eac827e6b65bb400db --- .../policy/impl/ImmersiveModeConfirmation.java | 12 ++---------- .../internal/policy/impl/PhoneWindowManager.java | 2 +- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/policy/src/com/android/internal/policy/impl/ImmersiveModeConfirmation.java b/policy/src/com/android/internal/policy/impl/ImmersiveModeConfirmation.java index 3cc74fc290106..5602206f0f646 100644 --- a/policy/src/com/android/internal/policy/impl/ImmersiveModeConfirmation.java +++ b/policy/src/com/android/internal/policy/impl/ImmersiveModeConfirmation.java @@ -84,9 +84,9 @@ public class ImmersiveModeConfirmation { return exit != null ? exit.getDuration() : 0; } - public void loadSetting() { + public void loadSetting(int currentUserId) { mConfirmed = false; - mCurrentUserId = getCurrentUser(); + mCurrentUserId = currentUserId; if (DEBUG) Slog.d(TAG, String.format("loadSetting() mCurrentUserId=%d resetForPanic=%s", mCurrentUserId, mUserPanicResets.get(mCurrentUserId, false))); String value = null; @@ -159,14 +159,6 @@ public class ImmersiveModeConfirmation { saveSetting(); } - private int getCurrentUser() { - try { - return ActivityManagerNative.getDefault().getCurrentUser().id; - } catch (RemoteException e) { - throw new IllegalStateException(e); // local call - } - } - private void handleHide() { if (mClingWindow != null) { if (DEBUG) Slog.d(TAG, "Hiding immersive mode confirmation"); diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index 96c395be491ed..ada649d6c14f0 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -1168,7 +1168,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { updateRotation = true; } if (mImmersiveModeConfirmation != null) { - mImmersiveModeConfirmation.loadSetting(); + mImmersiveModeConfirmation.loadSetting(mCurrentUserId); } PolicyControl.reloadFromSetting(mContext); } From 343d1e6f3013f90bceb3ebc5d7928a7b0312ec9e Mon Sep 17 00:00:00 2001 From: John Reck Date: Thu, 20 Feb 2014 13:18:42 -0800 Subject: [PATCH 022/119] Fix NPE in layer destruction Bug: 13111945 Fixes an issue where a layer is destroyed after the GLRenderer lost its Surface. Instead just check that the context we want is current regardless of the active surface Change-Id: I6537e6232b5c667b218b896ed5ef390fbe956344 --- core/java/android/view/GLRenderer.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/core/java/android/view/GLRenderer.java b/core/java/android/view/GLRenderer.java index abb59e34eb9a4..d61c4b137cf7c 100644 --- a/core/java/android/view/GLRenderer.java +++ b/core/java/android/view/GLRenderer.java @@ -499,12 +499,17 @@ public class GLRenderer extends HardwareRenderer { mAttachedLayers.add(hardwareLayer); } + boolean hasContext() { + return sEgl != null && mEglContext != null + && mEglContext.equals(sEgl.eglGetCurrentContext()); + } + @Override void onLayerDestroyed(HardwareLayer layer) { if (mGlCanvas != null) { mGlCanvas.cancelLayerUpdate(layer); } - if (Looper.myLooper() == Looper.getMainLooper() && validate()) { + if (hasContext()) { long backingLayer = layer.detachBackingLayer(); nDestroyLayer(backingLayer); } From 7a823ae00db95c0a7c5fbff14d5d2ea57116d1b0 Mon Sep 17 00:00:00 2001 From: Adam Lesinski Date: Fri, 21 Feb 2014 14:06:47 -0800 Subject: [PATCH 023/119] Fix broken IME when decrypting storage Bug:13113499 Change-Id: Icf767864c8ff694fd569b9237ae1004cc20204a2 --- .../java/com/android/server/SystemServer.java | 243 +++++++++--------- 1 file changed, 118 insertions(+), 125 deletions(-) diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 42193affb52c1..83dbbb2138e83 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -1001,138 +1001,131 @@ public final class SystemServer { // where third party code can really run (but before it has actually // started launching the initial applications), for us to complete our // initialization. - final Handler handler = new Handler(); mActivityManagerService.systemReady(new Runnable() { @Override public void run() { - // We initiate all boot phases on the SystemServer thread. - handler.post(new Runnable() { - @Override - public void run() { - Slog.i(TAG, "Making services ready"); - mSystemServiceManager.startBootPhase( - SystemService.PHASE_ACTIVITY_MANAGER_READY); + Slog.i(TAG, "Making services ready"); + mSystemServiceManager.startBootPhase( + SystemService.PHASE_ACTIVITY_MANAGER_READY); - try { - mActivityManagerService.startObservingNativeCrashes(); - } catch (Throwable e) { - reportWtf("observing native crashes", e); - } - try { - startSystemUi(context); - } catch (Throwable e) { - reportWtf("starting System UI", e); - } - try { - if (mountServiceF != null) mountServiceF.systemReady(); - } catch (Throwable e) { - reportWtf("making Mount Service ready", e); - } - try { - if (batteryF != null) batteryF.systemReady(); - } catch (Throwable e) { - reportWtf("making Battery Service ready", e); - } - try { - if (networkManagementF != null) networkManagementF.systemReady(); - } catch (Throwable e) { - reportWtf("making Network Managment Service ready", e); - } - try { - if (networkStatsF != null) networkStatsF.systemReady(); - } catch (Throwable e) { - reportWtf("making Network Stats Service ready", e); - } - try { - if (networkPolicyF != null) networkPolicyF.systemReady(); - } catch (Throwable e) { - reportWtf("making Network Policy Service ready", e); - } - try { - if (connectivityF != null) connectivityF.systemReady(); - } catch (Throwable e) { - reportWtf("making Connectivity Service ready", e); - } - try { - if (dockF != null) dockF.systemReady(); - } catch (Throwable e) { - reportWtf("making Dock Service ready", e); - } - try { - if (recognitionF != null) recognitionF.systemReady(); - } catch (Throwable e) { - reportWtf("making Recognition Service ready", e); - } - Watchdog.getInstance().start(); + try { + mActivityManagerService.startObservingNativeCrashes(); + } catch (Throwable e) { + reportWtf("observing native crashes", e); + } + try { + startSystemUi(context); + } catch (Throwable e) { + reportWtf("starting System UI", e); + } + try { + if (mountServiceF != null) mountServiceF.systemReady(); + } catch (Throwable e) { + reportWtf("making Mount Service ready", e); + } + try { + if (batteryF != null) batteryF.systemReady(); + } catch (Throwable e) { + reportWtf("making Battery Service ready", e); + } + try { + if (networkManagementF != null) networkManagementF.systemReady(); + } catch (Throwable e) { + reportWtf("making Network Managment Service ready", e); + } + try { + if (networkStatsF != null) networkStatsF.systemReady(); + } catch (Throwable e) { + reportWtf("making Network Stats Service ready", e); + } + try { + if (networkPolicyF != null) networkPolicyF.systemReady(); + } catch (Throwable e) { + reportWtf("making Network Policy Service ready", e); + } + try { + if (connectivityF != null) connectivityF.systemReady(); + } catch (Throwable e) { + reportWtf("making Connectivity Service ready", e); + } + try { + if (dockF != null) dockF.systemReady(); + } catch (Throwable e) { + reportWtf("making Dock Service ready", e); + } + try { + if (recognitionF != null) recognitionF.systemReady(); + } catch (Throwable e) { + reportWtf("making Recognition Service ready", e); + } + Watchdog.getInstance().start(); - // It is now okay to let the various system services start their - // third party code... - mSystemServiceManager.startBootPhase( - SystemService.PHASE_THIRD_PARTY_APPS_CAN_START); + // It is now okay to let the various system services start their + // third party code... + mSystemServiceManager.startBootPhase( + SystemService.PHASE_THIRD_PARTY_APPS_CAN_START); - try { - if (wallpaperF != null) wallpaperF.systemRunning(); - } catch (Throwable e) { - reportWtf("Notifying WallpaperService running", e); - } - try { - if (immF != null) immF.systemRunning(statusBarF); - } catch (Throwable e) { - reportWtf("Notifying InputMethodService running", e); - } - try { - if (locationF != null) locationF.systemRunning(); - } catch (Throwable e) { - reportWtf("Notifying Location Service running", e); - } - try { - if (countryDetectorF != null) countryDetectorF.systemRunning(); - } catch (Throwable e) { - reportWtf("Notifying CountryDetectorService running", e); - } - try { - if (networkTimeUpdaterF != null) networkTimeUpdaterF.systemRunning(); - } catch (Throwable e) { - reportWtf("Notifying NetworkTimeService running", e); - } - try { - if (commonTimeMgmtServiceF != null) { - commonTimeMgmtServiceF.systemRunning(); - } - } catch (Throwable e) { - reportWtf("Notifying CommonTimeManagementService running", e); - } - try { - if (textServiceManagerServiceF != null) - textServiceManagerServiceF.systemRunning(); - } catch (Throwable e) { - reportWtf("Notifying TextServicesManagerService running", e); - } - try { - if (atlasF != null) atlasF.systemRunning(); - } catch (Throwable e) { - reportWtf("Notifying AssetAtlasService running", e); - } - try { - // TODO(BT) Pass parameter to input manager - if (inputManagerF != null) inputManagerF.systemRunning(); - } catch (Throwable e) { - reportWtf("Notifying InputManagerService running", e); - } - try { - if (telephonyRegistryF != null) telephonyRegistryF.systemRunning(); - } catch (Throwable e) { - reportWtf("Notifying TelephonyRegistry running", e); - } - try { - if (mediaRouterF != null) mediaRouterF.systemRunning(); - } catch (Throwable e) { - reportWtf("Notifying MediaRouterService running", e); - } - - mSystemServiceManager.startBootPhase(SystemService.PHASE_BOOT_COMPLETE); + try { + if (wallpaperF != null) wallpaperF.systemRunning(); + } catch (Throwable e) { + reportWtf("Notifying WallpaperService running", e); + } + try { + if (immF != null) immF.systemRunning(statusBarF); + } catch (Throwable e) { + reportWtf("Notifying InputMethodService running", e); + } + try { + if (locationF != null) locationF.systemRunning(); + } catch (Throwable e) { + reportWtf("Notifying Location Service running", e); + } + try { + if (countryDetectorF != null) countryDetectorF.systemRunning(); + } catch (Throwable e) { + reportWtf("Notifying CountryDetectorService running", e); + } + try { + if (networkTimeUpdaterF != null) networkTimeUpdaterF.systemRunning(); + } catch (Throwable e) { + reportWtf("Notifying NetworkTimeService running", e); + } + try { + if (commonTimeMgmtServiceF != null) { + commonTimeMgmtServiceF.systemRunning(); } - }); + } catch (Throwable e) { + reportWtf("Notifying CommonTimeManagementService running", e); + } + try { + if (textServiceManagerServiceF != null) + textServiceManagerServiceF.systemRunning(); + } catch (Throwable e) { + reportWtf("Notifying TextServicesManagerService running", e); + } + try { + if (atlasF != null) atlasF.systemRunning(); + } catch (Throwable e) { + reportWtf("Notifying AssetAtlasService running", e); + } + try { + // TODO(BT) Pass parameter to input manager + if (inputManagerF != null) inputManagerF.systemRunning(); + } catch (Throwable e) { + reportWtf("Notifying InputManagerService running", e); + } + try { + if (telephonyRegistryF != null) telephonyRegistryF.systemRunning(); + } catch (Throwable e) { + reportWtf("Notifying TelephonyRegistry running", e); + } + try { + if (mediaRouterF != null) mediaRouterF.systemRunning(); + } catch (Throwable e) { + reportWtf("Notifying MediaRouterService running", e); + } + + mSystemServiceManager.startBootPhase(SystemService.PHASE_BOOT_COMPLETE); } }); } From 1ea9d3ca489ff89b8c437b1fd25532698f8a549a Mon Sep 17 00:00:00 2001 From: Michael Wright Date: Tue, 18 Feb 2014 22:50:50 -0800 Subject: [PATCH 024/119] Unbreak manual brightness setting. Change-Id: I0ba5b82f60eacd66db0dcf4166e9a919ee06f2e0 --- .../java/com/android/server/power/DisplayPowerController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/power/DisplayPowerController.java b/services/core/java/com/android/server/power/DisplayPowerController.java index 291bb64728a79..38d99ef8441d1 100644 --- a/services/core/java/com/android/server/power/DisplayPowerController.java +++ b/services/core/java/com/android/server/power/DisplayPowerController.java @@ -503,7 +503,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call boolean slow; int screenAutoBrightness = mAutomaticBrightnessController != null ? mAutomaticBrightnessController.getAutomaticScreenBrightness() : -1; - if (screenAutoBrightness >= 0) { + if (screenAutoBrightness >= 0 && mPowerRequest.useAutoBrightness) { // Use current auto-brightness value. target = screenAutoBrightness; slow = mUsingScreenAutoBrightness; From 3e98f8f421c615493522a783203fb91c9c227490 Mon Sep 17 00:00:00 2001 From: Alan Viverette Date: Mon, 24 Feb 2014 11:09:18 -0800 Subject: [PATCH 025/119] Check for null view root before checking for accessibility focus BUG: 13168971 Change-Id: Ia75d77b18112371f56a624e11f9509f14ec98093 --- core/java/android/widget/GridView.java | 45 ++++++++++++++------------ core/java/android/widget/ListView.java | 45 ++++++++++++++------------ 2 files changed, 48 insertions(+), 42 deletions(-) diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java index 4ed48ff08f904..04b18c1e873de 100644 --- a/core/java/android/widget/GridView.java +++ b/core/java/android/widget/GridView.java @@ -1335,27 +1335,30 @@ public class GridView extends AbsListView { } // Attempt to restore accessibility focus, if necessary. - final View newAccessibilityFocusedView = viewRootImpl.getAccessibilityFocusedHost(); - if (newAccessibilityFocusedView == null) { - if (accessibilityFocusLayoutRestoreView != null - && accessibilityFocusLayoutRestoreView.isAttachedToWindow()) { - final AccessibilityNodeProvider provider = - accessibilityFocusLayoutRestoreView.getAccessibilityNodeProvider(); - if (accessibilityFocusLayoutRestoreNode != null && provider != null) { - final int virtualViewId = AccessibilityNodeInfo.getVirtualDescendantId( - accessibilityFocusLayoutRestoreNode.getSourceNodeId()); - provider.performAction(virtualViewId, - AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null); - } else { - accessibilityFocusLayoutRestoreView.requestAccessibilityFocus(); - } - } else if (accessibilityFocusPosition != INVALID_POSITION) { - // Bound the position within the visible children. - final int position = MathUtils.constrain( - accessibilityFocusPosition - mFirstPosition, 0, getChildCount() - 1); - final View restoreView = getChildAt(position); - if (restoreView != null) { - restoreView.requestAccessibilityFocus(); + if (viewRootImpl != null) { + final View newAccessibilityFocusedView = viewRootImpl.getAccessibilityFocusedHost(); + if (newAccessibilityFocusedView == null) { + if (accessibilityFocusLayoutRestoreView != null + && accessibilityFocusLayoutRestoreView.isAttachedToWindow()) { + final AccessibilityNodeProvider provider = + accessibilityFocusLayoutRestoreView.getAccessibilityNodeProvider(); + if (accessibilityFocusLayoutRestoreNode != null && provider != null) { + final int virtualViewId = AccessibilityNodeInfo.getVirtualDescendantId( + accessibilityFocusLayoutRestoreNode.getSourceNodeId()); + provider.performAction(virtualViewId, + AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null); + } else { + accessibilityFocusLayoutRestoreView.requestAccessibilityFocus(); + } + } else if (accessibilityFocusPosition != INVALID_POSITION) { + // Bound the position within the visible children. + final int position = MathUtils.constrain( + accessibilityFocusPosition - mFirstPosition, 0, + getChildCount() - 1); + final View restoreView = getChildAt(position); + if (restoreView != null) { + restoreView.requestAccessibilityFocus(); + } } } } diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java index 63e13589b3b87..5de67c82cb44d 100644 --- a/core/java/android/widget/ListView.java +++ b/core/java/android/widget/ListView.java @@ -1738,27 +1738,30 @@ public class ListView extends AbsListView { } // Attempt to restore accessibility focus, if necessary. - final View newAccessibilityFocusedView = viewRootImpl.getAccessibilityFocusedHost(); - if (newAccessibilityFocusedView == null) { - if (accessibilityFocusLayoutRestoreView != null - && accessibilityFocusLayoutRestoreView.isAttachedToWindow()) { - final AccessibilityNodeProvider provider = - accessibilityFocusLayoutRestoreView.getAccessibilityNodeProvider(); - if (accessibilityFocusLayoutRestoreNode != null && provider != null) { - final int virtualViewId = AccessibilityNodeInfo.getVirtualDescendantId( - accessibilityFocusLayoutRestoreNode.getSourceNodeId()); - provider.performAction(virtualViewId, - AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null); - } else { - accessibilityFocusLayoutRestoreView.requestAccessibilityFocus(); - } - } else if (accessibilityFocusPosition != INVALID_POSITION) { - // Bound the position within the visible children. - final int position = MathUtils.constrain( - accessibilityFocusPosition - mFirstPosition, 0, getChildCount() - 1); - final View restoreView = getChildAt(position); - if (restoreView != null) { - restoreView.requestAccessibilityFocus(); + if (viewRootImpl != null) { + final View newAccessibilityFocusedView = viewRootImpl.getAccessibilityFocusedHost(); + if (newAccessibilityFocusedView == null) { + if (accessibilityFocusLayoutRestoreView != null + && accessibilityFocusLayoutRestoreView.isAttachedToWindow()) { + final AccessibilityNodeProvider provider = + accessibilityFocusLayoutRestoreView.getAccessibilityNodeProvider(); + if (accessibilityFocusLayoutRestoreNode != null && provider != null) { + final int virtualViewId = AccessibilityNodeInfo.getVirtualDescendantId( + accessibilityFocusLayoutRestoreNode.getSourceNodeId()); + provider.performAction(virtualViewId, + AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null); + } else { + accessibilityFocusLayoutRestoreView.requestAccessibilityFocus(); + } + } else if (accessibilityFocusPosition != INVALID_POSITION) { + // Bound the position within the visible children. + final int position = MathUtils.constrain( + accessibilityFocusPosition - mFirstPosition, 0, + getChildCount() - 1); + final View restoreView = getChildAt(position); + if (restoreView != null) { + restoreView.requestAccessibilityFocus(); + } } } } From 7468bb7156c72b5175604f2d5de5d3b2afa2f97b Mon Sep 17 00:00:00 2001 From: Jake Hamby Date: Thu, 6 Feb 2014 14:43:50 -0800 Subject: [PATCH 026/119] Remove unneeded new RIL command. Remove the recently added RIL_REQUEST_SET_RADIO_MODE command and update the definition of the RIL_REQUEST_NV_RESET_CONFIG parameter. Also remove some accidentally added debug log lines. Bug: 12864208 Change-Id: I6f035d6900c9fcb1427bad62057d7b4a1d3cd99c --- .../android/server/ConnectivityService.java | 6 ++--- .../android/telephony/TelephonyManager.java | 27 +++---------------- .../internal/telephony/ITelephony.aidl | 15 +++-------- .../internal/telephony/RILConstants.java | 5 ++-- 4 files changed, 12 insertions(+), 41 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 342336e1d8b58..2afb53d7b3d2b 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -169,9 +169,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { private static final String TAG = "ConnectivityService"; private static final boolean DBG = true; - private static final boolean VDBG = true; + private static final boolean VDBG = false; - private static final boolean LOGD_RULES = true; + private static final boolean LOGD_RULES = false; // TODO: create better separation between radio types and network types @@ -4504,7 +4504,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { * @param seconds */ private static void sleep(int seconds) { - log("XXXXX sleeping for " + seconds + " sec"); long stopTime = System.nanoTime() + (seconds * 1000000000); long sleepTime; while ((sleepTime = stopTime - System.nanoTime()) > 0) { @@ -4513,7 +4512,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { } catch (InterruptedException ignored) { } } - log("XXXXX returning from sleep"); } private static void log(String s) { diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 23e4d7700743f..d28d76d585a2f 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -1823,10 +1823,11 @@ public class TelephonyManager { } /** - * Perform the specified type of NV config reset. - * Used for device configuration by some CDMA operators. + * Perform the specified type of NV config reset. The radio will be taken offline + * and the device must be rebooted after the operation. Used for device + * configuration by some CDMA operators. * - * @param resetType the type of reset to perform (1 == factory reset; 2 == NV-only reset). + * @param resetType reset type: 1: reload NV reset, 2: erase NV reset, 3: factory NV reset * @return true on success; false on any failure. * @hide */ @@ -1840,24 +1841,4 @@ public class TelephonyManager { } return false; } - - /** - * Change the radio to the specified mode. - * Used for device configuration by some operators. - * - * @param radioMode is 0 for offline mode, 1 for online mode, 2 for low-power mode, - * or 3 to reset the radio. - * @return true on success; false on any failure. - * @hide - */ - public boolean setRadioMode(int radioMode) { - try { - return getITelephony().setRadioMode(radioMode); - } catch (RemoteException ex) { - Rlog.e(TAG, "setRadioMode RemoteException", ex); - } catch (NullPointerException ex) { - Rlog.e(TAG, "setRadioMode NPE", ex); - } - return false; - } } diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index 370e27a415883..554a9cbc21707 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -395,21 +395,12 @@ interface ITelephony { boolean nvWriteCdmaPrl(in byte[] preferredRoamingList); /** - * Perform the specified type of NV config reset. - * Used for device configuration by some CDMA operators. + * Perform the specified type of NV config reset. The radio will be taken offline + * and the device must be rebooted after the operation. Used for device + * configuration by some CDMA operators. * * @param resetType the type of reset to perform (1 == factory reset; 2 == NV-only reset). * @return true on success; false on any failure. */ boolean nvResetConfig(int resetType); - - /** - * Change the radio to the specified mode. - * Used for device configuration by some operators. - * - * @param radioMode is 0 for offline mode, 1 for online mode, 2 for low-power mode, - * or 3 to reset the radio. - * @return true on success; false on any failure. - */ - boolean setRadioMode(int radioMode); } diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java index 6015df0dcfd51..d338857490699 100644 --- a/telephony/java/com/android/internal/telephony/RILConstants.java +++ b/telephony/java/com/android/internal/telephony/RILConstants.java @@ -115,8 +115,9 @@ public interface RILConstants { int DEACTIVATE_REASON_PDP_RESET = 2; /* NV config radio reset types. */ - int NV_CONFIG_RESET_FACTORY = 1; - int NV_CONFIG_RESET_NV_ONLY = 2; + int NV_CONFIG_RELOAD_RESET = 1; + int NV_CONFIG_ERASE_RESET = 2; + int NV_CONFIG_FACTORY_RESET = 3; /* cat include/telephony/ril.h | \ From 011fcde0ee3ba9ac31fbea3024b9478a59784fbd Mon Sep 17 00:00:00 2001 From: Alan Viverette Date: Mon, 24 Feb 2014 12:24:11 -0800 Subject: [PATCH 027/119] Check for ongoing detachment in AbsListView BUG: 13167767 Change-Id: Ie1a828eadbb99daef46af77544f233fee09fd1bc --- core/java/android/widget/AbsListView.java | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index 3027be48b5769..86fdae3d6c627 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -703,6 +703,11 @@ public abstract class AbsListView extends AdapterView implements Te */ private SavedState mPendingSync; + /** + * Whether the view is in the process of detaching from its window. + */ + private boolean mIsDetaching; + /** * Interface definition for a callback to be invoked when the list or grid * has been scrolled. @@ -2788,6 +2793,8 @@ public abstract class AbsListView extends AdapterView implements Te protected void onDetachedFromWindow() { super.onDetachedFromWindow(); + mIsDetaching = true; + // Dismiss the popup in case onSaveInstanceState() was not invoked dismissPopup(); @@ -2836,6 +2843,8 @@ public abstract class AbsListView extends AdapterView implements Te removeCallbacks(mTouchModeReset); mTouchModeReset.run(); } + + mIsDetaching = false; } @Override @@ -3462,7 +3471,7 @@ public abstract class AbsListView extends AdapterView implements Te mPositionScroller.stop(); } - if (!isAttachedToWindow()) { + if (mIsDetaching || !isAttachedToWindow()) { // Something isn't right. // Since we rely on being attached to get data set change notifications, // don't risk doing anything where we might try to resync and find things @@ -3701,7 +3710,7 @@ public abstract class AbsListView extends AdapterView implements Te mTouchMode = TOUCH_MODE_REST; child.setPressed(false); setPressed(false); - if (!mDataChanged && isAttachedToWindow()) { + if (!mDataChanged && !mIsDetaching && isAttachedToWindow()) { performClick.run(); } } @@ -3976,7 +3985,7 @@ public abstract class AbsListView extends AdapterView implements Te mPositionScroller.stop(); } - if (!isAttachedToWindow()) { + if (mIsDetaching || !isAttachedToWindow()) { // Something isn't right. // Since we rely on being attached to get data set change notifications, // don't risk doing anything where we might try to resync and find things From ad1ac70417c23f3d742d14f96251e4a37f4f2fa2 Mon Sep 17 00:00:00 2001 From: Dan Sandler Date: Tue, 25 Feb 2014 12:11:05 -0500 Subject: [PATCH 028/119] Fix boot crash on devices defaulting to landscape. This is probably not what keyguard_simple_host_view should look like in landscape, but we need the resource. Bug: 13185323 Change-Id: Ib044db1f86510128d27ecf45546398c7c1b81aa4 --- .../layout-land/keyguard_simple_host_view.xml | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 packages/Keyguard/res/layout-land/keyguard_simple_host_view.xml diff --git a/packages/Keyguard/res/layout-land/keyguard_simple_host_view.xml b/packages/Keyguard/res/layout-land/keyguard_simple_host_view.xml new file mode 100644 index 0000000000000..ebd0a64307094 --- /dev/null +++ b/packages/Keyguard/res/layout-land/keyguard_simple_host_view.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + From 05175d17bd381c3b3840ddd81ca4de50ffdc6259 Mon Sep 17 00:00:00 2001 From: Jim Miller Date: Tue, 25 Feb 2014 15:36:13 -0800 Subject: [PATCH 029/119] Disable simple keyguard when notifications enabled. Enabling notifications on keyguard tripped keyguard into simple mode which isn't ready for prime-time. Disabled with variable. Fixes bug 13172958 Change-Id: Ia281b06d754cd62455010f9e31c0ee81e4937977 --- .../Keyguard/src/com/android/keyguard/KeyguardViewManager.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java b/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java index 43165eb75d8e4..40087cd01e6e9 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java @@ -71,6 +71,7 @@ public class KeyguardViewManager { // Timeout used for keypresses static final int DIGIT_PRESS_WAKE_MILLIS = 5000; + private static final boolean ENABLE_SIMPLE_KEYGUARD = false; private final Context mContext; private final ViewManager mViewManager; @@ -312,7 +313,7 @@ public class KeyguardViewManager { if (force || mKeyguardView == null) { mKeyguardHost.setCustomBackground(null); mKeyguardHost.removeAllViews(); - int layout = allowNotificationsOnSecureKeyguard() + int layout = (allowNotificationsOnSecureKeyguard() && ENABLE_SIMPLE_KEYGUARD) ? R.layout.keyguard_simple_host_view : R.layout.keyguard_host_view; if (mCurrentLayout != layout) { From d9c3eb125a31bb3d06fe555c1968116af5978fbe Mon Sep 17 00:00:00 2001 From: Alan Viverette Date: Thu, 27 Feb 2014 16:33:06 -0800 Subject: [PATCH 030/119] Refactor smooth scrolling sub-row calculation and clamp target BUG: 13205615 Change-Id: If3757be35593a072ba6e92aa9da085330a12fd9d --- core/java/android/widget/AbsListView.java | 115 +++++++++++----------- 1 file changed, 58 insertions(+), 57 deletions(-) diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index 66580f88c0b52..ffd5c45fb5d0d 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -56,7 +56,6 @@ import android.view.ViewConfiguration; import android.view.ViewDebug; import android.view.ViewGroup; import android.view.ViewParent; -import android.view.ViewRootImpl; import android.view.ViewTreeObserver; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; @@ -4479,6 +4478,7 @@ public abstract class AbsListView extends AdapterView implements Te * scroll such that the indicated position is displayed, but it will * stop early if scrolling further would scroll boundPosition out of * view. + * * @param position Scroll to this adapter position. * @param boundPosition Do not scroll if it would move this adapter * position out of view. @@ -7128,7 +7128,10 @@ public abstract class AbsListView extends AdapterView implements Te * understanding of layout. */ abstract class AbsSubPositionScroller extends AbsPositionScroller { - private static final int DEFAULT_SCROLL_DURATION = 200; + private static final int DURATION_AUTO = -1; + + private static final int DURATION_AUTO_MIN = 100; + private static final int DURATION_AUTO_MAX = 500; private final SubScroller mSubScroller = new SubScroller(); @@ -7157,9 +7160,11 @@ public abstract class AbsListView extends AdapterView implements Te return; } + final int itemCount = getCount(); + final int clampedPosition = MathUtils.constrain(targetPosition, 0, itemCount - 1); final int firstPosition = getFirstVisiblePosition(); final int lastPosition = firstPosition + getChildCount(); - final int targetRow = getRowForPosition(targetPosition); + final int targetRow = getRowForPosition(clampedPosition); final int firstRow = getRowForPosition(firstPosition); final int lastRow = getRowForPosition(lastPosition); if (useOffset || targetRow <= firstRow) { @@ -7168,7 +7173,7 @@ public abstract class AbsListView extends AdapterView implements Te } else if (targetRow >= lastRow - 1) { // Offset so the target row is bottom-aligned. final int listHeight = getHeight() - getPaddingTop() - getPaddingBottom(); - mOffset = listHeight - getHeightForPosition(targetPosition); + mOffset = getHeightForPosition(clampedPosition) - listHeight; } else { // Don't scroll, target is entirely on-screen. return; @@ -7190,7 +7195,7 @@ public abstract class AbsListView extends AdapterView implements Te final int firstChildHeight = firstChild.getHeight(); final float startOffsetRatio; if (firstChildHeight == 0) { - startOffsetRatio = 1; + startOffsetRatio = 0; } else { startOffsetRatio = -firstChild.getTop() / (float) firstChildHeight; } @@ -7202,40 +7207,63 @@ public abstract class AbsListView extends AdapterView implements Te return; } - mSubScroller.startScroll(startSubRow, endSubRow, duration); + final int durationMillis; + if (duration == DURATION_AUTO) { + final float subRowDelta = Math.abs(startSubRow - endSubRow); + durationMillis = (int) MathUtils.lerp( + DURATION_AUTO_MIN, DURATION_AUTO_MAX, subRowDelta / getCount()); + } else { + durationMillis = duration; + } + + mSubScroller.startScroll(startSubRow, endSubRow, durationMillis); postOnAnimation(mAnimationFrame); } - private float computeBoundSubRow(int targetRow, int boundRow) { - // If the final offset is greater than 0, we're aiming above the - // suggested target row. Compute the actual target row and offset - // within that row by subtracting the height of each preceeding row. - int remainingOffset = mOffset; + /** + * Given a target row and offset, computes the sub-row position that + * aligns with the top of the list. If the offset is negative, the + * resulting sub-row will be smaller than the target row. + */ + private float resolveOffset(int targetRow, int offset) { + // Compute the target sub-row position by finding the actual row + // indicated by the target and offset. + int remainingOffset = offset; int targetHeight = getHeightForRow(targetRow); - while (targetRow > 1 && remainingOffset > targetHeight) { - targetRow--; - remainingOffset -= targetHeight; - targetHeight = getHeightForRow(targetRow); + if (offset < 0) { + // Subtract row heights until we find the right row. + while (targetRow > 0 && remainingOffset < 0) { + remainingOffset += targetHeight; + targetRow--; + targetHeight = getHeightForRow(targetRow); + } + } else if (offset > 0) { + // Add row heights until we find the right row. + while (targetRow < getCount() - 1 && remainingOffset > targetHeight) { + remainingOffset -= targetHeight; + targetRow++; + targetHeight = getHeightForRow(targetRow); + } } - // Compute the offset within the actual target row. final float targetOffsetRatio; - if (remainingOffset > 0) { - // We can't reach that offset given the row count. + if (remainingOffset < 0 || targetHeight == 0) { targetOffsetRatio = 0; - } else if (targetHeight == 0) { - targetOffsetRatio = 1; } else { targetOffsetRatio = remainingOffset / (float) targetHeight; } - // The final offset has been accounted for, reset it. - final float targetSubRow = targetRow - targetOffsetRatio; + return targetRow + targetOffsetRatio; + } + + private float computeBoundSubRow(int targetRow, int boundRow) { + final float targetSubRow = resolveOffset(targetRow, mOffset); mOffset = 0; + // The target row is below the bound row, so the end position would + // push the bound position above the list. Abort! if (targetSubRow >= boundRow) { - // End position would push the bound position above the list. return boundRow; } @@ -7243,39 +7271,24 @@ public abstract class AbsListView extends AdapterView implements Te // bound position's view further below the list. final int listHeight = getHeight() - getPaddingTop() - getPaddingBottom(); final int boundHeight = getHeightForRow(boundRow); - int endRow = boundRow; - int totalHeight = boundHeight; - int endHeight; - do { - endRow--; - endHeight = getHeightForRow(endRow); - totalHeight += endHeight; - } while (totalHeight < listHeight && endRow > 0); + final float boundSubRow = resolveOffset(boundRow, -listHeight + boundHeight); - final float endOffsetRatio; - if (endHeight == 0) { - endOffsetRatio = 1; - } else { - endOffsetRatio = (totalHeight - listHeight) / (float) endHeight; - } - - final float boundSubRow = endRow + endOffsetRatio; return Math.max(boundSubRow, targetSubRow); } @Override public void start(int position) { - scrollToPosition(position, false, 0, INVALID_POSITION, DEFAULT_SCROLL_DURATION); + scrollToPosition(position, false, 0, INVALID_POSITION, DURATION_AUTO); } @Override public void start(int position, int boundPosition) { - scrollToPosition(position, false, 0, boundPosition, DEFAULT_SCROLL_DURATION); + scrollToPosition(position, false, 0, boundPosition, DURATION_AUTO); } @Override public void startWithOffset(int position, int offset) { - scrollToPosition(position, true, offset, INVALID_POSITION, DEFAULT_SCROLL_DURATION); + scrollToPosition(position, true, offset, INVALID_POSITION, DURATION_AUTO); } @Override @@ -7327,7 +7340,7 @@ public abstract class AbsListView extends AdapterView implements Te final int rowHeight = getHeightForRow(row); final int offset = (int) (rowHeight * (subRow - row)); final int addOffset = (int) (mOffset * mSubScroller.getInterpolatedValue()); - setSelectionFromTop(position, -offset + addOffset); + setSelectionFromTop(position, -offset - addOffset); if (shouldPost) { postOnAnimation(mAnimationFrame); @@ -7346,7 +7359,7 @@ public abstract class AbsListView extends AdapterView implements Te * Scroller capable of returning floating point positions. */ static class SubScroller { - private final Interpolator mInterpolator; + private static final Interpolator INTERPOLATOR = new AccelerateDecelerateInterpolator(); private float mStartPosition; private float mEndPosition; @@ -7356,18 +7369,6 @@ public abstract class AbsListView extends AdapterView implements Te private float mPosition; private float mInterpolatedValue; - public SubScroller() { - this(null); - } - - public SubScroller(Interpolator interpolator) { - if (interpolator == null) { - mInterpolator = new AccelerateDecelerateInterpolator(); - } else { - mInterpolator = interpolator; - } - } - public void startScroll(float startPosition, float endPosition, int duration) { mStartPosition = startPosition; mEndPosition = endPosition; @@ -7387,7 +7388,7 @@ public abstract class AbsListView extends AdapterView implements Te value = MathUtils.constrain(elapsed / (float) mDuration, 0, 1); } - mInterpolatedValue = mInterpolator.getInterpolation(value); + mInterpolatedValue = INTERPOLATOR.getInterpolation(value); mPosition = (mEndPosition - mStartPosition) * mInterpolatedValue + mStartPosition; return elapsed < mDuration; From c818e5ebaf6c5d7e75a2a51f66ba5a31aba982e7 Mon Sep 17 00:00:00 2001 From: Alan Viverette Date: Fri, 28 Feb 2014 12:18:38 -0800 Subject: [PATCH 031/119] Don't smooth scroll if the adapter is null BUG: 13235508 Change-Id: I1ca8a5675aa07b9a987e47a6eacdc0a1e4adde74 --- core/java/android/widget/AbsListView.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index ffd5c45fb5d0d..47d42dc287d0d 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -7160,8 +7160,14 @@ public abstract class AbsListView extends AdapterView implements Te return; } + if (mAdapter == null) { + // Can't scroll anywhere without an adapter. + return; + } + final int itemCount = getCount(); final int clampedPosition = MathUtils.constrain(targetPosition, 0, itemCount - 1); + final int clampedBoundPosition = MathUtils.constrain(boundPosition, 0, itemCount - 1); final int firstPosition = getFirstVisiblePosition(); final int lastPosition = firstPosition + getChildCount(); final int targetRow = getRowForPosition(clampedPosition); @@ -7180,8 +7186,8 @@ public abstract class AbsListView extends AdapterView implements Te } float endSubRow = targetRow; - if (boundPosition != INVALID_POSITION) { - final int boundRow = getRowForPosition(boundPosition); + if (clampedBoundPosition != INVALID_POSITION) { + final int boundRow = getRowForPosition(clampedBoundPosition); if (boundRow >= firstRow && boundRow < lastRow && boundRow != targetRow) { endSubRow = computeBoundSubRow(targetRow, boundRow); } From 07e68d2fd2fee27fc97d80a0c4cb5c4c22c2d083 Mon Sep 17 00:00:00 2001 From: John Spurlock Date: Mon, 3 Mar 2014 13:38:01 -0500 Subject: [PATCH 032/119] Handle non-exact measure passes in ZenModeView. Bug:13245581 Change-Id: I2c5f6632fde6559849e6f429d66c4d28d4d3a890 --- .../com/android/systemui/statusbar/phone/ZenModeView.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java index 783e3713628ae..c4d2cce3b1b53 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java @@ -261,10 +261,9 @@ public class ZenModeView extends RelativeLayout { protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (DEBUG) log("onMeasure %s %s", MeasureSpec.toString(widthMeasureSpec), MeasureSpec.toString(heightMeasureSpec)); - if (MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.EXACTLY) { - throw new UnsupportedOperationException("Width must be exact"); - } - if (widthMeasureSpec != mWidthSpec) { + final boolean widthExact = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY; + + if (!widthExact || (widthMeasureSpec != mWidthSpec)) { if (DEBUG) log(" super.onMeasure"); final int hms = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); super.onMeasure(widthMeasureSpec, hms); From 867717fb2799d086695ff2056b6a30971cfe767d Mon Sep 17 00:00:00 2001 From: Chris Wren Date: Mon, 3 Mar 2014 14:12:13 -0500 Subject: [PATCH 033/119] add missing tablet asset for heads up Bug: 13280212 Change-Id: I8af2ba7dd2efba6bcb55e0e7d65dae49850aed06 --- .../heads_up_window_bg.9.png | Bin 0 -> 504 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 packages/SystemUI/res/drawable-sw600dp-hdpi/heads_up_window_bg.9.png diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/heads_up_window_bg.9.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/heads_up_window_bg.9.png new file mode 100644 index 0000000000000000000000000000000000000000..b30cf15b28bf9390d521541c5798cea76e6d1723 GIT binary patch literal 504 zcmV$e0fk9K zK~zY`#g=VO!!Qs;pOdtd0+q@oIT6PMq*Ty+HRjJ+8ZEX(Q6(a+l%(tR^UT^Q-2RHU zEEcR_02+%HxC1s8Pxib6o`HwM;qdy`3H!c(0p5T!FakX=0~0U+7l{~TY$Kt7kHFRd zkH9^!xBH#N-WJx{Vpp4BFo+TOFsLu!U4A&KUs}M>ZaUmYjh4S2;9Y Date: Tue, 4 Mar 2014 11:52:01 -0800 Subject: [PATCH 034/119] Pass correct paint to HW layer bug:13299767 Change-Id: I8372a830b2076c489ed0837aba9a85650a4202fd --- core/java/android/view/View.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index de304da748b0c..39dc3f4370d2e 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -13676,7 +13676,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (layerType == LAYER_TYPE_HARDWARE) { HardwareLayer layer = getHardwareLayer(); if (layer != null) { - layer.setLayerPaint(paint); + layer.setLayerPaint(mLayerPaint); } invalidateViewProperty(false, false); } else { From 7ad4ad4edf92245fd06d8ed3a31b30816e9baa58 Mon Sep 17 00:00:00 2001 From: John Reck Date: Thu, 6 Mar 2014 22:06:20 +0000 Subject: [PATCH 035/119] Revert "Revert "Workaround apps not calling super.onDetachedFromWindow()"" This reverts commit bac16fae7e6fceb1e516252ede673844b772e7c3. Change-Id: I61e997b23fac1aa984129fdc0328426ff8891bdd --- core/java/android/view/SurfaceView.java | 5 +++-- core/java/android/view/TextureView.java | 5 +++-- core/java/android/view/View.java | 14 ++++++++++++++ core/java/android/widget/TextView.java | 7 ++++--- opengl/java/android/opengl/GLSurfaceView.java | 10 +++------- 5 files changed, 27 insertions(+), 14 deletions(-) diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index 9b23b35279681..1f211c21f0b0a 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -255,8 +255,9 @@ public class SurfaceView extends View { updateWindow(false, false); } + /** @hide */ @Override - protected void onDetachedFromWindow() { + protected void onDetachedFromWindowInternal() { if (mGlobalListenersAdded) { ViewTreeObserver observer = getViewTreeObserver(); observer.removeOnScrollChangedListener(mScrollChangedListener); @@ -278,7 +279,7 @@ public class SurfaceView extends View { mSession = null; mLayout.token = null; - super.onDetachedFromWindow(); + super.onDetachedFromWindowInternal(); } @Override diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java index ef0d80d73cde7..3cfe5e916937b 100644 --- a/core/java/android/view/TextureView.java +++ b/core/java/android/view/TextureView.java @@ -228,10 +228,11 @@ public class TextureView extends View { } } + /** @hide */ @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); + protected void onDetachedFromWindowInternal() { destroySurface(); + super.onDetachedFromWindowInternal(); } private void destroySurface() { diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index a57b3111cae79..bd6b2e15d2aa1 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -13110,6 +13110,19 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @see #onAttachedToWindow() */ protected void onDetachedFromWindow() { + } + + /** + * This is a framework-internal mirror of onDetachedFromWindow() that's called + * after onDetachedFromWindow(). + * + * If you override this you *MUST* call super.onDetachedFromWindowInternal()! + * The super method should be called at the end of the overriden method to ensure + * subclasses are destroyed first + * + * @hide + */ + protected void onDetachedFromWindowInternal() { mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT; mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT; @@ -13297,6 +13310,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } onDetachedFromWindow(); + onDetachedFromWindowInternal(); ListenerInfo li = mListenerInfo; final CopyOnWriteArrayList listeners = diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index e5cb16fa65e31..687036ca14efd 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -4729,10 +4729,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (mEditor != null) mEditor.onAttachedToWindow(); } + /** @hide */ @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - + protected void onDetachedFromWindowInternal() { if (mPreDrawRegistered) { getViewTreeObserver().removeOnPreDrawListener(this); mPreDrawRegistered = false; @@ -4741,6 +4740,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener resetResolvedDrawables(); if (mEditor != null) mEditor.onDetachedFromWindow(); + + super.onDetachedFromWindowInternal(); } @Override diff --git a/opengl/java/android/opengl/GLSurfaceView.java b/opengl/java/android/opengl/GLSurfaceView.java index 5a2e261fa3a43..a9322b9931011 100644 --- a/opengl/java/android/opengl/GLSurfaceView.java +++ b/opengl/java/android/opengl/GLSurfaceView.java @@ -595,13 +595,9 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback mDetached = false; } - /** - * This method is used as part of the View class and is not normally - * called or subclassed by clients of GLSurfaceView. - * Must not be called before a renderer has been set. - */ + /** @hide */ @Override - protected void onDetachedFromWindow() { + protected void onDetachedFromWindowInternal() { if (LOG_ATTACH_DETACH) { Log.d(TAG, "onDetachedFromWindow"); } @@ -609,7 +605,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback mGLThread.requestExitAndWait(); } mDetached = true; - super.onDetachedFromWindow(); + super.onDetachedFromWindowInternal(); } // ---------------------------------------------------------------------- From 88cf0a5550c57c066d67a92039cc6b729e74e0f2 Mon Sep 17 00:00:00 2001 From: John Reck Date: Thu, 6 Mar 2014 16:22:47 -0800 Subject: [PATCH 036/119] Make sure we register functor count Bug: 13339664 Change-Id: Iafb8ba77bdf1d971c1d0a345ff525e7f7fa80352 --- libs/hwui/DisplayList.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp index bdb2f8d4c4448..81d0435a331d9 100644 --- a/libs/hwui/DisplayList.cpp +++ b/libs/hwui/DisplayList.cpp @@ -109,6 +109,9 @@ void DisplayList::destroyDisplayListDeferred(DisplayList* displayList) { void DisplayList::setData(DisplayListData* data) { delete mDisplayListData; mDisplayListData = data; + if (mDisplayListData) { + Caches::getInstance().registerFunctors(mDisplayListData->functorCount); + } } /** From 88be3c9404df7f0015b042db83799fec73204674 Mon Sep 17 00:00:00 2001 From: John Reck Date: Mon, 10 Mar 2014 08:58:44 -0700 Subject: [PATCH 037/119] DisplayList lifecycle changes Bug: 13360343 Change DisplayList to be more forgiving with weaker lifecycle requirements. Is more self-managed with a strong reference to the renderer it needs Also fix naming mismatch Change-Id: I5c89453a72a52954f6f959f0846199705dbb6476 --- core/java/android/view/DisplayList.java | 34 ++++++++++++++------ core/java/android/view/GLRenderer.java | 6 ++-- core/java/android/view/HardwareLayer.java | 2 +- core/java/android/view/HardwareRenderer.java | 2 +- core/java/android/view/ThreadedRenderer.java | 6 ++-- core/java/android/view/View.java | 5 ++- core/java/android/widget/Editor.java | 3 +- core/jni/android_view_GLRenderer.cpp | 4 +-- core/jni/android_view_ThreadedRenderer.cpp | 6 ++-- libs/hwui/renderthread/CanvasContext.cpp | 2 +- libs/hwui/renderthread/CanvasContext.h | 2 +- libs/hwui/renderthread/RenderProxy.cpp | 8 ++--- libs/hwui/renderthread/RenderProxy.h | 2 +- 13 files changed, 48 insertions(+), 34 deletions(-) diff --git a/core/java/android/view/DisplayList.java b/core/java/android/view/DisplayList.java index 0ae36c1656c96..be6f4011e45d0 100644 --- a/core/java/android/view/DisplayList.java +++ b/core/java/android/view/DisplayList.java @@ -122,9 +122,6 @@ import android.graphics.Path; * @hide */ public class DisplayList { - private boolean mValid; - private final long mNativeDisplayList; - /** * Flag used when calling * {@link HardwareCanvas#drawDisplayList(DisplayList, android.graphics.Rect, int)} @@ -175,6 +172,10 @@ public class DisplayList { */ public static final int STATUS_DREW = 0x4; + private boolean mValid; + private final long mNativeDisplayList; + private HardwareRenderer mRenderer; + private DisplayList(String name) { mNativeDisplayList = nCreate(); nSetDisplayListName(mNativeDisplayList, name); @@ -233,7 +234,13 @@ public class DisplayList { GLES20RecordingCanvas canvas = (GLES20RecordingCanvas) endCanvas; canvas.onPostDraw(); long displayListData = canvas.finishRecording(); - renderer.swapDisplayListData(mNativeDisplayList, displayListData); + if (renderer != mRenderer) { + // If we are changing renderers first destroy with the old + // renderer, then set with the new one + destroyDisplayListData(); + } + mRenderer = renderer; + setDisplayListData(displayListData); canvas.recycle(); mValid = true; } @@ -245,14 +252,22 @@ public class DisplayList { * * @hide */ - public void destroyDisplayListData(HardwareRenderer renderer) { - if (renderer == null) { - throw new IllegalArgumentException("Cannot destroyDisplayListData with a null renderer"); - } - renderer.swapDisplayListData(mNativeDisplayList, 0); + public void destroyDisplayListData() { + if (!mValid) return; + + setDisplayListData(0); + mRenderer = null; mValid = false; } + private void setDisplayListData(long newData) { + if (mRenderer != null) { + mRenderer.setDisplayListData(mNativeDisplayList, newData); + } else { + throw new IllegalStateException("Trying to set data without a renderer! data=" + newData); + } + } + /** * Returns whether the display list is currently usable. If this returns false, * the display list should be re-recorded prior to replaying it. @@ -907,6 +922,7 @@ public class DisplayList { @Override protected void finalize() throws Throwable { try { + destroyDisplayListData(); nDestroyDisplayList(mNativeDisplayList); } finally { super.finalize(); diff --git a/core/java/android/view/GLRenderer.java b/core/java/android/view/GLRenderer.java index c90e4b08677ba..81f778d16af17 100644 --- a/core/java/android/view/GLRenderer.java +++ b/core/java/android/view/GLRenderer.java @@ -1196,10 +1196,10 @@ public class GLRenderer extends HardwareRenderer { } } - void swapDisplayListData(long displayList, long newData) { - nSwapDisplayListData(displayList, newData); + void setDisplayListData(long displayList, long newData) { + nSetDisplayListData(displayList, newData); } - private static native void nSwapDisplayListData(long displayList, long newData); + private static native void nSetDisplayListData(long displayList, long newData); private DisplayList buildDisplayList(View view, HardwareCanvas canvas) { if (mDrawDelta <= 0) { diff --git a/core/java/android/view/HardwareLayer.java b/core/java/android/view/HardwareLayer.java index c526dd29815be..46e26902ef1f2 100644 --- a/core/java/android/view/HardwareLayer.java +++ b/core/java/android/view/HardwareLayer.java @@ -88,7 +88,7 @@ final class HardwareLayer { } if (mDisplayList != null) { - mDisplayList.destroyDisplayListData(mRenderer); + mDisplayList.destroyDisplayListData(); mDisplayList = null; } if (mRenderer != null) { diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java index bcc28e303f61b..34efcf5fb5cf3 100644 --- a/core/java/android/view/HardwareRenderer.java +++ b/core/java/android/view/HardwareRenderer.java @@ -562,7 +562,7 @@ public abstract class HardwareRenderer { mRequested = requested; } - abstract void swapDisplayListData(long displayList, long newData); + abstract void setDisplayListData(long displayList, long newData); /** * Describes a series of frames that should be drawn on screen as a graph. diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java index 3dcfbb357779e..a1fb123fccadd 100644 --- a/core/java/android/view/ThreadedRenderer.java +++ b/core/java/android/view/ThreadedRenderer.java @@ -148,8 +148,8 @@ public class ThreadedRenderer extends HardwareRenderer { } @Override - void swapDisplayListData(long displayList, long newData) { - nSwapDisplayListData(mNativeProxy, displayList, newData); + void setDisplayListData(long displayList, long newData) { + nSetDisplayListData(mNativeProxy, displayList, newData); } @Override @@ -257,7 +257,7 @@ public class ThreadedRenderer extends HardwareRenderer { private static native boolean nInitialize(long nativeProxy, Surface window); private static native void nUpdateSurface(long nativeProxy, Surface window); private static native void nSetup(long nativeProxy, int width, int height); - private static native void nSwapDisplayListData(long nativeProxy, long displayList, + private static native void nSetDisplayListData(long nativeProxy, long displayList, long newData); private static native void nDrawDisplayList(long nativeProxy, long displayList, int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom); diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 9b45f97788256..904ec446f393d 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -14062,13 +14062,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } private void resetDisplayList() { - HardwareRenderer renderer = getHardwareRenderer(); if (mDisplayList != null && mDisplayList.isValid()) { - mDisplayList.destroyDisplayListData(renderer); + mDisplayList.destroyDisplayListData(); } if (mBackgroundDisplayList != null && mBackgroundDisplayList.isValid()) { - mBackgroundDisplayList.destroyDisplayListData(renderer); + mBackgroundDisplayList.destroyDisplayListData(); } } diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index 98b43b32d5372..53d9e28e0ed7c 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -287,13 +287,12 @@ public class Editor { } private void destroyDisplayListsData() { - HardwareRenderer renderer = mTextView.getHardwareRenderer(); if (mTextDisplayLists != null) { for (int i = 0; i < mTextDisplayLists.length; i++) { DisplayList displayList = mTextDisplayLists[i] != null ? mTextDisplayLists[i].displayList : null; if (displayList != null && displayList.isValid()) { - displayList.destroyDisplayListData(renderer); + displayList.destroyDisplayListData(); } } } diff --git a/core/jni/android_view_GLRenderer.cpp b/core/jni/android_view_GLRenderer.cpp index 5ea8460b840d5..b7e795e26d54e 100644 --- a/core/jni/android_view_GLRenderer.cpp +++ b/core/jni/android_view_GLRenderer.cpp @@ -140,7 +140,7 @@ static void android_view_GLRenderer_destroyLayer(JNIEnv* env, jobject clazz, LayerRenderer::destroyLayer(layer); } -static void android_view_GLRenderer_swapDisplayListData(JNIEnv* env, jobject clazz, +static void android_view_GLRenderer_setDisplayListData(JNIEnv* env, jobject clazz, jlong displayListPtr, jlong newDataPtr) { using namespace android::uirenderer; DisplayList* displayList = reinterpret_cast(displayListPtr); @@ -178,7 +178,7 @@ static JNINativeMethod gMethods[] = { { "getSystemTime", "()J", (void*) android_view_GLRenderer_getSystemTime }, { "nDestroyLayer", "(J)V", (void*) android_view_GLRenderer_destroyLayer }, - { "nSwapDisplayListData", "(JJ)V", (void*) android_view_GLRenderer_swapDisplayListData }, + { "nSetDisplayListData", "(JJ)V", (void*) android_view_GLRenderer_setDisplayListData }, #endif { "setupShadersDiskCache", "(Ljava/lang/String;)V", diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp index 444c8bec8f6f1..2b2075827284f 100644 --- a/core/jni/android_view_ThreadedRenderer.cpp +++ b/core/jni/android_view_ThreadedRenderer.cpp @@ -103,12 +103,12 @@ static void android_view_ThreadedRenderer_setup(JNIEnv* env, jobject clazz, proxy->setup(width, height); } -static void android_view_ThreadedRenderer_swapDisplayListData(JNIEnv* env, jobject clazz, +static void android_view_ThreadedRenderer_setDisplayListData(JNIEnv* env, jobject clazz, jlong proxyPtr, jlong displayListPtr, jlong newDataPtr) { RenderProxy* proxy = reinterpret_cast(proxyPtr); DisplayList* displayList = reinterpret_cast(displayListPtr); DisplayListData* newData = reinterpret_cast(newDataPtr); - proxy->swapDisplayListData(displayList, newData); + proxy->setDisplayListData(displayList, newData); } static void android_view_ThreadedRenderer_drawDisplayList(JNIEnv* env, jobject clazz, @@ -191,7 +191,7 @@ static JNINativeMethod gMethods[] = { { "nInitialize", "(JLandroid/view/Surface;)Z", (void*) android_view_ThreadedRenderer_initialize }, { "nUpdateSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_updateSurface }, { "nSetup", "(JII)V", (void*) android_view_ThreadedRenderer_setup }, - { "nSwapDisplayListData", "(JJJ)V", (void*) android_view_ThreadedRenderer_swapDisplayListData }, + { "nSetDisplayListData", "(JJJ)V", (void*) android_view_ThreadedRenderer_setDisplayListData }, { "nDrawDisplayList", "(JJIIII)V", (void*) android_view_ThreadedRenderer_drawDisplayList }, { "nDestroyCanvas", "(J)V", (void*) android_view_ThreadedRenderer_destroyCanvas }, { "nAttachFunctor", "(JJ)V", (void*) android_view_ThreadedRenderer_attachFunctor }, diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index 056885129bfa0..ce66d8f1b2704 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -373,7 +373,7 @@ void CanvasContext::setup(int width, int height) { mCanvas->setViewport(width, height); } -void CanvasContext::swapDisplayListData(DisplayList* displayList, DisplayListData* newData) { +void CanvasContext::setDisplayListData(DisplayList* displayList, DisplayListData* newData) { displayList->setData(newData); } diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index 2c9348cd55b53..649ffb63d9418 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -63,7 +63,7 @@ public: bool initialize(EGLNativeWindowType window); void updateSurface(EGLNativeWindowType window); void setup(int width, int height); - void swapDisplayListData(DisplayList* displayList, DisplayListData* newData); + void setDisplayListData(DisplayList* displayList, DisplayListData* newData); void processLayerUpdates(const Vector* layerUpdaters); void drawDisplayList(DisplayList* displayList, Rect* dirty); void destroyCanvas(); diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp index c3bf404115f1f..200c21f2c8c56 100644 --- a/libs/hwui/renderthread/RenderProxy.cpp +++ b/libs/hwui/renderthread/RenderProxy.cpp @@ -117,14 +117,14 @@ void RenderProxy::setup(int width, int height) { post(task); } -CREATE_BRIDGE3(swapDisplayListData, CanvasContext* context, DisplayList* displayList, +CREATE_BRIDGE3(setDisplayListData, CanvasContext* context, DisplayList* displayList, DisplayListData* newData) { - args->context->swapDisplayListData(args->displayList, args->newData); + args->context->setDisplayListData(args->displayList, args->newData); return NULL; } -void RenderProxy::swapDisplayListData(DisplayList* displayList, DisplayListData* newData) { - SETUP_TASK(swapDisplayListData); +void RenderProxy::setDisplayListData(DisplayList* displayList, DisplayListData* newData) { + SETUP_TASK(setDisplayListData); args->context = mContext; args->displayList = displayList; args->newData = newData; diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h index 0934b981db914..83a8a8f117c93 100644 --- a/libs/hwui/renderthread/RenderProxy.h +++ b/libs/hwui/renderthread/RenderProxy.h @@ -60,7 +60,7 @@ public: ANDROID_API bool initialize(EGLNativeWindowType window); ANDROID_API void updateSurface(EGLNativeWindowType window); ANDROID_API void setup(int width, int height); - ANDROID_API void swapDisplayListData(DisplayList* displayList, DisplayListData* newData); + ANDROID_API void setDisplayListData(DisplayList* displayList, DisplayListData* newData); ANDROID_API void drawDisplayList(DisplayList* displayList, int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom); ANDROID_API void destroyCanvas(); From 463e481ec74aa1d84c1e25722eed29711440bdad Mon Sep 17 00:00:00 2001 From: Brian Carlstrom Date: Mon, 10 Mar 2014 10:20:01 -0700 Subject: [PATCH 038/119] Only pass -Xprofile-* options to ART Bug: 13391896 Change-Id: I5d6a3b900c9b20f02e1d4ccb73f712e9260c7dfd --- core/jni/AndroidRuntime.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 06e47170ac48e..e50c1d8dd7c07 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -750,10 +750,11 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv) mOptions.add(opt); } - // libart tolerates libdvm flags, but not vice versa, so only pass these if libart. + // libart tolerates libdvm flags, but not vice versa, so only pass some options if libart. property_get("persist.sys.dalvik.vm.lib.1", dalvikVmLibBuf, "libdvm.so"); - if (strncmp(dalvikVmLibBuf, "libart", 6) == 0) { + bool libart = (strncmp(dalvikVmLibBuf, "libart", 6) == 0); + if (libart) { // Extra options for DexClassLoader. property_get("dalvik.vm.dex2oat-flags", dex2oatFlagsBuf, ""); parseExtraOpts(dex2oatFlagsBuf, "-Xcompiler-option"); @@ -784,7 +785,7 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv) /* * Set profiler options */ - { + if (libart) { char period[sizeof("-Xprofile-period:") + PROPERTY_VALUE_MAX]; char duration[sizeof("-Xprofile-duration:") + PROPERTY_VALUE_MAX]; char interval[sizeof("-Xprofile-interval:") + PROPERTY_VALUE_MAX]; From 36e393d9ecfb1166b7151d5d0f4187316b1eed22 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Wed, 19 Mar 2014 14:26:28 -0700 Subject: [PATCH 039/119] Catch Netd exceptions to avoid runtime restart bug:13475636 Change-Id: If36a0051a957fc066711fe8225f8981bc07add04 --- .../core/java/com/android/server/ConnectivityService.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 68b779c023e40..ca1c0aee2951f 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -2434,7 +2434,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (timeout > 0 && iface != null) { try { mNetd.addIdleTimer(iface, timeout, type); - } catch (RemoteException e) { + } catch (Exception e) { + // You shall not crash! + loge("Exception in setupDataActivityTracking " + e); } } } @@ -2451,7 +2453,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { try { // the call fails silently if no idletimer setup for this interface mNetd.removeIdleTimer(iface); - } catch (RemoteException e) { + } catch (Exception e) { + loge("Exception in removeDataActivityTracking " + e); } } } From 3570e149d16120988e84a944689fa255eeb76a90 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Thu, 20 Mar 2014 11:23:29 -0700 Subject: [PATCH 040/119] MediaHTTPConnection: fix JNI signature mNativeContext was changed to a long, fix the GetFieldID signature Change-Id: Ib19605d2c534a2aea7d75ab105349710905d716f --- media/jni/android_media_MediaHTTPConnection.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/media/jni/android_media_MediaHTTPConnection.cpp b/media/jni/android_media_MediaHTTPConnection.cpp index da3f74d867636..0e7d83ec9a1d8 100644 --- a/media/jni/android_media_MediaHTTPConnection.cpp +++ b/media/jni/android_media_MediaHTTPConnection.cpp @@ -106,7 +106,7 @@ static void android_media_MediaHTTPConnection_native_init(JNIEnv *env) { env, env->FindClass("android/media/MediaHTTPConnection")); CHECK(clazz.get() != NULL); - gFields.context = env->GetFieldID(clazz.get(), "mNativeContext", "I"); + gFields.context = env->GetFieldID(clazz.get(), "mNativeContext", "J"); CHECK(gFields.context != NULL); gFields.readAtMethodID = env->GetMethodID(clazz.get(), "readAt", "(J[BI)I"); From b37e362a7cefcc08498f91270083ad7e6bff7b39 Mon Sep 17 00:00:00 2001 From: John Reck Date: Tue, 25 Mar 2014 10:22:09 -0700 Subject: [PATCH 041/119] Add missing null check Bug: 13635394 mDisplayListData can be null, make sure to check for that before trying to walk through the children list in updateProperties Change-Id: I8d97b1656c1acf47b7c5df8a8771b0f30907261d --- libs/hwui/RenderNode.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index 62a9d71a5dc23..d3daec8e7dd3c 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -99,9 +99,11 @@ void RenderNode::updateProperties() { mProperties = mStagingProperties; } - for (size_t i = 0; i < mDisplayListData->children.size(); i++) { - RenderNode* childNode = mDisplayListData->children[i]->mDisplayList; - childNode->updateProperties(); + if (mDisplayListData) { + for (size_t i = 0; i < mDisplayListData->children.size(); i++) { + RenderNode* childNode = mDisplayListData->children[i]->mDisplayList; + childNode->updateProperties(); + } } } From a2b1650030d4d63e16bf87b082b9ef48912817b7 Mon Sep 17 00:00:00 2001 From: Svetoslav Date: Tue, 25 Mar 2014 17:26:04 -0700 Subject: [PATCH 042/119] Wrong constant used for undefined accessibility window id. Change-Id: I8b14db034a42a7ffd211a46fa3fee7bf2a6eac8f --- core/java/android/view/View.java | 5 ++- .../AccessibilityManagerService.java | 41 ++++++------------- 2 files changed, 16 insertions(+), 30 deletions(-) diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 49929609fa7af..31ef2edc3d3c4 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -5726,7 +5726,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @hide */ public int getAccessibilityWindowId() { - return mAttachInfo != null ? mAttachInfo.mAccessibilityWindowId : NO_ID; + return mAttachInfo != null ? mAttachInfo.mAccessibilityWindowId + : AccessibilityNodeInfo.UNDEFINED_ITEM_ID; } /** @@ -19724,7 +19725,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, /** * The id of the window for accessibility purposes. */ - int mAccessibilityWindowId = View.NO_ID; + int mAccessibilityWindowId = AccessibilityNodeInfo.UNDEFINED_ITEM_ID; /** * Flags related to accessibility processing. diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index 0edce1147e633..35f873ea24015 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -397,9 +397,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { return true; // yes, recycle the event } if (mSecurityPolicy.canDispatchAccessibilityEventLocked(event)) { + mSecurityPolicy.updateActiveWindowLocked(event.getWindowId(), event.getEventType()); mSecurityPolicy.updateEventSourceLocked(event); - mMainHandler.obtainMessage(MainHandler.MSG_UPDATE_ACTIVE_WINDOW, - event.getWindowId(), event.getEventType()).sendToTarget(); notifyAccessibilityServicesDelayedLocked(event, false); notifyAccessibilityServicesDelayedLocked(event, true); } @@ -503,7 +502,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { mGlobalWindowTokens.put(windowId, windowToken.asBinder()); if (DEBUG) { Slog.i(LOG_TAG, "Added global connection for pid:" + Binder.getCallingPid() - + " with windowId: " + windowId); + + " with windowId: " + windowId + " and token: " + windowToken.asBinder()); } } else { AccessibilityConnectionWrapper wrapper = new AccessibilityConnectionWrapper( @@ -514,12 +513,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { userState.mWindowTokens.put(windowId, windowToken.asBinder()); if (DEBUG) { Slog.i(LOG_TAG, "Added user connection for pid:" + Binder.getCallingPid() - + " with windowId: " + windowId + " and userId:" + mCurrentUserId); + + " with windowId: " + windowId + " and userId:" + mCurrentUserId + + " and token: " + windowToken.asBinder()); } } - if (DEBUG) { - Slog.i(LOG_TAG, "Adding interaction connection to windowId: " + windowId); - } return windowId; } } @@ -534,7 +531,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { if (removedWindowId >= 0) { if (DEBUG) { Slog.i(LOG_TAG, "Removed global connection for pid:" + Binder.getCallingPid() - + " with windowId: " + removedWindowId); + + " with windowId: " + removedWindowId + " and token: " + window.asBinder()); } return; } @@ -548,7 +545,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { if (DEBUG) { Slog.i(LOG_TAG, "Removed user connection for pid:" + Binder.getCallingPid() + " with windowId: " + removedWindowIdForUser + " and userId:" - + mUserStates.keyAt(i)); + + mUserStates.keyAt(i) + " and token: " + window.asBinder()); } return; } @@ -1622,7 +1619,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { public static final int MSG_SEND_ACCESSIBILITY_EVENT_TO_INPUT_FILTER = 1; public static final int MSG_SEND_STATE_TO_CLIENTS = 2; public static final int MSG_SEND_CLEARED_STATE_TO_CLIENTS_FOR_USER = 3; - public static final int MSG_UPDATE_ACTIVE_WINDOW = 4; public static final int MSG_ANNOUNCE_NEW_USER_IF_NEEDED = 5; public static final int MSG_UPDATE_INPUT_FILTER = 6; public static final int MSG_SHOW_ENABLED_TOUCH_EXPLORATION_DIALOG = 7; @@ -1669,12 +1665,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { sendStateToClientsForUser(0, userId); } break; - case MSG_UPDATE_ACTIVE_WINDOW: { - final int windowId = msg.arg1; - final int eventType = msg.arg2; - mSecurityPolicy.updateActiveWindow(windowId, eventType); - } break; - case MSG_ANNOUNCE_NEW_USER_IF_NEEDED: { announceNewUserIfNeeded(); } break; @@ -3168,7 +3158,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } } - public void updateActiveWindow(int windowId, int eventType) { + public void updateActiveWindowLocked(int windowId, int eventType) { // The active window is either the window that has input focus or // the window that the user is currently touching. If the user is // touching a window that does not have input focus as soon as the @@ -3185,17 +3175,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { // what the focused window is to update the active one. // The active window also determined events from which // windows are delivered. - boolean focusedWindowActive = false; synchronized (mLock) { - if (mWindowsForAccessibilityCallback == null) { - focusedWindowActive = true; - } - } - if (focusedWindowActive) { - if (windowId == getFocusedWindowId()) { - synchronized (mLock) { - mActiveWindowId = windowId; - } + if (mWindowsForAccessibilityCallback == null + && windowId == getFocusedWindowId()) { + mActiveWindowId = windowId; } } } break; @@ -3337,7 +3320,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { private int getFocusedWindowId() { IBinder token = mWindowManagerService.getFocusedWindowToken(); - return findWindowIdLocked(token); + synchronized (mLock) { + return findWindowIdLocked(token); + } } } From 12ef0b202c6c01173ab5c6c164b77503f1138d0a Mon Sep 17 00:00:00 2001 From: Christopher Tate Date: Wed, 26 Mar 2014 14:42:56 -0700 Subject: [PATCH 043/119] Don't crash when handling unlinked widget bindings A host can have an 'instance' the other end of which is still unlinked to a concrete provider. Don't crash when we hit those. Bug 13651057 Change-Id: I5a29afb0e6a7ab30976862aee04bd33f609543fa --- .../java/com/android/server/appwidget/AppWidgetServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java index b84df79e17e9d..b7c170427198b 100644 --- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java +++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java @@ -158,7 +158,7 @@ class AppWidgetServiceImpl { final int N = instances.size(); for (int i = 0; i < N; i++) { Provider p = instances.get(i).provider; - if (p.info != null && pkg.equals(p.info.provider.getPackageName())) { + if (p != null && p.info != null && pkg.equals(p.info.provider.getPackageName())) { return true; } } From 5776da2735b44590692e19a6839a22a5583a8496 Mon Sep 17 00:00:00 2001 From: Paul Lawrence Date: Wed, 26 Mar 2014 22:09:24 +0000 Subject: [PATCH 044/119] Revert "Don't prompt at boot if we already did that when decrypting" This reverts commit 493e3e7e6523fd94cc1acae3e45935a1227d58c3. Should fixes Bug: 13611885 Bug: 13656830 Change-Id: I117c988bb6679f44f8add4fcc18f45cb8238dfb4 --- .../android/os/storage/IMountService.java | 60 +------------------ .../internal/widget/ILockSettings.aidl | 1 - .../internal/widget/LockPatternUtils.java | 14 ----- .../keyguard/KeyguardViewMediator.java | 7 --- .../android/server/LockSettingsService.java | 41 ------------- .../java/com/android/server/MountService.java | 51 ---------------- 6 files changed, 1 insertion(+), 173 deletions(-) diff --git a/core/java/android/os/storage/IMountService.java b/core/java/android/os/storage/IMountService.java index 41808603356cb..b97734e83ed37 100644 --- a/core/java/android/os/storage/IMountService.java +++ b/core/java/android/os/storage/IMountService.java @@ -694,36 +694,6 @@ public interface IMountService extends IInterface { return _result; } - public String getPassword() throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - String _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - mRemote.transact(Stub.TRANSACTION_getPassword, _data, _reply, 0); - _reply.readException(); - _result = _reply.readString(); - } finally { - _reply.recycle(); - _data.recycle(); - } - return _result; - } - - public void clearPassword() throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - String _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - mRemote.transact(Stub.TRANSACTION_clearPassword, _data, _reply, 0); - _reply.readException(); - } finally { - _reply.recycle(); - _data.recycle(); - } - } - public StorageVolume[] getVolumeList() throws RemoteException { Parcel _data = Parcel.obtain(); Parcel _reply = Parcel.obtain(); @@ -876,11 +846,7 @@ public interface IMountService extends IInterface { static final int TRANSACTION_mkdirs = IBinder.FIRST_CALL_TRANSACTION + 34; - static final int TRANSACTION_getPasswordType = IBinder.FIRST_CALL_TRANSACTION + 35; - - static final int TRANSACTION_getPassword = IBinder.FIRST_CALL_TRANSACTION + 36; - - static final int TRANSACTION_clearPassword = IBinder.FIRST_CALL_TRANSACTION + 37; + static final int TRANSACTION_getPasswordType = IBinder.FIRST_CALL_TRANSACTION + 36; /** * Cast an IBinder object into an IMountService interface, generating a @@ -1242,19 +1208,6 @@ public interface IMountService extends IInterface { reply.writeInt(result); return true; } - case TRANSACTION_getPassword: { - data.enforceInterface(DESCRIPTOR); - String result = getPassword(); - reply.writeNoException(); - reply.writeString(result); - return true; - } - case TRANSACTION_clearPassword: { - data.enforceInterface(DESCRIPTOR); - clearPassword(); - reply.writeNoException(); - return true; - } } return super.onTransact(code, data, reply, flags); } @@ -1493,15 +1446,4 @@ public interface IMountService extends IInterface { * @return PasswordType */ public int getPasswordType() throws RemoteException; - - /** - * Get password from vold - * @return password or empty string - */ - public String getPassword() throws RemoteException; - - /** - * Securely clear password from vold - */ - public void clearPassword() throws RemoteException; } diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl index 9501f92fc75f2..91056f1609101 100644 --- a/core/java/com/android/internal/widget/ILockSettings.aidl +++ b/core/java/com/android/internal/widget/ILockSettings.aidl @@ -28,7 +28,6 @@ interface ILockSettings { boolean checkPattern(in String pattern, int userId); void setLockPassword(in String password, int userId); boolean checkPassword(in String password, int userId); - boolean checkVoldPassword(int userId); boolean havePattern(int userId); boolean havePassword(int userId); void removeUser(int userId); diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java index e5aaf7ef714bc..2d7949140ca1f 100644 --- a/core/java/com/android/internal/widget/LockPatternUtils.java +++ b/core/java/com/android/internal/widget/LockPatternUtils.java @@ -312,20 +312,6 @@ public class LockPatternUtils { } } - /** - * Check to see if vold already has the password. - * Note that this also clears vold's copy of the password. - * @return Whether the vold password matches or not. - */ - public boolean checkVoldPassword() { - final int userId = getCurrentOrCallingUserId(); - try { - return getLockSettings().checkVoldPassword(userId); - } catch (RemoteException re) { - return false; - } - } - /** * Check to see if a password matches any of the passwords stored in the * password history. diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java b/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java index 3fc562cb41102..31e806c2a1d81 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java @@ -979,13 +979,6 @@ public class KeyguardViewMediator { return; } - if (mLockPatternUtils.checkVoldPassword()) { - if (DEBUG) Log.d(TAG, "Not showing lock screen since just decrypted"); - // Without this, settings is not enabled until the lock screen first appears - hideLocked(); - return; - } - if (DEBUG) Log.d(TAG, "doKeyguard: showing the lock screen"); showLocked(options); } diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java index 19e8083ad21f8..fe814fc3be302 100644 --- a/services/core/java/com/android/server/LockSettingsService.java +++ b/services/core/java/com/android/server/LockSettingsService.java @@ -30,11 +30,7 @@ import android.database.sqlite.SQLiteOpenHelper; import android.database.sqlite.SQLiteStatement; import android.os.Binder; import android.os.Environment; -import android.os.IBinder; import android.os.RemoteException; -import android.os.storage.IMountService; -import android.os.ServiceManager; -import android.os.storage.StorageManager; import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; @@ -83,7 +79,6 @@ public class LockSettingsService extends ILockSettings.Stub { private final Context mContext; private LockPatternUtils mLockPatternUtils; - private boolean mFirstCallToVold; public LockSettingsService(Context context) { mContext = context; @@ -91,7 +86,6 @@ public class LockSettingsService extends ILockSettings.Stub { mOpenHelper = new DatabaseHelper(mContext); mLockPatternUtils = new LockPatternUtils(context); - mFirstCallToVold = true; } public void systemReady() { @@ -352,33 +346,6 @@ public class LockSettingsService extends ILockSettings.Stub { return true; } - @Override - public boolean checkVoldPassword(int userId) throws RemoteException { - if (!mFirstCallToVold) { - return false; - } - mFirstCallToVold = false; - - checkPasswordReadPermission(userId); - - // There's no guarantee that this will safely connect, but if it fails - // we will simply show the lock screen when we shouldn't, so relatively - // benign. There is an outside chance something nasty would happen if - // this service restarted before vold stales out the password in this - // case. The nastiness is limited to not showing the lock screen when - // we should, within the first minute of decrypting the phone if this - // service can't connect to vold, it restarts, and then the new instance - // does successfully connect. - final IMountService service = getMountService(); - String password = service.getPassword(); - service.clearPassword(); - if (service.getPasswordType() == StorageManager.CRYPT_TYPE_PATTERN) { - return checkPattern(password, userId); - } else { - return checkPassword(password, userId); - } - } - @Override public void removeUser(int userId) { checkWritePermission(userId); @@ -557,12 +524,4 @@ public class LockSettingsService extends ILockSettings.Stub { Secure.LOCK_SCREEN_OWNER_INFO_ENABLED, Secure.LOCK_SCREEN_OWNER_INFO }; - - private IMountService getMountService() { - final IBinder service = ServiceManager.getService("mount"); - if (service != null) { - return IMountService.Stub.asInterface(service); - } - return null; - } } diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java index b6e0d5fe9414b..cd74fed4d1b35 100644 --- a/services/core/java/com/android/server/MountService.java +++ b/services/core/java/com/android/server/MountService.java @@ -74,7 +74,6 @@ import com.google.android.collect.Lists; import com.google.android.collect.Maps; import org.apache.commons.codec.binary.Hex; -import org.apache.commons.codec.DecoderException; import org.xmlpull.v1.XmlPullParserException; import java.io.File; @@ -574,14 +573,6 @@ class MountService extends IMountService.Stub } } - private boolean isReady() { - try { - return mConnectedSignal.await(0, TimeUnit.MILLISECONDS); - } catch (InterruptedException e) { - return false; - } - } - private void handleSystemReady() { // Snapshot current volume states since it's not safe to call into vold // while holding locks. @@ -2090,19 +2081,6 @@ class MountService extends IMountService.Stub return new String(Hex.encodeHex(bytes)); } - private String fromHex(String hexPassword) { - if (hexPassword == null) { - return null; - } - - try { - byte[] bytes = Hex.decodeHex(hexPassword.toCharArray()); - return new String(bytes, StandardCharsets.UTF_8); - } catch (DecoderException e) { - return null; - } - } - @Override public int decryptStorage(String password) { if (TextUtils.isEmpty(password)) { @@ -2251,35 +2229,6 @@ class MountService extends IMountService.Stub } } - @Override - public String getPassword() throws RemoteException { - if (!isReady()) { - return new String(); - } - - final NativeDaemonEvent event; - try { - event = mConnector.execute("cryptfs", "getpw"); - return fromHex(event.getMessage()); - } catch (NativeDaemonConnectorException e) { - throw e.rethrowAsParcelableException(); - } - } - - @Override - public void clearPassword() throws RemoteException { - if (!isReady()) { - return; - } - - final NativeDaemonEvent event; - try { - event = mConnector.execute("cryptfs", "clearpw"); - } catch (NativeDaemonConnectorException e) { - throw e.rethrowAsParcelableException(); - } - } - @Override public int mkdirs(String callingPkg, String appPath) { final int userId = UserHandle.getUserId(Binder.getCallingUid()); From 2c3527500cdb2d77d9560889dc1da2331565411a Mon Sep 17 00:00:00 2001 From: Christopher Tate Date: Thu, 27 Mar 2014 13:10:50 -0700 Subject: [PATCH 045/119] Unlinked providers STILL shouldn't cause crashes Bug 13651057 Change-Id: Id7e5ba521ac3f201b1a44f122358ca5af2929e06 --- .../com/android/server/appwidget/AppWidgetServiceImpl.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java index b7c170427198b..2f56e62cbcf8a 100644 --- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java +++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java @@ -1751,7 +1751,8 @@ class AppWidgetServiceImpl { for (int i = 0; i < N; i++) { AppWidgetId id = mAppWidgetIds.get(i); if (backupTarget.equals(id.host.packageName) - || backupTarget.equals(id.provider.info.provider.getPackageName())) { + || (id.provider != null && backupTarget.equals( + id.provider.info.provider.getPackageName()))) { serializeAppWidgetId(out, id); } } From 6e3ee198b657374fce7944d4915284da64a225e0 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Thu, 27 Mar 2014 13:25:14 -0700 Subject: [PATCH 046/119] Make setServer() safe to call multiple times This makes it safe to call setServer() multiple times with the same server, different servers, or null. b/13622801 Change-Id: Id04440df720f830e67106eb543653ace42430d97 --- media/java/android/mtp/MtpDatabase.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java index 15ae238b232cd..fce3fd0f0cbf2 100755 --- a/media/java/android/mtp/MtpDatabase.java +++ b/media/java/android/mtp/MtpDatabase.java @@ -202,12 +202,17 @@ public class MtpDatabase { public void setServer(MtpServer server) { mServer = server; + // always unregister before registering + try { + mContext.unregisterReceiver(mBatteryReceiver); + } catch (IllegalArgumentException e) { + // wasn't previously registered, ignore + } + // register for battery notifications when we are connected if (server != null) { mContext.registerReceiver(mBatteryReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); - } else { - mContext.unregisterReceiver(mBatteryReceiver); } } From 2fc948ead5542355af7064b7b9137bf3f5228d04 Mon Sep 17 00:00:00 2001 From: John Reck Date: Thu, 27 Mar 2014 14:51:01 -0700 Subject: [PATCH 047/119] Force-enable hardware acceleration for apps Change-Id: Ie45581fac2b6b71aeb7b652485915e2518372efc --- core/java/android/view/ViewRootImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index e0e523e91cae8..fd85df992c590 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -678,13 +678,13 @@ public final class ViewRootImpl implements ViewParent, mAttachInfo.mHardwareAccelerationRequested = false; // Don't enable hardware acceleration when the application is in compatibility mode - if (mTranslator != null) return; + if (false && mTranslator != null) return; // Try to enable hardware acceleration if requested final boolean hardwareAccelerated = (attrs.flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0; - if (hardwareAccelerated) { + if (true || hardwareAccelerated) { if (!HardwareRenderer.isAvailable()) { return; } From 6294ef3a6a24e5b0c516f84d59379b0c276f71c2 Mon Sep 17 00:00:00 2001 From: Svetoslav Date: Fri, 28 Mar 2014 13:31:13 -0700 Subject: [PATCH 048/119] Disable node tree consistency check on user builds. Change-Id: I6ec8cfc41fefc12e4c8fb6f39715831f072cb074 --- core/java/android/view/AccessibilityInteractionController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java index abae0687ea565..477c9941825c8 100644 --- a/core/java/android/view/AccessibilityInteractionController.java +++ b/core/java/android/view/AccessibilityInteractionController.java @@ -52,7 +52,7 @@ import java.util.Queue; */ final class AccessibilityInteractionController { - private static final boolean ENFORCE_NODE_TREE_CONSISTENT = Build.IS_DEBUGGABLE; + private static final boolean ENFORCE_NODE_TREE_CONSISTENT = false; private final ArrayList mTempAccessibilityNodeInfoList = new ArrayList(); From bdfe0b756f1e4d2495ec4593271881f1ea94ea7f Mon Sep 17 00:00:00 2001 From: Chris Wren Date: Mon, 31 Mar 2014 13:36:25 -0400 Subject: [PATCH 049/119] add a null check around scrollAdapter access Bug: 13727213 Change-Id: Ia92c06b66fc4712a758bf813c30f543b08546a80 --- packages/SystemUI/src/com/android/systemui/ExpandHelper.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java index b85d5b93f61db..90b0c490f86e9 100644 --- a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java +++ b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java @@ -407,7 +407,8 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener { } case MotionEvent.ACTION_DOWN: - mWatchingForPull = isInside(mScrollAdapter.getHostView(), x, y); + mWatchingForPull = mScrollAdapter != null && + isInside(mScrollAdapter.getHostView(), x, y); mLastMotionY = y; break; From 16c22fee113c4316f6e9fafb9ec4fff9e546d015 Mon Sep 17 00:00:00 2001 From: John Reck Date: Tue, 1 Apr 2014 14:48:55 -0700 Subject: [PATCH 050/119] Disable RenderThread Now that there's a half dozen bugs to fix, switch back to the stable renderer until the issues are addressed Change-Id: I1513cf26717e8ab6b1a038e86ae9a40f5f1a3c50 --- core/java/android/view/HardwareRenderer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java index a92f89d9d4cae..4f646e10c7029 100644 --- a/core/java/android/view/HardwareRenderer.java +++ b/core/java/android/view/HardwareRenderer.java @@ -182,7 +182,7 @@ public abstract class HardwareRenderer { public static boolean sSystemRendererDisabled = false; /** @hide */ - public static boolean sUseRenderThread = true; + public static boolean sUseRenderThread = false; private boolean mEnabled; private boolean mRequested = true; From 1547c17d9d79181ab6f603fd26fad8a461a7e9e4 Mon Sep 17 00:00:00 2001 From: Alan Viverette Date: Wed, 2 Apr 2014 15:14:03 -0700 Subject: [PATCH 051/119] Disable content transitions, they are not implemented yet BUG: 13745751 Change-Id: I5d3c7c2f679084b7a161b7233e18264056eee211 --- core/res/res/values/themes_quantum.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/res/res/values/themes_quantum.xml b/core/res/res/values/themes_quantum.xml index d39a1f8682765..ae7dbae6cf17a 100644 --- a/core/res/res/values/themes_quantum.xml +++ b/core/res/res/values/themes_quantum.xml @@ -154,7 +154,7 @@ please see themes_device_defaults.xml. @style/WindowTitle.Quantum 25dip @style/WindowTitleBackground.Quantum - true + false @style/Animation.Quantum.Activity stateUnspecified|adjustUnspecified true From 21607b4797211e3cf90ec4311d21a4365f85e71c Mon Sep 17 00:00:00 2001 From: Christopher Tate Date: Thu, 3 Apr 2014 16:14:51 -0700 Subject: [PATCH 052/119] Significant preconditions are significant If you are going to check whether we've failed yet, make sure that the default state to test against has been established properly. Bug 13790971 Change-Id: I7fc6ff1bbbd9e569df59dcb65cc30f120c128efa --- .../core/java/com/android/server/pm/PackageManagerService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index dd22b2d9806e4..ff90cae821f5a 100755 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -9201,7 +9201,7 @@ public class PackageManagerService extends IPackageManager.Stub { } // Successfully disabled the old package. Now proceed with re-installation - mLastScanError = PackageManager.INSTALL_SUCCEEDED; + res.returnCode = mLastScanError = PackageManager.INSTALL_SUCCEEDED; pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; newPackage = scanPackageLI(pkg, parseFlags, scanMode, 0, user); if (newPackage == null) { From 92fd164b41c569c5d2527eff0e81365983dc0c81 Mon Sep 17 00:00:00 2001 From: Maxim Siniavine Date: Fri, 28 Mar 2014 16:24:29 -0700 Subject: [PATCH 053/119] DownloadManager test will wait until certain progress, is made during download before moving to next stage of the test. Increase the timeout for waiting for download to complete. Change-Id: I61820a9525256f4f2e16571e1ac075d2f5268cae --- .../DownloadManagerBaseTest.java | 11 ++++--- .../DownloadManagerTestApp.java | 33 +++++++++++-------- 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/downloadmanagertests/DownloadManagerBaseTest.java b/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/downloadmanagertests/DownloadManagerBaseTest.java index fc2897f2418ff..f4bab43e4c520 100644 --- a/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/downloadmanagertests/DownloadManagerBaseTest.java +++ b/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/downloadmanagertests/DownloadManagerBaseTest.java @@ -466,15 +466,16 @@ public class DownloadManagerBaseTest extends InstrumentationTestCase { * bytes downloaded so far. * * @param id DownloadManager download id that needs to be checked. + * @param bytesToReceive how many bytes do we need to wait to receive. * @throws Exception if timed out while waiting for the file to grow in size. */ - protected void waitToReceiveData(long id) throws Exception { + protected void waitToReceiveData(long id, long bytesToReceive) throws Exception { int currentWaitTime = 0; - long originalSize = getBytesDownloaded(id); + long expectedSize = getBytesDownloaded(id) + bytesToReceive; long currentSize = 0; - while ((currentSize = getBytesDownloaded(id)) <= originalSize) { - Log.i(LOG_TAG, String.format("orig: %d, cur: %d. Waiting for file to be written to...", - originalSize, currentSize)); + while ((currentSize = getBytesDownloaded(id)) <= expectedSize) { + Log.i(LOG_TAG, String.format("expect: %d, cur: %d. Waiting for file to be written to...", + expectedSize, currentSize)); currentWaitTime = timeoutWait(currentWaitTime, WAIT_FOR_DOWNLOAD_POLL_TIME, MAX_WAIT_FOR_DOWNLOAD_TIME, "Timed out waiting for file to be written to."); } diff --git a/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/downloadmanagertests/DownloadManagerTestApp.java b/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/downloadmanagertests/DownloadManagerTestApp.java index ef48a18b0bf87..bcf2e45d5bb2a 100644 --- a/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/downloadmanagertests/DownloadManagerTestApp.java +++ b/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/downloadmanagertests/DownloadManagerTestApp.java @@ -40,6 +40,9 @@ public class DownloadManagerTestApp extends DownloadManagerBaseTest { protected static final String DOWNLOAD_FILENAME = "External93mb.apk"; protected static final long DOWNLOAD_FILESIZE = 95251708; + // Wait until download manager actually start downloading something + // Will wait for 1 MB to be downloaded. + private static final long EXPECTED_PROGRESS = 1024 * 1024; private static final String FILE_CONCURRENT_DOWNLOAD_FILE_PREFIX = "file"; private static final String FILE_CONCURRENT_DOWNLOAD_FILE_EXTENSION = ".bin"; @@ -284,7 +287,7 @@ public class DownloadManagerTestApp extends DownloadManagerBaseTest { dlRequest = mDownloadManager.enqueue(request); waitForDownloadToStart(dlRequest); // make sure we're starting to download some data... - waitToReceiveData(dlRequest); + waitToReceiveData(dlRequest, EXPECTED_PROGRESS); // download disable setWiFiStateOn(false); @@ -292,27 +295,29 @@ public class DownloadManagerTestApp extends DownloadManagerBaseTest { // download disable Log.i(LOG_TAG, "Turning on airplane mode..."); setAirplaneModeOn(true); - Thread.sleep(30 * 1000); // wait 30 secs + Thread.sleep(5 * 1000); // wait 5 secs // download disable setWiFiStateOn(true); - Thread.sleep(30 * 1000); // wait 30 secs + Thread.sleep(5 * 1000); // wait 5 secs + waitToReceiveData(dlRequest, EXPECTED_PROGRESS); // download enable Log.i(LOG_TAG, "Turning off airplane mode..."); setAirplaneModeOn(false); Thread.sleep(5 * 1000); // wait 5 seconds + waitToReceiveData(dlRequest, EXPECTED_PROGRESS); // download disable Log.i(LOG_TAG, "Turning off WiFi..."); setWiFiStateOn(false); - Thread.sleep(30 * 1000); // wait 30 secs + Thread.sleep(5 * 1000); // wait 5 secs // finally, turn WiFi back on and finish up the download Log.i(LOG_TAG, "Turning on WiFi..."); setWiFiStateOn(true); - Log.i(LOG_TAG, "Waiting up to 3 minutes for download to complete..."); - assertTrue(waitForDownload(dlRequest, 3 * 60 * 1000)); + Log.i(LOG_TAG, "Waiting up to 10 minutes for download to complete..."); + assertTrue(waitForDownload(dlRequest, 10 * 60 * 1000)); ParcelFileDescriptor pfd = mDownloadManager.openDownloadedFile(dlRequest); verifyFileSize(pfd, filesize); } finally { @@ -358,7 +363,7 @@ public class DownloadManagerTestApp extends DownloadManagerBaseTest { dlRequest = mDownloadManager.enqueue(request); waitForDownloadToStart(dlRequest); // are we making any progress? - waitToReceiveData(dlRequest); + waitToReceiveData(dlRequest, EXPECTED_PROGRESS); // download disable Log.i(LOG_TAG, "Turning off WiFi..."); @@ -368,7 +373,7 @@ public class DownloadManagerTestApp extends DownloadManagerBaseTest { // enable download... Log.i(LOG_TAG, "Turning on WiFi again..."); setWiFiStateOn(true); - waitToReceiveData(dlRequest); + waitToReceiveData(dlRequest, EXPECTED_PROGRESS); // download disable Log.i(LOG_TAG, "Turning off WiFi..."); @@ -379,8 +384,8 @@ public class DownloadManagerTestApp extends DownloadManagerBaseTest { Log.i(LOG_TAG, "Turning on WiFi again..."); setWiFiStateOn(true); - Log.i(LOG_TAG, "Waiting up to 3 minutes for download to complete..."); - assertTrue(waitForDownload(dlRequest, 3 * 60 * 1000)); + Log.i(LOG_TAG, "Waiting up to 10 minutes for download to complete..."); + assertTrue(waitForDownload(dlRequest, 10 * 60 * 1000)); ParcelFileDescriptor pfd = mDownloadManager.openDownloadedFile(dlRequest); verifyFileSize(pfd, filesize); } finally { @@ -428,7 +433,7 @@ public class DownloadManagerTestApp extends DownloadManagerBaseTest { dlRequest = mDownloadManager.enqueue(request); waitForDownloadToStart(dlRequest); // are we making any progress? - waitToReceiveData(dlRequest); + waitToReceiveData(dlRequest, EXPECTED_PROGRESS); // download disable Log.i(LOG_TAG, "Turning on Airplane mode..."); @@ -439,7 +444,7 @@ public class DownloadManagerTestApp extends DownloadManagerBaseTest { Log.i(LOG_TAG, "Turning off Airplane mode..."); setAirplaneModeOn(false); // make sure we're starting to download some data... - waitToReceiveData(dlRequest); + waitToReceiveData(dlRequest, EXPECTED_PROGRESS); // reenable the connection to start up the download again Log.i(LOG_TAG, "Turning on Airplane mode again..."); @@ -450,8 +455,8 @@ public class DownloadManagerTestApp extends DownloadManagerBaseTest { Log.i(LOG_TAG, "Turning off Airplane mode again..."); setAirplaneModeOn(false); - Log.i(LOG_TAG, "Waiting up to 3 minutes for donwload to complete..."); - assertTrue(waitForDownload(dlRequest, 180 * 1000)); // wait up to 3 mins before timeout + Log.i(LOG_TAG, "Waiting up to 10 minutes for donwload to complete..."); + assertTrue(waitForDownload(dlRequest, 10 * 60 * 1000)); // wait up to 10 mins ParcelFileDescriptor pfd = mDownloadManager.openDownloadedFile(dlRequest); verifyFileSize(pfd, filesize); } finally { From 72aa6f210bc39d53f3451cd5ef330137a7ac35bb Mon Sep 17 00:00:00 2001 From: Selim Cinek Date: Mon, 7 Apr 2014 20:07:22 +0200 Subject: [PATCH 054/119] Fixed crash in PanelView dump Bugreports crashed when dumping PanelView. Bug: 13872972 Change-Id: I3bd2b5321dd208766248f6506c5592190366e5ea --- .../src/com/android/systemui/statusbar/phone/PanelView.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java index 3c8af3007b00a..ec35d41ea5571 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java @@ -793,7 +793,7 @@ public class PanelView extends FrameLayout { } public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - pw.println(String.format("[PanelView(%s): expandedHeight=%f maxPanelHeight=%f closing=%s" + pw.println(String.format("[PanelView(%s): expandedHeight=%f maxPanelHeight=%d closing=%s" + " tracking=%s rubberbanding=%s justPeeked=%s peekAnim=%s%s timeAnim=%s%s" + "]", this.getClass().getSimpleName(), From 9501d5443bcfb7e7fe4801c4dedb7b2a399b19c4 Mon Sep 17 00:00:00 2001 From: Selim Cinek Date: Mon, 7 Apr 2014 21:18:09 +0200 Subject: [PATCH 055/119] QuickSettings was inaccessible sometimes with empty shade. Fixed access to QuickSettings, when the shade was not full. Bug: 13879008 Change-Id: Ie8c88b91eb397dcb4d78834acfc2e2ab2a24bed9 --- .../src/com/android/systemui/statusbar/phone/PanelView.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java index ec35d41ea5571..20fb225c83821 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java @@ -529,7 +529,6 @@ public class PanelView extends FrameLayout { switch (event.getActionMasked()) { case MotionEvent.ACTION_DOWN: - mTracking = true; if (mHandleView != null) { mHandleView.setPressed(true); // catch the press state change @@ -561,6 +560,7 @@ public class PanelView extends FrameLayout { if (h < -mTouchSlop) { mInitialOffsetOnTouch = mExpandedHeight; mInitialTouchY = y; + mTracking = true; return true; } } From 140f55680c74ff22fce3b1fabdb6e46a7605ca6b Mon Sep 17 00:00:00 2001 From: John Reck Date: Tue, 8 Apr 2014 14:10:17 -0700 Subject: [PATCH 056/119] Don't make HardwareRenderer calls in the finalizer Bug: 13902530 Don't try to set the RenderNode's displayListData to 0 in the finalizer. The HardwareRenderer may have already been finalized and it's not valid to make calls into HardwareRenderer from another thread anyway. The fix is that now that RenderNode is a refcounted object, this step can be skipped entirely. The RenderNode destructor handles deleting its DisplayListData if it needs to. Change-Id: Ieab75575b98c24678a531dd5aa41a2d0afde0eef --- core/java/android/view/RenderNode.java | 1 - core/java/android/view/ThreadedRenderer.java | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java index 26eaef816f5fa..78ddf5b39af7c 100644 --- a/core/java/android/view/RenderNode.java +++ b/core/java/android/view/RenderNode.java @@ -909,7 +909,6 @@ public class RenderNode { @Override protected void finalize() throws Throwable { try { - destroyDisplayListData(); nDestroyDisplayList(mNativeDisplayList); } finally { super.finalize(); diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java index 3d143d777fd1b..a747ab601eabb 100644 --- a/core/java/android/view/ThreadedRenderer.java +++ b/core/java/android/view/ThreadedRenderer.java @@ -253,6 +253,7 @@ public class ThreadedRenderer extends HardwareRenderer { protected void finalize() throws Throwable { try { nDeleteProxy(mNativeProxy); + mNativeProxy = 0; } finally { super.finalize(); } From 94b7780eb5d3c448a3b826d62a5f8cf046d89dea Mon Sep 17 00:00:00 2001 From: Alan Viverette Date: Tue, 8 Apr 2014 14:52:01 -0700 Subject: [PATCH 057/119] Fix action bar theming Change-Id: If1a7040e4f6d2e8e1195a67a03ed0e24f31e68f4 --- core/res/res/values/themes_quantum.xml | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/core/res/res/values/themes_quantum.xml b/core/res/res/values/themes_quantum.xml index 17bab3071ec11..b5ac8fa3946a6 100644 --- a/core/res/res/values/themes_quantum.xml +++ b/core/res/res/values/themes_quantum.xml @@ -296,10 +296,11 @@ please see themes_device_defaults.xml. @style/Widget.Quantum.ActionBar.TabText @style/Widget.Quantum.ActionMode @style/Widget.Quantum.ActionButton.CloseMode - @style/Widget.Quantum.ActionBar + @style/Widget.Quantum.ActionBar.Solid @dimen/action_bar_default_height @style/Widget.Quantum.PopupWindow.ActionMode @null + @null @drawable/item_background_quantum @drawable/ic_menu_cut_quantum @@ -356,18 +357,18 @@ please see themes_device_defaults.xml. atThumb - @color/quantum_grey_700 - @color/quantum_grey_500 - @color/quantum_grey_100 + @color/quantum_blue_700 + @color/quantum_blue_500 + @color/quantum_blue_100 @color/quantum_teal_A200 ?attr/textColorSecondary - ?attr/colorPrimaryDark + ?attr/colorPrimary @color/quantum_grey_700 @color/quantum_grey_500 ?attr/colorPrimary - ?attr/colorPrimaryDark + ?attr/colorPrimaryLight @@ -634,6 +635,7 @@ please see themes_device_defaults.xml. @dimen/action_bar_default_height @style/Widget.Quantum.Light.PopupWindow.ActionMode @null + @null @drawable/item_background_quantum @drawable/ic_menu_cut_quantum @@ -686,18 +688,18 @@ please see themes_device_defaults.xml. atThumb - @color/quantum_grey_700 - @color/quantum_grey_500 - @color/quantum_grey_100 + @color/quantum_blue_700 + @color/quantum_blue_500 + @color/quantum_blue_100 @color/quantum_teal_A200 ?attr/textColorSecondary - ?attr/colorPrimaryLight + ?attr/colorPrimary @color/quantum_grey_100 @color/quantum_grey_500 ?attr/colorPrimary - ?attr/colorPrimaryLight + ?attr/colorPrimaryDark - - - \ No newline at end of file + android:background="#5f000000" + android:animateLayoutChanges="true" + android:columnCount="@integer/quick_settings_num_columns" /> \ No newline at end of file diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml index 8f4417ee83331..8a3f090375408 100644 --- a/packages/SystemUI/res/layout/status_bar_expanded.xml +++ b/packages/SystemUI/res/layout/status_bar_expanded.xml @@ -41,7 +41,7 @@ android:layout_width="50dp" android:layout_height="50dp" android:layout_gravity="right|top" - android:layout_marginTop="@*android:dimen/status_bar_height" + android:layout_marginTop="@dimen/status_bar_height" android:visibility="gone" /> + android:layout_height="@dimen/status_bar_height" /> + android:layout_marginBottom="@dimen/navigation_bar_height"> 6 + + 2 + 2 diff --git a/packages/SystemUI/res/values-sw600dp/config.xml b/packages/SystemUI/res/values-sw600dp/config.xml index 440ead6f1331d..c6bc44d5a9f51 100644 --- a/packages/SystemUI/res/values-sw600dp/config.xml +++ b/packages/SystemUI/res/values-sw600dp/config.xml @@ -26,6 +26,9 @@ 3 + + 4 + 1 diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 73e3e051de114..f908a1ead9d0a 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -81,6 +81,12 @@ 3 + + 4 + + + 3 + 1 diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index e7959ab858f16..9aacf42221b6a 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -269,4 +269,7 @@ 100dp + + 8dp + 30dp diff --git a/packages/SystemUI/res/values/internal.xml b/packages/SystemUI/res/values/internal.xml new file mode 100644 index 0000000000000..ddaab9422d79b --- /dev/null +++ b/packages/SystemUI/res/values/internal.xml @@ -0,0 +1,22 @@ + + + + + @*android:dimen/status_bar_height + @*android:dimen/navigation_bar_height + @*android:drawable/notification_quantum_bg + + diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java index 6f93bedbaf5db..45ac50b6f6866 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -30,11 +30,14 @@ public class NotificationPanelView extends PanelView { public static final boolean DEBUG_GESTURES = true; PhoneStatusBar mStatusBar; + private View mHeader; + private View mKeyguardStatusView; + private NotificationStackScrollLayout mNotificationStackScroller; private int[] mTempLocation = new int[2]; private int[] mTempChildLocation = new int[2]; private View mNotificationParent; - + private boolean mTrackingSettings; public NotificationPanelView(Context context, AttributeSet attrs) { super(context, attrs); @@ -59,6 +62,8 @@ public class NotificationPanelView extends PanelView { protected void onFinishInflate() { super.onFinishInflate(); + mHeader = findViewById(R.id.header); + mKeyguardStatusView = findViewById(R.id.keyguard_status_view); mNotificationStackScroller = (NotificationStackScrollLayout) findViewById(R.id.notification_stack_scroller); mNotificationParent = findViewById(R.id.notification_container_parent); @@ -98,10 +103,39 @@ public class NotificationPanelView extends PanelView { return mTempChildLocation[1] - mTempLocation[1]; } + @Override + public boolean onInterceptTouchEvent(MotionEvent event) { + // intercept for quick settings + if (event.getAction() == MotionEvent.ACTION_DOWN) { + final View target = mStatusBar.isOnKeyguard() ? mKeyguardStatusView : mHeader; + final boolean inTarget = PhoneStatusBar.inBounds(target, event, true); + if (inTarget && !isInSettings()) { + mTrackingSettings = true; + return true; + } + if (!inTarget && isInSettings()) { + mTrackingSettings = true; + return true; + } + } + return super.onInterceptTouchEvent(event); + } + @Override public boolean onTouchEvent(MotionEvent event) { // TODO: Handle doublefinger swipe to notifications again. Look at history for a reference // implementation. + if (mTrackingSettings) { + mStatusBar.onSettingsEvent(event); + if (event.getAction() == MotionEvent.ACTION_UP + || event.getAction() == MotionEvent.ACTION_CANCEL) { + mTrackingSettings = false; + } + return true; + } + if (isInSettings()) { + return true; + } return super.onTouchEvent(event); } 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 5f71516992772..d5770702e6a5b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -73,6 +73,7 @@ import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.View; +import android.view.ViewConfiguration; import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; import android.view.ViewPropertyAnimator; @@ -97,11 +98,9 @@ import com.android.systemui.statusbar.BaseStatusBar; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.GestureRecorder; import com.android.systemui.statusbar.InterceptedNotifications; -import com.android.systemui.statusbar.LatestItemView; import com.android.systemui.statusbar.NotificationData; import com.android.systemui.statusbar.NotificationData.Entry; import com.android.systemui.statusbar.NotificationOverflowContainer; -import com.android.systemui.statusbar.NotificationOverflowIconsView; import com.android.systemui.statusbar.SignalClusterView; import com.android.systemui.statusbar.StatusBarIconView; import com.android.systemui.statusbar.policy.BatteryController; @@ -233,8 +232,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { int mKeyguardMaxNotificationCount; View mDateTimeView; View mClearButton; - ImageView mSettingsButton, mNotificationButton; - View mKeyguardSettingsFlipButton; + FlipperButton mHeaderFlipper, mKeyguardFlipper; // carrier/wifi label private TextView mCarrierLabel; @@ -314,9 +312,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { if (MULTIUSER_DEBUG) Log.d(TAG, String.format("User setup changed: " + "selfChange=%s userSetup=%s mUserSetup=%s", selfChange, userSetup, mUserSetup)); - if (mSettingsButton != null && mHasFlipSettings) { - mSettingsButton.setVisibility(userSetup ? View.VISIBLE : View.INVISIBLE); - } + mHeaderFlipper.userSetup(userSetup); + mKeyguardFlipper.userSetup(userSetup); + if (mSettingsPanel != null) { mSettingsPanel.setEnabled(userSetup); } @@ -371,6 +369,11 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { private Runnable mOnFlipRunnable; private InterceptedNotifications mIntercepted; + private VelocityTracker mSettingsTracker; + private float mSettingsDownY; + private boolean mSettingsCancelled; + private boolean mSettingsClosing; + private int mNotificationPadding; private final OnChildLocationsChangedListener mOnChildLocationsChangedListener = new OnChildLocationsChangedListener() { @@ -631,35 +634,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { mDateTimeView.setEnabled(true); } - mSettingsButton = (ImageView) mStatusBarWindow.findViewById(R.id.settings_button); - if (mSettingsButton != null) { - mSettingsButton.setOnClickListener(mSettingsButtonListener); - if (mHasSettingsPanel) { - if (mStatusBarView.hasFullWidthNotifications()) { - // the settings panel is hiding behind this button - mSettingsButton.setImageResource(R.drawable.ic_notify_quicksettings); - mSettingsButton.setVisibility(View.VISIBLE); - } else { - // there is a settings panel, but it's on the other side of the (large) screen - final View buttonHolder = mStatusBarWindow.findViewById( - R.id.settings_button_holder); - if (buttonHolder != null) { - buttonHolder.setVisibility(View.GONE); - } - } - } else { - // no settings panel, go straight to settings - mSettingsButton.setVisibility(View.VISIBLE); - mSettingsButton.setImageResource(R.drawable.ic_notify_settings); - } - } - if (mHasFlipSettings) { - mNotificationButton = (ImageView) mStatusBarWindow.findViewById( - R.id.notification_button); - if (mNotificationButton != null) { - mNotificationButton.setOnClickListener(mNotificationButtonListener); - } - } + mHeaderFlipper = new FlipperButton(mNotificationPanelHeader + .findViewById(R.id.settings_button_holder)); + ViewStub flipStub = (ViewStub) mStatusBarWindow.findViewById(R.id.keyguard_flip_stub); + mKeyguardFlipper = new FlipperButton(flipStub.inflate()); if (!mNotificationPanelIsFullScreenWidth) { mNotificationPanel.setSystemUiVisibility( @@ -735,6 +713,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { } // Quick Settings (where available, some restrictions apply) + mNotificationPadding = mContext.getResources() + .getDimensionPixelSize(R.dimen.notification_side_padding); if (mHasSettingsPanel) { // first, figure out where quick settings should be inflated final View settings_stub; @@ -803,6 +783,87 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { return mStatusBarView; } + public boolean onSettingsEvent(MotionEvent event) { + if (mSettingsTracker != null) { + mSettingsTracker.addMovement(event); + } + + if (event.getAction() == MotionEvent.ACTION_DOWN) { + mSettingsTracker = VelocityTracker.obtain(); + mSettingsDownY = event.getY(); + mSettingsCancelled = false; + mSettingsClosing = mFlipSettingsView.getVisibility() == View.VISIBLE; + mFlipSettingsView.setVisibility(View.VISIBLE); + mStackScroller.setVisibility(View.VISIBLE); + positionSettings(0); + if (!mSettingsClosing) { + mFlipSettingsView.setTranslationY(-mNotificationPanel.getMeasuredHeight()); + } + dispatchSettingsEvent(event); + } else if (mSettingsTracker != null && (event.getAction() == MotionEvent.ACTION_UP + || event.getAction() == MotionEvent.ACTION_CANCEL)) { + final float dy = event.getY() - mSettingsDownY; + final FlipperButton flipper = mOnKeyguard ? mKeyguardFlipper : mHeaderFlipper; + final boolean inButton = flipper.inHolderBounds(event); + final int slop = ViewConfiguration.get(mContext).getScaledTouchSlop(); + final boolean qsTap = mSettingsClosing && Math.abs(dy) < slop; + if (!qsTap && !inButton) { + mSettingsTracker.computeCurrentVelocity(1000); + final float vy = mSettingsTracker.getYVelocity(); + if (dy <= slop || vy <= 0) { + flipToNotifications(); + } else { + flipToSettings(); + } + } + mSettingsTracker.recycle(); + mSettingsTracker = null; + dispatchSettingsEvent(event); + } else if (mSettingsTracker != null && event.getAction() == MotionEvent.ACTION_MOVE) { + final float dy = event.getY() - mSettingsDownY; + positionSettings(dy); + if (mSettingsClosing) { + final boolean qsTap = + Math.abs(dy) < ViewConfiguration.get(mContext).getScaledTouchSlop(); + if (!mSettingsCancelled && !qsTap) { + MotionEvent cancelEvent = MotionEvent.obtainNoHistory(event); + cancelEvent.setAction(MotionEvent.ACTION_CANCEL); + dispatchSettingsEvent(cancelEvent); + mSettingsCancelled = true; + } + } else { + dispatchSettingsEvent(event); + } + } + return true; + } + + private void dispatchSettingsEvent(MotionEvent event) { + final View target = mSettingsClosing ? mFlipSettingsView : mNotificationPanelHeader; + final int[] targetLoc = new int[2]; + target.getLocationInWindow(targetLoc); + final int[] panelLoc = new int[2]; + mNotificationPanel.getLocationInWindow(panelLoc); + final int dx = targetLoc[0] - panelLoc[0]; + final int dy = targetLoc[1] - panelLoc[1]; + event.offsetLocation(-dx, -dy); + target.dispatchTouchEvent(event); + } + + private void positionSettings(float dy) { + final int h = mFlipSettingsView.getMeasuredHeight(); + final int ph = mNotificationPanel.getMeasuredHeight(); + if (mSettingsClosing) { + dy = Math.min(Math.max(-ph, dy), 0); + mFlipSettingsView.setTranslationY(dy); + mStackScroller.setTranslationY(ph + dy); + } else { + dy = Math.min(Math.max(0, dy), ph); + mFlipSettingsView.setTranslationY(-h + dy - mNotificationPadding * 2); + mStackScroller.setTranslationY(dy); + } + } + private void startKeyguard() { KeyguardViewMediator keyguardViewMediator = getComponent(KeyguardViewMediator.class); mStatusBarKeyguardViewManager = keyguardViewMediator.registerStatusBar(this, @@ -1163,17 +1224,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { ((ImageView)mClearButton).setImageResource(R.drawable.ic_notify_clear); } - if (mSettingsButton != null) { - // Force asset reloading - mSettingsButton.setImageDrawable(null); - mSettingsButton.setImageResource(R.drawable.ic_notify_quicksettings); - } - - if (mNotificationButton != null) { - // Force asset reloading - mNotificationButton.setImageDrawable(null); - mNotificationButton.setImageResource(R.drawable.ic_notifications); - } + mHeaderFlipper.refreshLayout(); + mKeyguardFlipper.refreshLayout(); refreshAllStatusBarIcons(); } @@ -1228,9 +1280,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { } } - if (mSettingsButton != null) { - mSettingsButton.setEnabled(isDeviceProvisioned()); - } + mHeaderFlipper.provisionCheck(provisioned); + mKeyguardFlipper.provisionCheck(provisioned); } @Override @@ -1647,6 +1698,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { mStatusBarWindow.cancelExpandHelper(); mStatusBarView.collapseAllPanels(true); + if (isFlippedToSettings()) { + flipToNotifications(); + } } } @@ -1694,8 +1748,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { final int FLIP_DURATION_IN = 225; final int FLIP_DURATION = (FLIP_DURATION_IN + FLIP_DURATION_OUT); - Animator mScrollViewAnim, mFlipSettingsViewAnim, mNotificationButtonAnim, - mSettingsButtonAnim, mClearButtonAnim; + Animator mScrollViewAnim, mFlipSettingsViewAnim, mClearButtonAnim; @Override public void animateExpandNotificationsPanel() { @@ -1715,33 +1768,29 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { public void flipToNotifications() { if (mFlipSettingsViewAnim != null) mFlipSettingsViewAnim.cancel(); if (mScrollViewAnim != null) mScrollViewAnim.cancel(); - if (mSettingsButtonAnim != null) mSettingsButtonAnim.cancel(); - if (mNotificationButtonAnim != null) mNotificationButtonAnim.cancel(); + mHeaderFlipper.cancel(); + mKeyguardFlipper.cancel(); if (mClearButtonAnim != null) mClearButtonAnim.cancel(); mStackScroller.setVisibility(View.VISIBLE); + final int h = mNotificationPanel.getMeasuredHeight(); + final float settingsY = mSettingsTracker != null ? mFlipSettingsView.getTranslationY() : 0; + final float scrollerY = mSettingsTracker != null ? mStackScroller.getTranslationY() : h; mScrollViewAnim = start( - startDelay(FLIP_DURATION_OUT, + startDelay(0, interpolator(mDecelerateInterpolator, - ObjectAnimator.ofFloat(mStackScroller, View.SCALE_X, 0f, 1f) - .setDuration(FLIP_DURATION_IN) + ObjectAnimator.ofFloat(mStackScroller, View.TRANSLATION_Y, scrollerY, 0) + .setDuration(FLIP_DURATION) ))); mFlipSettingsViewAnim = start( setVisibilityWhenDone( - interpolator(mAccelerateInterpolator, - ObjectAnimator.ofFloat(mFlipSettingsView, View.SCALE_X, 1f, 0f) + interpolator(mDecelerateInterpolator, + ObjectAnimator.ofFloat(mFlipSettingsView, View.TRANSLATION_Y, settingsY, -h) ) - .setDuration(FLIP_DURATION_OUT), - mFlipSettingsView, View.INVISIBLE)); - mNotificationButtonAnim = start( - setVisibilityWhenDone( - ObjectAnimator.ofFloat(mNotificationButton, View.ALPHA, 0f) .setDuration(FLIP_DURATION), - mNotificationButton, View.INVISIBLE)); - mSettingsButton.setVisibility(View.VISIBLE); - mSettingsButtonAnim = start( - ObjectAnimator.ofFloat(mSettingsButton, View.ALPHA, 1f) - .setDuration(FLIP_DURATION)); + mFlipSettingsView, View.INVISIBLE)); + mHeaderFlipper.flipToNotifications(); + mKeyguardFlipper.flipToNotifications(); mClearButton.setVisibility(View.VISIBLE); mClearButton.setAlpha(0f); setAreThereNotifications(); // this will show/hide the button as necessary @@ -1767,7 +1816,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { if (mHasFlipSettings) { mNotificationPanel.expand(); - if (mFlipSettingsView.getVisibility() != View.VISIBLE) { + if (mFlipSettingsView.getVisibility() != View.VISIBLE + || mFlipSettingsView.getTranslationY() < 0) { flipToSettings(); } } else if (mSettingsPanel != null) { @@ -1777,23 +1827,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { if (false) postStartTracing(); } - public void switchToSettings() { - // Settings are not available in setup - if (!mUserSetup) return; - - mFlipSettingsView.setScaleX(1f); - mFlipSettingsView.setVisibility(View.VISIBLE); - mSettingsButton.setVisibility(View.GONE); - mStackScroller.setVisibility(View.GONE); - mStackScroller.setScaleX(0f); - mNotificationButton.setVisibility(View.VISIBLE); - mNotificationButton.setAlpha(1f); - mClearButton.setVisibility(View.GONE); - if (mOnFlipRunnable != null) { - mOnFlipRunnable.run(); - } - } - public boolean isFlippedToSettings() { if (mFlipSettingsView != null) { return mFlipSettingsView.getVisibility() == View.VISIBLE; @@ -1807,34 +1840,29 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { if (mFlipSettingsViewAnim != null) mFlipSettingsViewAnim.cancel(); if (mScrollViewAnim != null) mScrollViewAnim.cancel(); - if (mSettingsButtonAnim != null) mSettingsButtonAnim.cancel(); - if (mNotificationButtonAnim != null) mNotificationButtonAnim.cancel(); + mHeaderFlipper.cancel(); + mKeyguardFlipper.cancel(); if (mClearButtonAnim != null) mClearButtonAnim.cancel(); mFlipSettingsView.setVisibility(View.VISIBLE); - mFlipSettingsView.setScaleX(0f); + final int h = mNotificationPanel.getMeasuredHeight(); + final float settingsY = mSettingsTracker != null ? mFlipSettingsView.getTranslationY() : -h; + final float scrollerY = mSettingsTracker != null ? mStackScroller.getTranslationY() : 0; mFlipSettingsViewAnim = start( - startDelay(FLIP_DURATION_OUT, - interpolator(mDecelerateInterpolator, - ObjectAnimator.ofFloat(mFlipSettingsView, View.SCALE_X, 0f, 1f) - .setDuration(FLIP_DURATION_IN) - ))); + startDelay(0, + interpolator(mDecelerateInterpolator, + ObjectAnimator.ofFloat(mFlipSettingsView, View.TRANSLATION_Y, settingsY, 0f) + .setDuration(FLIP_DURATION) + ))); mScrollViewAnim = start( setVisibilityWhenDone( - interpolator(mAccelerateInterpolator, - ObjectAnimator.ofFloat(mStackScroller, View.SCALE_X, 1f, 0f) + interpolator(mDecelerateInterpolator, + ObjectAnimator.ofFloat(mStackScroller, View.TRANSLATION_Y, scrollerY, h) ) - .setDuration(FLIP_DURATION_OUT), - mStackScroller, View.INVISIBLE)); - mSettingsButtonAnim = start( - setVisibilityWhenDone( - ObjectAnimator.ofFloat(mSettingsButton, View.ALPHA, 0f) .setDuration(FLIP_DURATION), mStackScroller, View.INVISIBLE)); - mNotificationButton.setVisibility(View.VISIBLE); - mNotificationButtonAnim = start( - ObjectAnimator.ofFloat(mNotificationButton, View.ALPHA, 1f) - .setDuration(FLIP_DURATION)); + mHeaderFlipper.flipToSettings(); + mKeyguardFlipper.flipToSettings(); mClearButtonAnim = start( setVisibilityWhenDone( ObjectAnimator.ofFloat(mClearButton, View.ALPHA, 0f) @@ -1883,18 +1911,16 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { // reset things to their proper state if (mFlipSettingsViewAnim != null) mFlipSettingsViewAnim.cancel(); if (mScrollViewAnim != null) mScrollViewAnim.cancel(); - if (mSettingsButtonAnim != null) mSettingsButtonAnim.cancel(); - if (mNotificationButtonAnim != null) mNotificationButtonAnim.cancel(); if (mClearButtonAnim != null) mClearButtonAnim.cancel(); - mStackScroller.setScaleX(1f); mStackScroller.setVisibility(View.VISIBLE); - mSettingsButton.setAlpha(1f); - mSettingsButton.setVisibility(View.VISIBLE); mNotificationPanel.setVisibility(View.GONE); mFlipSettingsView.setVisibility(View.GONE); - mNotificationButton.setVisibility(View.GONE); + setAreThereNotifications(); // show the clear button + + mHeaderFlipper.reset(); + mKeyguardFlipper.reset(); } mExpandedVisible = false; @@ -2947,15 +2973,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { } mKeyguardStatusView.setVisibility(View.VISIBLE); mNotificationPanelHeader.setVisibility(View.GONE); - if (mKeyguardSettingsFlipButton == null) { - ViewStub flipStub = (ViewStub) mStatusBarWindow.findViewById(R.id.keyguard_flip_stub); - mKeyguardSettingsFlipButton = flipStub.inflate(); - installSettingsButton(mKeyguardSettingsFlipButton); - } - mKeyguardSettingsFlipButton.setVisibility(View.VISIBLE); - mKeyguardSettingsFlipButton.findViewById(R.id.settings_button).setVisibility(View.VISIBLE); - mKeyguardSettingsFlipButton.findViewById(R.id.notification_button) - .setVisibility(View.INVISIBLE); + + mKeyguardFlipper.setVisibility(View.VISIBLE); + mSettingsContainer.setKeyguardShowing(true); updateRowStates(); } @@ -2963,9 +2983,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { mOnKeyguard = false; mKeyguardStatusView.setVisibility(View.GONE); mNotificationPanelHeader.setVisibility(View.VISIBLE); - if (mKeyguardSettingsFlipButton != null) { - mKeyguardSettingsFlipButton.setVisibility(View.GONE); - } + + mKeyguardFlipper.setVisibility(View.GONE); + mSettingsContainer.setKeyguardShowing(false); updateRowStates(); instantCollapseNotificationPanel(); } @@ -3030,39 +3050,112 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { } } - private void installSettingsButton(View parent) { - final ImageView settingsButton = - (ImageView) mStatusBarWindow.findViewById(R.id.settings_button); - final ImageView notificationButton = - (ImageView) mStatusBarWindow.findViewById(R.id.notification_button); - if (settingsButton != null) { - settingsButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - animateExpandSettingsPanel(); - v.setVisibility(View.INVISIBLE); - notificationButton.setVisibility(View.VISIBLE); + public static boolean inBounds(View view, MotionEvent event, boolean orAbove) { + final int[] location = new int[2]; + view.getLocationInWindow(location); + final int rx = (int) event.getRawX(); + final int ry = (int) event.getRawY(); + return rx >= location[0] && rx <= location[0] + view.getMeasuredWidth() + && (orAbove || ry >= location[1]) && ry <= location[1] + view.getMeasuredHeight(); + } + + private final class FlipperButton { + private final View mHolder; + + private ImageView mSettingsButton, mNotificationButton; + private Animator mSettingsButtonAnim, mNotificationButtonAnim; + + public FlipperButton(View holder) { + mHolder = holder; + mSettingsButton = (ImageView) holder.findViewById(R.id.settings_button); + if (mSettingsButton != null) { + mSettingsButton.setOnClickListener(mSettingsButtonListener); + if (mHasSettingsPanel) { + // the settings panel is hiding behind this button + mSettingsButton.setImageResource(R.drawable.ic_notify_quicksettings); + mSettingsButton.setVisibility(View.VISIBLE); + } else { + // no settings panel, go straight to settings + mSettingsButton.setVisibility(View.VISIBLE); + mSettingsButton.setImageResource(R.drawable.ic_notify_settings); + } + } + if (mHasFlipSettings) { + mNotificationButton = (ImageView) holder.findViewById(R.id.notification_button); + if (mNotificationButton != null) { + mNotificationButton.setOnClickListener(mNotificationButtonListener); } - }); - settingsButton.setVisibility(View.VISIBLE); - if (mHasSettingsPanel) { - // the settings panel is hiding behind this button - settingsButton.setImageResource(R.drawable.ic_notify_quicksettings); - } else { - // no settings panel, go straight to settings - settingsButton.setImageResource(R.drawable.ic_notify_settings); } } - if (notificationButton != null) { - notificationButton.setVisibility(View.INVISIBLE); - notificationButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - flipToNotifications(); - v.setVisibility(View.INVISIBLE); - settingsButton.setVisibility(View.VISIBLE); - } - }); + + public boolean inHolderBounds(MotionEvent event) { + return inBounds(mHolder, event, false); + } + + public void provisionCheck(boolean provisioned) { + if (mSettingsButton != null) { + mSettingsButton.setEnabled(provisioned); + } + } + + public void userSetup(boolean userSetup) { + if (mSettingsButton != null && mHasFlipSettings) { + mSettingsButton.setVisibility(userSetup ? View.VISIBLE : View.INVISIBLE); + } + } + + public void reset() { + cancel(); + mSettingsButton.setVisibility(View.VISIBLE); + mNotificationButton.setVisibility(View.GONE); + } + + public void refreshLayout() { + if (mSettingsButton != null) { + // Force asset reloading + mSettingsButton.setImageDrawable(null); + mSettingsButton.setImageResource(R.drawable.ic_notify_quicksettings); + } + + if (mNotificationButton != null) { + // Force asset reloading + mNotificationButton.setImageDrawable(null); + mNotificationButton.setImageResource(R.drawable.ic_notifications); + } + } + + public void flipToSettings() { + mSettingsButtonAnim = start( + setVisibilityWhenDone( + ObjectAnimator.ofFloat(mSettingsButton, View.ALPHA, 0f) + .setDuration(FLIP_DURATION), + mStackScroller, View.INVISIBLE)); + mNotificationButton.setVisibility(View.VISIBLE); + mNotificationButtonAnim = start( + ObjectAnimator.ofFloat(mNotificationButton, View.ALPHA, 1f) + .setDuration(FLIP_DURATION)); + } + + public void flipToNotifications() { + mNotificationButtonAnim = start( + setVisibilityWhenDone( + ObjectAnimator.ofFloat(mNotificationButton, View.ALPHA, 0f) + .setDuration(FLIP_DURATION), + mNotificationButton, View.INVISIBLE)); + + mSettingsButton.setVisibility(View.VISIBLE); + mSettingsButtonAnim = start( + ObjectAnimator.ofFloat(mSettingsButton, View.ALPHA, 1f) + .setDuration(FLIP_DURATION)); + } + + public void cancel() { + if (mSettingsButtonAnim != null) mSettingsButtonAnim.cancel(); + if (mNotificationButtonAnim != null) mNotificationButtonAnim.cancel(); + } + + public void setVisibility(int vis) { + mHolder.setVisibility(vis); } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsContainerView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsContainerView.java index 17ee0177252eb..02e9c0d7ce57f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsContainerView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsContainerView.java @@ -19,7 +19,13 @@ package com.android.systemui.statusbar.phone; import android.animation.LayoutTransition; import android.content.Context; import android.content.res.Resources; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.Rect; +import android.graphics.Typeface; import android.util.AttributeSet; +import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; @@ -31,30 +37,58 @@ import com.android.systemui.R; */ class QuickSettingsContainerView extends FrameLayout { + private static boolean sShowScrim = true; + + private final Context mContext; + // The number of columns in the QuickSettings grid private int mNumColumns; + private boolean mKeyguardShowing; + private int mMaxRows; + private int mMaxRowsOnKeyguard; + // The gap between tiles in the QuickSettings grid private float mCellGap; + private ScrimView mScrim; + public QuickSettingsContainerView(Context context, AttributeSet attrs) { super(context, attrs); - + mContext = context; updateResources(); } @Override protected void onFinishInflate() { super.onFinishInflate(); - + mScrim = new ScrimView(mContext); + addView(mScrim); + mScrim.setAlpha(sShowScrim ? 1 : 0); // TODO: Setup the layout transitions LayoutTransition transitions = getLayoutTransition(); } + @Override + public boolean onTouchEvent(MotionEvent event) { + if (mScrim.getAlpha() == 1) { + mScrim.animate().alpha(0).setDuration(1000).start(); + sShowScrim = false; + } + return super.onTouchEvent(event); + } + void updateResources() { Resources r = getContext().getResources(); mCellGap = r.getDimension(R.dimen.quick_settings_cell_gap); mNumColumns = r.getInteger(R.integer.quick_settings_num_columns); + mMaxRows = r.getInteger(R.integer.quick_settings_max_rows); + mMaxRowsOnKeyguard = r.getInteger(R.integer.quick_settings_max_rows_keyguard); + requestLayout(); + } + + void setKeyguardShowing(boolean showing) { + mKeyguardShowing = showing; requestLayout(); } @@ -71,10 +105,18 @@ class QuickSettingsContainerView extends FrameLayout { final int N = getChildCount(); int cellHeight = 0; int cursor = 0; + int maxRows = mKeyguardShowing ? mMaxRowsOnKeyguard : mMaxRows; + for (int i = 0; i < N; ++i) { + if (getChildAt(i).equals(mScrim)) { + continue; + } // Update the child's width QuickSettingsTileView v = (QuickSettingsTileView) getChildAt(i); if (v.getVisibility() != View.GONE) { + int row = (int) (cursor / mNumColumns); + if (row >= maxRows) continue; + ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) v.getLayoutParams(); int colSpan = v.getColumnSpan(); lp.width = (int) ((colSpan * cellWidth) + (colSpan - 1) * mCellGap); @@ -102,6 +144,7 @@ class QuickSettingsContainerView extends FrameLayout { @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + mScrim.bringToFront(); final int N = getChildCount(); final boolean isLayoutRtl = isLayoutRtl(); final int width = getWidth(); @@ -109,8 +152,18 @@ class QuickSettingsContainerView extends FrameLayout { int x = getPaddingStart(); int y = getPaddingTop(); int cursor = 0; + int maxRows = mKeyguardShowing ? mMaxRowsOnKeyguard : mMaxRows; for (int i = 0; i < N; ++i) { + if (getChildAt(i).equals(mScrim)) { + int w = right - left - getPaddingLeft() - getPaddingRight(); + int h = bottom - top - getPaddingTop() - getPaddingBottom(); + mScrim.measure( + MeasureSpec.makeMeasureSpec(w, MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(h, MeasureSpec.EXACTLY)); + mScrim.layout(getPaddingLeft(), getPaddingTop(), right, bottom); + continue; + } QuickSettingsTileView child = (QuickSettingsTileView) getChildAt(i); ViewGroup.LayoutParams lp = child.getLayoutParams(); if (child.getVisibility() != GONE) { @@ -121,6 +174,7 @@ class QuickSettingsContainerView extends FrameLayout { final int childHeight = lp.height; int row = (int) (cursor / mNumColumns); + if (row >= maxRows) continue; // Push the item to the next row if it can't fit on this one if ((col + colSpan) > mNumColumns) { @@ -150,4 +204,87 @@ class QuickSettingsContainerView extends FrameLayout { } } } + + private static final class ScrimView extends View { + private static final int COLOR = 0xaf4285f4; + + private final Paint mLinePaint; + private final int mStrokeWidth; + private final Rect mTmp = new Rect(); + private final Paint mTextPaint; + private final int mTextSize; + + public ScrimView(Context context) { + super(context); + setFocusable(false); + final Resources res = context.getResources(); + mStrokeWidth = res.getDimensionPixelSize(R.dimen.quick_settings_tmp_scrim_stroke_width); + mTextSize = res.getDimensionPixelSize(R.dimen.quick_settings_tmp_scrim_text_size); + + mLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mLinePaint.setColor(COLOR); + mLinePaint.setStrokeWidth(mStrokeWidth); + mLinePaint.setStrokeJoin(Paint.Join.ROUND); + mLinePaint.setStrokeCap(Paint.Cap.ROUND); + mLinePaint.setStyle(Paint.Style.STROKE); + + mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mTextPaint.setColor(COLOR); + mTextPaint.setTextSize(mTextSize); + mTextPaint.setTypeface(Typeface.create("sans-serif-condensed", Typeface.BOLD)); + } + + @Override + protected void onDraw(Canvas canvas) { + final int w = getMeasuredWidth(); + final int h = getMeasuredHeight(); + final int f = mStrokeWidth * 3 / 4; + + canvas.drawPath(line(f, h / 2, w - f, h / 2), mLinePaint); + canvas.drawPath(line(w / 2, f, w / 2, h - f), mLinePaint); + + final int s = mStrokeWidth; + mTextPaint.setTextAlign(Paint.Align.RIGHT); + canvas.drawText("FUTURE", w / 2 - s, h / 2 - s, mTextPaint); + mTextPaint.setTextAlign(Paint.Align.LEFT); + canvas.drawText("SITE OF", w / 2 + s, h / 2 - s , mTextPaint); + mTextPaint.setTextAlign(Paint.Align.RIGHT); + drawUnder(canvas, "QUANTUM", w / 2 - s, h / 2 + s); + mTextPaint.setTextAlign(Paint.Align.LEFT); + drawUnder(canvas, "SETTINGS", w / 2 + s, h / 2 + s); + } + + private void drawUnder(Canvas c, String text, float x, float y) { + if (mTmp.isEmpty()) { + mTextPaint.getTextBounds(text, 0, text.length(), mTmp); + } + c.drawText(text, x, y + mTmp.height() * .85f, mTextPaint); + } + + private Path line(float x1, float y1, float x2, float y2) { + final int a = mStrokeWidth * 2; + final Path p = new Path(); + p.moveTo(x1, y1); + p.lineTo(x2, y2); + if (y1 == y2) { + p.moveTo(x1 + a, y1 + a); + p.lineTo(x1, y1); + p.lineTo(x1 + a, y1 - a); + + p.moveTo(x2 - a, y2 - a); + p.lineTo(x2, y2); + p.lineTo(x2 - a, y2 + a); + } + if (x1 == x2) { + p.moveTo(x1 - a, y1 + a); + p.lineTo(x1, y1); + p.lineTo(x1 + a, y1 + a); + + p.moveTo(x2 - a, y2 - a); + p.lineTo(x2, y2); + p.lineTo(x2 + a, y2 - a); + } + return p; + } + } } \ No newline at end of file From 3f4ed0f5c3bfd1afdab70030b96d5786753dd077 Mon Sep 17 00:00:00 2001 From: Jorim Jaggi Date: Thu, 17 Apr 2014 20:17:30 +0200 Subject: [PATCH 070/119] Fix not being able to unlock SIM PIN. Bug: 14120902 Change-Id: I812d9679000242eabea617ea75cf8355d16926b2 --- .../res/layout/keyguard_sim_pin_view.xml | 22 +++++++++---------- .../res/layout/keyguard_sim_puk_view.xml | 22 +++++++++---------- .../android/keyguard/KeyguardSimPinView.java | 2 +- .../android/keyguard/KeyguardSimPukView.java | 2 +- 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/packages/Keyguard/res/layout/keyguard_sim_pin_view.xml b/packages/Keyguard/res/layout/keyguard_sim_pin_view.xml index e96220ecc655f..0e2b33af427fe 100644 --- a/packages/Keyguard/res/layout/keyguard_sim_pin_view.xml +++ b/packages/Keyguard/res/layout/keyguard_sim_pin_view.xml @@ -52,7 +52,7 @@ android:orientation="horizontal" android:layout_weight="1" > - @@ -130,7 +130,7 @@ android:layout_width="0px" android:layout_height="match_parent" android:layout_weight="1" - androidprv:textView="@+id/pinEntry" + androidprv:textView="@+id/simPinEntry" androidprv:digit="4" /> @@ -164,7 +164,7 @@ android:layout_width="0px" android:layout_height="match_parent" android:layout_weight="1" - androidprv:textView="@+id/pinEntry" + androidprv:textView="@+id/simPinEntry" androidprv:digit="7" /> @@ -203,7 +203,7 @@ android:layout_width="0px" android:layout_height="match_parent" android:layout_weight="1" - androidprv:textView="@+id/pinEntry" + androidprv:textView="@+id/simPinEntry" androidprv:digit="0" /> - @@ -131,7 +131,7 @@ android:layout_width="0px" android:layout_height="match_parent" android:layout_weight="1" - androidprv:textView="@+id/pinEntry" + androidprv:textView="@+id/pukEntry" androidprv:digit="4" /> @@ -165,7 +165,7 @@ android:layout_width="0px" android:layout_height="match_parent" android:layout_weight="1" - androidprv:textView="@+id/pinEntry" + androidprv:textView="@+id/pukEntry" androidprv:digit="7" /> @@ -204,7 +204,7 @@ android:layout_width="0px" android:layout_height="match_parent" android:layout_weight="1" - androidprv:textView="@+id/pinEntry" + androidprv:textView="@+id/pukEntry" androidprv:digit="0" /> Date: Thu, 17 Apr 2014 20:36:15 +0200 Subject: [PATCH 071/119] Fix global screen rotation issue. Bug: 14080683 Change-Id: I0144faafa0e01c14c8c8e6a6c9fc81a10d25f47d --- .../statusbar/phone/StatusBarWindowManager.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java index 716e326d5911e..d175d7ac57f34 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java @@ -99,10 +99,14 @@ public class StatusBarWindowManager { } private void adjustScreenOrientation(State state) { - if (!state.isKeyguardShowingAndNotOccluded() || mKeyguardScreenRotation) { - mLp.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_USER; + if (state.isKeyguardShowingAndNotOccluded()) { + if (mKeyguardScreenRotation) { + mLp.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_USER; + } else { + mLp.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR; + } } else { - mLp.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR; + mLp.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; } } From d4f775758d27dea0ff465215e62daf6926da6eb8 Mon Sep 17 00:00:00 2001 From: John Spurlock Date: Thu, 17 Apr 2014 23:45:50 +0000 Subject: [PATCH 072/119] Revert "Fix broken status bar when activity is showing above keyguard" This reverts commit 25ab3d94387597a24619723df687214320f17e76. Change-Id: I7dba397a9fe09d70b87ff4e638805c010c192599 --- .../phone/StatusBarKeyguardViewManager.java | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index 460f122325179..41b5b7c94448b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -56,7 +56,6 @@ public class StatusBarKeyguardViewManager { private boolean mScreenOn = false; private KeyguardBouncer mBouncer; private boolean mShowing; - private boolean mOccluded = false; public StatusBarKeyguardViewManager(Context context, ViewMediatorCallback callback, LockPatternUtils lockPatternUtils) { @@ -103,10 +102,8 @@ public class StatusBarKeyguardViewManager { } public void showBouncer() { - if (!mOccluded) { - mBouncer.show(); - updateBackButtonState(); - } + mBouncer.show(); + updateBackButtonState(); } /** @@ -155,13 +152,6 @@ public class StatusBarKeyguardViewManager { } public void setOccluded(boolean occluded) { - mOccluded = occluded; - if (occluded) { - mPhoneStatusBar.hideKeyguard(); - mBouncer.hide(); - } else { - showBouncerOrKeyguard(); - } mStatusBarWindowManager.setKeyguardOccluded(occluded); } From 5493c44a0f21749b1bce492f75eaff15921f79d1 Mon Sep 17 00:00:00 2001 From: Dan Sandler Date: Mon, 21 Apr 2014 12:05:00 -0400 Subject: [PATCH 073/119] Avoid NPE when mRoot is null. Bug: 14162288 Change-Id: I36793d706ab1d29576f536562a0c06f7805a0d50 --- .../com/android/systemui/statusbar/phone/KeyguardBouncer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java index f2054a210f164..cf31b445c6b2f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java @@ -83,7 +83,7 @@ public class KeyguardBouncer { } public void onScreenTurnedOff() { - if (mKeyguardView != null && mRoot.getVisibility() == View.VISIBLE) { + if (mKeyguardView != null && mRoot != null && mRoot.getVisibility() == View.VISIBLE) { mKeyguardView.onPause(); } } From cdd2cd9de53f115cce891e1f8c9715f50258c59a Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Mon, 21 Apr 2014 14:50:28 -0700 Subject: [PATCH 074/119] Make sure events handled on same looper Two handlers are used to call a function, but the init was not forcing them on the same looper/thread, so we could get synchronization problems as a result. Moved to a single looper. Also added finally clauses to clean up if a broadcast throws an uncaught exception. bug:13399768 Change-Id: I0044e2442335ee45a15588f910064e848cf6ac55 --- .../server/NetworkManagementService.java | 164 +++++++++++------- 1 file changed, 99 insertions(+), 65 deletions(-) diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java index 9629bd1d02df8..705862ab8b977 100644 --- a/services/core/java/com/android/server/NetworkManagementService.java +++ b/services/core/java/com/android/server/NetworkManagementService.java @@ -153,7 +153,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub */ private NativeDaemonConnector mConnector; - private final Handler mMainHandler = new Handler(); + private final Handler mFgHandler; private IBatteryStats mBatteryStats; @@ -203,6 +203,9 @@ public class NetworkManagementService extends INetworkManagementService.Stub private NetworkManagementService(Context context, String socket) { mContext = context; + // make sure this is on the same looper as our NativeDaemonConnector for sync purposes + mFgHandler = new Handler(FgThread.get().getLooper()); + if ("simulator".equals(SystemProperties.get("ro.product.device"))) { return; } @@ -271,14 +274,17 @@ public class NetworkManagementService extends INetworkManagementService.Stub */ private void notifyInterfaceStatusChanged(String iface, boolean up) { final int length = mObservers.beginBroadcast(); - for (int i = 0; i < length; i++) { - try { - mObservers.getBroadcastItem(i).interfaceStatusChanged(iface, up); - } catch (RemoteException e) { - } catch (RuntimeException e) { + try { + for (int i = 0; i < length; i++) { + try { + mObservers.getBroadcastItem(i).interfaceStatusChanged(iface, up); + } catch (RemoteException e) { + } catch (RuntimeException e) { + } } + } finally { + mObservers.finishBroadcast(); } - mObservers.finishBroadcast(); } /** @@ -287,14 +293,17 @@ public class NetworkManagementService extends INetworkManagementService.Stub */ private void notifyInterfaceLinkStateChanged(String iface, boolean up) { final int length = mObservers.beginBroadcast(); - for (int i = 0; i < length; i++) { - try { - mObservers.getBroadcastItem(i).interfaceLinkStateChanged(iface, up); - } catch (RemoteException e) { - } catch (RuntimeException e) { + try { + for (int i = 0; i < length; i++) { + try { + mObservers.getBroadcastItem(i).interfaceLinkStateChanged(iface, up); + } catch (RemoteException e) { + } catch (RuntimeException e) { + } } + } finally { + mObservers.finishBroadcast(); } - mObservers.finishBroadcast(); } /** @@ -302,14 +311,17 @@ public class NetworkManagementService extends INetworkManagementService.Stub */ private void notifyInterfaceAdded(String iface) { final int length = mObservers.beginBroadcast(); - for (int i = 0; i < length; i++) { - try { - mObservers.getBroadcastItem(i).interfaceAdded(iface); - } catch (RemoteException e) { - } catch (RuntimeException e) { + try { + for (int i = 0; i < length; i++) { + try { + mObservers.getBroadcastItem(i).interfaceAdded(iface); + } catch (RemoteException e) { + } catch (RuntimeException e) { + } } + } finally { + mObservers.finishBroadcast(); } - mObservers.finishBroadcast(); } /** @@ -322,14 +334,17 @@ public class NetworkManagementService extends INetworkManagementService.Stub mActiveQuotas.remove(iface); final int length = mObservers.beginBroadcast(); - for (int i = 0; i < length; i++) { - try { - mObservers.getBroadcastItem(i).interfaceRemoved(iface); - } catch (RemoteException e) { - } catch (RuntimeException e) { + try { + for (int i = 0; i < length; i++) { + try { + mObservers.getBroadcastItem(i).interfaceRemoved(iface); + } catch (RemoteException e) { + } catch (RuntimeException e) { + } } + } finally { + mObservers.finishBroadcast(); } - mObservers.finishBroadcast(); } /** @@ -337,14 +352,17 @@ public class NetworkManagementService extends INetworkManagementService.Stub */ private void notifyLimitReached(String limitName, String iface) { final int length = mObservers.beginBroadcast(); - for (int i = 0; i < length; i++) { - try { - mObservers.getBroadcastItem(i).limitReached(limitName, iface); - } catch (RemoteException e) { - } catch (RuntimeException e) { + try { + for (int i = 0; i < length; i++) { + try { + mObservers.getBroadcastItem(i).limitReached(limitName, iface); + } catch (RemoteException e) { + } catch (RuntimeException e) { + } } + } finally { + mObservers.finishBroadcast(); } - mObservers.finishBroadcast(); } /** @@ -357,15 +375,18 @@ public class NetworkManagementService extends INetworkManagementService.Stub } final int length = mObservers.beginBroadcast(); - for (int i = 0; i < length; i++) { - try { - mObservers.getBroadcastItem(i).interfaceClassDataActivityChanged( - Integer.toString(type), active, tsNanos); - } catch (RemoteException e) { - } catch (RuntimeException e) { + try { + for (int i = 0; i < length; i++) { + try { + mObservers.getBroadcastItem(i).interfaceClassDataActivityChanged( + Integer.toString(type), active, tsNanos); + } catch (RemoteException e) { + } catch (RuntimeException e) { + } } + } finally { + mObservers.finishBroadcast(); } - mObservers.finishBroadcast(); boolean report = false; synchronized (mIdleTimerLock) { @@ -456,14 +477,17 @@ public class NetworkManagementService extends INetworkManagementService.Stub */ private void notifyAddressUpdated(String iface, LinkAddress address) { final int length = mObservers.beginBroadcast(); - for (int i = 0; i < length; i++) { - try { - mObservers.getBroadcastItem(i).addressUpdated(iface, address); - } catch (RemoteException e) { - } catch (RuntimeException e) { + try { + for (int i = 0; i < length; i++) { + try { + mObservers.getBroadcastItem(i).addressUpdated(iface, address); + } catch (RemoteException e) { + } catch (RuntimeException e) { + } } + } finally { + mObservers.finishBroadcast(); } - mObservers.finishBroadcast(); } /** @@ -471,14 +495,17 @@ public class NetworkManagementService extends INetworkManagementService.Stub */ private void notifyAddressRemoved(String iface, LinkAddress address) { final int length = mObservers.beginBroadcast(); - for (int i = 0; i < length; i++) { - try { - mObservers.getBroadcastItem(i).addressRemoved(iface, address); - } catch (RemoteException e) { - } catch (RuntimeException e) { + try { + for (int i = 0; i < length; i++) { + try { + mObservers.getBroadcastItem(i).addressRemoved(iface, address); + } catch (RemoteException e) { + } catch (RuntimeException e) { + } } + } finally { + mObservers.finishBroadcast(); } - mObservers.finishBroadcast(); } /** @@ -486,14 +513,18 @@ public class NetworkManagementService extends INetworkManagementService.Stub */ private void notifyInterfaceDnsServerInfo(String iface, long lifetime, String[] addresses) { final int length = mObservers.beginBroadcast(); - for (int i = 0; i < length; i++) { - try { - mObservers.getBroadcastItem(i).interfaceDnsServerInfo(iface, lifetime, addresses); - } catch (RemoteException e) { - } catch (RuntimeException e) { + try { + for (int i = 0; i < length; i++) { + try { + mObservers.getBroadcastItem(i).interfaceDnsServerInfo(iface, lifetime, + addresses); + } catch (RemoteException e) { + } catch (RuntimeException e) { + } } + } finally { + mObservers.finishBroadcast(); } - mObservers.finishBroadcast(); } // @@ -509,7 +540,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub mConnectedSignal.countDown(); mConnectedSignal = null; } else { - mMainHandler.post(new Runnable() { + mFgHandler.post(new Runnable() { @Override public void run() { prepareNativeDaemon(); @@ -1270,7 +1301,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub if (ConnectivityManager.isNetworkTypeMobile(type)) { mNetworkActive = false; } - mMainHandler.post(new Runnable() { + mFgHandler.post(new Runnable() { @Override public void run() { notifyInterfaceClassActivity(type, true, SystemClock.elapsedRealtimeNanos()); } @@ -1297,7 +1328,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub throw e.rethrowAsParcelableException(); } mActiveIdleTimers.remove(iface); - mMainHandler.post(new Runnable() { + mFgHandler.post(new Runnable() { @Override public void run() { notifyInterfaceClassActivity(params.type, false, SystemClock.elapsedRealtimeNanos()); @@ -1880,14 +1911,17 @@ public class NetworkManagementService extends INetworkManagementService.Stub private void reportNetworkActive() { final int length = mNetworkActivityListeners.beginBroadcast(); - for (int i = 0; i < length; i++) { - try { - mNetworkActivityListeners.getBroadcastItem(i).onNetworkActive(); - } catch (RemoteException e) { - } catch (RuntimeException e) { + try { + for (int i = 0; i < length; i++) { + try { + mNetworkActivityListeners.getBroadcastItem(i).onNetworkActive(); + } catch (RemoteException e) { + } catch (RuntimeException e) { + } } + } finally { + mNetworkActivityListeners.finishBroadcast(); } - mNetworkActivityListeners.finishBroadcast(); } /** {@inheritDoc} */ From 70f79a435e3594bd071f6c5cc9cf9f594facac95 Mon Sep 17 00:00:00 2001 From: Ji-Hwan Lee Date: Tue, 22 Apr 2014 12:39:26 +0900 Subject: [PATCH 075/119] Add config resource for disabling KeyguardService Bug: 14102545 Change-Id: I0c7936e16a8bda98e49e6a2c396117d7a8fd5664 --- packages/SystemUI/AndroidManifest.xml | 3 ++- packages/SystemUI/res/values/config.xml | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index d371d70c901d6..327df8d35c85a 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -273,7 +273,8 @@ + android:exported="true" + android:enabled="@bool/config_enableKeyguardService" /> size), in ms --> 333 333 - + false @@ -122,6 +122,9 @@ 96 + + true + 4 From 625fd4b3f39739070dc175c1b5b88a08dbcf3692 Mon Sep 17 00:00:00 2001 From: Dan Sandler Date: Tue, 22 Apr 2014 11:51:42 -0400 Subject: [PATCH 076/119] Avoid sending broadcasts before BOOT_COMPLETED. SystemUI instances can now take advantage of a new lifecycle callback, onBootCompleted(), to avoid jumping the gun. Bug: 14092537 Change-Id: I3f7db7a4753f874c4d75235f263c2bd374debec4 --- .../src/com/android/systemui/SystemUI.java | 3 ++ .../android/systemui/SystemUIApplication.java | 38 +++++++++++++++++++ .../com/android/systemui/recent/Recents.java | 35 +++++++++++++---- 3 files changed, 69 insertions(+), 7 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/SystemUI.java b/packages/SystemUI/src/com/android/systemui/SystemUI.java index cb624adeaf896..85befff9eed3c 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUI.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUI.java @@ -35,6 +35,9 @@ public abstract class SystemUI { public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { } + protected void onBootCompleted() { + } + @SuppressWarnings("unchecked") public T getComponent(Class interfaceType) { return (T) (mComponents != null ? mComponents.get(interfaceType) : null); diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java index 0f556833f9d07..103991a1bd5c3 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java @@ -17,7 +17,12 @@ package com.android.systemui; import android.app.Application; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; import android.content.res.Configuration; +import android.os.SystemProperties; import android.util.Log; import java.util.HashMap; @@ -49,6 +54,7 @@ public class SystemUIApplication extends Application { */ private final SystemUI[] mServices = new SystemUI[SERVICES.length]; private boolean mServicesStarted; + private boolean mBootCompleted; private final Map, Object> mComponents = new HashMap, Object>(); @Override @@ -58,6 +64,23 @@ public class SystemUIApplication extends Application { // application theme in the manifest does only work for activities. Keep this in sync with // the theme set there. setTheme(R.style.systemui_theme); + + registerReceiver(new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (mBootCompleted) return; + + if (DEBUG) Log.v(TAG, "BOOT_COMPLETED received"); + unregisterReceiver(this); + mBootCompleted = true; + if (mServicesStarted) { + final int N = mServices.length; + for (int i = 0; i < N; i++) { + mServices[i].onBootCompleted(); + } + } + } + }, new IntentFilter(Intent.ACTION_BOOT_COMPLETED)); } /** @@ -71,6 +94,17 @@ public class SystemUIApplication extends Application { if (mServicesStarted) { return; } + + if (!mBootCompleted) { + // check to see if maybe it was already completed long before we began + // see ActivityManagerService.finishBooting() + if ("1".equals(SystemProperties.get("sys.boot_completed"))) { + mBootCompleted = true; + if (DEBUG) Log.v(TAG, "BOOT_COMPLETED was already sent"); + } + } + + Log.v(TAG, "Starting SystemUI services."); final int N = SERVICES.length; for (int i=0; i cl = SERVICES[i]; @@ -86,6 +120,10 @@ public class SystemUIApplication extends Application { mServices[i].mComponents = mComponents; if (DEBUG) Log.d(TAG, "running: " + mServices[i]); mServices[i].start(); + + if (mBootCompleted) { + mServices[i].onBootCompleted(); + } } mServicesStarted = true; } diff --git a/packages/SystemUI/src/com/android/systemui/recent/Recents.java b/packages/SystemUI/src/com/android/systemui/recent/Recents.java index 10b6d49ec6461..21c292668e880 100644 --- a/packages/SystemUI/src/com/android/systemui/recent/Recents.java +++ b/packages/SystemUI/src/com/android/systemui/recent/Recents.java @@ -26,6 +26,7 @@ import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; +import android.os.Bundle; import android.os.SystemProperties; import android.os.UserHandle; import android.util.DisplayMetrics; @@ -45,6 +46,7 @@ public class Recents extends SystemUI implements RecentsComponent { // Which recents to use boolean mUseAlternateRecents; AlternateRecentsComponent mAlternateRecents; + boolean mBootCompleted = false; @Override public void start() { @@ -59,6 +61,11 @@ public class Recents extends SystemUI implements RecentsComponent { putComponent(RecentsComponent.class, this); } + @Override + protected void onBootCompleted() { + mBootCompleted = true; + } + @Override public void toggleRecents(Display display, int layoutDirection, View statusBarView) { if (mUseAlternateRecents) { @@ -197,13 +204,11 @@ public class Recents extends SystemUI implements RecentsComponent { Intent intent = new Intent(RecentsActivity.WINDOW_ANIMATION_START_INTENT); intent.setPackage("com.android.systemui"); - mContext.sendBroadcastAsUser(intent, - new UserHandle(UserHandle.USER_CURRENT)); + sendBroadcastSafely(intent); } }); intent.putExtra(RecentsActivity.WAITING_FOR_WINDOW_ANIMATION_PARAM, true); - mContext.startActivityAsUser(intent, opts.toBundle(), new UserHandle( - UserHandle.USER_CURRENT)); + startActivitySafely(intent, opts.toBundle()); } } catch (ActivityNotFoundException e) { Log.e(TAG, "Failed to launch RecentAppsIntent", e); @@ -225,7 +230,7 @@ public class Recents extends SystemUI implements RecentsComponent { Intent intent = new Intent(RecentsActivity.PRELOAD_INTENT); intent.setClassName("com.android.systemui", "com.android.systemui.recent.RecentsPreloadReceiver"); - mContext.sendBroadcastAsUser(intent, new UserHandle(UserHandle.USER_CURRENT)); + sendBroadcastSafely(intent); RecentTasksLoader.getInstance(mContext).preloadFirstTask(); } @@ -239,7 +244,7 @@ public class Recents extends SystemUI implements RecentsComponent { Intent intent = new Intent(RecentsActivity.CANCEL_PRELOAD_INTENT); intent.setClassName("com.android.systemui", "com.android.systemui.recent.RecentsPreloadReceiver"); - mContext.sendBroadcastAsUser(intent, new UserHandle(UserHandle.USER_CURRENT)); + sendBroadcastSafely(intent); RecentTasksLoader.getInstance(mContext).cancelPreloadingFirstTask(); } @@ -252,9 +257,25 @@ public class Recents extends SystemUI implements RecentsComponent { } else { Intent intent = new Intent(RecentsActivity.CLOSE_RECENTS_INTENT); intent.setPackage("com.android.systemui"); - mContext.sendBroadcastAsUser(intent, new UserHandle(UserHandle.USER_CURRENT)); + sendBroadcastSafely(intent); RecentTasksLoader.getInstance(mContext).cancelPreloadingFirstTask(); } } + + /** + * Send broadcast only if BOOT_COMPLETED + */ + private void sendBroadcastSafely(Intent intent) { + if (!mBootCompleted) return; + mContext.sendBroadcastAsUser(intent, new UserHandle(UserHandle.USER_CURRENT)); + } + + /** + * Start activity only if BOOT_COMPLETED + */ + private void startActivitySafely(Intent intent, Bundle opts) { + if (!mBootCompleted) return; + mContext.startActivityAsUser(intent, opts, new UserHandle(UserHandle.USER_CURRENT)); + } } From ea8ac4347996b8c77bc0ee1b73f290bd9316b0d6 Mon Sep 17 00:00:00 2001 From: John Spurlock Date: Tue, 22 Apr 2014 12:58:26 -0400 Subject: [PATCH 077/119] Apply insets manually in StatusBarWindowView. Bug:14131489 Change-Id: Ie4be2185cae98764ea44b2e042210f13412a02aa --- .../systemui/statusbar/phone/StatusBarWindowView.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java index 1d675bd017f37..c5dae8540f88e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java @@ -20,6 +20,7 @@ import android.app.StatusBarManager; import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; +import android.graphics.Rect; import android.util.AttributeSet; import android.view.KeyEvent; import android.view.MotionEvent; @@ -51,6 +52,16 @@ public class StatusBarWindowView extends FrameLayout setWillNotDraw(!DEBUG); } + @Override + protected boolean fitSystemWindows(Rect insets) { + if (getFitsSystemWindows()) { + setPadding(insets.left, insets.top, insets.right, insets.bottom); + } else { + setPadding(0, 0, 0, 0); + } + return true; + } + @Override protected void onAttachedToWindow () { super.onAttachedToWindow(); From 32e3918826d641cda31dc290057d90cae17775cc Mon Sep 17 00:00:00 2001 From: Alan Viverette Date: Wed, 23 Apr 2014 10:20:11 -0700 Subject: [PATCH 078/119] Fix null and bounds checks BUG: 14271950 BUG: 14271753 BUG: 14270202 Change-Id: I8708107d3803b170a323f584a268ea6b096458ce --- core/java/android/widget/AbsSeekBar.java | 2 +- core/java/android/widget/CompoundButton.java | 2 +- .../android/graphics/drawable/TouchFeedbackDrawable.java | 8 +++++++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java index 8a30def2fb9a2..225cd6d589ca1 100644 --- a/core/java/android/widget/AbsSeekBar.java +++ b/core/java/android/widget/AbsSeekBar.java @@ -314,7 +314,7 @@ public abstract class AbsSeekBar extends ProgressBar { final int right = left + thumbWidth; final Drawable background = getBackground(); - if (background.supportsHotspots()) { + if (background != null && background.supportsHotspots()) { final Rect bounds = mThumb.getBounds(); final int offsetX = mPaddingLeft - mThumbOffset; final int offsetY = mPaddingTop; diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java index ddc8b050af188..9e17cca07cc70 100644 --- a/core/java/android/widget/CompoundButton.java +++ b/core/java/android/widget/CompoundButton.java @@ -285,7 +285,7 @@ public abstract class CompoundButton extends Button implements Checkable { buttonDrawable.setBounds(left, top, right, bottom); final Drawable background = getBackground(); - if (background.supportsHotspots()) { + if (background != null && background.supportsHotspots()) { background.setHotspotBounds(left, top, right, bottom); } } diff --git a/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java b/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java index 1958cfead2152..5c370a4638c50 100644 --- a/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java +++ b/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java @@ -25,12 +25,13 @@ import android.graphics.Color; import android.graphics.Paint; import android.graphics.PixelFormat; import android.graphics.PorterDuff.Mode; -import android.graphics.drawable.Ripple.RippleAnimator; import android.graphics.PorterDuffXfermode; import android.graphics.Rect; +import android.graphics.drawable.Ripple.RippleAnimator; import android.os.SystemClock; import android.util.AttributeSet; import android.util.DisplayMetrics; +import android.util.Log; import android.util.SparseArray; import com.android.internal.R; @@ -45,6 +46,7 @@ import java.util.Arrays; * Documentation pending. */ public class TouchFeedbackDrawable extends LayerDrawable { + private static final String LOG_TAG = TouchFeedbackDrawable.class.getSimpleName(); private static final PorterDuffXfermode DST_IN = new PorterDuffXfermode(Mode.DST_IN); /** The maximum number of ripples supported. */ @@ -308,6 +310,10 @@ public class TouchFeedbackDrawable extends LayerDrawable { mTouchedRipples = new SparseArray(); mActiveRipples = new Ripple[MAX_RIPPLES]; } + + if (mActiveRipplesCount >= MAX_RIPPLES) { + Log.e(LOG_TAG, "Max ripple count exceeded", new RuntimeException()); + } final Ripple ripple = mTouchedRipples.get(id); if (ripple == null) { From a277dd2d87ceae3dcb41bc23ca57be2a84724e8c Mon Sep 17 00:00:00 2001 From: Alan Viverette Date: Wed, 23 Apr 2014 10:33:47 -0700 Subject: [PATCH 079/119] Prevent new ripples when max reached BUG: 14270202 Change-Id: I53b0522a175eca043ba1cf007377312d03fd8f6d --- .../java/android/graphics/drawable/TouchFeedbackDrawable.java | 1 + 1 file changed, 1 insertion(+) diff --git a/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java b/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java index 5c370a4638c50..5101e3584aeb6 100644 --- a/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java +++ b/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java @@ -313,6 +313,7 @@ public class TouchFeedbackDrawable extends LayerDrawable { if (mActiveRipplesCount >= MAX_RIPPLES) { Log.e(LOG_TAG, "Max ripple count exceeded", new RuntimeException()); + return; } final Ripple ripple = mTouchedRipples.get(id); From d0e49b892f261f6d91bac8c739084adfa22c4824 Mon Sep 17 00:00:00 2001 From: Alan Viverette Date: Wed, 23 Apr 2014 12:51:16 -0700 Subject: [PATCH 080/119] Add null bg check to switch BUG: 14271950 Change-Id: I6f4833c916ddc8d939f5bfa6ab7b1ed1993e862e --- core/java/android/widget/Switch.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java index d013e7b6eef0b..08af4dee6c641 100644 --- a/core/java/android/widget/Switch.java +++ b/core/java/android/widget/Switch.java @@ -799,7 +799,7 @@ public class Switch extends CompoundButton { thumbDrawable.setBounds(thumbLeft, switchTop, thumbRight, switchBottom); final Drawable background = getBackground(); - if (background.supportsHotspots()) { + if (background != null && background.supportsHotspots()) { background.setHotspotBounds(thumbLeft, switchTop, thumbRight, switchBottom); } From 2ae8d1c5dbe88fef70a2dea8caed950569ca1e94 Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Mon, 21 Apr 2014 14:45:27 -0700 Subject: [PATCH 081/119] Enabling doc centric recents on phones. Change-Id: If853cdcbf3fc75001060e522bce2e0d49d2ddea3 --- core/java/android/app/ActivityThread.java | 4 +++- .../SystemUI/src/com/android/systemui/recent/Recents.java | 3 ++- .../core/java/com/android/server/am/ActivityStack.java | 4 +++- .../core/java/com/android/server/wm/AppTransition.java | 8 +++----- .../java/com/android/server/wm/WindowManagerService.java | 5 ++--- 5 files changed, 13 insertions(+), 11 deletions(-) diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 88eae7f2638cb..4562d6e95ff21 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -3003,7 +3003,9 @@ public final class ActivityThread { int h; if (w < 0) { Resources res = r.activity.getResources(); - if (SystemProperties.getBoolean("persist.recents.use_alternate", false)) { + Configuration config = res.getConfiguration(); + boolean useAlternateRecents = (config.smallestScreenWidthDp < 600); + if (useAlternateRecents) { int wId = com.android.internal.R.dimen.recents_thumbnail_width; int hId = com.android.internal.R.dimen.recents_thumbnail_height; mThumbnailWidth = w = res.getDimensionPixelSize(wId); diff --git a/packages/SystemUI/src/com/android/systemui/recent/Recents.java b/packages/SystemUI/src/com/android/systemui/recent/Recents.java index 21c292668e880..ae18aa8ea30ff 100644 --- a/packages/SystemUI/src/com/android/systemui/recent/Recents.java +++ b/packages/SystemUI/src/com/android/systemui/recent/Recents.java @@ -50,7 +50,8 @@ public class Recents extends SystemUI implements RecentsComponent { @Override public void start() { - mUseAlternateRecents = SystemProperties.getBoolean("persist.recents.use_alternate", false); + Configuration config = mContext.getResources().getConfiguration(); + mUseAlternateRecents = (config.smallestScreenWidthDp < 600); if (mUseAlternateRecents) { if (mAlternateRecents == null) { mAlternateRecents = new AlternateRecentsComponent(mContext); diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 0acde0950eb81..3adf7e09c895b 100755 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -735,7 +735,9 @@ final class ActivityStack { int w = mThumbnailWidth; int h = mThumbnailHeight; if (w < 0) { - if (SystemProperties.getBoolean("persist.recents.use_alternate", false)) { + Configuration config = res.getConfiguration(); + boolean useAlternateRecents = (config.smallestScreenWidthDp < 600); + if (useAlternateRecents) { mThumbnailWidth = w = res.getDimensionPixelSize(com.android.internal.R.dimen.recents_thumbnail_width); mThumbnailHeight = h = diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java index f17b2f48ce4bf..90392369b8561 100644 --- a/services/core/java/com/android/server/wm/AppTransition.java +++ b/services/core/java/com/android/server/wm/AppTransition.java @@ -162,13 +162,10 @@ public class AppTransition implements Dump { private final Interpolator mThumbnailFadeoutInterpolator; private int mCurrentUserId = 0; - private boolean mUseAlternateThumbnailAnimation; AppTransition(Context context, Handler h) { mContext = context; mH = h; - mUseAlternateThumbnailAnimation = - SystemProperties.getBoolean("persist.anim.use_alt_thumbnail", false); mConfigShortAnimTime = context.getResources().getInteger( com.android.internal.R.integer.config_shortAnimTime); mDecelerateInterpolator = AnimationUtils.loadInterpolator(context, @@ -668,7 +665,7 @@ public class AppTransition implements Dump { Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter, int appWidth, int appHeight, int orientation, - Rect containingFrame, Rect contentInsets) { + Rect containingFrame, Rect contentInsets, Configuration configuration) { Animation a; if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM) { a = loadAnimation(mNextAppTransitionPackage, enter ? @@ -689,7 +686,8 @@ public class AppTransition implements Dump { mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN) { mNextAppTransitionScaleUp = (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP); - if (mUseAlternateThumbnailAnimation) { + boolean useAlternateThumbnailAnimation = (configuration.smallestScreenWidthDp < 600); + if (useAlternateThumbnailAnimation) { a = createAlternateThumbnailEnterExitAnimationLocked( getThumbnailTransitionState(enter), appWidth, appHeight, orientation, transit, containingFrame, contentInsets); diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 524d78bc9f99a..0aa4f5c1b92b2 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -3192,7 +3192,7 @@ public class WindowManagerService extends IWindowManager.Stub } Animation a = mAppTransition.loadAnimation(lp, transit, enter, width, height, - mCurConfiguration.orientation, containingFrame, contentInsets); + mCurConfiguration.orientation, containingFrame, contentInsets, mCurConfiguration); if (a != null) { if (DEBUG_ANIM) { RuntimeException e = null; @@ -8660,8 +8660,7 @@ public class WindowManagerService extends IWindowManager.Stub wtoken.deferClearAllDrawn = false; } - boolean useAlternateThumbnailAnimation = - SystemProperties.getBoolean("persist.anim.use_alt_thumbnail", false); + boolean useAlternateThumbnailAnimation = (mCurConfiguration.smallestScreenWidthDp < 600); AppWindowAnimator appAnimator = topOpeningApp == null ? null : topOpeningApp.mAppAnimator; Bitmap nextAppTransitionThumbnail = mAppTransition.getNextAppTransitionThumbnail(); From dea94648642f8b3554c9f53c4a63a3f2e899a3e8 Mon Sep 17 00:00:00 2001 From: Craig Mautner Date: Thu, 24 Apr 2014 10:19:20 -0700 Subject: [PATCH 082/119] Take screenshots of pausing activity Previous CL to optimize out excessive screenshots (ag/379669) was too effective and didn't take screenshots when going into an activity that had attribute Window_windowNoDisplay. Adding in the test for ActivityRecord.noDisplay allows screenshots for this situation. Fixes bug 13410507. Change-Id: Ieafebf44b7d1a3ba18115e762fba113f8d1c0252 --- services/core/java/com/android/server/am/ActivityStack.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 3adf7e09c895b..a2a9336157d89 100755 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -795,7 +795,7 @@ final class ActivityStack { prev.task.touchActiveTime(); clearLaunchTime(prev); final ActivityRecord next = mStackSupervisor.topRunningActivityLocked(); - if (next == null || next.task != prev.task) { + if (next == null || next.noDisplay || next.task != prev.task) { prev.updateThumbnail(screenshotActivities(prev), null); } stopFullyDrawnTraceIfNeeded(); From 037d1ed3b2b79744758c0fd908deb823ad6e4845 Mon Sep 17 00:00:00 2001 From: Christopher Tate Date: Wed, 23 Apr 2014 16:55:57 -0700 Subject: [PATCH 083/119] Fix native-lib dir assignment & updating The per-package /system/lib/* feature introduced bugs in the native library path handling during app upgrade installs. The crux of the fix is that when recalulating the desired native library directory, the basis for the calculation needs to be the scanned APK's location rather than the extant package settings entry -- because that entry refers to the pre-upgrade state of the application, not the new state. Bug 14233983 Change-Id: I76c3249c72ecc055115d430529d386599e52ae42 --- .../com/android/server/pm/PackageManagerService.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 702d9d2632486..3e6100977d13a 100755 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -104,7 +104,6 @@ import android.os.Environment.UserEnvironment; import android.os.FileObserver; import android.os.FileUtils; import android.os.Handler; -import android.os.HandlerThread; import android.os.IBinder; import android.os.Looper; import android.os.Message; @@ -4839,7 +4838,6 @@ public class PackageManagerService extends IPackageManager.Stub { pkg.applicationInfo.nativeLibraryDir = pkgSetting.nativeLibraryPathString; } } - pkgSetting.uidError = uidError; } @@ -5420,7 +5418,8 @@ public class PackageManagerService extends IPackageManager.Stub { } } - private String calculateApkRoot(final File codePath) { + private String calculateApkRoot(final String codePathString) { + final File codePath = new File(codePathString); final File codeRoot; if (FileUtils.contains(Environment.getRootDirectory(), codePath)) { codeRoot = Environment.getRootDirectory(); @@ -5457,12 +5456,12 @@ public class PackageManagerService extends IPackageManager.Stub { PackageSetting pkgSetting) { // "bundled" here means system-installed with no overriding update final boolean bundledApk = isSystemApp(pkg) && !isUpdatedSystemApp(pkg); - final String apkName = getApkName(pkgSetting.codePathString); + final String apkName = getApkName(pkg.applicationInfo.sourceDir); final File libDir; if (bundledApk) { // If "/system/lib64/apkname" exists, assume that is the per-package // native library directory to use; otherwise use "/system/lib/apkname". - String apkRoot = calculateApkRoot(pkgSetting.codePath); + String apkRoot = calculateApkRoot(pkg.applicationInfo.sourceDir); File lib64 = new File(apkRoot, LIB64_DIR_NAME); File packLib64 = new File(lib64, apkName); libDir = (packLib64.exists()) ? lib64 : new File(apkRoot, LIB_DIR_NAME); From 12316f961d5b4a2a61868c7a3d498f209cb3f019 Mon Sep 17 00:00:00 2001 From: Alan Viverette Date: Mon, 28 Apr 2014 11:22:40 -0700 Subject: [PATCH 084/119] Pull out dirty bounds before nulling ripples BUG: 14378485 Change-Id: I286374db9865d2338852fd0df896928099a8eb24 --- .../drawable/TouchFeedbackDrawable.java | 45 ++++++++++--------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java b/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java index 824e108585d12..0e8831ffbf731 100644 --- a/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java +++ b/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java @@ -501,10 +501,32 @@ public class TouchFeedbackDrawable extends LayerDrawable { } private int drawRippleLayer(Canvas canvas, Rect bounds, boolean maskOnly) { - final Ripple[] activeRipples = mActiveRipples; final int ripplesCount = mActiveRipplesCount; + if (ripplesCount == 0) { + return -1; + } + + final Ripple[] activeRipples = mActiveRipples; + final boolean projected = isProjected(); + final Rect layerBounds = projected ? getDirtyBounds() : bounds; + + // Separate the ripple color and alpha channel. The alpha will be + // applied when we merge the ripples down to the canvas. + final int rippleColor; + if (mState.mTint != null) { + rippleColor = mState.mTint.getColorForState(getState(), Color.TRANSPARENT); + } else { + rippleColor = Color.TRANSPARENT; + } + final int rippleAlpha = Color.alpha(rippleColor); + + if (mRipplePaint == null) { + mRipplePaint = new Paint(); + mRipplePaint.setAntiAlias(true); + } + final Paint ripplePaint = mRipplePaint; + ripplePaint.setColor(rippleColor); - Paint ripplePaint = null; boolean drewRipples = false; int restoreToCount = -1; int activeRipplesCount = 0; @@ -524,20 +546,9 @@ public class TouchFeedbackDrawable extends LayerDrawable { // If we're masking the ripple layer, make sure we have a layer // first. This will merge SRC_OVER (directly) onto the canvas. if (restoreToCount < 0) { - // Separate the ripple color and alpha channel. The alpha will be - // applied when we merge the ripples down to the canvas. - final int rippleColor; - if (mState.mTint != null) { - rippleColor = mState.mTint.getColorForState(getState(), Color.TRANSPARENT); - } else { - rippleColor = Color.TRANSPARENT; - } - final int rippleAlpha = Color.alpha(rippleColor); - // If we're projecting or we only have a mask, we want to treat the // underlying canvas as our content and merge the ripple layer down // using the tint xfermode. - final boolean projected = isProjected(); final PorterDuffXfermode xfermode; if (projected || maskOnly) { xfermode = mState.getTintXfermode(); @@ -547,18 +558,12 @@ public class TouchFeedbackDrawable extends LayerDrawable { final Paint layerPaint = getMaskingPaint(xfermode); layerPaint.setAlpha(rippleAlpha); - final Rect layerBounds = projected ? getDirtyBounds() : bounds; restoreToCount = canvas.saveLayer(layerBounds.left, layerBounds.top, layerBounds.right, layerBounds.bottom, layerPaint); layerPaint.setAlpha(255); } - if (mRipplePaint == null) { - mRipplePaint = new Paint(); - mRipplePaint.setAntiAlias(true); - } - - drewRipples |= ripple.draw(canvas, mRipplePaint); + drewRipples |= ripple.draw(canvas, ripplePaint); activeRipples[activeRipplesCount] = activeRipples[i]; activeRipplesCount++; From 576d3cd5f8fdde081ca65c0d79d0a586a5e8428c Mon Sep 17 00:00:00 2001 From: Selim Cinek Date: Mon, 28 Apr 2014 20:23:30 +0200 Subject: [PATCH 085/119] Fixed race condition regarding first child max height The scroller could crash due to a race condition when updating the maxheight of the first view. Bug: 14295010 Change-Id: I911c724a26c8624e2326118e3b392ee675001bc6 --- .../systemui/statusbar/stack/StackScrollAlgorithm.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java index d9e7f6697faa5..8757d57999ba2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java @@ -542,9 +542,13 @@ public class StackScrollAlgorithm { public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { - mFirstChildMaxHeight = getMaxAllowedChildHeight( - mFirstChildWhileExpanding); - mFirstChildWhileExpanding.removeOnLayoutChangeListener(this); + if (mFirstChildWhileExpanding != null) { + mFirstChildMaxHeight = getMaxAllowedChildHeight( + mFirstChildWhileExpanding); + } else { + mFirstChildMaxHeight = 0; + } + v.removeOnLayoutChangeListener(this); } }); } else { From 53a2d785a2a0a9549a037fd6c59b7086ecd631bb Mon Sep 17 00:00:00 2001 From: Jorim Jaggi Date: Mon, 28 Apr 2014 20:04:11 +0200 Subject: [PATCH 086/119] Attemp to fix blank lockscreen #2. Bug: 14280857 Change-Id: Ib868cc7a01d24f7169310774a5397b90a2d5b35f --- .../android/systemui/statusbar/phone/PhoneStatusBar.java | 9 +++++---- .../systemui/statusbar/phone/PhoneStatusBarView.java | 2 +- 2 files changed, 6 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 a274de6dcf981..9326946a547d8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -1622,9 +1622,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { return (mDisabled & StatusBarManager.DISABLE_EXPAND) == 0; } - void makeExpandedVisible() { + void makeExpandedVisible(boolean force) { if (SPEW) Log.d(TAG, "Make expanded visible: expanded visible=" + mExpandedVisible); - if (mExpandedVisible || !panelsEnabled()) { + if (!force && (mExpandedVisible || !panelsEnabled())) { return; } @@ -3003,8 +3003,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { private void instantExpandNotificationsPanel() { - // Make our window larger. - mStatusBarWindowManager.setStatusBarExpanded(true); + // Make our window larger and the panel visible. + makeExpandedVisible(true); + mNotificationPanel.setVisibility(View.VISIBLE); // Wait for window manager to pickup the change, so we know the maximum height of the panel // then. 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 bf7dd5c67c1f2..79c63f735bbc3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java @@ -106,7 +106,7 @@ public class PhoneStatusBarView extends PanelBar { @Override public void onPanelPeeked() { super.onPanelPeeked(); - mBar.makeExpandedVisible(); + mBar.makeExpandedVisible(false); } @Override From b01f0eee230f7b2a5ab96678a3ce7bca8c7eb6ca Mon Sep 17 00:00:00 2001 From: Alan Viverette Date: Mon, 28 Apr 2014 13:30:08 -0700 Subject: [PATCH 087/119] Fix alert dialog icon Previously, failing to call setIcon() would result in a blank icon rather than hiding the icon. Also, calling setIcon(icon) followed by setIcon(null) could be a no-op depending on whether the alert had already been constructed. Change-Id: I65a96a4e89b9eac1123cbbf5d57e7e366e7b4d4e --- .../android/internal/app/AlertController.java | 63 +++++++++++-------- 1 file changed, 36 insertions(+), 27 deletions(-) diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java index 76407490d7751..4726da73b3c9e 100644 --- a/core/java/com/android/internal/app/AlertController.java +++ b/core/java/com/android/internal/app/AlertController.java @@ -102,7 +102,7 @@ public class AlertController { private ScrollView mScrollView; - private int mIconId = -1; + private int mIconId = 0; private Drawable mIcon; @@ -337,25 +337,39 @@ public class AlertController { } /** - * Set resId to 0 if you don't want an icon. - * @param resId the resourceId of the drawable to use as the icon or 0 - * if you don't want an icon. + * Specifies the icon to display next to the alert title. + * + * @param resId the resource identifier of the drawable to use as the icon, + * or 0 for no icon */ public void setIcon(int resId) { + mIcon = null; mIconId = resId; + if (mIconView != null) { - if (resId > 0) { + if (resId != 0) { mIconView.setImageResource(mIconId); - } else if (resId == 0) { + } else { mIconView.setVisibility(View.GONE); } } } - + + /** + * Specifies the icon to display next to the alert title. + * + * @param icon the drawable to use as the icon or null for no icon + */ public void setIcon(Drawable icon) { mIcon = icon; - if ((mIconView != null) && (mIcon != null)) { - mIconView.setImageDrawable(icon); + mIconId = 0; + + if (mIconView != null) { + if (icon != null) { + mIconView.setImageDrawable(icon); + } else { + mIconView.setVisibility(View.GONE); + } } } @@ -485,28 +499,24 @@ public class AlertController { View titleTemplate = mWindow.findViewById(R.id.title_template); titleTemplate.setVisibility(View.GONE); } else { - final boolean hasTextTitle = !TextUtils.isEmpty(mTitle); - mIconView = (ImageView) mWindow.findViewById(R.id.icon); - if (hasTextTitle) { - /* Display the title if a title is supplied, else hide it */ - mTitleView = (TextView) mWindow.findViewById(R.id.alertTitle); + final boolean hasTextTitle = !TextUtils.isEmpty(mTitle); + if (hasTextTitle) { + // Display the title if a title is supplied, else hide it. + mTitleView = (TextView) mWindow.findViewById(R.id.alertTitle); mTitleView.setText(mTitle); - - /* Do this last so that if the user has supplied any - * icons we use them instead of the default ones. If the - * user has specified 0 then make it disappear. - */ - if (mIconId > 0) { + + // Do this last so that if the user has supplied any icons we + // use them instead of the default ones. If the user has + // specified 0 then make it disappear. + if (mIconId != 0) { mIconView.setImageResource(mIconId); } else if (mIcon != null) { mIconView.setImageDrawable(mIcon); - } else if (mIconId == 0) { - - /* Apply the padding from the icon to ensure the - * title is aligned correctly. - */ + } else { + // Apply the padding from the icon to ensure the title is + // aligned correctly. mTitleView.setPadding(mIconView.getPaddingLeft(), mIconView.getPaddingTop(), mIconView.getPaddingRight(), @@ -514,9 +524,8 @@ public class AlertController { mIconView.setVisibility(View.GONE); } } else { - // Hide the title template - View titleTemplate = mWindow.findViewById(R.id.title_template); + final View titleTemplate = mWindow.findViewById(R.id.title_template); titleTemplate.setVisibility(View.GONE); mIconView.setVisibility(View.GONE); topPanel.setVisibility(View.GONE); From 54cacc1f7c5b102d795882e1c4dba5e7d35e228e Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Mon, 28 Apr 2014 15:11:56 -0700 Subject: [PATCH 088/119] Fixing NPE. (Bug 14385152) Change-Id: Ie6d1e7c3e5dcf721e945c4933c077fa6abb10067 --- .../server/am/ActivityManagerService.java | 24 +++++++++++-------- .../com/android/server/am/ActivityStack.java | 5 +++- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index b6a41bf92f1f3..0c919079d3976 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -1859,24 +1859,28 @@ public final class ActivityManagerService extends ActivityManagerNative @Override public boolean onPackageChanged(String packageName, int uid, String[] components) { final PackageManager pm = mContext.getPackageManager(); - final ArrayList recentTasks = new ArrayList(); - final ArrayList tasksToRemove = new ArrayList(); + final ArrayList> recentTaskIntents = + new ArrayList>(); + final ArrayList tasksToRemove = new ArrayList(); // Copy the list of recent tasks so that we don't hold onto the lock on // ActivityManagerService for long periods while checking if components exist. synchronized (ActivityManagerService.this) { - recentTasks.addAll(mRecentTasks); + for (int i = mRecentTasks.size() - 1; i >= 0; i--) { + TaskRecord tr = mRecentTasks.get(i); + recentTaskIntents.add(new Pair(tr.intent, tr.taskId)); + } } // Check the recent tasks and filter out all tasks with components that no longer exist. Intent tmpI = new Intent(); - for (int i = recentTasks.size() - 1; i >= 0; i--) { - TaskRecord tr = recentTasks.get(i); - ComponentName cn = tr.intent.getComponent(); + for (int i = recentTaskIntents.size() - 1; i >= 0; i--) { + Pair p = recentTaskIntents.get(i); + ComponentName cn = p.first.getComponent(); if (cn != null && cn.getPackageName().equals(packageName)) { try { // Add the task to the list to remove if the component no longer exists tmpI.setComponent(cn); if (pm.queryIntentActivities(tmpI, PackageManager.MATCH_DEFAULT_ONLY).isEmpty()) { - tasksToRemove.add(tr); + tasksToRemove.add(p.second); } } catch (Exception e) {} } @@ -1884,9 +1888,9 @@ public final class ActivityManagerService extends ActivityManagerNative // Prune all the tasks with removed components from the list of recent tasks synchronized (ActivityManagerService.this) { for (int i = tasksToRemove.size() - 1; i >= 0; i--) { - TaskRecord tr = tasksToRemove.get(i); - // Remove the task but don't kill the process - removeTaskByIdLocked(tr.taskId, 0); + // Remove the task but don't kill the process (since other components in that + // package may still be running and in the background) + removeTaskByIdLocked(tasksToRemove.get(i), 0); } } return true; diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index bea926fbbd8a3..6769c9c33ea22 100755 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -2329,7 +2329,10 @@ final class ActivityStack { mStackSupervisor.moveHomeToTop(); } } - mService.setFocusedActivityLocked(mStackSupervisor.topRunningActivityLocked()); + ActivityRecord top = mStackSupervisor.topRunningActivityLocked(); + if (top != null) { + mService.setFocusedActivityLocked(top); + } } } From fa0493e0053bff7f37b9e40e454d71d1d339dc9a Mon Sep 17 00:00:00 2001 From: Narayan Kamath Date: Wed, 30 Apr 2014 13:33:38 +0100 Subject: [PATCH 089/119] Don't adjust ABI if PackageSetting#pkg is null. If means the package hasn't been scanned yet, and we will adjust the ABI during the scan of the last package in the shared user group. NOTE: This needs some more cleaning up, which will be done along with the remaining TODO in this function. Change-Id: Ie332806b64e22ab4a4856e1ccd064ff6a01616bf --- .../android/server/pm/PackageManagerService.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 038e2ddb08590..fffce8cb68e78 100755 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -5633,12 +5633,13 @@ public class PackageManagerService extends IPackageManager.Stub { for (PackageSetting ps : packagesForUser) { if (ps.requiredCpuAbiString == null) { ps.requiredCpuAbiString = requirer.requiredCpuAbiString; - ps.pkg.applicationInfo.requiredCpuAbi = requirer.requiredCpuAbiString; - - Slog.i(TAG, "Adjusting ABI for : " + ps.pkg.packageName + " to " + ps.requiredCpuAbiString); - if (doDexOpt) { - performDexOptLI(ps.pkg, forceDexOpt, deferDexOpt, true); - mInstaller.rmdex(ps.codePathString, getPreferredInstructionSet()); + if (ps.pkg != null) { + ps.pkg.applicationInfo.requiredCpuAbi = requirer.requiredCpuAbiString; + Slog.i(TAG, "Adjusting ABI for : " + ps.name + " to " + ps.requiredCpuAbiString); + if (doDexOpt) { + performDexOptLI(ps.pkg, forceDexOpt, deferDexOpt, true); + mInstaller.rmdex(ps.codePathString, getPreferredInstructionSet()); + } } } } From a9581cdbff0e27aa809c784458c0086a3960777d Mon Sep 17 00:00:00 2001 From: Narayan Kamath Date: Wed, 30 Apr 2014 16:45:07 +0100 Subject: [PATCH 090/119] Fix x86 build in app_process. Look for __i386__ and not __x86__. Change-Id: Iffa3709f9d0c96cce17f3183a6f036a78eccc787 --- cmds/app_process/app_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmds/app_process/app_main.cpp b/cmds/app_process/app_main.cpp index 391c1977b6fe3..74ccbc2b9220c 100644 --- a/cmds/app_process/app_main.cpp +++ b/cmds/app_process/app_main.cpp @@ -145,7 +145,7 @@ static void maybeCreateDalvikCache() { static const char kInstructionSet[] = "x86_64"; #elif defined(__arm__) static const char kInstructionSet[] = "arm"; -#elif defined(__x86__) +#elif defined(__i386__) static const char kInstructionSet[] = "x86"; #elif defined (__mips__) static const char kInstructionSet[] = "mips"; From adc6bc2b96afb57d488cc35d11cedf3a5e219c79 Mon Sep 17 00:00:00 2001 From: Selim Cinek Date: Thu, 1 May 2014 21:23:59 +0200 Subject: [PATCH 091/119] Fixed a bug where the notification scroller could crash. Due to a race condition the scroller could crash in certain cases after an animation. Bug: 14458203 Change-Id: Idc52109550270924bae5857e581574c63452f159 --- .../systemui/statusbar/stack/NotificationStackScrollLayout.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java index 9a43e37ab1631..ea34506336649 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java @@ -1077,7 +1077,7 @@ public class NotificationStackScrollLayout extends ViewGroup } public void onChildAnimationFinished() { - applyCurrentState(); + updateChildren(); mAnimationEvents.clear(); } From ab8e64d0a43cc9bfbfd8f2b7f428830efd3eb557 Mon Sep 17 00:00:00 2001 From: Amith Yamasani Date: Thu, 1 May 2014 14:39:35 -0700 Subject: [PATCH 092/119] Deliver package broadcasts only to related profiles. Store the listener's userhandle in a cookie and compare profile relationships before delivering package broadcasts to a listener. Basically, don't leave TODOs around, they'll result in bugs :) Bug: 14436558 Change-Id: I57a21719caab6cf54b78de7be2eca3e398dc6288 --- .../server/pm/LauncherAppsService.java | 68 ++++++++++++++++--- 1 file changed, 59 insertions(+), 9 deletions(-) diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java index ab63c9ca65650..48e97378273a1 100644 --- a/services/core/java/com/android/server/pm/LauncherAppsService.java +++ b/services/core/java/com/android/server/pm/LauncherAppsService.java @@ -38,6 +38,7 @@ import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; +import android.util.Log; import android.util.Slog; import com.android.internal.content.PackageMonitor; @@ -50,7 +51,7 @@ import java.util.List; * managed profiles. */ public class LauncherAppsService extends ILauncherApps.Stub { - + private static final boolean DEBUG = false; private static final String TAG = "LauncherAppsService"; private final Context mContext; private final PackageManager mPm; @@ -73,11 +74,17 @@ public class LauncherAppsService extends ILauncherApps.Stub { @Override public void addOnAppsChangedListener(IOnAppsChangedListener listener) throws RemoteException { synchronized (mListeners) { + if (DEBUG) { + Log.d(TAG, "Adding listener from " + Binder.getCallingUserHandle()); + } if (mListeners.getRegisteredCallbackCount() == 0) { + if (DEBUG) { + Log.d(TAG, "Starting package monitoring"); + } startWatchingPackageBroadcasts(); } mListeners.unregister(listener); - mListeners.register(listener); + mListeners.register(listener, Binder.getCallingUserHandle()); } } @@ -89,6 +96,9 @@ public class LauncherAppsService extends ILauncherApps.Stub { public void removeOnAppsChangedListener(IOnAppsChangedListener listener) throws RemoteException { synchronized (mListeners) { + if (DEBUG) { + Log.d(TAG, "Removing listener from " + Binder.getCallingUserHandle()); + } mListeners.unregister(listener); if (mListeners.getRegisteredCallbackCount() == 0) { stopWatchingPackageBroadcasts(); @@ -107,11 +117,17 @@ public class LauncherAppsService extends ILauncherApps.Stub { * Unregister package broadcast receiver */ private void stopWatchingPackageBroadcasts() { + if (DEBUG) { + Log.d(TAG, "Stopped watching for packages"); + } mPackageMonitor.unregister(); } void checkCallbackCount() { - synchronized (LauncherAppsService.this) { + synchronized (mListeners) { + if (DEBUG) { + Log.d(TAG, "Callback count = " + mListeners.getRegisteredCallbackCount()); + } if (mListeners.getRegisteredCallbackCount() == 0) { stopWatchingPackageBroadcasts(); } @@ -223,13 +239,44 @@ public class LauncherAppsService extends ILauncherApps.Stub { private class MyPackageMonitor extends PackageMonitor { + /** Checks if user is a profile of or same as listeningUser. */ + private boolean isProfileOf(UserHandle user, UserHandle listeningUser, String debugMsg) { + if (user.getIdentifier() == listeningUser.getIdentifier()) { + if (DEBUG) Log.d(TAG, "Delivering msg to same user " + debugMsg); + return true; + } + long ident = Binder.clearCallingIdentity(); + try { + UserInfo userInfo = mUm.getUserInfo(user.getIdentifier()); + UserInfo listeningUserInfo = mUm.getUserInfo(listeningUser.getIdentifier()); + if (userInfo == null || listeningUserInfo == null + || userInfo.profileGroupId == UserInfo.NO_PROFILE_GROUP_ID + || userInfo.profileGroupId != listeningUserInfo.profileGroupId) { + if (DEBUG) { + Log.d(TAG, "Not delivering msg from " + user + " to " + listeningUser + ":" + + debugMsg); + } + return false; + } else { + if (DEBUG) { + Log.d(TAG, "Delivering msg from " + user + " to " + listeningUser + ":" + + debugMsg); + } + return true; + } + } finally { + Binder.restoreCallingIdentity(ident); + } + } + @Override public void onPackageAdded(String packageName, int uid) { UserHandle user = new UserHandle(getChangingUserId()); - // TODO: if (!isProfile(user)) return; final int n = mListeners.beginBroadcast(); for (int i = 0; i < n; i++) { IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); + UserHandle listeningUser = (UserHandle) mListeners.getBroadcastCookie(i); + if (!isProfileOf(user, listeningUser, "onPackageAdded")) continue; try { listener.onPackageAdded(user, packageName); } catch (RemoteException re) { @@ -244,10 +291,11 @@ public class LauncherAppsService extends ILauncherApps.Stub { @Override public void onPackageRemoved(String packageName, int uid) { UserHandle user = new UserHandle(getChangingUserId()); - // TODO: if (!isCurrentProfile(user)) return; final int n = mListeners.beginBroadcast(); for (int i = 0; i < n; i++) { IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); + UserHandle listeningUser = (UserHandle) mListeners.getBroadcastCookie(i); + if (!isProfileOf(user, listeningUser, "onPackageRemoved")) continue; try { listener.onPackageRemoved(user, packageName); } catch (RemoteException re) { @@ -262,10 +310,11 @@ public class LauncherAppsService extends ILauncherApps.Stub { @Override public void onPackageModified(String packageName) { UserHandle user = new UserHandle(getChangingUserId()); - // TODO: if (!isProfile(user)) return; final int n = mListeners.beginBroadcast(); for (int i = 0; i < n; i++) { IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); + UserHandle listeningUser = (UserHandle) mListeners.getBroadcastCookie(i); + if (!isProfileOf(user, listeningUser, "onPackageModified")) continue; try { listener.onPackageChanged(user, packageName); } catch (RemoteException re) { @@ -280,10 +329,11 @@ public class LauncherAppsService extends ILauncherApps.Stub { @Override public void onPackagesAvailable(String[] packages) { UserHandle user = new UserHandle(getChangingUserId()); - // TODO: if (!isProfile(user)) return; final int n = mListeners.beginBroadcast(); for (int i = 0; i < n; i++) { IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); + UserHandle listeningUser = (UserHandle) mListeners.getBroadcastCookie(i); + if (!isProfileOf(user, listeningUser, "onPackagesAvailable")) continue; try { listener.onPackagesAvailable(user, packages, isReplacing()); } catch (RemoteException re) { @@ -298,10 +348,11 @@ public class LauncherAppsService extends ILauncherApps.Stub { @Override public void onPackagesUnavailable(String[] packages) { UserHandle user = new UserHandle(getChangingUserId()); - // TODO: if (!isProfile(user)) return; final int n = mListeners.beginBroadcast(); for (int i = 0; i < n; i++) { IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); + UserHandle listeningUser = (UserHandle) mListeners.getBroadcastCookie(i); + if (!isProfileOf(user, listeningUser, "onPackagesUnavailable")) continue; try { listener.onPackagesUnavailable(user, packages, isReplacing()); } catch (RemoteException re) { @@ -316,7 +367,6 @@ public class LauncherAppsService extends ILauncherApps.Stub { } class PackageCallbackList extends RemoteCallbackList { - @Override public void onCallbackDied(T callback, Object cookie) { checkCallbackCount(); From ab9223b0753fe9a17fd4c8b8a17e5ebdfa5e499a Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Fri, 2 May 2014 13:21:16 -0700 Subject: [PATCH 093/119] Fix issue #14492403: Oom scores appear to be incorrect... ...and causing runtime restarts Got a little too aggressive with the delete key. *blush* Change-Id: Icd4637827424211abc2347f7f9407c2d4c95cfad --- .../java/com/android/server/am/ActivityManagerService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 9eaddbd2f0e5b..5dc99dca1db98 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -15305,8 +15305,8 @@ public final class ActivityManagerService extends ActivityManagerNative // it when computing the final cached adj later. Note that we don't need to // worry about this for max adj above, since max adj will always be used to // keep it out of the cached vaues. - adj = app.modifyRawOomAdj(adj); - + app.curAdj = app.modifyRawOomAdj(adj); + app.curSchedGroup = schedGroup; app.curProcState = procState; app.foregroundActivities = foregroundActivities; From a8a67df0d3750ae8bae48049be46bd2bdc9861f1 Mon Sep 17 00:00:00 2001 From: Jose Lima Date: Wed, 30 Apr 2014 12:59:27 -0700 Subject: [PATCH 094/119] Allow activities to be visible behind the Home Stack - Only hide/stop activities behind the Home stack if the Home stack contains a full-screen/opaque activity. Change-Id: I69f951b91753f48d0344a9d534569cfb8de1d57f --- .../com/android/server/am/ActivityStack.java | 34 +++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 6769c9c33ea22..0e6dbb1642668 100755 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -1098,6 +1098,36 @@ final class ActivityStack { ensureActivitiesVisibleLocked(r, starting, null, configChanges, forceHomeShown); } + // Checks if any of the stacks above this one has a fullscreen activity behind it. + // If so, this stack is hidden, otherwise it is visible. + private boolean isStackVisible() { + if (!isAttached()) { + return false; + } + + if (mStackSupervisor.isFrontStack(this)) { + return true; + } + + // Start at the task above this one and go up, looking for a visible + // fullscreen activity, or a translucent activity that requested the + // wallpaper to be shown behind it. + for (int i = mStacks.indexOf(this) + 1; i < mStacks.size(); i++) { + final ArrayList tasks = mStacks.get(i).getAllTasks(); + for (int taskNdx = 0; taskNdx < tasks.size(); taskNdx++) { + final ArrayList activities = tasks.get(taskNdx).mActivities; + for (int activityNdx = 0; activityNdx < activities.size(); activityNdx++) { + final ActivityRecord r = activities.get(activityNdx); + if (!r.finishing && r.visible && r.fullscreen) { + return false; + } + } + } + } + + return true; + } + /** * Make sure that all activities that need to be visible (that is, they * currently can be seen by the user) actually are. @@ -1122,8 +1152,8 @@ final class ActivityStack { // make sure any activities under it are now visible. boolean aboveTop = true; boolean showHomeBehindStack = false; - boolean behindFullscreen = !mStackSupervisor.isFrontStack(this) && - !(forceHomeShown && isHomeStack()); + boolean behindFullscreen = !isStackVisible(); + for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) { final TaskRecord task = mTaskHistory.get(taskNdx); final ArrayList activities = task.mActivities; From c497d08e3be3222d91ea598278315db293a8001b Mon Sep 17 00:00:00 2001 From: Jorim Jaggi Date: Tue, 6 May 2014 14:53:04 +0200 Subject: [PATCH 095/119] Fix overly huge PanelView. Bug: 14489968 Change-Id: Ibdc820348eb7d045ffb5ad07093ac86e5ff7abb0 --- .../com/android/systemui/statusbar/phone/PanelView.java | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java index 328a1728c3edb..0cdca660c5e75 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java @@ -623,9 +623,7 @@ public class PanelView extends FrameLayout { mExpandedHeight = mMaxPanelHeight; } } - heightMeasureSpec = MeasureSpec.makeMeasureSpec( - getDesiredMeasureHeight(), MeasureSpec.AT_MOST); - setMeasuredDimension(widthMeasureSpec, heightMeasureSpec); + setMeasuredDimension(getMeasuredWidth(), getDesiredMeasureHeight()); } protected int getDesiredMeasureHeight() { @@ -705,11 +703,6 @@ public class PanelView extends FrameLayout { * @return the default implementation simply returns the maximum height. */ protected int getMaxPanelHeight() { - if (mMaxPanelHeight <= 0) { - if (DEBUG) logf("Forcing measure() since mMaxPanelHeight=" + mMaxPanelHeight); - measure(MeasureSpec.makeMeasureSpec(android.view.ViewGroup.LayoutParams.WRAP_CONTENT, MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(android.view.ViewGroup.LayoutParams.WRAP_CONTENT, MeasureSpec.EXACTLY)); - } return mMaxPanelHeight; } From 34b3ed4601fa2afbe221fa219b2ed12e059f0ac6 Mon Sep 17 00:00:00 2001 From: Alan Viverette Date: Wed, 7 May 2014 11:33:02 -0700 Subject: [PATCH 096/119] Non-animated checkbox BUG: 14603986 Change-Id: I9ed24fabf50db6100c60257fbc53a4488ba8e000 --- core/res/res/values/themes_quantum.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/res/res/values/themes_quantum.xml b/core/res/res/values/themes_quantum.xml index 39c8beb041636..768fd9a66b60c 100644 --- a/core/res/res/values/themes_quantum.xml +++ b/core/res/res/values/themes_quantum.xml @@ -123,7 +123,7 @@ please see themes_device_defaults.xml. @style/Widget.Quantum.TextView.ListSeparator @drawable/btn_radio_quantum - @drawable/btn_check_quantum_anim + @drawable/btn_check_quantum @drawable/list_selector_quantum @@ -467,7 +467,7 @@ please see themes_device_defaults.xml. @style/Widget.Quantum.Light.TextView.ListSeparator @drawable/btn_radio_quantum - @drawable/btn_check_quantum_anim + @drawable/btn_check_quantum @drawable/list_selector_quantum From 1e24710cbe86ca38f2664a3cc5273157f26422b1 Mon Sep 17 00:00:00 2001 From: Selim Cinek Date: Thu, 8 May 2014 15:12:05 +0200 Subject: [PATCH 097/119] Improved animation logic of the new notifications Scrolling and other local updates work much better now when an animation is already in place. Change-Id: I602899bc75ae132ebb30591e723be3f00f744e18 --- packages/SystemUI/res/values/ids.xml | 6 + .../statusbar/stack/StackStateAnimator.java | 215 ++++++++++++------ 2 files changed, 146 insertions(+), 75 deletions(-) diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml index 43697415b0671..6418930d2c73e 100644 --- a/packages/SystemUI/res/values/ids.xml +++ b/packages/SystemUI/res/values/ids.xml @@ -28,5 +28,11 @@ + + + + + + diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java index c9526986515f3..ca383aa411d5a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java @@ -54,6 +54,12 @@ public class StackStateAnimator { private static final int TAG_END_ALPHA = R.id.alpha_animator_end_value_tag; private static final int TAG_END_HEIGHT = R.id.height_animator_end_value_tag; private static final int TAG_END_TOP_INSET = R.id.top_inset_animator_end_value_tag; + private static final int TAG_START_TRANSLATION_Y = R.id.translation_y_animator_start_value_tag; + private static final int TAG_START_TRANSLATION_Z = R.id.translation_z_animator_start_value_tag; + private static final int TAG_START_SCALE = R.id.scale_animator_start_value_tag; + private static final int TAG_START_ALPHA = R.id.alpha_animator_start_value_tag; + private static final int TAG_START_HEIGHT = R.id.height_animator_start_value_tag; + private static final int TAG_START_TOP_INSET = R.id.top_inset_animator_start_value_tag; private final Interpolator mFastOutSlowInInterpolator; public NotificationStackScrollLayout mHostLayout; @@ -139,23 +145,34 @@ public class StackStateAnimator { private void startHeightAnimation(final ExpandableView child, StackScrollState.ViewState viewState) { + Integer previousStartValue = getChildTag(child, TAG_START_HEIGHT); Integer previousEndValue = getChildTag(child, TAG_END_HEIGHT); - if (previousEndValue != null && previousEndValue == viewState.height) { + int newEndValue = viewState.height; + if (previousEndValue != null && previousEndValue == newEndValue) { return; } ValueAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_HEIGHT); - long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator, - mAnimationFilter.animateHeight); - if (newDuration <= 0) { - // no new animation needed, let's just apply the value - child.setActualHeight(viewState.height, false /* notifyListeners */); - if (previousAnimator != null && !isRunning()) { - onAnimationFinished(); + if (!mAnimationFilter.animateHeight) { + // just a local update was performed + if (previousAnimator != null) { + // we need to increase all animation keyframes of the previous animator by the + // relative change to the end value + PropertyValuesHolder[] values = previousAnimator.getValues(); + int relativeDiff = newEndValue - previousEndValue; + int newStartValue = previousStartValue + relativeDiff; + values[0].setIntValues(newStartValue, newEndValue); + child.setTag(TAG_START_HEIGHT, newStartValue); + child.setTag(TAG_END_HEIGHT, newEndValue); + previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime()); + return; + } else { + // no new animation needed, let's just apply the value + child.setActualHeight(newEndValue, false); + return; } - return; } - ValueAnimator animator = ValueAnimator.ofInt(child.getActualHeight(), viewState.height); + ValueAnimator animator = ValueAnimator.ofInt(child.getActualHeight(), newEndValue); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { @@ -164,6 +181,7 @@ public class StackStateAnimator { } }); animator.setInterpolator(mFastOutSlowInInterpolator); + long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator); animator.setDuration(newDuration); animator.addListener(getGlobalAnimationFinishedListener()); // remove the tag when the animation is finished @@ -171,38 +189,49 @@ public class StackStateAnimator { @Override public void onAnimationEnd(Animator animation) { child.setTag(TAG_ANIMATOR_HEIGHT, null); + child.setTag(TAG_START_HEIGHT, null); child.setTag(TAG_END_HEIGHT, null); } }); startInstantly(animator); child.setTag(TAG_ANIMATOR_HEIGHT, animator); - child.setTag(TAG_END_HEIGHT, viewState.height); + child.setTag(TAG_START_HEIGHT, child.getActualHeight()); + child.setTag(TAG_END_HEIGHT, newEndValue); } private void startAlphaAnimation(final ExpandableView child, final StackScrollState.ViewState viewState) { - final float endAlpha = viewState.alpha; + Float previousStartValue = getChildTag(child,TAG_START_ALPHA); Float previousEndValue = getChildTag(child,TAG_END_ALPHA); - if (previousEndValue != null && previousEndValue == endAlpha) { + final float newEndValue = viewState.alpha; + if (previousEndValue != null && previousEndValue == newEndValue) { return; } ObjectAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_ALPHA); - long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator, - mAnimationFilter.animateAlpha); - if (newDuration <= 0) { - // no new animation needed, let's just apply the value - child.setAlpha(endAlpha); - if (endAlpha == 0) { - child.setVisibility(View.INVISIBLE); + if (!mAnimationFilter.animateAlpha) { + // just a local update was performed + if (previousAnimator != null) { + // we need to increase all animation keyframes of the previous animator by the + // relative change to the end value + PropertyValuesHolder[] values = previousAnimator.getValues(); + float relativeDiff = newEndValue - previousEndValue; + float newStartValue = previousStartValue + relativeDiff; + values[0].setFloatValues(newStartValue, newEndValue); + child.setTag(TAG_START_ALPHA, newStartValue); + child.setTag(TAG_END_ALPHA, newEndValue); + previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime()); + return; + } else { + // no new animation needed, let's just apply the value + child.setAlpha(newEndValue); + if (newEndValue == 0) { + child.setVisibility(View.INVISIBLE); + } } - if (previousAnimator != null && !isRunning()) { - onAnimationFinished(); - } - return; } ObjectAnimator animator = ObjectAnimator.ofFloat(child, View.ALPHA, - child.getAlpha(), endAlpha); + child.getAlpha(), newEndValue); animator.setInterpolator(mFastOutSlowInInterpolator); // Handle layer type final int currentLayerType = child.getLayerType(); @@ -213,10 +242,11 @@ public class StackStateAnimator { @Override public void onAnimationEnd(Animator animation) { child.setLayerType(currentLayerType, null); - if (endAlpha == 0 && !mWasCancelled) { + if (newEndValue == 0 && !mWasCancelled) { child.setVisibility(View.INVISIBLE); } child.setTag(TAG_ANIMATOR_ALPHA, null); + child.setTag(TAG_START_ALPHA, null); child.setTag(TAG_END_ALPHA, null); } @@ -230,6 +260,7 @@ public class StackStateAnimator { mWasCancelled = false; } }); + long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator); animator.setDuration(newDuration); animator.addListener(getGlobalAnimationFinishedListener()); // remove the tag when the animation is finished @@ -241,31 +272,42 @@ public class StackStateAnimator { }); startInstantly(animator); child.setTag(TAG_ANIMATOR_ALPHA, animator); - child.setTag(TAG_END_ALPHA, endAlpha); + child.setTag(TAG_START_ALPHA, child.getAlpha()); + child.setTag(TAG_END_ALPHA, newEndValue); } private void startZTranslationAnimation(final ExpandableView child, final StackScrollState.ViewState viewState) { + Float previousStartValue = getChildTag(child,TAG_START_TRANSLATION_Z); Float previousEndValue = getChildTag(child,TAG_END_TRANSLATION_Z); - if (previousEndValue != null && previousEndValue == viewState.zTranslation) { + float newEndValue = viewState.zTranslation; + if (previousEndValue != null && previousEndValue == newEndValue) { return; } ObjectAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_TRANSLATION_Z); - long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator, - mAnimationFilter.animateZ); - if (newDuration <= 0) { - // no new animation needed, let's just apply the value - child.setTranslationZ(viewState.zTranslation); - - if (previousAnimator != null && !isRunning()) { - onAnimationFinished(); + if (!mAnimationFilter.animateZ) { + // just a local update was performed + if (previousAnimator != null) { + // we need to increase all animation keyframes of the previous animator by the + // relative change to the end value + PropertyValuesHolder[] values = previousAnimator.getValues(); + float relativeDiff = newEndValue - previousEndValue; + float newStartValue = previousStartValue + relativeDiff; + values[0].setFloatValues(newStartValue, newEndValue); + child.setTag(TAG_START_TRANSLATION_Z, newStartValue); + child.setTag(TAG_END_TRANSLATION_Z, newEndValue); + previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime()); + return; + } else { + // no new animation needed, let's just apply the value + child.setTranslationZ(newEndValue); } - return; } ObjectAnimator animator = ObjectAnimator.ofFloat(child, View.TRANSLATION_Z, - child.getTranslationZ(), viewState.zTranslation); + child.getTranslationZ(), newEndValue); animator.setInterpolator(mFastOutSlowInInterpolator); + long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator); animator.setDuration(newDuration); animator.addListener(getGlobalAnimationFinishedListener()); // remove the tag when the animation is finished @@ -273,35 +315,49 @@ public class StackStateAnimator { @Override public void onAnimationEnd(Animator animation) { child.setTag(TAG_ANIMATOR_TRANSLATION_Z, null); + child.setTag(TAG_START_TRANSLATION_Z, null); child.setTag(TAG_END_TRANSLATION_Z, null); } }); startInstantly(animator); child.setTag(TAG_ANIMATOR_TRANSLATION_Z, animator); - child.setTag(TAG_END_TRANSLATION_Z, viewState.zTranslation); + child.setTag(TAG_START_TRANSLATION_Z, child.getTranslationZ()); + child.setTag(TAG_END_TRANSLATION_Z, newEndValue); } private void startYTranslationAnimation(final ExpandableView child, StackScrollState.ViewState viewState) { + Float previousStartValue = getChildTag(child,TAG_START_TRANSLATION_Y); Float previousEndValue = getChildTag(child,TAG_END_TRANSLATION_Y); - if (previousEndValue != null && previousEndValue == viewState.yTranslation) { + float newEndValue = viewState.yTranslation; + if (previousEndValue != null && previousEndValue == newEndValue) { return; } ObjectAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_TRANSLATION_Y); - long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator, - mAnimationFilter.animateY); - if (newDuration <= 0) { - // no new animation needed, let's just apply the value - child.setTranslationY(viewState.yTranslation); - if (previousAnimator != null && !isRunning()) { - onAnimationFinished(); + if (!mAnimationFilter.animateY) { + // just a local update was performed + if (previousAnimator != null) { + // we need to increase all animation keyframes of the previous animator by the + // relative change to the end value + PropertyValuesHolder[] values = previousAnimator.getValues(); + float relativeDiff = newEndValue - previousEndValue; + float newStartValue = previousStartValue + relativeDiff; + values[0].setFloatValues(newStartValue, newEndValue); + child.setTag(TAG_START_TRANSLATION_Y, newStartValue); + child.setTag(TAG_END_TRANSLATION_Y, newEndValue); + previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime()); + return; + } else { + // no new animation needed, let's just apply the value + child.setTranslationY(newEndValue); + return; } - return; } ObjectAnimator animator = ObjectAnimator.ofFloat(child, View.TRANSLATION_Y, - child.getTranslationY(), viewState.yTranslation); + child.getTranslationY(), newEndValue); animator.setInterpolator(mFastOutSlowInInterpolator); + long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator); animator.setDuration(newDuration); animator.addListener(getGlobalAnimationFinishedListener()); // remove the tag when the animation is finished @@ -309,39 +365,53 @@ public class StackStateAnimator { @Override public void onAnimationEnd(Animator animation) { child.setTag(TAG_ANIMATOR_TRANSLATION_Y, null); + child.setTag(TAG_START_TRANSLATION_Y, null); child.setTag(TAG_END_TRANSLATION_Y, null); } }); startInstantly(animator); child.setTag(TAG_ANIMATOR_TRANSLATION_Y, animator); - child.setTag(TAG_END_TRANSLATION_Y, viewState.yTranslation); + child.setTag(TAG_START_TRANSLATION_Y, child.getTranslationY()); + child.setTag(TAG_END_TRANSLATION_Y, newEndValue); } private void startScaleAnimation(final ExpandableView child, StackScrollState.ViewState viewState) { + Float previousStartValue = getChildTag(child, TAG_START_SCALE); Float previousEndValue = getChildTag(child, TAG_END_SCALE); - if (previousEndValue != null && previousEndValue == viewState.scale) { + float newEndValue = viewState.scale; + if (previousEndValue != null && previousEndValue == newEndValue) { return; } ObjectAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_SCALE); - long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator, - mAnimationFilter.animateScale); - if (newDuration <= 0) { - // no new animation needed, let's just apply the value - child.setScaleX(viewState.scale); - child.setScaleY(viewState.scale); - if (previousAnimator != null && !isRunning()) { - onAnimationFinished(); + if (!mAnimationFilter.animateScale) { + // just a local update was performed + if (previousAnimator != null) { + // we need to increase all animation keyframes of the previous animator by the + // relative change to the end value + PropertyValuesHolder[] values = previousAnimator.getValues(); + float relativeDiff = newEndValue - previousEndValue; + float newStartValue = previousStartValue + relativeDiff; + values[0].setFloatValues(newStartValue, newEndValue); + values[1].setFloatValues(newStartValue, newEndValue); + child.setTag(TAG_START_SCALE, newStartValue); + child.setTag(TAG_END_SCALE, newEndValue); + previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime()); + return; + } else { + // no new animation needed, let's just apply the value + child.setScaleX(newEndValue); + child.setScaleY(newEndValue); } - return; } PropertyValuesHolder holderX = - PropertyValuesHolder.ofFloat(View.SCALE_X, child.getScaleX(), viewState.scale); + PropertyValuesHolder.ofFloat(View.SCALE_X, child.getScaleX(), newEndValue); PropertyValuesHolder holderY = - PropertyValuesHolder.ofFloat(View.SCALE_Y, child.getScaleY(), viewState.scale); + PropertyValuesHolder.ofFloat(View.SCALE_Y, child.getScaleY(), newEndValue); ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(child, holderX, holderY); animator.setInterpolator(mFastOutSlowInInterpolator); + long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator); animator.setDuration(newDuration); animator.addListener(getGlobalAnimationFinishedListener()); // remove the tag when the animation is finished @@ -349,12 +419,14 @@ public class StackStateAnimator { @Override public void onAnimationEnd(Animator animation) { child.setTag(TAG_ANIMATOR_SCALE, null); + child.setTag(TAG_START_SCALE, null); child.setTag(TAG_END_SCALE, null); } }); startInstantly(animator); child.setTag(TAG_ANIMATOR_SCALE, animator); - child.setTag(TAG_END_SCALE, viewState.scale); + child.setTag(TAG_START_SCALE, child.getScaleX()); + child.setTag(TAG_END_SCALE, newEndValue); } /** @@ -408,23 +480,16 @@ public class StackStateAnimator { * Cancel the previous animator and get the duration of the new animation. * * @param previousAnimator the animator which was running before - * @param newAnimationNeeded indicating whether a new animation should be started for this - * property * @return the new duration */ - private long cancelAnimatorAndGetNewDuration(ValueAnimator previousAnimator, - boolean newAnimationNeeded) { + private long cancelAnimatorAndGetNewDuration(ValueAnimator previousAnimator) { long newDuration = mCurrentLength; if (previousAnimator != null) { - if (!newAnimationNeeded) { - // This is only an update, no new event came in. lets just take the remaining - // duration as the new duration - newDuration = previousAnimator.getDuration() - - previousAnimator.getCurrentPlayTime(); - } + // We take either the desired length of the new animation or the remaining time of + // the previous animator, whichever is longer. + newDuration = Math.max(previousAnimator.getDuration() + - previousAnimator.getCurrentPlayTime(), newDuration); previousAnimator.cancel(); - } else if (!newAnimationNeeded){ - newDuration = 0; } return newDuration; } From 42eab1b72137ec0a19b0ab9db95185b6a0a806e9 Mon Sep 17 00:00:00 2001 From: Craig Mautner Date: Thu, 8 May 2014 09:07:43 -0700 Subject: [PATCH 098/119] Make ChooserActivity intents doccentric and transitory Activities launched from the chooser activity will now appear in their own tasks which will be automatically removed from recents when they are finished. Also qualified application of new flags with null check and Action check. Must be either ACTION_SEND or ACTION_SEND_MULTIPLE. Fixes bug 14463859. Fixes bug 14633773. Change-Id: I8832462163958f6a43bc4c6a020f78948ce70ac3 --- .../android/widget/ShareActionProvider.java | 15 +++++++++++--- .../android/internal/app/ChooserActivity.java | 20 ++++++++++++++++--- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/core/java/android/widget/ShareActionProvider.java b/core/java/android/widget/ShareActionProvider.java index e4ad354497e5a..99a7886ed5f12 100644 --- a/core/java/android/widget/ShareActionProvider.java +++ b/core/java/android/widget/ShareActionProvider.java @@ -276,8 +276,13 @@ public class ShareActionProvider extends ActionProvider { * @see Intent#ACTION_SEND_MULTIPLE */ public void setShareIntent(Intent shareIntent) { - shareIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT | + if (shareIntent != null) { + final String action = shareIntent.getAction(); + if (Intent.ACTION_SEND.equals(action) || Intent.ACTION_SEND_MULTIPLE.equals(action)) { + shareIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT | Intent.FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS); + } + } ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, mShareHistoryFileName); dataModel.setIntent(shareIntent); @@ -294,8 +299,12 @@ public class ShareActionProvider extends ActionProvider { final int itemId = item.getItemId(); Intent launchIntent = dataModel.chooseActivity(itemId); if (launchIntent != null) { - launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT | - Intent.FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS); + final String action = launchIntent.getAction(); + if (Intent.ACTION_SEND.equals(action) || + Intent.ACTION_SEND_MULTIPLE.equals(action)) { + launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT | + Intent.FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS); + } mContext.startActivity(launchIntent); } return true; diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index 1eda373477bb5..106ac0b2ef0a5 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -33,6 +33,14 @@ public class ChooserActivity extends ResolverActivity { return; } Intent target = (Intent)targetParcelable; + if (target != null) { + final String action = target.getAction(); + if (Intent.ACTION_SEND.equals(action) || + Intent.ACTION_SEND_MULTIPLE.equals(action)) { + target.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT | + Intent.FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS); + } + } CharSequence title = intent.getCharSequenceExtra(Intent.EXTRA_TITLE); if (title == null) { title = getResources().getText(com.android.internal.R.string.chooseActivity); @@ -43,13 +51,19 @@ public class ChooserActivity extends ResolverActivity { initialIntents = new Intent[pa.length]; for (int i=0; i Date: Thu, 8 May 2014 14:52:10 -0400 Subject: [PATCH 099/119] Don't show notifications above FLAG_SHOW_WHEN_LOCKED windows. We need to hide the bouncer when the lockscreen is occluded by a show-when-locked window, but we also need to double-check any time the screen comes on in case the bouncer has been shown for some other reason since the occlusion originally happened. Bug: 14294001 Change-Id: Ief4ea8e39322d9c4b26ec217dbc14b6c6f16ad45 --- .../phone/StatusBarKeyguardViewManager.java | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index e24ddd9f5af7a..f24c1b625ea4b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -95,7 +95,9 @@ public class StatusBarKeyguardViewManager { } private void showBouncer() { - mBouncer.show(); + if (!mOccluded) { + mBouncer.show(); + } updateStates(); } @@ -103,7 +105,12 @@ public class StatusBarKeyguardViewManager { * Reset the state of the view. */ public void reset() { - showBouncerOrKeyguard(); + if (mOccluded) { + mPhoneStatusBar.hideKeyguard(); + mBouncer.hide(); + } else { + showBouncerOrKeyguard(); + } updateStates(); } @@ -114,6 +121,7 @@ public class StatusBarKeyguardViewManager { public void onScreenTurnedOn(final IKeyguardShowCallback callback) { mScreenOn = true; + reset(); if (callback != null) { callbackAfterDraw(callback); } @@ -147,7 +155,7 @@ public class StatusBarKeyguardViewManager { public void setOccluded(boolean occluded) { mOccluded = occluded; mStatusBarWindowManager.setKeyguardOccluded(occluded); - updateStates(); + reset(); } /** From 48ee942f279ca6c1782fb7b672d919b42bb0daf2 Mon Sep 17 00:00:00 2001 From: Michael Wright Date: Thu, 8 May 2014 15:57:23 -0700 Subject: [PATCH 100/119] Temporarily remove the dpad keys from system keys. Bug: 14438911 Change-Id: Ibb58a4af89585b6e266f5236df22f0465dd17bd4 --- core/java/android/view/KeyEvent.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java index 05e202bf8a7ca..2d1016a682337 100644 --- a/core/java/android/view/KeyEvent.java +++ b/core/java/android/view/KeyEvent.java @@ -1685,10 +1685,6 @@ public class KeyEvent extends InputEvent implements Parcelable { case KeyEvent.KEYCODE_BRIGHTNESS_DOWN: case KeyEvent.KEYCODE_BRIGHTNESS_UP: case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: - case KeyEvent.KEYCODE_DPAD_UP: - case KeyEvent.KEYCODE_DPAD_RIGHT: - case KeyEvent.KEYCODE_DPAD_DOWN: - case KeyEvent.KEYCODE_DPAD_LEFT: return true; } From ba9037966eecd69cd693e49812ae5120826712d4 Mon Sep 17 00:00:00 2001 From: Jorim Jaggi Date: Fri, 9 May 2014 16:05:53 +0200 Subject: [PATCH 101/119] Fix lockscreen occluded states #2. Bug: 14656767 Bug: 14294001 Change-Id: Ibc428cbba8b48b6adc26756d8276a63183b8a690 --- .../phone/StatusBarKeyguardViewManager.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index f24c1b625ea4b..48c54fc7a85f4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -73,8 +73,7 @@ public class StatusBarKeyguardViewManager { public void show(Bundle options) { mShowing = true; mStatusBarWindowManager.setKeyguardShowing(true); - showBouncerOrKeyguard(); - updateStates(); + reset(); } /** @@ -105,13 +104,15 @@ public class StatusBarKeyguardViewManager { * Reset the state of the view. */ public void reset() { - if (mOccluded) { - mPhoneStatusBar.hideKeyguard(); - mBouncer.hide(); - } else { - showBouncerOrKeyguard(); + if (mShowing) { + if (mOccluded) { + mPhoneStatusBar.hideKeyguard(); + mBouncer.hide(); + } else { + showBouncerOrKeyguard(); + } + updateStates(); } - updateStates(); } public void onScreenTurnedOff() { @@ -121,7 +122,6 @@ public class StatusBarKeyguardViewManager { public void onScreenTurnedOn(final IKeyguardShowCallback callback) { mScreenOn = true; - reset(); if (callback != null) { callbackAfterDraw(callback); } From 8f0c1a6375903583e906247ee2e3dd994781f0b1 Mon Sep 17 00:00:00 2001 From: Jason Monk Date: Fri, 9 May 2014 09:53:08 -0400 Subject: [PATCH 102/119] Fix badness from proxy refactoring. When no PAC file getPacFileUrl() can return null now, which you cannot call toString() on. Change-Id: Ife00f641c2c17fbc1bde17017d9af59d23cb9182 --- core/java/android/net/Proxy.java | 4 +++- .../java/com/android/server/am/ActivityManagerService.java | 6 ++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/core/java/android/net/Proxy.java b/core/java/android/net/Proxy.java index 8f41e8561876e..daf0065d1c475 100644 --- a/core/java/android/net/Proxy.java +++ b/core/java/android/net/Proxy.java @@ -278,7 +278,9 @@ public final class Proxy { host = p.getHost(); port = Integer.toString(p.getPort()); exclList = p.getExclusionListAsString(); - pacFileUrl = p.getPacFileUrl().toString(); + if (p.getPacFileUrl() != null) { + pacFileUrl = p.getPacFileUrl().toString(); + } } setHttpProxySystemProperty(host, port, exclList, pacFileUrl); } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index a09b8d2f3afdf..5a85a66b7dfaf 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -1327,12 +1327,14 @@ public final class ActivityManagerService extends ActivityManagerNative String host = ""; String port = ""; String exclList = ""; - String pacFileUrl = null; + String pacFileUrl = ""; if (proxy != null) { host = proxy.getHost(); port = Integer.toString(proxy.getPort()); exclList = proxy.getExclusionListAsString(); - pacFileUrl = proxy.getPacFileUrl().toString(); + if (proxy.getPacFileUrl() != null) { + pacFileUrl = proxy.getPacFileUrl().toString(); + } } synchronized (ActivityManagerService.this) { for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) { From cddbc7e9dda6b3fd3ce1e50da89039e6e1291ff6 Mon Sep 17 00:00:00 2001 From: Jessica Hummel Date: Thu, 10 Apr 2014 17:39:43 +0100 Subject: [PATCH 103/119] Allow setting password restrictions from a managed profile. A managed profile will now share password settings with its parent. - the current password is always stored in the parent - admins of profiles are notified if that password changes - checks for password quality now take the requirements of admins on the parent and its profiles into account Todo: - Currently KeyguardSecurityContainer wipes the whole device when the maximum fails has been reached on any profile. We need to limit the wipe to the profile for which the fails exceeded the maximum number. - Intents with ACTION_SET_NEW_PASSWORD need to be forwarded to the parent of the profile when sent from a managed profile Change-Id: I8532c59f753f8d9c61200f553f275214ad90276e --- .../app/admin/DevicePolicyManager.java | 56 +-- .../DevicePolicyManagerService.java | 409 ++++++++++++------ 2 files changed, 298 insertions(+), 167 deletions(-) diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 209c536593fee..b902f537da8e9 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -16,8 +16,6 @@ package android.app.admin; -import org.xmlpull.v1.XmlPullParserException; - import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.content.ComponentName; @@ -39,6 +37,8 @@ import android.util.Log; import com.android.org.conscrypt.TrustedCertificateStore; +import org.xmlpull.v1.XmlPullParserException; + import java.io.ByteArrayInputStream; import java.io.IOException; import java.net.InetSocketAddress; @@ -359,8 +359,8 @@ public class DevicePolicyManager { } /** - * Retrieve the current minimum password quality for all admins - * or a particular one. + * Retrieve the current minimum password quality for all admins of this user + * and its profiles or a particular one. * @param admin The name of the admin component to check, or null to aggregate * all admins. */ @@ -412,8 +412,8 @@ public class DevicePolicyManager { } /** - * Retrieve the current minimum password length for all admins - * or a particular one. + * Retrieve the current minimum password length for all admins of this + * user and its profiles or a particular one. * @param admin The name of the admin component to check, or null to aggregate * all admins. */ @@ -467,8 +467,9 @@ public class DevicePolicyManager { /** * Retrieve the current number of upper case letters required in the - * password for all admins or a particular one. This is the same value as - * set by {#link {@link #setPasswordMinimumUpperCase(ComponentName, int)} + * password for all admins of this user and its profiles or a particular one. + * This is the same value as set by + * {#link {@link #setPasswordMinimumUpperCase(ComponentName, int)} * and only applies when the password quality is * {@link #PASSWORD_QUALITY_COMPLEX}. * @@ -527,8 +528,9 @@ public class DevicePolicyManager { /** * Retrieve the current number of lower case letters required in the - * password for all admins or a particular one. This is the same value as - * set by {#link {@link #setPasswordMinimumLowerCase(ComponentName, int)} + * password for all admins of this user and its profiles or a particular one. + * This is the same value as set by + * {#link {@link #setPasswordMinimumLowerCase(ComponentName, int)} * and only applies when the password quality is * {@link #PASSWORD_QUALITY_COMPLEX}. * @@ -644,8 +646,9 @@ public class DevicePolicyManager { /** * Retrieve the current number of numerical digits required in the password - * for all admins or a particular one. This is the same value as - * set by {#link {@link #setPasswordMinimumNumeric(ComponentName, int)} + * for all admins of this user and its profiles or a particular one. + * This is the same value as set by + * {#link {@link #setPasswordMinimumNumeric(ComponentName, int)} * and only applies when the password quality is * {@link #PASSWORD_QUALITY_COMPLEX}. * @@ -760,8 +763,9 @@ public class DevicePolicyManager { /** * Retrieve the current number of non-letter characters required in the - * password for all admins or a particular one. This is the same value as - * set by {#link {@link #setPasswordMinimumNonLetter(ComponentName, int)} + * password for all admins of this user and its profiles or a particular one. + * This is the same value as set by + * {#link {@link #setPasswordMinimumNonLetter(ComponentName, int)} * and only applies when the password quality is * {@link #PASSWORD_QUALITY_COMPLEX}. * @@ -868,9 +872,10 @@ public class DevicePolicyManager { /** * Get the current password expiration time for the given admin or an aggregate of - * all admins if admin is null. If the password is expired, this will return the time since - * the password expired as a negative number. If admin is null, then a composite of all - * expiration timeouts is returned - which will be the minimum of all timeouts. + * all admins of this user and its profiles if admin is null. If the password is + * expired, this will return the time since the password expired as a negative number. + * If admin is null, then a composite of all expiration timeouts is returned + * - which will be the minimum of all timeouts. * * @param admin The name of the admin component to check, or null to aggregate all admins. * @return The password expiration time, in ms. @@ -887,8 +892,8 @@ public class DevicePolicyManager { } /** - * Retrieve the current password history length for all admins - * or a particular one. + * Retrieve the current password history length for all admins of this + * user and its profiles or a particular one. * @param admin The name of the admin component to check, or null to aggregate * all admins. * @return The length of the password history @@ -923,14 +928,13 @@ public class DevicePolicyManager { /** * Determine whether the current password the user has set is sufficient * to meet the policy requirements (quality, minimum length) that have been - * requested. + * requested by the admins of this user and its profiles. * *

The calling device admin must have requested * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call * this method; if it has not, a security exception will be thrown. * - * @return Returns true if the password meets the current requirements, - * else false. + * @return Returns true if the password meets the current requirements, else false. */ public boolean isActivePasswordSufficient() { if (mService != null) { @@ -993,7 +997,7 @@ public class DevicePolicyManager { /** * Retrieve the current maximum number of login attempts that are allowed - * before the device wipes itself, for all admins + * before the device wipes itself, for all admins of this user and its profiles * or a particular one. * @param admin The name of the admin component to check, or null to aggregate * all admins. @@ -1037,6 +1041,8 @@ public class DevicePolicyManager { * {@link DeviceAdminInfo#USES_POLICY_RESET_PASSWORD} to be able to call * this method; if it has not, a security exception will be thrown. * + * Can not be called from a managed profile. + * * @param password The new password for the user. * @param flags May be 0 or {@link #RESET_PASSWORD_REQUIRE_ENTRY}. * @return Returns true if the password was applied, or false if it is @@ -1077,8 +1083,8 @@ public class DevicePolicyManager { } /** - * Retrieve the current maximum time to unlock for all admins - * or a particular one. + * Retrieve the current maximum time to unlock for all admins of this user + * and its profiles or a particular one. * @param admin The name of the admin component to check, or null to aggregate * all admins. */ diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index dcca8377cba38..6f88cf3894fbf 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -126,6 +126,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private static final boolean DBG = false; final Context mContext; + final UserManager mUserManager; final PowerManager.WakeLock mWakeLock; IPowerManager mIPowerManager; @@ -202,7 +203,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { + action + " for user " + userHandle); mHandler.post(new Runnable() { public void run() { - handlePasswordExpirationNotification(getUserData(userHandle)); + handlePasswordExpirationNotification(userHandle); } }); } @@ -575,6 +576,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { */ public DevicePolicyManagerService(Context context) { mContext = context; + mUserManager = UserManager.get(mContext); mHasFeature = context.getPackageManager().hasSystemFeature( PackageManager.FEATURE_DEVICE_ADMIN); mWakeLock = ((PowerManager)context.getSystemService(Context.POWER_SERVICE)) @@ -782,6 +784,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { sendAdminCommandLocked(admin, action, null); } + /** + * Send an update to one specific admin, get notified when that admin returns a result. + */ void sendAdminCommandLocked(ActiveAdmin admin, String action, BroadcastReceiver result) { Intent intent = new Intent(action); intent.setComponent(admin.info.getComponent()); @@ -796,12 +801,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } + /** + * Send an update to all admins of a user that enforce a specified policy. + */ void sendAdminCommandLocked(String action, int reqPolicy, int userHandle) { final DevicePolicyData policy = getUserData(userHandle); final int count = policy.mAdminList.size(); if (count > 0) { for (int i = 0; i < count; i++) { - ActiveAdmin admin = policy.mAdminList.get(i); + final ActiveAdmin admin = policy.mAdminList.get(i); if (admin.info.usesPolicy(reqPolicy)) { sendAdminCommandLocked(admin, action); } @@ -809,6 +817,19 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } + /** + * Send an update intent to all admins of a user and its profiles. Only send to admins that + * enforce a specified policy. + */ + private void sendAdminCommandToSelfAndProfilesLocked(String action, int reqPolicy, + int userHandle) { + List profiles = mUserManager.getProfiles(userHandle); + for (UserInfo ui : profiles) { + int id = ui.getUserHandle().getIdentifier(); + sendAdminCommandLocked(action, reqPolicy, id); + } + } + void removeActiveAdminLocked(final ComponentName adminReceiver, int userHandle) { final ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver, userHandle); if (admin != null) { @@ -1141,23 +1162,29 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } - private void handlePasswordExpirationNotification(DevicePolicyData policy) { + private void handlePasswordExpirationNotification(int userHandle) { synchronized (this) { final long now = System.currentTimeMillis(); - final int N = policy.mAdminList.size(); - if (N <= 0) { - return; - } - for (int i=0; i < N; i++) { - ActiveAdmin admin = policy.mAdminList.get(i); - if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD) - && admin.passwordExpirationTimeout > 0L - && admin.passwordExpirationDate > 0L - && now >= admin.passwordExpirationDate - EXPIRATION_GRACE_PERIOD_MS) { - sendAdminCommandLocked(admin, DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING); + + List profiles = mUserManager.getProfiles(userHandle); + for (UserInfo ui : profiles) { + int profileUserHandle = ui.getUserHandle().getIdentifier(); + final DevicePolicyData policy = getUserData(profileUserHandle); + final int count = policy.mAdminList.size(); + if (count > 0) { + for (int i = 0; i < count; i++) { + final ActiveAdmin admin = policy.mAdminList.get(i); + if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD) + && admin.passwordExpirationTimeout > 0L + && now >= admin.passwordExpirationDate - EXPIRATION_GRACE_PERIOD_MS + && admin.passwordExpirationDate > 0L) { + sendAdminCommandLocked(admin, + DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING); + } + } } } - setExpirationAlarmCheckLocked(mContext, policy); + setExpirationAlarmCheckLocked(mContext, getUserData(userHandle)); } } @@ -1167,8 +1194,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { final boolean hasCert = DevicePolicyManager.hasAnyCaCertsInstalled(); if (! hasCert) { if (intent.getAction().equals(KeyChain.ACTION_STORAGE_CHANGED)) { - UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE); - for (UserInfo user : um.getUsers()) { + for (UserInfo user : mUserManager.getUsers()) { notificationManager.cancelAsUser( null, MONITORING_CERT_NOTIFICATION_ID, user.getUserHandle()); } @@ -1207,8 +1233,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // If this is a boot intent, this will fire for each user. But if this is a storage changed // intent, it will fire once, so we need to notify all users. if (intent.getAction().equals(KeyChain.ACTION_STORAGE_CHANGED)) { - UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE); - for (UserInfo user : um.getUsers()) { + for (UserInfo user : mUserManager.getUsers()) { notificationManager.notifyAsUser( null, MONITORING_CERT_NOTIFICATION_ID, noti, user.getUserHandle()); } @@ -1385,18 +1410,22 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { enforceCrossUserPermission(userHandle); synchronized (this) { int mode = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; - DevicePolicyData policy = getUserData(userHandle); if (who != null) { ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle); return admin != null ? admin.passwordQuality : mode; } - final int N = policy.mAdminList.size(); - for (int i=0; i profiles = mUserManager.getProfiles(userHandle); + for (UserInfo userInfo : profiles) { + DevicePolicyData policy = getUserData(userInfo.getUserHandle().getIdentifier()); + final int N = policy.mAdminList.size(); + for (int i=0; i profiles = mUserManager.getProfiles(userHandle); + for (UserInfo userInfo : profiles) { + DevicePolicyData policy = getUserData(userInfo.getUserHandle().getIdentifier()); + final int N = policy.mAdminList.size(); + for (int i=0; i profiles = mUserManager.getProfiles(userHandle); + for (UserInfo userInfo : profiles) { + DevicePolicyData policy = getUserData(userInfo.getUserHandle().getIdentifier()); + final int N = policy.mAdminList.size(); + for (int i = 0; i < N; i++) { + ActiveAdmin admin = policy.mAdminList.get(i); + if (length < admin.passwordHistoryLength) { + length = admin.passwordHistoryLength; + } } } return length; @@ -1528,19 +1565,23 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } enforceCrossUserPermission(userHandle); synchronized (this) { + long timeout = 0L; + if (who != null) { ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle); - return admin != null ? admin.passwordExpirationTimeout : 0L; + return admin != null ? admin.passwordExpirationTimeout : timeout; } - long timeout = 0L; - DevicePolicyData policy = getUserData(userHandle); - final int N = policy.mAdminList.size(); - for (int i = 0; i < N; i++) { - ActiveAdmin admin = policy.mAdminList.get(i); - if (timeout == 0L || (admin.passwordExpirationTimeout != 0L - && timeout > admin.passwordExpirationTimeout)) { - timeout = admin.passwordExpirationTimeout; + List profiles = mUserManager.getProfiles(userHandle); + for (UserInfo userInfo : profiles) { + DevicePolicyData policy = getUserData(userInfo.getUserHandle().getIdentifier()); + final int N = policy.mAdminList.size(); + for (int i = 0; i < N; i++) { + ActiveAdmin admin = policy.mAdminList.get(i); + if (timeout == 0L || (admin.passwordExpirationTimeout != 0L + && timeout > admin.passwordExpirationTimeout)) { + timeout = admin.passwordExpirationTimeout; + } } } return timeout; @@ -1552,19 +1593,23 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { * Returns 0 if not configured. */ private long getPasswordExpirationLocked(ComponentName who, int userHandle) { + long timeout = 0L; + if (who != null) { ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle); - return admin != null ? admin.passwordExpirationDate : 0L; + return admin != null ? admin.passwordExpirationDate : timeout; } - long timeout = 0L; - DevicePolicyData policy = getUserData(userHandle); - final int N = policy.mAdminList.size(); - for (int i = 0; i < N; i++) { - ActiveAdmin admin = policy.mAdminList.get(i); - if (timeout == 0L || (admin.passwordExpirationDate != 0 - && timeout > admin.passwordExpirationDate)) { - timeout = admin.passwordExpirationDate; + List profiles = mUserManager.getProfiles(userHandle); + for (UserInfo userInfo : profiles) { + DevicePolicyData policy = getUserData(userInfo.getUserHandle().getIdentifier()); + final int N = policy.mAdminList.size(); + for (int i = 0; i < N; i++) { + ActiveAdmin admin = policy.mAdminList.get(i); + if (timeout == 0L || (admin.passwordExpirationDate != 0 + && timeout > admin.passwordExpirationDate)) { + timeout = admin.passwordExpirationDate; + } } } return timeout; @@ -1611,12 +1656,16 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return admin != null ? admin.minimumPasswordUpperCase : length; } - DevicePolicyData policy = getUserData(userHandle); - final int N = policy.mAdminList.size(); - for (int i=0; i profiles = mUserManager.getProfiles(userHandle); + for (UserInfo userInfo : profiles) { + DevicePolicyData policy = getUserData(userInfo.getUserHandle().getIdentifier()); + final int N = policy.mAdminList.size(); + for (int i=0; i profiles = mUserManager.getProfiles(userHandle); + for (UserInfo userInfo : profiles) { + DevicePolicyData policy = getUserData(userInfo.getUserHandle().getIdentifier()); + final int N = policy.mAdminList.size(); + for (int i=0; i profiles = mUserManager.getProfiles(userHandle); + for (UserInfo userInfo : profiles) { + DevicePolicyData policy = getUserData(userInfo.getUserHandle().getIdentifier()); + final int N = policy.mAdminList.size(); + for (int i=0; i profiles = mUserManager.getProfiles(userHandle); + for (UserInfo userInfo : profiles) { + DevicePolicyData policy = getUserData(userInfo.getUserHandle().getIdentifier()); + final int N = policy.mAdminList.size(); + for (int i = 0; i < N; i++) { + ActiveAdmin admin = policy.mAdminList.get(i); + if (length < admin.minimumPasswordNumeric) { + length = admin.minimumPasswordNumeric; + } } } return length; @@ -1780,12 +1841,16 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return admin != null ? admin.minimumPasswordSymbols : length; } - DevicePolicyData policy = getUserData(userHandle); - final int N = policy.mAdminList.size(); - for (int i=0; i profiles = mUserManager.getProfiles(userHandle); + for (UserInfo userInfo : profiles) { + DevicePolicyData policy = getUserData(userInfo.getUserHandle().getIdentifier()); + final int N = policy.mAdminList.size(); + for (int i=0; i profiles = mUserManager.getProfiles(userHandle); + for (UserInfo userInfo : profiles) { + DevicePolicyData policy = getUserData(userInfo.getUserHandle().getIdentifier()); + final int N = policy.mAdminList.size(); + for (int i=0; i admin.maximumFailedPasswordsForWipe) { - count = admin.maximumFailedPasswordsForWipe; + // Return strictest policy for this user and profiles that are visible from this user. + List profiles = mUserManager.getProfiles(userHandle); + for (UserInfo userInfo : profiles) { + DevicePolicyData policy = getUserData(userInfo.getUserHandle().getIdentifier()); + final int N = policy.mAdminList.size(); + for (int i=0; i admin.maximumFailedPasswordsForWipe) { + count = admin.maximumFailedPasswordsForWipe; + } } } return count; @@ -1925,9 +2012,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return false; } enforceCrossUserPermission(userHandle); + enforceNotManagedProfile(userHandle, "reset the password"); + int quality; synchronized (this) { - // This API can only be called by an active device admin, + // This api can only be called by an active device admin, // so try to retrieve it to check that the caller is one. getActiveAdminForCallerLocked(null, DeviceAdminInfo.USES_POLICY_RESET_PASSWORD); @@ -2105,15 +2194,19 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return admin != null ? admin.maximumTimeToUnlock : time; } - DevicePolicyData policy = getUserData(userHandle); - final int N = policy.mAdminList.size(); - for (int i=0; i admin.maximumTimeToUnlock) { - time = admin.maximumTimeToUnlock; + // Return strictest policy for this user and profiles that are visible from this user. + List profiles = mUserManager.getProfiles(userHandle); + for (UserInfo userInfo : profiles) { + DevicePolicyData policy = getUserData(userInfo.getUserHandle().getIdentifier()); + final int N = policy.mAdminList.size(); + for (int i=0; i admin.maximumTimeToUnlock) { + time = admin.maximumTimeToUnlock; + } } } return time; @@ -2271,7 +2364,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { public void run() { try { ActivityManagerNative.getDefault().switchUser(UserHandle.USER_OWNER); - ((UserManager) mContext.getSystemService(Context.USER_SERVICE)) + (mUserManager) .removeUser(userHandle); } catch (RemoteException re) { // Shouldn't happen @@ -2319,6 +2412,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return; } enforceCrossUserPermission(userHandle); + enforceNotManagedProfile(userHandle, "set the active password"); + mContext.enforceCallingOrSelfPermission( android.Manifest.permission.BIND_DEVICE_ADMIN, null); DevicePolicyData p = getUserData(userHandle); @@ -2347,7 +2442,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { saveSettingsLocked(userHandle); updatePasswordExpirationsLocked(userHandle); setExpirationAlarmCheckLocked(mContext, p); - sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED, + sendAdminCommandToSelfAndProfilesLocked( + DeviceAdminReceiver.ACTION_PASSWORD_CHANGED, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, userHandle); } finally { Binder.restoreCallingIdentity(ident); @@ -2357,26 +2453,31 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } /** - * Called any time the device password is updated. Resets all password expiration clocks. + * Called any time the device password is updated. Resets all password expiration clocks. */ private void updatePasswordExpirationsLocked(int userHandle) { - DevicePolicyData policy = getUserData(userHandle); - final int N = policy.mAdminList.size(); - if (N > 0) { - for (int i=0; i 0L ? (timeout + System.currentTimeMillis()) : 0L; - admin.passwordExpirationDate = expiration; + List profiles = mUserManager.getProfiles(userHandle); + for (UserInfo userInfo : profiles) { + int profileId = userInfo.getUserHandle().getIdentifier(); + DevicePolicyData policy = getUserData(profileId); + final int N = policy.mAdminList.size(); + if (N > 0) { + for (int i=0; i 0L ? (timeout + System.currentTimeMillis()) : 0L; + admin.passwordExpirationDate = expiration; + } + } } + saveSettingsLocked(profileId); } - saveSettingsLocked(userHandle); - } } public void reportFailedPasswordAttempt(int userHandle) { enforceCrossUserPermission(userHandle); + enforceNotManagedProfile(userHandle, "report failed password attempt"); mContext.enforceCallingOrSelfPermission( android.Manifest.permission.BIND_DEVICE_ADMIN, null); @@ -2391,7 +2492,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (max > 0 && policy.mFailedPasswordAttempts >= max) { wipeDeviceOrUserLocked(0, userHandle); } - sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_FAILED, + sendAdminCommandToSelfAndProfilesLocked( + DeviceAdminReceiver.ACTION_PASSWORD_FAILED, DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle); } } finally { @@ -2414,7 +2516,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { policy.mPasswordOwner = -1; saveSettingsLocked(userHandle); if (mHasFeature) { - sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_SUCCEEDED, + sendAdminCommandToSelfAndProfilesLocked( + DeviceAdminReceiver.ACTION_PASSWORD_SUCCEEDED, DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle); } } finally { @@ -2443,7 +2546,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // Scan through active admins and find if anyone has already // set the global proxy. Set compSet = policy.mAdminMap.keySet(); - for (ComponentName component : compSet) { + for (ComponentName component : compSet) { ActiveAdmin ap = policy.mAdminMap.get(component); if ((ap.specifiesGlobalProxy) && (!component.equals(who))) { // Another admin already sets the global proxy @@ -2472,8 +2575,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // Reset the global proxy accordingly // Do this using system permissions, as apps cannot write to secure settings long origId = Binder.clearCallingIdentity(); - resetGlobalProxyLocked(policy); - Binder.restoreCallingIdentity(origId); + try { + resetGlobalProxyLocked(policy); + } finally { + Binder.restoreCallingIdentity(origId); + } return null; } } @@ -2858,8 +2964,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null); - UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE); - if (um.getUserInfo(userHandle) == null) { + if (mUserManager.getUserInfo(userHandle) == null) { // User doesn't exist. throw new IllegalArgumentException( "Attempted to set profile owner for invalid userId: " + userHandle); @@ -2905,10 +3010,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { int userId = UserHandle.getCallingUserId(); Slog.d(LOG_TAG, "Enabling the profile for: " + userId); - UserManager um = UserManager.get(mContext); long id = Binder.clearCallingIdentity(); try { - um.setUserEnabled(userId); + mUserManager.setUserEnabled(userId); Intent intent = new Intent(Intent.ACTION_MANAGED_PROFILE_ADDED); intent.putExtra(Intent.EXTRA_USER, new UserHandle(UserHandle.getCallingUserId())); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY | @@ -2972,6 +3076,30 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } + private void enforceNotManagedProfile(int userHandle, String message) { + if(isManagedProfile(userHandle)) { + throw new SecurityException("You can not " + message + " from a managed profile. "); + } + } + + private UserInfo getProfileParent(int userHandle) { + long ident = Binder.clearCallingIdentity(); + try { + return mUserManager.getProfileParent(userHandle); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + private boolean isManagedProfile(int userHandle) { + long ident = Binder.clearCallingIdentity(); + try { + return mUserManager.getUserInfo(userHandle).isManagedProfile(); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + private void enableIfNecessary(String packageName, int userId) { try { IPackageManager ipm = AppGlobals.getPackageManager(); @@ -3075,10 +3203,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); - UserManager um = UserManager.get(mContext); long id = Binder.clearCallingIdentity(); try { - um.setApplicationRestrictions(packageName, settings, userHandle); + mUserManager.setApplicationRestrictions(packageName, settings, userHandle); } finally { restoreCallingIdentity(id); } @@ -3142,10 +3269,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); - UserManager um = UserManager.get(mContext); long id = Binder.clearCallingIdentity(); try { - return um.getApplicationRestrictions(packageName, userHandle); + return mUserManager.getApplicationRestrictions(packageName, userHandle); } finally { restoreCallingIdentity(id); } @@ -3162,10 +3288,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); - UserManager um = UserManager.get(mContext); long id = Binder.clearCallingIdentity(); try { - um.setUserRestriction(key, enabled, userHandle); + mUserManager.setUserRestriction(key, enabled, userHandle); } finally { restoreCallingIdentity(id); } From 08e5f4ae19fdd36aef22acfb5f46d1956a857d61 Mon Sep 17 00:00:00 2001 From: Brian Carlstrom Date: Fri, 9 May 2014 09:48:33 -0700 Subject: [PATCH 104/119] If PackageUsage information is missing, treat as first boot and compile everything Bug: 14663243 Change-Id: I0ae33882044211f777590f482e17e87596be4463 Conflicts: services/java/com/android/server/pm/PackageManagerService.java --- .../server/pm/PackageManagerService.java | 12296 ++++++++++++++++ 1 file changed, 12296 insertions(+) create mode 100755 services/java/com/android/server/pm/PackageManagerService.java diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java new file mode 100755 index 0000000000000..51c450bc0286c --- /dev/null +++ b/services/java/com/android/server/pm/PackageManagerService.java @@ -0,0 +1,12296 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.pm; + +import static android.Manifest.permission.GRANT_REVOKE_PERMISSIONS; +import static android.Manifest.permission.READ_EXTERNAL_STORAGE; +import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; +import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED; +import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED; +import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER; +import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED; +import static android.system.OsConstants.S_IRWXU; +import static android.system.OsConstants.S_IRGRP; +import static android.system.OsConstants.S_IXGRP; +import static android.system.OsConstants.S_IROTH; +import static android.system.OsConstants.S_IXOTH; +import static android.os.Process.PACKAGE_INFO_GID; +import static android.os.Process.SYSTEM_UID; +import static com.android.internal.util.ArrayUtils.appendInt; +import static com.android.internal.util.ArrayUtils.removeInt; + +import com.android.internal.R; +import com.android.internal.app.IMediaContainerService; +import com.android.internal.app.ResolverActivity; +import com.android.internal.content.NativeLibraryHelper; +import com.android.internal.content.PackageHelper; +import com.android.internal.util.FastPrintWriter; +import com.android.internal.util.FastXmlSerializer; +import com.android.internal.util.XmlUtils; +import com.android.server.DeviceStorageMonitorService; +import com.android.server.EventLogTags; +import com.android.server.IntentResolver; +import com.android.server.Watchdog; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlSerializer; + +import android.app.ActivityManager; +import android.app.ActivityManagerNative; +import android.app.IActivityManager; +import android.app.admin.IDevicePolicyManager; +import android.app.backup.IBackupManager; +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.Context; +import android.content.IIntentReceiver; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.IntentSender; +import android.content.IntentSender.SendIntentException; +import android.content.ServiceConnection; +import android.content.pm.ActivityInfo; +import android.content.pm.ApplicationInfo; +import android.content.pm.ContainerEncryptionParams; +import android.content.pm.FeatureInfo; +import android.content.pm.IPackageDataObserver; +import android.content.pm.IPackageDeleteObserver; +import android.content.pm.IPackageInstallObserver; +import android.content.pm.IPackageManager; +import android.content.pm.IPackageMoveObserver; +import android.content.pm.IPackageStatsObserver; +import android.content.pm.InstrumentationInfo; +import android.content.pm.ManifestDigest; +import android.content.pm.PackageCleanItem; +import android.content.pm.PackageInfo; +import android.content.pm.PackageInfoLite; +import android.content.pm.PackageManager; +import android.content.pm.PackageParser.ActivityIntentInfo; +import android.content.pm.PackageParser; +import android.content.pm.PackageStats; +import android.content.pm.PackageUserState; +import android.content.pm.ParceledListSlice; +import android.content.pm.PermissionGroupInfo; +import android.content.pm.PermissionInfo; +import android.content.pm.ProviderInfo; +import android.content.pm.ResolveInfo; +import android.content.pm.ServiceInfo; +import android.content.pm.Signature; +import android.content.pm.VerificationParams; +import android.content.pm.VerifierDeviceIdentity; +import android.content.pm.VerifierInfo; +import android.content.res.Resources; +import android.net.Uri; +import android.os.Binder; +import android.os.Build; +import android.os.Bundle; +import android.os.Environment; +import android.os.Environment.UserEnvironment; +import android.os.FileObserver; +import android.os.FileUtils; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.IBinder; +import android.os.Looper; +import android.os.Message; +import android.os.Parcel; +import android.os.ParcelFileDescriptor; +import android.os.Process; +import android.os.RemoteException; +import android.os.SELinux; +import android.os.ServiceManager; +import android.os.SystemClock; +import android.os.SystemProperties; +import android.os.UserHandle; +import android.os.UserManager; +import android.security.KeyStore; +import android.security.SystemKeyStore; +import android.system.ErrnoException; +import android.system.Os; +import android.system.StructStat; +import android.text.TextUtils; +import android.util.AtomicFile; +import android.util.DisplayMetrics; +import android.util.EventLog; +import android.util.Log; +import android.util.LogPrinter; +import android.util.PrintStreamPrinter; +import android.util.Slog; +import android.util.SparseArray; +import android.util.Xml; +import android.view.Display; +import android.view.WindowManager; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileDescriptor; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.FilenameFilter; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintWriter; +import java.nio.charset.StandardCharsets; +import java.security.NoSuchAlgorithmException; +import java.security.PublicKey; +import java.security.cert.CertificateException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; + +import dalvik.system.DexFile; +import dalvik.system.StaleDexCacheError; +import dalvik.system.VMRuntime; +import libcore.io.IoUtils; + +/** + * Keep track of all those .apks everywhere. + * + * This is very central to the platform's security; please run the unit + * tests whenever making modifications here: + * +mmm frameworks/base/tests/AndroidTests +adb install -r -f out/target/product/passion/data/app/AndroidTests.apk +adb shell am instrument -w -e class com.android.unit_tests.PackageManagerTests com.android.unit_tests/android.test.InstrumentationTestRunner + * + * {@hide} + */ +public class PackageManagerService extends IPackageManager.Stub { + static final String TAG = "PackageManager"; + static final boolean DEBUG_SETTINGS = false; + static final boolean DEBUG_PREFERRED = false; + static final boolean DEBUG_UPGRADE = false; + private static final boolean DEBUG_INSTALL = false; + private static final boolean DEBUG_REMOVE = false; + private static final boolean DEBUG_BROADCASTS = false; + private static final boolean DEBUG_SHOW_INFO = false; + private static final boolean DEBUG_PACKAGE_INFO = false; + private static final boolean DEBUG_INTENT_MATCHING = false; + private static final boolean DEBUG_PACKAGE_SCANNING = false; + private static final boolean DEBUG_APP_DIR_OBSERVER = false; + private static final boolean DEBUG_VERIFY = false; + private static final boolean DEBUG_DEXOPT = false; + + private static final int RADIO_UID = Process.PHONE_UID; + private static final int LOG_UID = Process.LOG_UID; + private static final int NFC_UID = Process.NFC_UID; + private static final int BLUETOOTH_UID = Process.BLUETOOTH_UID; + private static final int SHELL_UID = Process.SHELL_UID; + + private static final boolean GET_CERTIFICATES = true; + + private static final int REMOVE_EVENTS = + FileObserver.CLOSE_WRITE | FileObserver.DELETE | FileObserver.MOVED_FROM; + private static final int ADD_EVENTS = + FileObserver.CLOSE_WRITE /*| FileObserver.CREATE*/ | FileObserver.MOVED_TO; + + private static final int OBSERVER_EVENTS = REMOVE_EVENTS | ADD_EVENTS; + // Suffix used during package installation when copying/moving + // package apks to install directory. + private static final String INSTALL_PACKAGE_SUFFIX = "-"; + + static final int SCAN_MONITOR = 1<<0; + static final int SCAN_NO_DEX = 1<<1; + static final int SCAN_FORCE_DEX = 1<<2; + static final int SCAN_UPDATE_SIGNATURE = 1<<3; + static final int SCAN_NEW_INSTALL = 1<<4; + static final int SCAN_NO_PATHS = 1<<5; + static final int SCAN_UPDATE_TIME = 1<<6; + static final int SCAN_DEFER_DEX = 1<<7; + static final int SCAN_BOOTING = 1<<8; + static final int SCAN_TRUSTED_OVERLAY = 1<<9; + + static final int REMOVE_CHATTY = 1<<16; + + /** + * Timeout (in milliseconds) after which the watchdog should declare that + * our handler thread is wedged. The usual default for such things is one + * minute but we sometimes do very lengthy I/O operations on this thread, + * such as installing multi-gigabyte applications, so ours needs to be longer. + */ + private static final long WATCHDOG_TIMEOUT = 1000*60*10; // ten minutes + + /** + * Whether verification is enabled by default. + */ + private static final boolean DEFAULT_VERIFY_ENABLE = true; + + /** + * The default maximum time to wait for the verification agent to return in + * milliseconds. + */ + private static final long DEFAULT_VERIFICATION_TIMEOUT = 10 * 1000; + + /** + * The default response for package verification timeout. + * + * This can be either PackageManager.VERIFICATION_ALLOW or + * PackageManager.VERIFICATION_REJECT. + */ + private static final int DEFAULT_VERIFICATION_RESPONSE = PackageManager.VERIFICATION_ALLOW; + + static final String DEFAULT_CONTAINER_PACKAGE = "com.android.defcontainer"; + + static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName( + DEFAULT_CONTAINER_PACKAGE, + "com.android.defcontainer.DefaultContainerService"); + + private static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive"; + + private static final String LIB_DIR_NAME = "lib"; + private static final String LIB64_DIR_NAME = "lib64"; + + private static final String VENDOR_OVERLAY_DIR = "/vendor/overlay"; + + static final String mTempContainerPrefix = "smdl2tmp"; + + private static String sPreferredInstructionSet; + + private static final String IDMAP_PREFIX = "/data/resource-cache/"; + private static final String IDMAP_SUFFIX = "@idmap"; + + final HandlerThread mHandlerThread = new HandlerThread("PackageManager", + Process.THREAD_PRIORITY_BACKGROUND); + final PackageHandler mHandler; + + final int mSdkVersion = Build.VERSION.SDK_INT; + final String mSdkCodename = "REL".equals(Build.VERSION.CODENAME) + ? null : Build.VERSION.CODENAME; + + final Context mContext; + final boolean mFactoryTest; + final boolean mOnlyCore; + final DisplayMetrics mMetrics; + final int mDefParseFlags; + final String[] mSeparateProcesses; + + // This is where all application persistent data goes. + final File mAppDataDir; + + // This is where all application persistent data goes for secondary users. + final File mUserAppDataDir; + + /** The location for ASEC container files on internal storage. */ + final String mAsecInternalPath; + + // This is the object monitoring the framework dir. + final FileObserver mFrameworkInstallObserver; + + // This is the object monitoring the system app dir. + final FileObserver mSystemInstallObserver; + + // This is the object monitoring the privileged system app dir. + final FileObserver mPrivilegedInstallObserver; + + // This is the object monitoring the system app dir. + final FileObserver mVendorInstallObserver; + + // This is the object monitoring the vendor overlay package dir. + final FileObserver mVendorOverlayInstallObserver; + + // This is the object monitoring mAppInstallDir. + final FileObserver mAppInstallObserver; + + // This is the object monitoring mDrmAppPrivateInstallDir. + final FileObserver mDrmAppInstallObserver; + + // Used for privilege escalation. MUST NOT BE CALLED WITH mPackages + // LOCK HELD. Can be called with mInstallLock held. + final Installer mInstaller; + + final File mAppInstallDir; + + /** + * Directory to which applications installed internally have native + * libraries copied. + */ + private File mAppLibInstallDir; + + // Directory containing the private parts (e.g. code and non-resource assets) of forward-locked + // apps. + final File mDrmAppPrivateInstallDir; + + // ---------------------------------------------------------------- + + // Lock for state used when installing and doing other long running + // operations. Methods that must be called with this lock held have + // the prefix "LI". + final Object mInstallLock = new Object(); + + // These are the directories in the 3rd party applications installed dir + // that we have currently loaded packages from. Keys are the application's + // installed zip file (absolute codePath), and values are Package. + final HashMap mAppDirs = + new HashMap(); + + // Information for the parser to write more useful error messages. + File mScanningPath; + int mLastScanError; + + // ---------------------------------------------------------------- + + // Keys are String (package name), values are Package. This also serves + // as the lock for the global state. Methods that must be called with + // this lock held have the prefix "LP". + final HashMap mPackages = + new HashMap(); + + // Tracks available target package names -> overlay package paths. + final HashMap> mOverlays = + new HashMap>(); + + final Settings mSettings; + boolean mRestoredSettings; + + // Group-ids that are given to all packages as read from etc/permissions/*.xml. + int[] mGlobalGids; + + // These are the built-in uid -> permission mappings that were read from the + // etc/permissions.xml file. + final SparseArray> mSystemPermissions = + new SparseArray>(); + + static final class SharedLibraryEntry { + final String path; + final String apk; + + SharedLibraryEntry(String _path, String _apk) { + path = _path; + apk = _apk; + } + } + + // These are the built-in shared libraries that were read from the + // etc/permissions.xml file. + final HashMap mSharedLibraries + = new HashMap(); + + // Temporary for building the final shared libraries for an .apk. + String[] mTmpSharedLibraries = null; + + // These are the features this devices supports that were read from the + // etc/permissions.xml file. + final HashMap mAvailableFeatures = + new HashMap(); + + // If mac_permissions.xml was found for seinfo labeling. + boolean mFoundPolicyFile; + + // If a recursive restorecon of /data/data/ is needed. + private boolean mShouldRestoreconData = SELinuxMMAC.shouldRestorecon(); + + // All available activities, for your resolving pleasure. + final ActivityIntentResolver mActivities = + new ActivityIntentResolver(); + + // All available receivers, for your resolving pleasure. + final ActivityIntentResolver mReceivers = + new ActivityIntentResolver(); + + // All available services, for your resolving pleasure. + final ServiceIntentResolver mServices = new ServiceIntentResolver(); + + // All available providers, for your resolving pleasure. + final ProviderIntentResolver mProviders = new ProviderIntentResolver(); + + // Mapping from provider base names (first directory in content URI codePath) + // to the provider information. + final HashMap mProvidersByAuthority = + new HashMap(); + + // Mapping from instrumentation class names to info about them. + final HashMap mInstrumentation = + new HashMap(); + + // Mapping from permission names to info about them. + final HashMap mPermissionGroups = + new HashMap(); + + // Packages whose data we have transfered into another package, thus + // should no longer exist. + final HashSet mTransferedPackages = new HashSet(); + + // Broadcast actions that are only available to the system. + final HashSet mProtectedBroadcasts = new HashSet(); + + /** List of packages waiting for verification. */ + final SparseArray mPendingVerification + = new SparseArray(); + + HashSet mDeferredDexOpt = null; + + /** Token for keys in mPendingVerification. */ + private int mPendingVerificationToken = 0; + + boolean mSystemReady; + boolean mSafeMode; + boolean mHasSystemUidErrors; + + ApplicationInfo mAndroidApplication; + final ActivityInfo mResolveActivity = new ActivityInfo(); + final ResolveInfo mResolveInfo = new ResolveInfo(); + ComponentName mResolveComponentName; + PackageParser.Package mPlatformPackage; + ComponentName mCustomResolverComponentName; + + boolean mResolverReplaced = false; + + // Set of pending broadcasts for aggregating enable/disable of components. + static class PendingPackageBroadcasts { + // for each user id, a map of components within that package> + final SparseArray>> mUidMap; + + public PendingPackageBroadcasts() { + mUidMap = new SparseArray>>(2); + } + + public ArrayList get(int userId, String packageName) { + HashMap> packages = getOrAllocate(userId); + return packages.get(packageName); + } + + public void put(int userId, String packageName, ArrayList components) { + HashMap> packages = getOrAllocate(userId); + packages.put(packageName, components); + } + + public void remove(int userId, String packageName) { + HashMap> packages = mUidMap.get(userId); + if (packages != null) { + packages.remove(packageName); + } + } + + public void remove(int userId) { + mUidMap.remove(userId); + } + + public int userIdCount() { + return mUidMap.size(); + } + + public int userIdAt(int n) { + return mUidMap.keyAt(n); + } + + public HashMap> packagesForUserId(int userId) { + return mUidMap.get(userId); + } + + public int size() { + // total number of pending broadcast entries across all userIds + int num = 0; + for (int i = 0; i< mUidMap.size(); i++) { + num += mUidMap.valueAt(i).size(); + } + return num; + } + + public void clear() { + mUidMap.clear(); + } + + private HashMap> getOrAllocate(int userId) { + HashMap> map = mUidMap.get(userId); + if (map == null) { + map = new HashMap>(); + mUidMap.put(userId, map); + } + return map; + } + } + final PendingPackageBroadcasts mPendingBroadcasts = new PendingPackageBroadcasts(); + + // Service Connection to remote media container service to copy + // package uri's from external media onto secure containers + // or internal storage. + private IMediaContainerService mContainerService = null; + + static final int SEND_PENDING_BROADCAST = 1; + static final int MCS_BOUND = 3; + static final int END_COPY = 4; + static final int INIT_COPY = 5; + static final int MCS_UNBIND = 6; + static final int START_CLEANING_PACKAGE = 7; + static final int FIND_INSTALL_LOC = 8; + static final int POST_INSTALL = 9; + static final int MCS_RECONNECT = 10; + static final int MCS_GIVE_UP = 11; + static final int UPDATED_MEDIA_STATUS = 12; + static final int WRITE_SETTINGS = 13; + static final int WRITE_PACKAGE_RESTRICTIONS = 14; + static final int PACKAGE_VERIFIED = 15; + static final int CHECK_PENDING_VERIFICATION = 16; + + static final int WRITE_SETTINGS_DELAY = 10*1000; // 10 seconds + + // Delay time in millisecs + static final int BROADCAST_DELAY = 10 * 1000; + + static UserManagerService sUserManager; + + // Stores a list of users whose package restrictions file needs to be updated + private HashSet mDirtyUsers = new HashSet(); + + final private DefaultContainerConnection mDefContainerConn = + new DefaultContainerConnection(); + class DefaultContainerConnection implements ServiceConnection { + public void onServiceConnected(ComponentName name, IBinder service) { + if (DEBUG_SD_INSTALL) Log.i(TAG, "onServiceConnected"); + IMediaContainerService imcs = + IMediaContainerService.Stub.asInterface(service); + mHandler.sendMessage(mHandler.obtainMessage(MCS_BOUND, imcs)); + } + + public void onServiceDisconnected(ComponentName name) { + if (DEBUG_SD_INSTALL) Log.i(TAG, "onServiceDisconnected"); + } + }; + + // Recordkeeping of restore-after-install operations that are currently in flight + // between the Package Manager and the Backup Manager + class PostInstallData { + public InstallArgs args; + public PackageInstalledInfo res; + + PostInstallData(InstallArgs _a, PackageInstalledInfo _r) { + args = _a; + res = _r; + } + }; + final SparseArray mRunningInstalls = new SparseArray(); + int mNextInstallToken = 1; // nonzero; will be wrapped back to 1 when ++ overflows + + private final String mRequiredVerifierPackage; + + private final PackageUsage mPackageUsage = new PackageUsage(); + + private class PackageUsage { + private static final int WRITE_INTERVAL + = (DEBUG_DEXOPT) ? 0 : 30*60*1000; // 30m in ms + + private final Object mFileLock = new Object(); + private final AtomicLong mLastWritten = new AtomicLong(0); + private final AtomicBoolean mBackgroundWriteRunning = new AtomicBoolean(false); + + private boolean mIsFirstBoot = false; + + boolean isFirstBoot() { + return mIsFirstBoot; + } + + void write(boolean force) { + if (force) { + write(); + return; + } + if (SystemClock.elapsedRealtime() - mLastWritten.get() < WRITE_INTERVAL + && !DEBUG_DEXOPT) { + return; + } + if (mBackgroundWriteRunning.compareAndSet(false, true)) { + new Thread("PackageUsage_DiskWriter") { + @Override + public void run() { + try { + write(true); + } finally { + mBackgroundWriteRunning.set(false); + } + } + }.start(); + } + } + + private void write() { + synchronized (mPackages) { + synchronized (mFileLock) { + AtomicFile file = getFile(); + FileOutputStream f = null; + try { + f = file.startWrite(); + BufferedOutputStream out = new BufferedOutputStream(f); + FileUtils.setPermissions(file.getBaseFile().getPath(), 0660, SYSTEM_UID, PACKAGE_INFO_GID); + StringBuilder sb = new StringBuilder(); + for (PackageParser.Package pkg : mPackages.values()) { + if (pkg.mLastPackageUsageTimeInMills == 0) { + continue; + } + sb.setLength(0); + sb.append(pkg.packageName); + sb.append(' '); + sb.append((long)pkg.mLastPackageUsageTimeInMills); + sb.append('\n'); + out.write(sb.toString().getBytes(StandardCharsets.US_ASCII)); + } + out.flush(); + file.finishWrite(f); + } catch (IOException e) { + if (f != null) { + file.failWrite(f); + } + Log.e(TAG, "Failed to write package usage times", e); + } + } + } + mLastWritten.set(SystemClock.elapsedRealtime()); + } + + void readLP() { + synchronized (mFileLock) { + AtomicFile file = getFile(); + BufferedInputStream in = null; + try { + in = new BufferedInputStream(file.openRead()); + StringBuffer sb = new StringBuffer(); + while (true) { + String packageName = readToken(in, sb, ' '); + if (packageName == null) { + break; + } + String timeInMillisString = readToken(in, sb, '\n'); + if (timeInMillisString == null) { + throw new IOException("Failed to find last usage time for package " + + packageName); + } + PackageParser.Package pkg = mPackages.get(packageName); + if (pkg == null) { + continue; + } + long timeInMillis; + try { + timeInMillis = Long.parseLong(timeInMillisString.toString()); + } catch (NumberFormatException e) { + throw new IOException("Failed to parse " + timeInMillisString + + " as a long.", e); + } + pkg.mLastPackageUsageTimeInMills = timeInMillis; + } + } catch (FileNotFoundException expected) { + mIsFirstBoot = true; + } catch (IOException e) { + Log.w(TAG, "Failed to read package usage times", e); + } finally { + IoUtils.closeQuietly(in); + } + } + mLastWritten.set(SystemClock.elapsedRealtime()); + } + + private String readToken(InputStream in, StringBuffer sb, char endOfToken) + throws IOException { + sb.setLength(0); + while (true) { + int ch = in.read(); + if (ch == -1) { + if (sb.length() == 0) { + return null; + } + throw new IOException("Unexpected EOF"); + } + if (ch == endOfToken) { + return sb.toString(); + } + sb.append((char)ch); + } + } + + private AtomicFile getFile() { + File dataDir = Environment.getDataDirectory(); + File systemDir = new File(dataDir, "system"); + File fname = new File(systemDir, "package-usage.list"); + return new AtomicFile(fname); + } + } + + class PackageHandler extends Handler { + private boolean mBound = false; + final ArrayList mPendingInstalls = + new ArrayList(); + + private boolean connectToService() { + if (DEBUG_SD_INSTALL) Log.i(TAG, "Trying to bind to" + + " DefaultContainerService"); + Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT); + Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT); + if (mContext.bindServiceAsUser(service, mDefContainerConn, + Context.BIND_AUTO_CREATE, UserHandle.OWNER)) { + Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); + mBound = true; + return true; + } + Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); + return false; + } + + private void disconnectService() { + mContainerService = null; + mBound = false; + Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT); + mContext.unbindService(mDefContainerConn); + Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); + } + + PackageHandler(Looper looper) { + super(looper); + } + + public void handleMessage(Message msg) { + try { + doHandleMessage(msg); + } finally { + Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); + } + } + + void doHandleMessage(Message msg) { + switch (msg.what) { + case INIT_COPY: { + HandlerParams params = (HandlerParams) msg.obj; + int idx = mPendingInstalls.size(); + if (DEBUG_INSTALL) Slog.i(TAG, "init_copy idx=" + idx + ": " + params); + // If a bind was already initiated we dont really + // need to do anything. The pending install + // will be processed later on. + if (!mBound) { + // If this is the only one pending we might + // have to bind to the service again. + if (!connectToService()) { + Slog.e(TAG, "Failed to bind to media container service"); + params.serviceError(); + return; + } else { + // Once we bind to the service, the first + // pending request will be processed. + mPendingInstalls.add(idx, params); + } + } else { + mPendingInstalls.add(idx, params); + // Already bound to the service. Just make + // sure we trigger off processing the first request. + if (idx == 0) { + mHandler.sendEmptyMessage(MCS_BOUND); + } + } + break; + } + case MCS_BOUND: { + if (DEBUG_INSTALL) Slog.i(TAG, "mcs_bound"); + if (msg.obj != null) { + mContainerService = (IMediaContainerService) msg.obj; + } + if (mContainerService == null) { + // Something seriously wrong. Bail out + Slog.e(TAG, "Cannot bind to media container service"); + for (HandlerParams params : mPendingInstalls) { + // Indicate service bind error + params.serviceError(); + } + mPendingInstalls.clear(); + } else if (mPendingInstalls.size() > 0) { + HandlerParams params = mPendingInstalls.get(0); + if (params != null) { + if (params.startCopy()) { + // We are done... look for more work or to + // go idle. + if (DEBUG_SD_INSTALL) Log.i(TAG, + "Checking for more work or unbind..."); + // Delete pending install + if (mPendingInstalls.size() > 0) { + mPendingInstalls.remove(0); + } + if (mPendingInstalls.size() == 0) { + if (mBound) { + if (DEBUG_SD_INSTALL) Log.i(TAG, + "Posting delayed MCS_UNBIND"); + removeMessages(MCS_UNBIND); + Message ubmsg = obtainMessage(MCS_UNBIND); + // Unbind after a little delay, to avoid + // continual thrashing. + sendMessageDelayed(ubmsg, 10000); + } + } else { + // There are more pending requests in queue. + // Just post MCS_BOUND message to trigger processing + // of next pending install. + if (DEBUG_SD_INSTALL) Log.i(TAG, + "Posting MCS_BOUND for next woek"); + mHandler.sendEmptyMessage(MCS_BOUND); + } + } + } + } else { + // Should never happen ideally. + Slog.w(TAG, "Empty queue"); + } + break; + } + case MCS_RECONNECT: { + if (DEBUG_INSTALL) Slog.i(TAG, "mcs_reconnect"); + if (mPendingInstalls.size() > 0) { + if (mBound) { + disconnectService(); + } + if (!connectToService()) { + Slog.e(TAG, "Failed to bind to media container service"); + for (HandlerParams params : mPendingInstalls) { + // Indicate service bind error + params.serviceError(); + } + mPendingInstalls.clear(); + } + } + break; + } + case MCS_UNBIND: { + // If there is no actual work left, then time to unbind. + if (DEBUG_INSTALL) Slog.i(TAG, "mcs_unbind"); + + if (mPendingInstalls.size() == 0 && mPendingVerification.size() == 0) { + if (mBound) { + if (DEBUG_INSTALL) Slog.i(TAG, "calling disconnectService()"); + + disconnectService(); + } + } else if (mPendingInstalls.size() > 0) { + // There are more pending requests in queue. + // Just post MCS_BOUND message to trigger processing + // of next pending install. + mHandler.sendEmptyMessage(MCS_BOUND); + } + + break; + } + case MCS_GIVE_UP: { + if (DEBUG_INSTALL) Slog.i(TAG, "mcs_giveup too many retries"); + mPendingInstalls.remove(0); + break; + } + case SEND_PENDING_BROADCAST: { + String packages[]; + ArrayList components[]; + int size = 0; + int uids[]; + Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT); + synchronized (mPackages) { + if (mPendingBroadcasts == null) { + return; + } + size = mPendingBroadcasts.size(); + if (size <= 0) { + // Nothing to be done. Just return + return; + } + packages = new String[size]; + components = new ArrayList[size]; + uids = new int[size]; + int i = 0; // filling out the above arrays + + for (int n = 0; n < mPendingBroadcasts.userIdCount(); n++) { + int packageUserId = mPendingBroadcasts.userIdAt(n); + Iterator>> it + = mPendingBroadcasts.packagesForUserId(packageUserId) + .entrySet().iterator(); + while (it.hasNext() && i < size) { + Map.Entry> ent = it.next(); + packages[i] = ent.getKey(); + components[i] = ent.getValue(); + PackageSetting ps = mSettings.mPackages.get(ent.getKey()); + uids[i] = (ps != null) + ? UserHandle.getUid(packageUserId, ps.appId) + : -1; + i++; + } + } + size = i; + mPendingBroadcasts.clear(); + } + // Send broadcasts + for (int i = 0; i < size; i++) { + sendPackageChangedBroadcast(packages[i], true, components[i], uids[i]); + } + Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); + break; + } + case START_CLEANING_PACKAGE: { + Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT); + final String packageName = (String)msg.obj; + final int userId = msg.arg1; + final boolean andCode = msg.arg2 != 0; + synchronized (mPackages) { + if (userId == UserHandle.USER_ALL) { + int[] users = sUserManager.getUserIds(); + for (int user : users) { + mSettings.addPackageToCleanLPw( + new PackageCleanItem(user, packageName, andCode)); + } + } else { + mSettings.addPackageToCleanLPw( + new PackageCleanItem(userId, packageName, andCode)); + } + } + Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); + startCleaningPackages(); + } break; + case POST_INSTALL: { + if (DEBUG_INSTALL) Log.v(TAG, "Handling post-install for " + msg.arg1); + PostInstallData data = mRunningInstalls.get(msg.arg1); + mRunningInstalls.delete(msg.arg1); + boolean deleteOld = false; + + if (data != null) { + InstallArgs args = data.args; + PackageInstalledInfo res = data.res; + + if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) { + res.removedInfo.sendBroadcast(false, true, false); + Bundle extras = new Bundle(1); + extras.putInt(Intent.EXTRA_UID, res.uid); + // Determine the set of users who are adding this + // package for the first time vs. those who are seeing + // an update. + int[] firstUsers; + int[] updateUsers = new int[0]; + if (res.origUsers == null || res.origUsers.length == 0) { + firstUsers = res.newUsers; + } else { + firstUsers = new int[0]; + for (int i=0; i AVAILABLE"); + } + int[] uidArray = new int[] { res.pkg.applicationInfo.uid }; + ArrayList pkgList = new ArrayList(1); + pkgList.add(res.pkg.applicationInfo.packageName); + sendResourcesChangedBroadcast(true, false, + pkgList,uidArray, null); + } + } + if (res.removedInfo.args != null) { + // Remove the replaced package's older resources safely now + deleteOld = true; + } + + // Log current value of "unknown sources" setting + EventLog.writeEvent(EventLogTags.UNKNOWN_SOURCES_ENABLED, + getUnknownSourcesSettings()); + } + // Force a gc to clear up things + Runtime.getRuntime().gc(); + // We delete after a gc for applications on sdcard. + if (deleteOld) { + synchronized (mInstallLock) { + res.removedInfo.args.doPostDeleteLI(true); + } + } + if (args.observer != null) { + try { + args.observer.packageInstalled(res.name, res.returnCode); + } catch (RemoteException e) { + Slog.i(TAG, "Observer no longer exists."); + } + } + } else { + Slog.e(TAG, "Bogus post-install token " + msg.arg1); + } + } break; + case UPDATED_MEDIA_STATUS: { + if (DEBUG_SD_INSTALL) Log.i(TAG, "Got message UPDATED_MEDIA_STATUS"); + boolean reportStatus = msg.arg1 == 1; + boolean doGc = msg.arg2 == 1; + if (DEBUG_SD_INSTALL) Log.i(TAG, "reportStatus=" + reportStatus + ", doGc = " + doGc); + if (doGc) { + // Force a gc to clear up stale containers. + Runtime.getRuntime().gc(); + } + if (msg.obj != null) { + @SuppressWarnings("unchecked") + Set args = (Set) msg.obj; + if (DEBUG_SD_INSTALL) Log.i(TAG, "Unloading all containers"); + // Unload containers + unloadAllContainers(args); + } + if (reportStatus) { + try { + if (DEBUG_SD_INSTALL) Log.i(TAG, "Invoking MountService call back"); + PackageHelper.getMountService().finishMediaUpdate(); + } catch (RemoteException e) { + Log.e(TAG, "MountService not running?"); + } + } + } break; + case WRITE_SETTINGS: { + Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT); + synchronized (mPackages) { + removeMessages(WRITE_SETTINGS); + removeMessages(WRITE_PACKAGE_RESTRICTIONS); + mSettings.writeLPr(); + mDirtyUsers.clear(); + } + Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); + } break; + case WRITE_PACKAGE_RESTRICTIONS: { + Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT); + synchronized (mPackages) { + removeMessages(WRITE_PACKAGE_RESTRICTIONS); + for (int userId : mDirtyUsers) { + mSettings.writePackageRestrictionsLPr(userId); + } + mDirtyUsers.clear(); + } + Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); + } break; + case CHECK_PENDING_VERIFICATION: { + final int verificationId = msg.arg1; + final PackageVerificationState state = mPendingVerification.get(verificationId); + + if ((state != null) && !state.timeoutExtended()) { + final InstallArgs args = state.getInstallArgs(); + Slog.i(TAG, "Verification timed out for " + args.packageURI.toString()); + mPendingVerification.remove(verificationId); + + int ret = PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE; + + if (getDefaultVerificationResponse() == PackageManager.VERIFICATION_ALLOW) { + Slog.i(TAG, "Continuing with installation of " + + args.packageURI.toString()); + state.setVerifierResponse(Binder.getCallingUid(), + PackageManager.VERIFICATION_ALLOW_WITHOUT_SUFFICIENT); + broadcastPackageVerified(verificationId, args.packageURI, + PackageManager.VERIFICATION_ALLOW, + state.getInstallArgs().getUser()); + try { + ret = args.copyApk(mContainerService, true); + } catch (RemoteException e) { + Slog.e(TAG, "Could not contact the ContainerService"); + } + } else { + broadcastPackageVerified(verificationId, args.packageURI, + PackageManager.VERIFICATION_REJECT, + state.getInstallArgs().getUser()); + } + + processPendingInstall(args, ret); + mHandler.sendEmptyMessage(MCS_UNBIND); + } + break; + } + case PACKAGE_VERIFIED: { + final int verificationId = msg.arg1; + + final PackageVerificationState state = mPendingVerification.get(verificationId); + if (state == null) { + Slog.w(TAG, "Invalid verification token " + verificationId + " received"); + break; + } + + final PackageVerificationResponse response = (PackageVerificationResponse) msg.obj; + + state.setVerifierResponse(response.callerUid, response.code); + + if (state.isVerificationComplete()) { + mPendingVerification.remove(verificationId); + + final InstallArgs args = state.getInstallArgs(); + + int ret; + if (state.isInstallAllowed()) { + ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR; + broadcastPackageVerified(verificationId, args.packageURI, + response.code, state.getInstallArgs().getUser()); + try { + ret = args.copyApk(mContainerService, true); + } catch (RemoteException e) { + Slog.e(TAG, "Could not contact the ContainerService"); + } + } else { + ret = PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE; + } + + processPendingInstall(args, ret); + + mHandler.sendEmptyMessage(MCS_UNBIND); + } + + break; + } + } + } + } + + void scheduleWriteSettingsLocked() { + if (!mHandler.hasMessages(WRITE_SETTINGS)) { + mHandler.sendEmptyMessageDelayed(WRITE_SETTINGS, WRITE_SETTINGS_DELAY); + } + } + + void scheduleWritePackageRestrictionsLocked(int userId) { + if (!sUserManager.exists(userId)) return; + mDirtyUsers.add(userId); + if (!mHandler.hasMessages(WRITE_PACKAGE_RESTRICTIONS)) { + mHandler.sendEmptyMessageDelayed(WRITE_PACKAGE_RESTRICTIONS, WRITE_SETTINGS_DELAY); + } + } + + public static final IPackageManager main(Context context, Installer installer, + boolean factoryTest, boolean onlyCore) { + PackageManagerService m = new PackageManagerService(context, installer, + factoryTest, onlyCore); + ServiceManager.addService("package", m); + return m; + } + + static String[] splitString(String str, char sep) { + int count = 1; + int i = 0; + while ((i=str.indexOf(sep, i)) >= 0) { + count++; + i++; + } + + String[] res = new String[count]; + i=0; + count = 0; + int lastI=0; + while ((i=str.indexOf(sep, i)) >= 0) { + res[count] = str.substring(lastI, i); + count++; + i++; + lastI = i; + } + res[count] = str.substring(lastI, str.length()); + return res; + } + + public PackageManagerService(Context context, Installer installer, + boolean factoryTest, boolean onlyCore) { + EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START, + SystemClock.uptimeMillis()); + + if (mSdkVersion <= 0) { + Slog.w(TAG, "**** ro.build.version.sdk not set!"); + } + + mContext = context; + mFactoryTest = factoryTest; + mOnlyCore = onlyCore; + mMetrics = new DisplayMetrics(); + mSettings = new Settings(context); + mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID, + ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED); + mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID, + ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED); + mSettings.addSharedUserLPw("android.uid.log", LOG_UID, + ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED); + mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID, + ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED); + mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID, + ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED); + mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID, + ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED); + + String separateProcesses = SystemProperties.get("debug.separate_processes"); + if (separateProcesses != null && separateProcesses.length() > 0) { + if ("*".equals(separateProcesses)) { + mDefParseFlags = PackageParser.PARSE_IGNORE_PROCESSES; + mSeparateProcesses = null; + Slog.w(TAG, "Running with debug.separate_processes: * (ALL)"); + } else { + mDefParseFlags = 0; + mSeparateProcesses = separateProcesses.split(","); + Slog.w(TAG, "Running with debug.separate_processes: " + + separateProcesses); + } + } else { + mDefParseFlags = 0; + mSeparateProcesses = null; + } + + mInstaller = installer; + + WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE); + Display d = wm.getDefaultDisplay(); + d.getMetrics(mMetrics); + + synchronized (mInstallLock) { + // writer + synchronized (mPackages) { + mHandlerThread.start(); + mHandler = new PackageHandler(mHandlerThread.getLooper()); + Watchdog.getInstance().addThread(mHandler, mHandlerThread.getName(), + WATCHDOG_TIMEOUT); + + File dataDir = Environment.getDataDirectory(); + mAppDataDir = new File(dataDir, "data"); + mAppInstallDir = new File(dataDir, "app"); + mAppLibInstallDir = new File(dataDir, "app-lib"); + mAsecInternalPath = new File(dataDir, "app-asec").getPath(); + mUserAppDataDir = new File(dataDir, "user"); + mDrmAppPrivateInstallDir = new File(dataDir, "app-private"); + + sUserManager = new UserManagerService(context, this, + mInstallLock, mPackages); + + readPermissions(); + + mFoundPolicyFile = SELinuxMMAC.readInstallPolicy(); + + mRestoredSettings = mSettings.readLPw(this, sUserManager.getUsers(false), + mSdkVersion, mOnlyCore); + + String customResolverActivity = Resources.getSystem().getString( + R.string.config_customResolverActivity); + if (TextUtils.isEmpty(customResolverActivity)) { + customResolverActivity = null; + } else { + mCustomResolverComponentName = ComponentName.unflattenFromString( + customResolverActivity); + } + + long startTime = SystemClock.uptimeMillis(); + + EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START, + startTime); + + // Set flag to monitor and not change apk file paths when + // scanning install directories. + int scanMode = SCAN_MONITOR | SCAN_NO_PATHS | SCAN_DEFER_DEX | SCAN_BOOTING; + + final HashSet alreadyDexOpted = new HashSet(); + + /** + * Add everything in the in the boot class path to the + * list of process files because dexopt will have been run + * if necessary during zygote startup. + */ + String bootClassPath = System.getProperty("java.boot.class.path"); + if (bootClassPath != null) { + String[] paths = splitString(bootClassPath, ':'); + for (int i=0; i instructionSets = getAllInstructionSets(); + + /** + * Ensure all external libraries have had dexopt run on them. + */ + if (mSharedLibraries.size() > 0) { + // NOTE: For now, we're compiling these system "shared libraries" + // (and framework jars) into all available architectures. It's possible + // to compile them only when we come across an app that uses them (there's + // already logic for that in scanPackageLI) but that adds some complexity. + for (String instructionSet : instructionSets) { + for (SharedLibraryEntry libEntry : mSharedLibraries.values()) { + final String lib = libEntry.path; + if (lib == null) { + continue; + } + + try { + if (DexFile.isDexOptNeededInternal(lib, null, instructionSet, false)) { + alreadyDexOpted.add(lib); + + // The list of "shared libraries" we have at this point is + mInstaller.dexopt(lib, Process.SYSTEM_UID, true, instructionSet); + didDexOptLibraryOrTool = true; + } + } catch (FileNotFoundException e) { + Slog.w(TAG, "Library not found: " + lib); + } catch (IOException e) { + Slog.w(TAG, "Cannot dexopt " + lib + "; is it an APK or JAR? " + + e.getMessage()); + } + } + } + } + + File frameworkDir = new File(Environment.getRootDirectory(), "framework"); + + // Gross hack for now: we know this file doesn't contain any + // code, so don't dexopt it to avoid the resulting log spew. + alreadyDexOpted.add(frameworkDir.getPath() + "/framework-res.apk"); + + // Gross hack for now: we know this file is only part of + // the boot class path for art, so don't dexopt it to + // avoid the resulting log spew. + alreadyDexOpted.add(frameworkDir.getPath() + "/core-libart.jar"); + + /** + * And there are a number of commands implemented in Java, which + * we currently need to do the dexopt on so that they can be + * run from a non-root shell. + */ + String[] frameworkFiles = frameworkDir.list(); + if (frameworkFiles != null) { + // TODO: We could compile these only for the most preferred ABI. We should + // first double check that the dex files for these commands are not referenced + // by other system apps. + for (String instructionSet : instructionSets) { + for (int i=0; i possiblyDeletedUpdatedSystemApps = new ArrayList(); + if (!mOnlyCore) { + Iterator psit = mSettings.mPackages.values().iterator(); + while (psit.hasNext()) { + PackageSetting ps = psit.next(); + + /* + * If this is not a system app, it can't be a + * disable system app. + */ + if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) { + continue; + } + + /* + * If the package is scanned, it's not erased. + */ + final PackageParser.Package scannedPkg = mPackages.get(ps.name); + if (scannedPkg != null) { + /* + * If the system app is both scanned and in the + * disabled packages list, then it must have been + * added via OTA. Remove it from the currently + * scanned package so the previously user-installed + * application can be scanned. + */ + if (mSettings.isDisabledSystemPackageLPr(ps.name)) { + Slog.i(TAG, "Expecting better updatd system app for " + ps.name + + "; removing system app"); + removePackageLI(ps, true); + } + + continue; + } + + if (!mSettings.isDisabledSystemPackageLPr(ps.name)) { + psit.remove(); + String msg = "System package " + ps.name + + " no longer exists; wiping its data"; + reportSettingsProblem(Log.WARN, msg); + removeDataDirsLI(ps.name); + } else { + final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(ps.name); + if (disabledPs.codePath == null || !disabledPs.codePath.exists()) { + possiblyDeletedUpdatedSystemApps.add(ps.name); + } + } + } + } + + //look for any incomplete package installations + ArrayList deletePkgsList = mSettings.getListOfIncompleteInstallPackagesLPr(); + //clean up list + for(int i = 0; i < deletePkgsList.size(); i++) { + //clean up here + cleanupInstallFailedPackage(deletePkgsList.get(i)); + } + //delete tmp files + deleteTempPackageFiles(); + + // Remove any shared userIDs that have no associated packages + mSettings.pruneSharedUsersLPw(); + + if (!mOnlyCore) { + EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START, + SystemClock.uptimeMillis()); + mAppInstallObserver = new AppDirObserver( + mAppInstallDir.getPath(), OBSERVER_EVENTS, false, false); + mAppInstallObserver.startWatching(); + scanDirLI(mAppInstallDir, 0, scanMode, 0); + + mDrmAppInstallObserver = new AppDirObserver( + mDrmAppPrivateInstallDir.getPath(), OBSERVER_EVENTS, false, false); + mDrmAppInstallObserver.startWatching(); + scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK, + scanMode, 0); + + /** + * Remove disable package settings for any updated system + * apps that were removed via an OTA. If they're not a + * previously-updated app, remove them completely. + * Otherwise, just revoke their system-level permissions. + */ + for (String deletedAppName : possiblyDeletedUpdatedSystemApps) { + PackageParser.Package deletedPkg = mPackages.get(deletedAppName); + mSettings.removeDisabledSystemPackageLPw(deletedAppName); + + String msg; + if (deletedPkg == null) { + msg = "Updated system package " + deletedAppName + + " no longer exists; wiping its data"; + removeDataDirsLI(deletedAppName); + } else { + msg = "Updated system app + " + deletedAppName + + " no longer present; removing system privileges for " + + deletedAppName; + + deletedPkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_SYSTEM; + + PackageSetting deletedPs = mSettings.mPackages.get(deletedAppName); + deletedPs.pkgFlags &= ~ApplicationInfo.FLAG_SYSTEM; + } + reportSettingsProblem(Log.WARN, msg); + } + } else { + mAppInstallObserver = null; + mDrmAppInstallObserver = null; + } + + // Now that we know all of the shared libraries, update all clients to have + // the correct library paths. + updateAllSharedLibrariesLPw(); + + for (SharedUserSetting setting : mSettings.getAllSharedUsersLPw()) { + adjustCpuAbisForSharedUserLPw(setting.packages, true /* do dexopt */, + false /* force dexopt */, false /* defer dexopt */); + } + + // Now that we know all the packages we are keeping, + // read and update their last usage times. + mPackageUsage.readLP(); + + EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END, + SystemClock.uptimeMillis()); + Slog.i(TAG, "Time to scan packages: " + + ((SystemClock.uptimeMillis()-startTime)/1000f) + + " seconds"); + + // If the platform SDK has changed since the last time we booted, + // we need to re-grant app permission to catch any new ones that + // appear. This is really a hack, and means that apps can in some + // cases get permissions that the user didn't initially explicitly + // allow... it would be nice to have some better way to handle + // this situation. + final boolean regrantPermissions = mSettings.mInternalSdkPlatform + != mSdkVersion; + if (regrantPermissions) Slog.i(TAG, "Platform changed from " + + mSettings.mInternalSdkPlatform + " to " + mSdkVersion + + "; regranting permissions for internal storage"); + mSettings.mInternalSdkPlatform = mSdkVersion; + + updatePermissionsLPw(null, null, UPDATE_PERMISSIONS_ALL + | (regrantPermissions + ? (UPDATE_PERMISSIONS_REPLACE_PKG|UPDATE_PERMISSIONS_REPLACE_ALL) + : 0)); + + // If this is the first boot, and it is a normal boot, then + // we need to initialize the default preferred apps. + if (!mRestoredSettings && !onlyCore) { + mSettings.readDefaultPreferredAppsLPw(this, 0); + } + + // can downgrade to reader + mSettings.writeLPr(); + + EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY, + SystemClock.uptimeMillis()); + + // Now after opening every single application zip, make sure they + // are all flushed. Not really needed, but keeps things nice and + // tidy. + Runtime.getRuntime().gc(); + + mRequiredVerifierPackage = getRequiredVerifierLPr(); + } // synchronized (mPackages) + } // synchronized (mInstallLock) + } + + private static void pruneDexFiles(File cacheDir) { + // If we had to do a dexopt of one of the previous + // things, then something on the system has changed. + // Consider this significant, and wipe away all other + // existing dexopt files to ensure we don't leave any + // dangling around. + // + // Additionally, delete all dex files from the root directory + // since there shouldn't be any there anyway. + // + // Note: This isn't as good an indicator as it used to be. It + // used to include the boot classpath but at some point + // DexFile.isDexOptNeeded started returning false for the boot + // class path files in all cases. It is very possible in a + // small maintenance release update that the library and tool + // jars may be unchanged but APK could be removed resulting in + // unused dalvik-cache files. + File[] files = cacheDir.listFiles(); + if (files != null) { + for (File file : files) { + if (!file.isDirectory()) { + Slog.i(TAG, "Pruning dalvik file: " + file.getAbsolutePath()); + file.delete(); + } else { + File[] subDirList = file.listFiles(); + if (subDirList != null) { + for (File subDirFile : subDirList) { + final String fn = subDirFile.getName(); + if (fn.startsWith("data@app@") || fn.startsWith("data@app-private@")) { + Slog.i(TAG, "Pruning dalvik file: " + fn); + subDirFile.delete(); + } + } + } + } + } + } + } + + @Override + public boolean isFirstBoot() { + return !mRestoredSettings || mPackageUsage.isFirstBoot(); + } + + @Override + public boolean isOnlyCoreApps() { + return mOnlyCore; + } + + private String getRequiredVerifierLPr() { + final Intent verification = new Intent(Intent.ACTION_PACKAGE_NEEDS_VERIFICATION); + final List receivers = queryIntentReceivers(verification, PACKAGE_MIME_TYPE, + PackageManager.GET_DISABLED_COMPONENTS, 0 /* TODO: Which userId? */); + + String requiredVerifier = null; + + final int N = receivers.size(); + for (int i = 0; i < N; i++) { + final ResolveInfo info = receivers.get(i); + + if (info.activityInfo == null) { + continue; + } + + final String packageName = info.activityInfo.packageName; + + final PackageSetting ps = mSettings.mPackages.get(packageName); + if (ps == null) { + continue; + } + + final GrantedPermissions gp = ps.sharedUser != null ? ps.sharedUser : ps; + if (!gp.grantedPermissions + .contains(android.Manifest.permission.PACKAGE_VERIFICATION_AGENT)) { + continue; + } + + if (requiredVerifier != null) { + throw new RuntimeException("There can be only one required verifier"); + } + + requiredVerifier = packageName; + } + + return requiredVerifier; + } + + @Override + public boolean onTransact(int code, Parcel data, Parcel reply, int flags) + throws RemoteException { + try { + return super.onTransact(code, data, reply, flags); + } catch (RuntimeException e) { + if (!(e instanceof SecurityException) && !(e instanceof IllegalArgumentException)) { + Slog.wtf(TAG, "Package Manager Crash", e); + } + throw e; + } + } + + void cleanupInstallFailedPackage(PackageSetting ps) { + Slog.i(TAG, "Cleaning up incompletely installed app: " + ps.name); + removeDataDirsLI(ps.name); + if (ps.codePath != null) { + if (!ps.codePath.delete()) { + Slog.w(TAG, "Unable to remove old code file: " + ps.codePath); + } + } + if (ps.resourcePath != null) { + if (!ps.resourcePath.delete() && !ps.resourcePath.equals(ps.codePath)) { + Slog.w(TAG, "Unable to remove old code file: " + ps.resourcePath); + } + } + mSettings.removePackageLPw(ps.name); + } + + void readPermissions() { + // Read permissions from .../etc/permission directory. + File libraryDir = new File(Environment.getRootDirectory(), "etc/permissions"); + if (!libraryDir.exists() || !libraryDir.isDirectory()) { + Slog.w(TAG, "No directory " + libraryDir + ", skipping"); + return; + } + if (!libraryDir.canRead()) { + Slog.w(TAG, "Directory " + libraryDir + " cannot be read"); + return; + } + + // Iterate over the files in the directory and scan .xml files + for (File f : libraryDir.listFiles()) { + // We'll read platform.xml last + if (f.getPath().endsWith("etc/permissions/platform.xml")) { + continue; + } + + if (!f.getPath().endsWith(".xml")) { + Slog.i(TAG, "Non-xml file " + f + " in " + libraryDir + " directory, ignoring"); + continue; + } + if (!f.canRead()) { + Slog.w(TAG, "Permissions library file " + f + " cannot be read"); + continue; + } + + readPermissionsFromXml(f); + } + + // Read permissions from .../etc/permissions/platform.xml last so it will take precedence + final File permFile = new File(Environment.getRootDirectory(), + "etc/permissions/platform.xml"); + readPermissionsFromXml(permFile); + } + + private void readPermissionsFromXml(File permFile) { + FileReader permReader = null; + try { + permReader = new FileReader(permFile); + } catch (FileNotFoundException e) { + Slog.w(TAG, "Couldn't find or open permissions file " + permFile); + return; + } + + try { + XmlPullParser parser = Xml.newPullParser(); + parser.setInput(permReader); + + XmlUtils.beginDocument(parser, "permissions"); + + while (true) { + XmlUtils.nextElement(parser); + if (parser.getEventType() == XmlPullParser.END_DOCUMENT) { + break; + } + + String name = parser.getName(); + if ("group".equals(name)) { + String gidStr = parser.getAttributeValue(null, "gid"); + if (gidStr != null) { + int gid = Process.getGidForName(gidStr); + mGlobalGids = appendInt(mGlobalGids, gid); + } else { + Slog.w(TAG, " without gid at " + + parser.getPositionDescription()); + } + + XmlUtils.skipCurrentTag(parser); + continue; + } else if ("permission".equals(name)) { + String perm = parser.getAttributeValue(null, "name"); + if (perm == null) { + Slog.w(TAG, " without name at " + + parser.getPositionDescription()); + XmlUtils.skipCurrentTag(parser); + continue; + } + perm = perm.intern(); + readPermission(parser, perm); + + } else if ("assign-permission".equals(name)) { + String perm = parser.getAttributeValue(null, "name"); + if (perm == null) { + Slog.w(TAG, " without name at " + + parser.getPositionDescription()); + XmlUtils.skipCurrentTag(parser); + continue; + } + String uidStr = parser.getAttributeValue(null, "uid"); + if (uidStr == null) { + Slog.w(TAG, " without uid at " + + parser.getPositionDescription()); + XmlUtils.skipCurrentTag(parser); + continue; + } + int uid = Process.getUidForName(uidStr); + if (uid < 0) { + Slog.w(TAG, " with unknown uid \"" + + uidStr + "\" at " + + parser.getPositionDescription()); + XmlUtils.skipCurrentTag(parser); + continue; + } + perm = perm.intern(); + HashSet perms = mSystemPermissions.get(uid); + if (perms == null) { + perms = new HashSet(); + mSystemPermissions.put(uid, perms); + } + perms.add(perm); + XmlUtils.skipCurrentTag(parser); + + } else if ("library".equals(name)) { + String lname = parser.getAttributeValue(null, "name"); + String lfile = parser.getAttributeValue(null, "file"); + if (lname == null) { + Slog.w(TAG, " without name at " + + parser.getPositionDescription()); + } else if (lfile == null) { + Slog.w(TAG, " without file at " + + parser.getPositionDescription()); + } else { + //Log.i(TAG, "Got library " + lname + " in " + lfile); + mSharedLibraries.put(lname, new SharedLibraryEntry(lfile, null)); + } + XmlUtils.skipCurrentTag(parser); + continue; + + } else if ("feature".equals(name)) { + String fname = parser.getAttributeValue(null, "name"); + if (fname == null) { + Slog.w(TAG, " without name at " + + parser.getPositionDescription()); + } else { + //Log.i(TAG, "Got feature " + fname); + FeatureInfo fi = new FeatureInfo(); + fi.name = fname; + mAvailableFeatures.put(fname, fi); + } + XmlUtils.skipCurrentTag(parser); + continue; + + } else { + XmlUtils.skipCurrentTag(parser); + continue; + } + + } + permReader.close(); + } catch (XmlPullParserException e) { + Slog.w(TAG, "Got execption parsing permissions.", e); + } catch (IOException e) { + Slog.w(TAG, "Got execption parsing permissions.", e); + } + } + + void readPermission(XmlPullParser parser, String name) + throws IOException, XmlPullParserException { + + name = name.intern(); + + BasePermission bp = mSettings.mPermissions.get(name); + if (bp == null) { + bp = new BasePermission(name, null, BasePermission.TYPE_BUILTIN); + mSettings.mPermissions.put(name, bp); + } + int outerDepth = parser.getDepth(); + int type; + while ((type=parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG + || parser.getDepth() > outerDepth)) { + if (type == XmlPullParser.END_TAG + || type == XmlPullParser.TEXT) { + continue; + } + + String tagName = parser.getName(); + if ("group".equals(tagName)) { + String gidStr = parser.getAttributeValue(null, "gid"); + if (gidStr != null) { + int gid = Process.getGidForName(gidStr); + bp.gids = appendInt(bp.gids, gid); + } else { + Slog.w(TAG, " without gid at " + + parser.getPositionDescription()); + } + } + XmlUtils.skipCurrentTag(parser); + } + } + + static int[] appendInts(int[] cur, int[] add) { + if (add == null) return cur; + if (cur == null) return add; + final int N = add.length; + for (int i=0; i=0; i--) { + PackageSetting ps = mSettings.mPackages.get(names[i]); + out[i] = ps != null && ps.realName != null ? ps.realName : names[i]; + } + } + return out; + } + + @Override + public String[] canonicalToCurrentPackageNames(String[] names) { + String[] out = new String[names.length]; + // reader + synchronized (mPackages) { + for (int i=names.length-1; i>=0; i--) { + String cur = mSettings.mRenamedPackages.get(names[i]); + out[i] = cur != null ? cur : names[i]; + } + } + return out; + } + + @Override + public int getPackageUid(String packageName, int userId) { + if (!sUserManager.exists(userId)) return -1; + enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "get package uid"); + // reader + synchronized (mPackages) { + PackageParser.Package p = mPackages.get(packageName); + if(p != null) { + return UserHandle.getUid(userId, p.applicationInfo.uid); + } + PackageSetting ps = mSettings.mPackages.get(packageName); + if((ps == null) || (ps.pkg == null) || (ps.pkg.applicationInfo == null)) { + return -1; + } + p = ps.pkg; + return p != null ? UserHandle.getUid(userId, p.applicationInfo.uid) : -1; + } + } + + @Override + public int[] getPackageGids(String packageName) { + // reader + synchronized (mPackages) { + PackageParser.Package p = mPackages.get(packageName); + if (DEBUG_PACKAGE_INFO) + Log.v(TAG, "getPackageGids" + packageName + ": " + p); + if (p != null) { + final PackageSetting ps = (PackageSetting)p.mExtras; + return ps.getGids(); + } + } + // stupid thing to indicate an error. + return new int[0]; + } + + static final PermissionInfo generatePermissionInfo( + BasePermission bp, int flags) { + if (bp.perm != null) { + return PackageParser.generatePermissionInfo(bp.perm, flags); + } + PermissionInfo pi = new PermissionInfo(); + pi.name = bp.name; + pi.packageName = bp.sourcePackage; + pi.nonLocalizedLabel = bp.name; + pi.protectionLevel = bp.protectionLevel; + return pi; + } + + @Override + public PermissionInfo getPermissionInfo(String name, int flags) { + // reader + synchronized (mPackages) { + final BasePermission p = mSettings.mPermissions.get(name); + if (p != null) { + return generatePermissionInfo(p, flags); + } + return null; + } + } + + @Override + public List queryPermissionsByGroup(String group, int flags) { + // reader + synchronized (mPackages) { + ArrayList out = new ArrayList(10); + for (BasePermission p : mSettings.mPermissions.values()) { + if (group == null) { + if (p.perm == null || p.perm.info.group == null) { + out.add(generatePermissionInfo(p, flags)); + } + } else { + if (p.perm != null && group.equals(p.perm.info.group)) { + out.add(PackageParser.generatePermissionInfo(p.perm, flags)); + } + } + } + + if (out.size() > 0) { + return out; + } + return mPermissionGroups.containsKey(group) ? out : null; + } + } + + @Override + public PermissionGroupInfo getPermissionGroupInfo(String name, int flags) { + // reader + synchronized (mPackages) { + return PackageParser.generatePermissionGroupInfo( + mPermissionGroups.get(name), flags); + } + } + + @Override + public List getAllPermissionGroups(int flags) { + // reader + synchronized (mPackages) { + final int N = mPermissionGroups.size(); + ArrayList out + = new ArrayList(N); + for (PackageParser.PermissionGroup pg : mPermissionGroups.values()) { + out.add(PackageParser.generatePermissionGroupInfo(pg, flags)); + } + return out; + } + } + + private ApplicationInfo generateApplicationInfoFromSettingsLPw(String packageName, int flags, + int userId) { + if (!sUserManager.exists(userId)) return null; + PackageSetting ps = mSettings.mPackages.get(packageName); + if (ps != null) { + if (ps.pkg == null) { + PackageInfo pInfo = generatePackageInfoFromSettingsLPw(packageName, + flags, userId); + if (pInfo != null) { + return pInfo.applicationInfo; + } + return null; + } + return PackageParser.generateApplicationInfo(ps.pkg, flags, + ps.readUserState(userId), userId); + } + return null; + } + + private PackageInfo generatePackageInfoFromSettingsLPw(String packageName, int flags, + int userId) { + if (!sUserManager.exists(userId)) return null; + PackageSetting ps = mSettings.mPackages.get(packageName); + if (ps != null) { + PackageParser.Package pkg = ps.pkg; + if (pkg == null) { + if ((flags & PackageManager.GET_UNINSTALLED_PACKAGES) == 0) { + return null; + } + pkg = new PackageParser.Package(packageName); + pkg.applicationInfo.packageName = packageName; + pkg.applicationInfo.flags = ps.pkgFlags | ApplicationInfo.FLAG_IS_DATA_ONLY; + pkg.applicationInfo.publicSourceDir = ps.resourcePathString; + pkg.applicationInfo.sourceDir = ps.codePathString; + pkg.applicationInfo.dataDir = + getDataPathForPackage(packageName, 0).getPath(); + pkg.applicationInfo.nativeLibraryDir = ps.nativeLibraryPathString; + pkg.applicationInfo.requiredCpuAbi = ps.requiredCpuAbiString; + } + return generatePackageInfo(pkg, flags, userId); + } + return null; + } + + @Override + public ApplicationInfo getApplicationInfo(String packageName, int flags, int userId) { + if (!sUserManager.exists(userId)) return null; + enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "get application info"); + // writer + synchronized (mPackages) { + PackageParser.Package p = mPackages.get(packageName); + if (DEBUG_PACKAGE_INFO) Log.v( + TAG, "getApplicationInfo " + packageName + + ": " + p); + if (p != null) { + PackageSetting ps = mSettings.mPackages.get(packageName); + if (ps == null) return null; + // Note: isEnabledLP() does not apply here - always return info + return PackageParser.generateApplicationInfo( + p, flags, ps.readUserState(userId), userId); + } + if ("android".equals(packageName)||"system".equals(packageName)) { + return mAndroidApplication; + } + if ((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) { + return generateApplicationInfoFromSettingsLPw(packageName, flags, userId); + } + } + return null; + } + + + @Override + public void freeStorageAndNotify(final long freeStorageSize, final IPackageDataObserver observer) { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.CLEAR_APP_CACHE, null); + // Queue up an async operation since clearing cache may take a little while. + mHandler.post(new Runnable() { + public void run() { + mHandler.removeCallbacks(this); + int retCode = -1; + synchronized (mInstallLock) { + retCode = mInstaller.freeCache(freeStorageSize); + if (retCode < 0) { + Slog.w(TAG, "Couldn't clear application caches"); + } + } + if (observer != null) { + try { + observer.onRemoveCompleted(null, (retCode >= 0)); + } catch (RemoteException e) { + Slog.w(TAG, "RemoveException when invoking call back"); + } + } + } + }); + } + + @Override + public void freeStorage(final long freeStorageSize, final IntentSender pi) { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.CLEAR_APP_CACHE, null); + // Queue up an async operation since clearing cache may take a little while. + mHandler.post(new Runnable() { + public void run() { + mHandler.removeCallbacks(this); + int retCode = -1; + synchronized (mInstallLock) { + retCode = mInstaller.freeCache(freeStorageSize); + if (retCode < 0) { + Slog.w(TAG, "Couldn't clear application caches"); + } + } + if(pi != null) { + try { + // Callback via pending intent + int code = (retCode >= 0) ? 1 : 0; + pi.sendIntent(null, code, null, + null, null); + } catch (SendIntentException e1) { + Slog.i(TAG, "Failed to send pending intent"); + } + } + } + }); + } + + @Override + public ActivityInfo getActivityInfo(ComponentName component, int flags, int userId) { + if (!sUserManager.exists(userId)) return null; + enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "get activity info"); + synchronized (mPackages) { + PackageParser.Activity a = mActivities.mActivities.get(component); + + if (DEBUG_PACKAGE_INFO) Log.v(TAG, "getActivityInfo " + component + ": " + a); + if (a != null && mSettings.isEnabledLPr(a.info, flags, userId)) { + PackageSetting ps = mSettings.mPackages.get(component.getPackageName()); + if (ps == null) return null; + return PackageParser.generateActivityInfo(a, flags, ps.readUserState(userId), + userId); + } + if (mResolveComponentName.equals(component)) { + return mResolveActivity; + } + } + return null; + } + + @Override + public ActivityInfo getReceiverInfo(ComponentName component, int flags, int userId) { + if (!sUserManager.exists(userId)) return null; + enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "get receiver info"); + synchronized (mPackages) { + PackageParser.Activity a = mReceivers.mActivities.get(component); + if (DEBUG_PACKAGE_INFO) Log.v( + TAG, "getReceiverInfo " + component + ": " + a); + if (a != null && mSettings.isEnabledLPr(a.info, flags, userId)) { + PackageSetting ps = mSettings.mPackages.get(component.getPackageName()); + if (ps == null) return null; + return PackageParser.generateActivityInfo(a, flags, ps.readUserState(userId), + userId); + } + } + return null; + } + + @Override + public ServiceInfo getServiceInfo(ComponentName component, int flags, int userId) { + if (!sUserManager.exists(userId)) return null; + enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "get service info"); + synchronized (mPackages) { + PackageParser.Service s = mServices.mServices.get(component); + if (DEBUG_PACKAGE_INFO) Log.v( + TAG, "getServiceInfo " + component + ": " + s); + if (s != null && mSettings.isEnabledLPr(s.info, flags, userId)) { + PackageSetting ps = mSettings.mPackages.get(component.getPackageName()); + if (ps == null) return null; + return PackageParser.generateServiceInfo(s, flags, ps.readUserState(userId), + userId); + } + } + return null; + } + + @Override + public ProviderInfo getProviderInfo(ComponentName component, int flags, int userId) { + if (!sUserManager.exists(userId)) return null; + enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "get provider info"); + synchronized (mPackages) { + PackageParser.Provider p = mProviders.mProviders.get(component); + if (DEBUG_PACKAGE_INFO) Log.v( + TAG, "getProviderInfo " + component + ": " + p); + if (p != null && mSettings.isEnabledLPr(p.info, flags, userId)) { + PackageSetting ps = mSettings.mPackages.get(component.getPackageName()); + if (ps == null) return null; + return PackageParser.generateProviderInfo(p, flags, ps.readUserState(userId), + userId); + } + } + return null; + } + + @Override + public String[] getSystemSharedLibraryNames() { + Set libSet; + synchronized (mPackages) { + libSet = mSharedLibraries.keySet(); + int size = libSet.size(); + if (size > 0) { + String[] libs = new String[size]; + libSet.toArray(libs); + return libs; + } + } + return null; + } + + @Override + public FeatureInfo[] getSystemAvailableFeatures() { + Collection featSet; + synchronized (mPackages) { + featSet = mAvailableFeatures.values(); + int size = featSet.size(); + if (size > 0) { + FeatureInfo[] features = new FeatureInfo[size+1]; + featSet.toArray(features); + FeatureInfo fi = new FeatureInfo(); + fi.reqGlEsVersion = SystemProperties.getInt("ro.opengles.version", + FeatureInfo.GL_ES_VERSION_UNDEFINED); + features[size] = fi; + return features; + } + } + return null; + } + + @Override + public boolean hasSystemFeature(String name) { + synchronized (mPackages) { + return mAvailableFeatures.containsKey(name); + } + } + + private void checkValidCaller(int uid, int userId) { + if (UserHandle.getUserId(uid) == userId || uid == Process.SYSTEM_UID || uid == 0) + return; + + throw new SecurityException("Caller uid=" + uid + + " is not privileged to communicate with user=" + userId); + } + + @Override + public int checkPermission(String permName, String pkgName) { + synchronized (mPackages) { + PackageParser.Package p = mPackages.get(pkgName); + if (p != null && p.mExtras != null) { + PackageSetting ps = (PackageSetting)p.mExtras; + if (ps.sharedUser != null) { + if (ps.sharedUser.grantedPermissions.contains(permName)) { + return PackageManager.PERMISSION_GRANTED; + } + } else if (ps.grantedPermissions.contains(permName)) { + return PackageManager.PERMISSION_GRANTED; + } + } + } + return PackageManager.PERMISSION_DENIED; + } + + @Override + public int checkUidPermission(String permName, int uid) { + synchronized (mPackages) { + Object obj = mSettings.getUserIdLPr(UserHandle.getAppId(uid)); + if (obj != null) { + GrantedPermissions gp = (GrantedPermissions)obj; + if (gp.grantedPermissions.contains(permName)) { + return PackageManager.PERMISSION_GRANTED; + } + } else { + HashSet perms = mSystemPermissions.get(uid); + if (perms != null && perms.contains(permName)) { + return PackageManager.PERMISSION_GRANTED; + } + } + } + return PackageManager.PERMISSION_DENIED; + } + + /** + * Checks if the request is from the system or an app that has INTERACT_ACROSS_USERS + * or INTERACT_ACROSS_USERS_FULL permissions, if the userid is not for the caller. + * @param message the message to log on security exception + * @return + */ + private void enforceCrossUserPermission(int callingUid, int userId, + boolean requireFullPermission, String message) { + if (userId < 0) { + throw new IllegalArgumentException("Invalid userId " + userId); + } + if (userId == UserHandle.getUserId(callingUid)) return; + if (callingUid != Process.SYSTEM_UID && callingUid != 0) { + if (requireFullPermission) { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, message); + } else { + try { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, message); + } catch (SecurityException se) { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.INTERACT_ACROSS_USERS, message); + } + } + } + } + + private BasePermission findPermissionTreeLP(String permName) { + for(BasePermission bp : mSettings.mPermissionTrees.values()) { + if (permName.startsWith(bp.name) && + permName.length() > bp.name.length() && + permName.charAt(bp.name.length()) == '.') { + return bp; + } + } + return null; + } + + private BasePermission checkPermissionTreeLP(String permName) { + if (permName != null) { + BasePermission bp = findPermissionTreeLP(permName); + if (bp != null) { + if (bp.uid == UserHandle.getAppId(Binder.getCallingUid())) { + return bp; + } + throw new SecurityException("Calling uid " + + Binder.getCallingUid() + + " is not allowed to add to permission tree " + + bp.name + " owned by uid " + bp.uid); + } + } + throw new SecurityException("No permission tree found for " + permName); + } + + static boolean compareStrings(CharSequence s1, CharSequence s2) { + if (s1 == null) { + return s2 == null; + } + if (s2 == null) { + return false; + } + if (s1.getClass() != s2.getClass()) { + return false; + } + return s1.equals(s2); + } + + static boolean comparePermissionInfos(PermissionInfo pi1, PermissionInfo pi2) { + if (pi1.icon != pi2.icon) return false; + if (pi1.logo != pi2.logo) return false; + if (pi1.protectionLevel != pi2.protectionLevel) return false; + if (!compareStrings(pi1.name, pi2.name)) return false; + if (!compareStrings(pi1.nonLocalizedLabel, pi2.nonLocalizedLabel)) return false; + // We'll take care of setting this one. + if (!compareStrings(pi1.packageName, pi2.packageName)) return false; + // These are not currently stored in settings. + //if (!compareStrings(pi1.group, pi2.group)) return false; + //if (!compareStrings(pi1.nonLocalizedDescription, pi2.nonLocalizedDescription)) return false; + //if (pi1.labelRes != pi2.labelRes) return false; + //if (pi1.descriptionRes != pi2.descriptionRes) return false; + return true; + } + + boolean addPermissionLocked(PermissionInfo info, boolean async) { + if (info.labelRes == 0 && info.nonLocalizedLabel == null) { + throw new SecurityException("Label must be specified in permission"); + } + BasePermission tree = checkPermissionTreeLP(info.name); + BasePermission bp = mSettings.mPermissions.get(info.name); + boolean added = bp == null; + boolean changed = true; + int fixedLevel = PermissionInfo.fixProtectionLevel(info.protectionLevel); + if (added) { + bp = new BasePermission(info.name, tree.sourcePackage, + BasePermission.TYPE_DYNAMIC); + } else if (bp.type != BasePermission.TYPE_DYNAMIC) { + throw new SecurityException( + "Not allowed to modify non-dynamic permission " + + info.name); + } else { + if (bp.protectionLevel == fixedLevel + && bp.perm.owner.equals(tree.perm.owner) + && bp.uid == tree.uid + && comparePermissionInfos(bp.perm.info, info)) { + changed = false; + } + } + bp.protectionLevel = fixedLevel; + info = new PermissionInfo(info); + info.protectionLevel = fixedLevel; + bp.perm = new PackageParser.Permission(tree.perm.owner, info); + bp.perm.info.packageName = tree.perm.info.packageName; + bp.uid = tree.uid; + if (added) { + mSettings.mPermissions.put(info.name, bp); + } + if (changed) { + if (!async) { + mSettings.writeLPr(); + } else { + scheduleWriteSettingsLocked(); + } + } + return added; + } + + @Override + public boolean addPermission(PermissionInfo info) { + synchronized (mPackages) { + return addPermissionLocked(info, false); + } + } + + @Override + public boolean addPermissionAsync(PermissionInfo info) { + synchronized (mPackages) { + return addPermissionLocked(info, true); + } + } + + @Override + public void removePermission(String name) { + synchronized (mPackages) { + checkPermissionTreeLP(name); + BasePermission bp = mSettings.mPermissions.get(name); + if (bp != null) { + if (bp.type != BasePermission.TYPE_DYNAMIC) { + throw new SecurityException( + "Not allowed to modify non-dynamic permission " + + name); + } + mSettings.mPermissions.remove(name); + mSettings.writeLPr(); + } + } + } + + private static void checkGrantRevokePermissions(PackageParser.Package pkg, BasePermission bp) { + int index = pkg.requestedPermissions.indexOf(bp.name); + if (index == -1) { + throw new SecurityException("Package " + pkg.packageName + + " has not requested permission " + bp.name); + } + boolean isNormal = + ((bp.protectionLevel&PermissionInfo.PROTECTION_MASK_BASE) + == PermissionInfo.PROTECTION_NORMAL); + boolean isDangerous = + ((bp.protectionLevel&PermissionInfo.PROTECTION_MASK_BASE) + == PermissionInfo.PROTECTION_DANGEROUS); + boolean isDevelopment = + ((bp.protectionLevel&PermissionInfo.PROTECTION_FLAG_DEVELOPMENT) != 0); + + if (!isNormal && !isDangerous && !isDevelopment) { + throw new SecurityException("Permission " + bp.name + + " is not a changeable permission type"); + } + + if (isNormal || isDangerous) { + if (pkg.requestedPermissionsRequired.get(index)) { + throw new SecurityException("Can't change " + bp.name + + ". It is required by the application"); + } + } + } + + @Override + public void grantPermission(String packageName, String permissionName) { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.GRANT_REVOKE_PERMISSIONS, null); + synchronized (mPackages) { + final PackageParser.Package pkg = mPackages.get(packageName); + if (pkg == null) { + throw new IllegalArgumentException("Unknown package: " + packageName); + } + final BasePermission bp = mSettings.mPermissions.get(permissionName); + if (bp == null) { + throw new IllegalArgumentException("Unknown permission: " + permissionName); + } + + checkGrantRevokePermissions(pkg, bp); + + final PackageSetting ps = (PackageSetting) pkg.mExtras; + if (ps == null) { + return; + } + final GrantedPermissions gp = (ps.sharedUser != null) ? ps.sharedUser : ps; + if (gp.grantedPermissions.add(permissionName)) { + if (ps.haveGids) { + gp.gids = appendInts(gp.gids, bp.gids); + } + mSettings.writeLPr(); + } + } + } + + @Override + public void revokePermission(String packageName, String permissionName) { + int changedAppId = -1; + + synchronized (mPackages) { + final PackageParser.Package pkg = mPackages.get(packageName); + if (pkg == null) { + throw new IllegalArgumentException("Unknown package: " + packageName); + } + if (pkg.applicationInfo.uid != Binder.getCallingUid()) { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.GRANT_REVOKE_PERMISSIONS, null); + } + final BasePermission bp = mSettings.mPermissions.get(permissionName); + if (bp == null) { + throw new IllegalArgumentException("Unknown permission: " + permissionName); + } + + checkGrantRevokePermissions(pkg, bp); + + final PackageSetting ps = (PackageSetting) pkg.mExtras; + if (ps == null) { + return; + } + final GrantedPermissions gp = (ps.sharedUser != null) ? ps.sharedUser : ps; + if (gp.grantedPermissions.remove(permissionName)) { + gp.grantedPermissions.remove(permissionName); + if (ps.haveGids) { + gp.gids = removeInts(gp.gids, bp.gids); + } + mSettings.writeLPr(); + changedAppId = ps.appId; + } + } + + if (changedAppId >= 0) { + // We changed the perm on someone, kill its processes. + IActivityManager am = ActivityManagerNative.getDefault(); + if (am != null) { + final int callingUserId = UserHandle.getCallingUserId(); + final long ident = Binder.clearCallingIdentity(); + try { + //XXX we should only revoke for the calling user's app permissions, + // but for now we impact all users. + //am.killUid(UserHandle.getUid(callingUserId, changedAppId), + // "revoke " + permissionName); + int[] users = sUserManager.getUserIds(); + for (int user : users) { + am.killUid(UserHandle.getUid(user, changedAppId), + "revoke " + permissionName); + } + } catch (RemoteException e) { + } finally { + Binder.restoreCallingIdentity(ident); + } + } + } + } + + @Override + public boolean isProtectedBroadcast(String actionName) { + synchronized (mPackages) { + return mProtectedBroadcasts.contains(actionName); + } + } + + @Override + public int checkSignatures(String pkg1, String pkg2) { + synchronized (mPackages) { + final PackageParser.Package p1 = mPackages.get(pkg1); + final PackageParser.Package p2 = mPackages.get(pkg2); + if (p1 == null || p1.mExtras == null + || p2 == null || p2.mExtras == null) { + return PackageManager.SIGNATURE_UNKNOWN_PACKAGE; + } + return compareSignatures(p1.mSignatures, p2.mSignatures); + } + } + + @Override + public int checkUidSignatures(int uid1, int uid2) { + // Map to base uids. + uid1 = UserHandle.getAppId(uid1); + uid2 = UserHandle.getAppId(uid2); + // reader + synchronized (mPackages) { + Signature[] s1; + Signature[] s2; + Object obj = mSettings.getUserIdLPr(uid1); + if (obj != null) { + if (obj instanceof SharedUserSetting) { + s1 = ((SharedUserSetting)obj).signatures.mSignatures; + } else if (obj instanceof PackageSetting) { + s1 = ((PackageSetting)obj).signatures.mSignatures; + } else { + return PackageManager.SIGNATURE_UNKNOWN_PACKAGE; + } + } else { + return PackageManager.SIGNATURE_UNKNOWN_PACKAGE; + } + obj = mSettings.getUserIdLPr(uid2); + if (obj != null) { + if (obj instanceof SharedUserSetting) { + s2 = ((SharedUserSetting)obj).signatures.mSignatures; + } else if (obj instanceof PackageSetting) { + s2 = ((PackageSetting)obj).signatures.mSignatures; + } else { + return PackageManager.SIGNATURE_UNKNOWN_PACKAGE; + } + } else { + return PackageManager.SIGNATURE_UNKNOWN_PACKAGE; + } + return compareSignatures(s1, s2); + } + } + + static int compareSignatures(Signature[] s1, Signature[] s2) { + if (s1 == null) { + return s2 == null + ? PackageManager.SIGNATURE_NEITHER_SIGNED + : PackageManager.SIGNATURE_FIRST_NOT_SIGNED; + } + if (s2 == null) { + return PackageManager.SIGNATURE_SECOND_NOT_SIGNED; + } + HashSet set1 = new HashSet(); + for (Signature sig : s1) { + set1.add(sig); + } + HashSet set2 = new HashSet(); + for (Signature sig : s2) { + set2.add(sig); + } + // Make sure s2 contains all signatures in s1. + if (set1.equals(set2)) { + return PackageManager.SIGNATURE_MATCH; + } + return PackageManager.SIGNATURE_NO_MATCH; + } + + @Override + public String[] getPackagesForUid(int uid) { + uid = UserHandle.getAppId(uid); + // reader + synchronized (mPackages) { + Object obj = mSettings.getUserIdLPr(uid); + if (obj instanceof SharedUserSetting) { + final SharedUserSetting sus = (SharedUserSetting) obj; + final int N = sus.packages.size(); + final String[] res = new String[N]; + final Iterator it = sus.packages.iterator(); + int i = 0; + while (it.hasNext()) { + res[i++] = it.next().name; + } + return res; + } else if (obj instanceof PackageSetting) { + final PackageSetting ps = (PackageSetting) obj; + return new String[] { ps.name }; + } + } + return null; + } + + @Override + public String getNameForUid(int uid) { + // reader + synchronized (mPackages) { + Object obj = mSettings.getUserIdLPr(UserHandle.getAppId(uid)); + if (obj instanceof SharedUserSetting) { + final SharedUserSetting sus = (SharedUserSetting) obj; + return sus.name + ":" + sus.userId; + } else if (obj instanceof PackageSetting) { + final PackageSetting ps = (PackageSetting) obj; + return ps.name; + } + } + return null; + } + + @Override + public int getUidForSharedUser(String sharedUserName) { + if(sharedUserName == null) { + return -1; + } + // reader + synchronized (mPackages) { + final SharedUserSetting suid = mSettings.getSharedUserLPw(sharedUserName, 0, false); + if (suid == null) { + return -1; + } + return suid.userId; + } + } + + @Override + public int getFlagsForUid(int uid) { + synchronized (mPackages) { + Object obj = mSettings.getUserIdLPr(UserHandle.getAppId(uid)); + if (obj instanceof SharedUserSetting) { + final SharedUserSetting sus = (SharedUserSetting) obj; + return sus.pkgFlags; + } else if (obj instanceof PackageSetting) { + final PackageSetting ps = (PackageSetting) obj; + return ps.pkgFlags; + } + } + return 0; + } + + @Override + public ResolveInfo resolveIntent(Intent intent, String resolvedType, + int flags, int userId) { + if (!sUserManager.exists(userId)) return null; + enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "resolve intent"); + List query = queryIntentActivities(intent, resolvedType, flags, userId); + return chooseBestActivity(intent, resolvedType, flags, query, userId); + } + + @Override + public void setLastChosenActivity(Intent intent, String resolvedType, int flags, + IntentFilter filter, int match, ComponentName activity) { + final int userId = UserHandle.getCallingUserId(); + if (DEBUG_PREFERRED) { + Log.v(TAG, "setLastChosenActivity intent=" + intent + + " resolvedType=" + resolvedType + + " flags=" + flags + + " filter=" + filter + + " match=" + match + + " activity=" + activity); + filter.dump(new PrintStreamPrinter(System.out), " "); + } + intent.setComponent(null); + List query = queryIntentActivities(intent, resolvedType, flags, userId); + // Find any earlier preferred or last chosen entries and nuke them + findPreferredActivity(intent, resolvedType, + flags, query, 0, false, true, false, userId); + // Add the new activity as the last chosen for this filter + addPreferredActivityInternal(filter, match, null, activity, false, userId); + } + + @Override + public ResolveInfo getLastChosenActivity(Intent intent, String resolvedType, int flags) { + final int userId = UserHandle.getCallingUserId(); + if (DEBUG_PREFERRED) Log.v(TAG, "Querying last chosen activity for " + intent); + List query = queryIntentActivities(intent, resolvedType, flags, userId); + return findPreferredActivity(intent, resolvedType, flags, query, 0, + false, false, false, userId); + } + + private ResolveInfo chooseBestActivity(Intent intent, String resolvedType, + int flags, List query, int userId) { + if (query != null) { + final int N = query.size(); + if (N == 1) { + return query.get(0); + } else if (N > 1) { + final boolean debug = ((intent.getFlags() & Intent.FLAG_DEBUG_LOG_RESOLUTION) != 0); + // If there is more than one activity with the same priority, + // then let the user decide between them. + ResolveInfo r0 = query.get(0); + ResolveInfo r1 = query.get(1); + if (DEBUG_INTENT_MATCHING || debug) { + Slog.v(TAG, r0.activityInfo.name + "=" + r0.priority + " vs " + + r1.activityInfo.name + "=" + r1.priority); + } + // If the first activity has a higher priority, or a different + // default, then it is always desireable to pick it. + if (r0.priority != r1.priority + || r0.preferredOrder != r1.preferredOrder + || r0.isDefault != r1.isDefault) { + return query.get(0); + } + // If we have saved a preference for a preferred activity for + // this Intent, use that. + ResolveInfo ri = findPreferredActivity(intent, resolvedType, + flags, query, r0.priority, true, false, debug, userId); + if (ri != null) { + return ri; + } + if (userId != 0) { + ri = new ResolveInfo(mResolveInfo); + ri.activityInfo = new ActivityInfo(ri.activityInfo); + ri.activityInfo.applicationInfo = new ApplicationInfo( + ri.activityInfo.applicationInfo); + ri.activityInfo.applicationInfo.uid = UserHandle.getUid(userId, + UserHandle.getAppId(ri.activityInfo.applicationInfo.uid)); + return ri; + } + return mResolveInfo; + } + } + return null; + } + + ResolveInfo findPreferredActivity(Intent intent, String resolvedType, int flags, + List query, int priority, boolean always, + boolean removeMatches, boolean debug, int userId) { + if (!sUserManager.exists(userId)) return null; + // writer + synchronized (mPackages) { + if (intent.getSelector() != null) { + intent = intent.getSelector(); + } + if (DEBUG_PREFERRED) intent.addFlags(Intent.FLAG_DEBUG_LOG_RESOLUTION); + PreferredIntentResolver pir = mSettings.mPreferredActivities.get(userId); + // Get the list of preferred activities that handle the intent + if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Looking for preferred activities..."); + List prefs = pir != null + ? pir.queryIntent(intent, resolvedType, + (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, userId) + : null; + if (prefs != null && prefs.size() > 0) { + // First figure out how good the original match set is. + // We will only allow preferred activities that came + // from the same match quality. + int match = 0; + + if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Figuring out best match..."); + + final int N = query.size(); + for (int j=0; j match) { + match = ri.match; + } + } + + if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Best match: 0x" + + Integer.toHexString(match)); + + match &= IntentFilter.MATCH_CATEGORY_MASK; + final int M = prefs.size(); + for (int i=0; i") + + "\n component=" + pa.mPref.mComponent); + pa.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " "); + } + if (pa.mPref.mMatch != match) { + if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Skipping bad match " + + Integer.toHexString(pa.mPref.mMatch)); + continue; + } + // If it's not an "always" type preferred activity and that's what we're + // looking for, skip it. + if (always && !pa.mPref.mAlways) { + if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Skipping mAlways=false entry"); + continue; + } + final ActivityInfo ai = getActivityInfo(pa.mPref.mComponent, + flags | PackageManager.GET_DISABLED_COMPONENTS, userId); + if (DEBUG_PREFERRED || debug) { + Slog.v(TAG, "Found preferred activity:"); + if (ai != null) { + ai.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " "); + } else { + Slog.v(TAG, " null"); + } + } + if (ai == null) { + // This previously registered preferred activity + // component is no longer known. Most likely an update + // to the app was installed and in the new version this + // component no longer exists. Clean it up by removing + // it from the preferred activities list, and skip it. + Slog.w(TAG, "Removing dangling preferred activity: " + + pa.mPref.mComponent); + pir.removeFilter(pa); + continue; + } + for (int j=0; j queryIntentActivities(Intent intent, + String resolvedType, int flags, int userId) { + if (!sUserManager.exists(userId)) return Collections.emptyList(); + enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "query intent activities"); + ComponentName comp = intent.getComponent(); + if (comp == null) { + if (intent.getSelector() != null) { + intent = intent.getSelector(); + comp = intent.getComponent(); + } + } + + if (comp != null) { + final List list = new ArrayList(1); + final ActivityInfo ai = getActivityInfo(comp, flags, userId); + if (ai != null) { + final ResolveInfo ri = new ResolveInfo(); + ri.activityInfo = ai; + list.add(ri); + } + return list; + } + + // reader + synchronized (mPackages) { + final String pkgName = intent.getPackage(); + if (pkgName == null) { + return mActivities.queryIntent(intent, resolvedType, flags, userId); + } + final PackageParser.Package pkg = mPackages.get(pkgName); + if (pkg != null) { + return mActivities.queryIntentForPackage(intent, resolvedType, flags, + pkg.activities, userId); + } + return new ArrayList(); + } + } + + @Override + public List queryIntentActivityOptions(ComponentName caller, + Intent[] specifics, String[] specificTypes, Intent intent, + String resolvedType, int flags, int userId) { + if (!sUserManager.exists(userId)) return Collections.emptyList(); + enforceCrossUserPermission(Binder.getCallingUid(), userId, false, + "query intent activity options"); + final String resultsAction = intent.getAction(); + + List results = queryIntentActivities(intent, resolvedType, flags + | PackageManager.GET_RESOLVED_FILTER, userId); + + if (DEBUG_INTENT_MATCHING) { + Log.v(TAG, "Query " + intent + ": " + results); + } + + int specificsPos = 0; + int N; + + // todo: note that the algorithm used here is O(N^2). This + // isn't a problem in our current environment, but if we start running + // into situations where we have more than 5 or 10 matches then this + // should probably be changed to something smarter... + + // First we go through and resolve each of the specific items + // that were supplied, taking care of removing any corresponding + // duplicate items in the generic resolve list. + if (specifics != null) { + for (int i=0; i it = rii.filter.actionsIterator(); + if (it == null) { + continue; + } + while (it.hasNext()) { + final String action = it.next(); + if (resultsAction != null && resultsAction.equals(action)) { + // If this action was explicitly requested, then don't + // remove things that have it. + continue; + } + for (int j=i+1; j queryIntentReceivers(Intent intent, String resolvedType, int flags, + int userId) { + if (!sUserManager.exists(userId)) return Collections.emptyList(); + ComponentName comp = intent.getComponent(); + if (comp == null) { + if (intent.getSelector() != null) { + intent = intent.getSelector(); + comp = intent.getComponent(); + } + } + if (comp != null) { + List list = new ArrayList(1); + ActivityInfo ai = getReceiverInfo(comp, flags, userId); + if (ai != null) { + ResolveInfo ri = new ResolveInfo(); + ri.activityInfo = ai; + list.add(ri); + } + return list; + } + + // reader + synchronized (mPackages) { + String pkgName = intent.getPackage(); + if (pkgName == null) { + return mReceivers.queryIntent(intent, resolvedType, flags, userId); + } + final PackageParser.Package pkg = mPackages.get(pkgName); + if (pkg != null) { + return mReceivers.queryIntentForPackage(intent, resolvedType, flags, pkg.receivers, + userId); + } + return null; + } + } + + @Override + public ResolveInfo resolveService(Intent intent, String resolvedType, int flags, int userId) { + List query = queryIntentServices(intent, resolvedType, flags, userId); + if (!sUserManager.exists(userId)) return null; + if (query != null) { + if (query.size() >= 1) { + // If there is more than one service with the same priority, + // just arbitrarily pick the first one. + return query.get(0); + } + } + return null; + } + + @Override + public List queryIntentServices(Intent intent, String resolvedType, int flags, + int userId) { + if (!sUserManager.exists(userId)) return Collections.emptyList(); + ComponentName comp = intent.getComponent(); + if (comp == null) { + if (intent.getSelector() != null) { + intent = intent.getSelector(); + comp = intent.getComponent(); + } + } + if (comp != null) { + final List list = new ArrayList(1); + final ServiceInfo si = getServiceInfo(comp, flags, userId); + if (si != null) { + final ResolveInfo ri = new ResolveInfo(); + ri.serviceInfo = si; + list.add(ri); + } + return list; + } + + // reader + synchronized (mPackages) { + String pkgName = intent.getPackage(); + if (pkgName == null) { + return mServices.queryIntent(intent, resolvedType, flags, userId); + } + final PackageParser.Package pkg = mPackages.get(pkgName); + if (pkg != null) { + return mServices.queryIntentForPackage(intent, resolvedType, flags, pkg.services, + userId); + } + return null; + } + } + + @Override + public List queryIntentContentProviders( + Intent intent, String resolvedType, int flags, int userId) { + if (!sUserManager.exists(userId)) return Collections.emptyList(); + ComponentName comp = intent.getComponent(); + if (comp == null) { + if (intent.getSelector() != null) { + intent = intent.getSelector(); + comp = intent.getComponent(); + } + } + if (comp != null) { + final List list = new ArrayList(1); + final ProviderInfo pi = getProviderInfo(comp, flags, userId); + if (pi != null) { + final ResolveInfo ri = new ResolveInfo(); + ri.providerInfo = pi; + list.add(ri); + } + return list; + } + + // reader + synchronized (mPackages) { + String pkgName = intent.getPackage(); + if (pkgName == null) { + return mProviders.queryIntent(intent, resolvedType, flags, userId); + } + final PackageParser.Package pkg = mPackages.get(pkgName); + if (pkg != null) { + return mProviders.queryIntentForPackage( + intent, resolvedType, flags, pkg.providers, userId); + } + return null; + } + } + + @Override + public ParceledListSlice getInstalledPackages(int flags, int userId) { + final boolean listUninstalled = (flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0; + + enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "get installed packages"); + + // writer + synchronized (mPackages) { + ArrayList list; + if (listUninstalled) { + list = new ArrayList(mSettings.mPackages.size()); + for (PackageSetting ps : mSettings.mPackages.values()) { + PackageInfo pi; + if (ps.pkg != null) { + pi = generatePackageInfo(ps.pkg, flags, userId); + } else { + pi = generatePackageInfoFromSettingsLPw(ps.name, flags, userId); + } + if (pi != null) { + list.add(pi); + } + } + } else { + list = new ArrayList(mPackages.size()); + for (PackageParser.Package p : mPackages.values()) { + PackageInfo pi = generatePackageInfo(p, flags, userId); + if (pi != null) { + list.add(pi); + } + } + } + + return new ParceledListSlice(list); + } + } + + private void addPackageHoldingPermissions(ArrayList list, PackageSetting ps, + String[] permissions, boolean[] tmp, int flags, int userId) { + int numMatch = 0; + final GrantedPermissions gp = ps.sharedUser != null ? ps.sharedUser : ps; + for (int i=0; i getPackagesHoldingPermissions( + String[] permissions, int flags, int userId) { + if (!sUserManager.exists(userId)) return null; + final boolean listUninstalled = (flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0; + + // writer + synchronized (mPackages) { + ArrayList list = new ArrayList(); + boolean[] tmpBools = new boolean[permissions.length]; + if (listUninstalled) { + for (PackageSetting ps : mSettings.mPackages.values()) { + addPackageHoldingPermissions(list, ps, permissions, tmpBools, flags, userId); + } + } else { + for (PackageParser.Package pkg : mPackages.values()) { + PackageSetting ps = (PackageSetting)pkg.mExtras; + if (ps != null) { + addPackageHoldingPermissions(list, ps, permissions, tmpBools, flags, + userId); + } + } + } + + return new ParceledListSlice(list); + } + } + + @Override + public ParceledListSlice getInstalledApplications(int flags, int userId) { + if (!sUserManager.exists(userId)) return null; + final boolean listUninstalled = (flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0; + + // writer + synchronized (mPackages) { + ArrayList list; + if (listUninstalled) { + list = new ArrayList(mSettings.mPackages.size()); + for (PackageSetting ps : mSettings.mPackages.values()) { + ApplicationInfo ai; + if (ps.pkg != null) { + ai = PackageParser.generateApplicationInfo(ps.pkg, flags, + ps.readUserState(userId), userId); + } else { + ai = generateApplicationInfoFromSettingsLPw(ps.name, flags, userId); + } + if (ai != null) { + list.add(ai); + } + } + } else { + list = new ArrayList(mPackages.size()); + for (PackageParser.Package p : mPackages.values()) { + if (p.mExtras != null) { + ApplicationInfo ai = PackageParser.generateApplicationInfo(p, flags, + ((PackageSetting)p.mExtras).readUserState(userId), userId); + if (ai != null) { + list.add(ai); + } + } + } + } + + return new ParceledListSlice(list); + } + } + + public List getPersistentApplications(int flags) { + final ArrayList finalList = new ArrayList(); + + // reader + synchronized (mPackages) { + final Iterator i = mPackages.values().iterator(); + final int userId = UserHandle.getCallingUserId(); + while (i.hasNext()) { + final PackageParser.Package p = i.next(); + if (p.applicationInfo != null + && (p.applicationInfo.flags&ApplicationInfo.FLAG_PERSISTENT) != 0 + && (!mSafeMode || isSystemApp(p))) { + PackageSetting ps = mSettings.mPackages.get(p.packageName); + if (ps != null) { + ApplicationInfo ai = PackageParser.generateApplicationInfo(p, flags, + ps.readUserState(userId), userId); + if (ai != null) { + finalList.add(ai); + } + } + } + } + } + + return finalList; + } + + @Override + public ProviderInfo resolveContentProvider(String name, int flags, int userId) { + if (!sUserManager.exists(userId)) return null; + // reader + synchronized (mPackages) { + final PackageParser.Provider provider = mProvidersByAuthority.get(name); + PackageSetting ps = provider != null + ? mSettings.mPackages.get(provider.owner.packageName) + : null; + return ps != null + && mSettings.isEnabledLPr(provider.info, flags, userId) + && (!mSafeMode || (provider.info.applicationInfo.flags + &ApplicationInfo.FLAG_SYSTEM) != 0) + ? PackageParser.generateProviderInfo(provider, flags, + ps.readUserState(userId), userId) + : null; + } + } + + /** + * @deprecated + */ + @Deprecated + public void querySyncProviders(List outNames, List outInfo) { + // reader + synchronized (mPackages) { + final Iterator> i = mProvidersByAuthority + .entrySet().iterator(); + final int userId = UserHandle.getCallingUserId(); + while (i.hasNext()) { + Map.Entry entry = i.next(); + PackageParser.Provider p = entry.getValue(); + PackageSetting ps = mSettings.mPackages.get(p.owner.packageName); + + if (ps != null && p.syncable + && (!mSafeMode || (p.info.applicationInfo.flags + &ApplicationInfo.FLAG_SYSTEM) != 0)) { + ProviderInfo info = PackageParser.generateProviderInfo(p, 0, + ps.readUserState(userId), userId); + if (info != null) { + outNames.add(entry.getKey()); + outInfo.add(info); + } + } + } + } + } + + @Override + public List queryContentProviders(String processName, + int uid, int flags) { + ArrayList finalList = null; + // reader + synchronized (mPackages) { + final Iterator i = mProviders.mProviders.values().iterator(); + final int userId = processName != null ? + UserHandle.getUserId(uid) : UserHandle.getCallingUserId(); + while (i.hasNext()) { + final PackageParser.Provider p = i.next(); + PackageSetting ps = mSettings.mPackages.get(p.owner.packageName); + if (ps != null && p.info.authority != null + && (processName == null + || (p.info.processName.equals(processName) + && UserHandle.isSameApp(p.info.applicationInfo.uid, uid))) + && mSettings.isEnabledLPr(p.info, flags, userId) + && (!mSafeMode + || (p.info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0)) { + if (finalList == null) { + finalList = new ArrayList(3); + } + ProviderInfo info = PackageParser.generateProviderInfo(p, flags, + ps.readUserState(userId), userId); + if (info != null) { + finalList.add(info); + } + } + } + } + + if (finalList != null) { + Collections.sort(finalList, mProviderInitOrderSorter); + } + + return finalList; + } + + @Override + public InstrumentationInfo getInstrumentationInfo(ComponentName name, + int flags) { + // reader + synchronized (mPackages) { + final PackageParser.Instrumentation i = mInstrumentation.get(name); + return PackageParser.generateInstrumentationInfo(i, flags); + } + } + + @Override + public List queryInstrumentation(String targetPackage, + int flags) { + ArrayList finalList = + new ArrayList(); + + // reader + synchronized (mPackages) { + final Iterator i = mInstrumentation.values().iterator(); + while (i.hasNext()) { + final PackageParser.Instrumentation p = i.next(); + if (targetPackage == null + || targetPackage.equals(p.info.targetPackage)) { + InstrumentationInfo ii = PackageParser.generateInstrumentationInfo(p, + flags); + if (ii != null) { + finalList.add(ii); + } + } + } + } + + return finalList; + } + + private void createIdmapsForPackageLI(PackageParser.Package pkg) { + HashMap overlays = mOverlays.get(pkg.packageName); + if (overlays == null) { + Slog.w(TAG, "Unable to create idmap for " + pkg.packageName + ": no overlay packages"); + return; + } + for (PackageParser.Package opkg : overlays.values()) { + // Not much to do if idmap fails: we already logged the error + // and we certainly don't want to abort installation of pkg simply + // because an overlay didn't fit properly. For these reasons, + // ignore the return value of createIdmapForPackagePairLI. + createIdmapForPackagePairLI(pkg, opkg); + } + } + + private boolean createIdmapForPackagePairLI(PackageParser.Package pkg, + PackageParser.Package opkg) { + if (!opkg.mTrustedOverlay) { + Slog.w(TAG, "Skipping target and overlay pair " + pkg.mScanPath + " and " + + opkg.mScanPath + ": overlay not trusted"); + return false; + } + HashMap overlaySet = mOverlays.get(pkg.packageName); + if (overlaySet == null) { + Slog.e(TAG, "was about to create idmap for " + pkg.mScanPath + " and " + + opkg.mScanPath + " but target package has no known overlays"); + return false; + } + final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid); + if (mInstaller.idmap(pkg.mScanPath, opkg.mScanPath, sharedGid) != 0) { + Slog.e(TAG, "Failed to generate idmap for " + pkg.mScanPath + " and " + opkg.mScanPath); + return false; + } + PackageParser.Package[] overlayArray = + overlaySet.values().toArray(new PackageParser.Package[0]); + Comparator cmp = new Comparator() { + public int compare(PackageParser.Package p1, PackageParser.Package p2) { + return p1.mOverlayPriority - p2.mOverlayPriority; + } + }; + Arrays.sort(overlayArray, cmp); + + pkg.applicationInfo.resourceDirs = new String[overlayArray.length]; + int i = 0; + for (PackageParser.Package p : overlayArray) { + pkg.applicationInfo.resourceDirs[i++] = p.applicationInfo.sourceDir; + } + return true; + } + + private void scanDirLI(File dir, int flags, int scanMode, long currentTime) { + String[] files = dir.list(); + if (files == null) { + Log.d(TAG, "No files in app dir " + dir); + return; + } + + if (DEBUG_PACKAGE_SCANNING) { + Log.d(TAG, "Scanning app dir " + dir + " scanMode=" + scanMode + + " flags=0x" + Integer.toHexString(flags)); + } + + int i; + for (i=0; i