Merge "Disable verbose RingtonePlayer debugging." into jb-dev
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index e2ebeba..5085b1e 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -275,7 +275,7 @@
}
public String toString() {
- ComponentName componentName = intent.getComponent();
+ ComponentName componentName = intent != null ? intent.getComponent() : null;
return "ActivityRecord{"
+ Integer.toHexString(System.identityHashCode(this))
+ " token=" + token + " " + (componentName == null
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index c791e47..da09a18 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -810,11 +810,17 @@
* <p>
* As a convenience, an Intent of this form can be created with the
* {@link #createChooser} function.
- * <p>Input: No data should be specified. get*Extra must have
+ * <p>
+ * If the target {@link #EXTRA_INTENT} contains {@link ClipData}, you should
+ * also copy it to this intent along with relevant flags, such as
+ * {@link #FLAG_GRANT_READ_URI_PERMISSION}.
+ * <p>
+ * Input: No data should be specified. get*Extra must have
* a {@link #EXTRA_INTENT} field containing the Intent being executed,
* and can optionally have a {@link #EXTRA_TITLE} field containing the
* title text to display in the chooser.
- * <p>Output: Depends on the protocol of {@link #EXTRA_INTENT}.
+ * <p>
+ * Output: Depends on the protocol of {@link #EXTRA_INTENT}.
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_CHOOSER = "android.intent.action.CHOOSER";
@@ -835,8 +841,17 @@
if (title != null) {
intent.putExtra(EXTRA_TITLE, title);
}
+
+ // Migrate any clip data and flags from target.
+ final ClipData targetClipData = target.getClipData();
+ if (targetClipData != null) {
+ intent.setClipData(targetClipData);
+ intent.addFlags(target.getFlags()
+ & (FLAG_GRANT_READ_URI_PERMISSION | FLAG_GRANT_WRITE_URI_PERMISSION));
+ }
return intent;
}
+
/**
* Activity Action: Allow the user to select a particular kind of data and
* return it. This is different than {@link #ACTION_PICK} in that here we
@@ -6587,19 +6602,35 @@
/**
* Migrate any {@link #EXTRA_STREAM} in {@link #ACTION_SEND} and
- * {@link #ACTION_SEND_MULTIPLE} to {@link ClipData}.
+ * {@link #ACTION_SEND_MULTIPLE} to {@link ClipData}. Also inspects nested
+ * intents in {@link #ACTION_CHOOSER}.
*
+ * @return Whether any contents were migrated.
* @hide
*/
- public void migrateExtraStreamToClipData() {
+ public boolean migrateExtraStreamToClipData() {
// Refuse to touch if extras already parcelled
- if (mExtras != null && mExtras.isParcelled()) return;
+ if (mExtras != null && mExtras.isParcelled()) return false;
// Bail when someone already gave us ClipData
- if (getClipData() != null) return;
+ if (getClipData() != null) return false;
final String action = getAction();
- if (ACTION_SEND.equals(action)) {
+ if (ACTION_CHOOSER.equals(action)) {
+ // Inspect target intent to see if we need to migrate
+ final Intent target = getParcelableExtra(EXTRA_INTENT);
+ if (target.migrateExtraStreamToClipData()) {
+ // Since we migrated in child, we need to promote ClipData and
+ // flags to ourselves to grant.
+ setClipData(target.getClipData());
+ addFlags(target.getFlags()
+ & (FLAG_GRANT_READ_URI_PERMISSION | FLAG_GRANT_WRITE_URI_PERMISSION));
+ return true;
+ } else {
+ return false;
+ }
+
+ } else if (ACTION_SEND.equals(action)) {
try {
final Uri stream = getParcelableExtra(EXTRA_STREAM);
final CharSequence text = getCharSequenceExtra(EXTRA_TEXT);
@@ -6610,6 +6641,7 @@
new ClipData.Item(text, htmlText, null, stream));
setClipData(clipData);
addFlags(FLAG_GRANT_READ_URI_PERMISSION);
+ return true;
}
} catch (ClassCastException e) {
}
@@ -6626,14 +6658,14 @@
if (texts != null) {
if (num >= 0 && num != texts.size()) {
// Wha...! F- you.
- return;
+ return false;
}
num = texts.size();
}
if (htmlTexts != null) {
if (num >= 0 && num != htmlTexts.size()) {
// Wha...! F- you.
- return;
+ return false;
}
num = htmlTexts.size();
}
@@ -6648,10 +6680,13 @@
setClipData(clipData);
addFlags(FLAG_GRANT_READ_URI_PERMISSION);
+ return true;
}
} catch (ClassCastException e) {
}
}
+
+ return false;
}
private static ClipData.Item makeClipItem(ArrayList<Uri> streams, ArrayList<CharSequence> texts,
diff --git a/core/java/android/preference/VolumePreference.java b/core/java/android/preference/VolumePreference.java
index fe5e76c..caf55d7 100644
--- a/core/java/android/preference/VolumePreference.java
+++ b/core/java/android/preference/VolumePreference.java
@@ -239,9 +239,7 @@
public void onChange(boolean selfChange) {
super.onChange(selfChange);
if (mSeekBar != null && mAudioManager != null) {
- int volume = mAudioManager.isStreamMute(mStreamType) ?
- mAudioManager.getLastAudibleStreamVolume(mStreamType)
- : mAudioManager.getStreamVolume(mStreamType);
+ int volume = mAudioManager.getStreamVolume(mStreamType);
mSeekBar.setProgress(volume);
}
}
diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java
index d42757d..16f9a18 100644
--- a/core/java/android/view/AccessibilityInteractionController.java
+++ b/core/java/android/view/AccessibilityInteractionController.java
@@ -330,7 +330,7 @@
if (provider != null) {
List<AccessibilityNodeInfo> infosFromProvider =
provider.findAccessibilityNodeInfosByText(text,
- virtualDescendantId);
+ AccessibilityNodeInfo.UNDEFINED);
if (infosFromProvider != null) {
infos.addAll(infosFromProvider);
}
@@ -491,20 +491,28 @@
if ((direction & View.FOCUS_ACCESSIBILITY) == View.FOCUS_ACCESSIBILITY) {
AccessibilityNodeProvider provider = root.getAccessibilityNodeProvider();
if (provider != null) {
- next = provider.accessibilityFocusSearch(direction,
- virtualDescendantId);
- } else if (virtualDescendantId == View.NO_ID) {
- View nextView = root.focusSearch(direction);
- if (nextView != null) {
- // If the focus search reached a node with a provider
- // we delegate to the provider to find the next one.
- provider = nextView.getAccessibilityNodeProvider();
- if (provider != null) {
- next = provider.accessibilityFocusSearch(direction,
- virtualDescendantId);
- } else {
- next = nextView.createAccessibilityNodeInfo();
- }
+ next = provider.accessibilityFocusSearch(direction, virtualDescendantId);
+ if (next != null) {
+ return;
+ }
+ }
+ View nextView = root.focusSearch(direction);
+ while (nextView != null) {
+ // If the focus search reached a node with a provider
+ // we delegate to the provider to find the next one.
+ // If the provider does not return a virtual view to
+ // take accessibility focus we try the next view found
+ // by the focus search algorithm.
+ provider = nextView.getAccessibilityNodeProvider();
+ if (provider != null) {
+ next = provider.accessibilityFocusSearch(direction, View.NO_ID);
+ if (next != null) {
+ break;
+ }
+ nextView = nextView.focusSearch(direction);
+ } else {
+ next = nextView.createAccessibilityNodeInfo();
+ break;
}
}
} else {
diff --git a/core/java/android/view/FocusFinder.java b/core/java/android/view/FocusFinder.java
index 6bf1888..9063cea 100644
--- a/core/java/android/view/FocusFinder.java
+++ b/core/java/android/view/FocusFinder.java
@@ -276,7 +276,10 @@
return focusables.get(position + 1);
}
}
- return focusables.get(0);
+ if (!focusables.isEmpty()) {
+ return focusables.get(0);
+ }
+ return null;
}
private static View getBackwardFocusable(ViewGroup root, View focused,
@@ -293,7 +296,10 @@
return focusables.get(position - 1);
}
}
- return focusables.get(count - 1);
+ if (!focusables.isEmpty()) {
+ return focusables.get(count - 1);
+ }
+ return null;
}
/**
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 0bb5f9f..1631fb3 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -833,19 +833,40 @@
@Override
public void drawBitmap(int[] colors, int offset, int stride, float x, float y,
int width, int height, boolean hasAlpha, Paint paint) {
+ if (width < 0) {
+ throw new IllegalArgumentException("width must be >= 0");
+ }
+
+ if (height < 0) {
+ throw new IllegalArgumentException("height must be >= 0");
+ }
+
+ if (Math.abs(stride) < width) {
+ throw new IllegalArgumentException("abs(stride) must be >= width");
+ }
+
+ int lastScanline = offset + (height - 1) * stride;
+ int length = colors.length;
+
+ if (offset < 0 || (offset + width > length) || lastScanline < 0 ||
+ (lastScanline + width > length)) {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+
// Shaders are ignored when drawing bitmaps
int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
try {
- final Bitmap.Config config = hasAlpha ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
- final Bitmap b = Bitmap.createBitmap(colors, offset, stride, width, height, config);
final int nativePaint = paint == null ? 0 : paint.mNativePaint;
- nDrawBitmap(mRenderer, b.mNativeBitmap, b.mBuffer, x, y, nativePaint);
- b.recycle();
+ nDrawBitmap(mRenderer, colors, offset, stride, x, y,
+ width, height, hasAlpha, nativePaint);
} finally {
if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
}
}
+ private static native void nDrawBitmap(int renderer, int[] colors, int offset, int stride,
+ float x, float y, int width, int height, boolean hasAlpha, int nativePaint);
+
@Override
public void drawBitmap(int[] colors, int offset, int stride, int x, int y,
int width, int height, boolean hasAlpha, Paint paint) {
diff --git a/core/java/android/view/VelocityTracker.java b/core/java/android/view/VelocityTracker.java
index f703e34..f5870e1 100644
--- a/core/java/android/view/VelocityTracker.java
+++ b/core/java/android/view/VelocityTracker.java
@@ -60,8 +60,7 @@
private static native void nativeComputeCurrentVelocity(int ptr, int units, float maxVelocity);
private static native float nativeGetXVelocity(int ptr, int id);
private static native float nativeGetYVelocity(int ptr, int id);
- private static native boolean nativeGetEstimator(int ptr, int id,
- int degree, int horizonMillis, Estimator outEstimator);
+ private static native boolean nativeGetEstimator(int ptr, int id, Estimator outEstimator);
/**
* Retrieve a new VelocityTracker object to watch the velocity of a
@@ -227,21 +226,17 @@
* this method.
*
* @param id Which pointer's velocity to return.
- * @param degree The desired polynomial degree. The actual estimator may have
- * a lower degree than what is requested here. If -1, uses the default degree.
- * @param horizonMillis The maximum age of the oldest sample to consider, in milliseconds.
- * If -1, uses the default horizon.
* @param outEstimator The estimator to populate.
* @return True if an estimator was obtained, false if there is no information
* available about the pointer.
*
* @hide For internal use only. Not a final API.
*/
- public boolean getEstimator(int id, int degree, int horizonMillis, Estimator outEstimator) {
+ public boolean getEstimator(int id, Estimator outEstimator) {
if (outEstimator == null) {
throw new IllegalArgumentException("outEstimator must not be null");
}
- return nativeGetEstimator(mPtr, id, degree, horizonMillis, outEstimator);
+ return nativeGetEstimator(mPtr, id, outEstimator);
}
/**
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 501cf29..a4fcd41 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -4737,11 +4737,9 @@
getBoundsOnScreen(bounds);
info.setBoundsInScreen(bounds);
- if ((mPrivateFlags & IS_ROOT_NAMESPACE) == 0) {
- ViewParent parent = getParentForAccessibility();
- if (parent instanceof View) {
- info.setParent((View) parent);
- }
+ ViewParent parent = getParentForAccessibility();
+ if (parent instanceof View) {
+ info.setParent((View) parent);
}
info.setVisibleToUser(isVisibleToUser());
@@ -6029,8 +6027,7 @@
return;
}
if ((focusableMode & FOCUSABLES_ACCESSIBILITY) == FOCUSABLES_ACCESSIBILITY) {
- if (AccessibilityManager.getInstance(mContext).isEnabled()
- && includeForAccessibility()) {
+ if (canTakeAccessibilityFocusFromHover() || getAccessibilityNodeProvider() != null) {
views.add(this);
return;
}
@@ -6159,12 +6156,15 @@
* @hide
*/
public void clearAccessibilityFocus() {
- if ((mPrivateFlags2 & ACCESSIBILITY_FOCUSED) != 0) {
- mPrivateFlags2 &= ~ACCESSIBILITY_FOCUSED;
- ViewRootImpl viewRootImpl = getViewRootImpl();
- if (viewRootImpl != null) {
+ ViewRootImpl viewRootImpl = getViewRootImpl();
+ if (viewRootImpl != null) {
+ View focusHost = viewRootImpl.getAccessibilityFocusedHost();
+ if (focusHost != null && ViewRootImpl.isViewDescendantOf(focusHost, this)) {
viewRootImpl.setAccessibilityFocusedHost(null);
}
+ }
+ if ((mPrivateFlags2 & ACCESSIBILITY_FOCUSED) != 0) {
+ mPrivateFlags2 &= ~ACCESSIBILITY_FOCUSED;
invalidate();
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED);
notifyAccessibilityStateChanged();
@@ -6183,57 +6183,28 @@
}
}
- /**
- * Find the best view to take accessibility focus from a hover.
- * This function finds the deepest actionable view and if that
- * fails ask the parent to take accessibility focus from hover.
- *
- * @param x The X hovered location in this view coorditantes.
- * @param y The Y hovered location in this view coorditantes.
- * @return Whether the request was handled.
- *
- * @hide
- */
- public boolean requestAccessibilityFocusFromHover(float x, float y) {
- if (onRequestAccessibilityFocusFromHover(x, y)) {
- return true;
- }
- ViewParent parent = mParent;
- if (parent instanceof View) {
- View parentView = (View) parent;
-
- float[] position = mAttachInfo.mTmpTransformLocation;
- position[0] = x;
- position[1] = y;
-
- // Compensate for the transformation of the current matrix.
- if (!hasIdentityMatrix()) {
- getMatrix().mapPoints(position);
+ private void requestAccessibilityFocusFromHover() {
+ if (includeForAccessibility() && isActionableForAccessibility()) {
+ requestAccessibilityFocus();
+ } else {
+ if (mParent != null) {
+ View nextFocus = mParent.findViewToTakeAccessibilityFocusFromHover(this, this);
+ if (nextFocus != null) {
+ nextFocus.requestAccessibilityFocus();
+ }
}
-
- // Compensate for the parent scroll and the offset
- // of this view stop from the parent top.
- position[0] += mLeft - parentView.mScrollX;
- position[1] += mTop - parentView.mScrollY;
-
- return parentView.requestAccessibilityFocusFromHover(position[0], position[1]);
}
- return false;
}
/**
- * Requests to give this View focus from hover.
- *
- * @param x The X hovered location in this view coorditantes.
- * @param y The Y hovered location in this view coorditantes.
- * @return Whether the request was handled.
- *
* @hide
*/
- public boolean onRequestAccessibilityFocusFromHover(float x, float y) {
- if (includeForAccessibility()
- && (isActionableForAccessibility() || hasListenersForAccessibility())) {
- return requestAccessibilityFocus();
+ public boolean canTakeAccessibilityFocusFromHover() {
+ if (includeForAccessibility() && isActionableForAccessibility()) {
+ return true;
+ }
+ if (mParent != null) {
+ return (mParent.findViewToTakeAccessibilityFocusFromHover(this, this) == this);
}
return false;
}
@@ -6495,14 +6466,15 @@
* important for accessibility are regarded.
*
* @return Whether to regard the view for accessibility.
+ *
+ * @hide
*/
- boolean includeForAccessibility() {
+ public boolean includeForAccessibility() {
if (mAttachInfo != null) {
if (!mAttachInfo.mIncludeNotImportantViews) {
return isImportantForAccessibility();
- } else {
- return true;
}
+ return true;
}
return false;
}
@@ -6513,8 +6485,10 @@
* accessiiblity.
*
* @return True if the view is actionable for accessibility.
+ *
+ * @hide
*/
- private boolean isActionableForAccessibility() {
+ public boolean isActionableForAccessibility() {
return (isClickable() || isLongClickable() || isFocusable());
}
@@ -6546,6 +6520,9 @@
* that is interesting for accessilility purposes.
*/
public void notifyAccessibilityStateChanged() {
+ if (!AccessibilityManager.getInstance(mContext).isEnabled()) {
+ return;
+ }
if ((mPrivateFlags2 & ACCESSIBILITY_STATE_CHANGED) == 0) {
mPrivateFlags2 |= ACCESSIBILITY_STATE_CHANGED;
if (mParent != null) {
@@ -7687,7 +7664,7 @@
&& pointInView(event.getX(), event.getY())) {
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER);
mSendingHoverAccessibilityEvents = true;
- requestAccessibilityFocusFromHover((int) event.getX(), (int) event.getY());
+ requestAccessibilityFocusFromHover();
}
} else {
if (action == MotionEvent.ACTION_HOVER_EXIT
@@ -15309,10 +15286,12 @@
/**
* Sets the next animation to play for this view.
* If you want the animation to play immediately, use
- * startAnimation. This method provides allows fine-grained
+ * {@link #startAnimation(android.view.animation.Animation)} instead.
+ * This method provides allows fine-grained
* control over the start time and invalidation, but you
* must make sure that 1) the animation has a start time set, and
- * 2) the view will be invalidated when the animation is supposed to
+ * 2) the view's parent (which controls animations on its children)
+ * will be invalidated when the animation is supposed to
* start.
*
* @param animation The next animation, or null.
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index b3c8895..b95ca5e 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -628,7 +628,11 @@
* FOCUS_RIGHT, or 0 for not applicable.
*/
public View focusSearch(View focused, int direction) {
- if (isRootNamespace()) {
+ // If we are moving accessibility focus we want to consider all
+ // views no matter if they are on the screen. It is responsibility
+ // of the accessibility service to check whether the result is in
+ // the screen.
+ if (isRootNamespace() && (direction & FOCUS_ACCESSIBILITY) == 0) {
// root namespace means we should consider ourselves the top of the
// tree for focus searching; otherwise we could be focus searching
// into other tabs. see LocalActivityManager and TabHost for more info
@@ -857,20 +861,13 @@
* {@inheritDoc}
*/
@Override
- public void addFocusables(ArrayList<View> views, int direction) {
- addFocusables(views, direction, FOCUSABLES_TOUCH_MODE);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
final int focusableCount = views.size();
final int descendantFocusability = getDescendantFocusability();
- if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) {
+ if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS
+ || (focusableMode & FOCUSABLES_ACCESSIBILITY) == FOCUSABLES_ACCESSIBILITY) {
final int count = mChildrenCount;
final View[] children = mChildren;
@@ -886,10 +883,11 @@
// FOCUS_AFTER_DESCENDANTS and there are some descendants focusable. this is
// to avoid the focus search finding layouts when a more precise search
// among the focusable children would be more interesting.
- if (
- descendantFocusability != FOCUS_AFTER_DESCENDANTS ||
+ if (descendantFocusability != FOCUS_AFTER_DESCENDANTS
// No focusable descendants
- (focusableCount == views.size())) {
+ || (focusableCount == views.size())
+ // We are collecting accessibility focusables.
+ || (focusableMode & FOCUSABLES_ACCESSIBILITY) == FOCUSABLES_ACCESSIBILITY) {
super.addFocusables(views, direction, focusableMode);
}
}
@@ -1635,8 +1633,7 @@
final int childrenCount = children.getChildCount();
for (int i = 0; i < childrenCount; i++) {
View child = children.getChildAt(i);
- if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE
- && (child.mPrivateFlags & IS_ROOT_NAMESPACE) == 0) {
+ if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
if (child.includeForAccessibility()) {
childrenForAccessibility.add(child);
} else {
@@ -1660,6 +1657,20 @@
}
/**
+ * @hide
+ */
+ @Override
+ public View findViewToTakeAccessibilityFocusFromHover(View child, View descendant) {
+ if (includeForAccessibility() && isActionableForAccessibility()) {
+ return this;
+ }
+ if (mParent != null) {
+ return mParent.findViewToTakeAccessibilityFocusFromHover(this, descendant);
+ }
+ return null;
+ }
+
+ /**
* Implement this method to intercept hover events before they are handled
* by child views.
* <p>
diff --git a/core/java/android/view/ViewParent.java b/core/java/android/view/ViewParent.java
index ddff91d..d93b996 100644
--- a/core/java/android/view/ViewParent.java
+++ b/core/java/android/view/ViewParent.java
@@ -295,4 +295,16 @@
* @hide
*/
public void childAccessibilityStateChanged(View child);
+
+ /**
+ * A descendant requests this view to find a candidate to take accessibility
+ * focus from hover.
+ *
+ * @param child The child making the call.
+ * @param descendant The descendant that made the initial request.
+ * @return A view to take accessibility focus.
+ *
+ * @hide
+ */
+ public View findViewToTakeAccessibilityFocusFromHover(View child, View descendant);
}
diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java
index 2012db2..ce6f4c5 100644
--- a/core/java/android/view/ViewPropertyAnimator.java
+++ b/core/java/android/view/ViewPropertyAnimator.java
@@ -342,6 +342,7 @@
* otherwise), then this method can be used.
*/
public void start() {
+ mView.removeCallbacks(mAnimationStarter);
startAnimation();
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 90e6034..41cd887 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -488,7 +488,9 @@
mFallbackEventHandler.setView(view);
mWindowAttributes.copyFrom(attrs);
attrs = mWindowAttributes;
-
+
+ setAccessibilityFocusedHost(null);
+
if (view instanceof RootViewSurfaceTaker) {
mSurfaceHolderCallback =
((RootViewSurfaceTaker)view).willYouTakeTheSurface();
@@ -556,6 +558,7 @@
mInputChannel = null;
mFallbackEventHandler.setView(null);
unscheduleTraversals();
+ setAccessibilityFocusedHost(null);
throw new RuntimeException("Adding window failed", e);
} finally {
if (restore) {
@@ -575,6 +578,7 @@
mAdded = false;
mFallbackEventHandler.setView(null);
unscheduleTraversals();
+ setAccessibilityFocusedHost(null);
switch (res) {
case WindowManagerImpl.ADD_BAD_APP_TOKEN:
case WindowManagerImpl.ADD_BAD_SUBWINDOW_TOKEN:
@@ -635,8 +639,6 @@
if (view.getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
view.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
}
-
- setAccessibilityFocusedHost(null);
}
}
}
@@ -1853,18 +1855,15 @@
performDraw();
}
} else {
- // End any pending transitions on this non-visible window
- if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
+ if (viewVisibility == View.VISIBLE) {
+ // Try again
+ scheduleTraversals();
+ } else if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
for (int i = 0; i < mPendingTransitions.size(); ++i) {
mPendingTransitions.get(i).endChangingAnimations();
}
mPendingTransitions.clear();
}
-
- if (viewVisibility == View.VISIBLE) {
- // Try again
- scheduleTraversals();
- }
}
}
@@ -2325,6 +2324,14 @@
return true;
}
+ @Override
+ public View findViewToTakeAccessibilityFocusFromHover(View child, View descendant) {
+ if (descendant.includeForAccessibility()) {
+ return descendant;
+ }
+ return null;
+ }
+
/**
* We want to draw a highlight around the current accessibility focused.
* Since adding a style for all possible view is not a viable option we
@@ -2520,12 +2527,66 @@
return handled;
}
+ /**
+ * @hide
+ */
+ public View getAccessibilityFocusedHost() {
+ return mAccessibilityFocusedHost;
+ }
+
+ /**
+ * @hide
+ */
+ public AccessibilityNodeInfo getAccessibilityFocusedVirtualView() {
+ return mAccessibilityFocusedVirtualView;
+ }
+
void setAccessibilityFocusedHost(View host) {
- if (mAccessibilityFocusedHost != null && mAccessibilityFocusedVirtualView == null) {
+ // If we have a virtual view with accessibility focus we need
+ // to clear the focus and invalidate the virtual view bounds.
+ if (mAccessibilityFocusedVirtualView != null) {
+
+ AccessibilityNodeInfo focusNode = mAccessibilityFocusedVirtualView;
+ View focusHost = mAccessibilityFocusedHost;
+ focusHost.clearAccessibilityFocusNoCallbacks();
+
+ // Wipe the state of the current accessibility focus since
+ // the call into the provider to clear accessibility focus
+ // will fire an accessibility event which will end up calling
+ // this method and we want to have clean state when this
+ // invocation happens.
+ mAccessibilityFocusedHost = null;
+ mAccessibilityFocusedVirtualView = null;
+
+ AccessibilityNodeProvider provider = focusHost.getAccessibilityNodeProvider();
+ if (provider != null) {
+ // Invalidate the area of the cleared accessibility focus.
+ focusNode.getBoundsInParent(mTempRect);
+ focusHost.invalidate(mTempRect);
+ // Clear accessibility focus in the virtual node.
+ final int virtualNodeId = AccessibilityNodeInfo.getVirtualDescendantId(
+ focusNode.getSourceNodeId());
+ provider.performAction(virtualNodeId,
+ AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null);
+ }
+ }
+ if (mAccessibilityFocusedHost != null) {
+ // Clear accessibility focus in the view.
mAccessibilityFocusedHost.clearAccessibilityFocusNoCallbacks();
}
+
+ // Set the new focus host.
mAccessibilityFocusedHost = host;
- mAccessibilityFocusedVirtualView = null;
+
+ // If the host has a provide find the virtual descendant that has focus.
+ if (mAccessibilityFocusedHost != null) {
+ AccessibilityNodeProvider provider =
+ mAccessibilityFocusedHost.getAccessibilityNodeProvider();
+ if (provider != null) {
+ mAccessibilityFocusedVirtualView = provider.findAccessibilityFocus(View.NO_ID);
+ return;
+ }
+ }
}
public void requestChildFocus(View child, View focused) {
@@ -2611,6 +2672,8 @@
destroyHardwareRenderer();
+ setAccessibilityFocusedHost(null);
+
mView = null;
mAttachInfo.mRootView = null;
mAttachInfo.mSurface = null;
@@ -2672,7 +2735,7 @@
/**
* Return true if child is an ancestor of parent, (or equal to the parent).
*/
- static boolean isViewDescendantOf(View child, View parent) {
+ public static boolean isViewDescendantOf(View child, View parent) {
if (child == parent) {
return true;
}
@@ -4586,6 +4649,31 @@
if (mView == null) {
return false;
}
+ // Watch for accessibility focus change events from virtual nodes
+ // to keep track of accessibility focus being on a virtual node.
+ final int eventType = event.getEventType();
+ switch (eventType) {
+ case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED: {
+ final long sourceId = event.getSourceNodeId();
+ // If the event is not from a virtual node we are not interested.
+ final int virtualViewId = AccessibilityNodeInfo.getVirtualDescendantId(sourceId);
+ if (virtualViewId == AccessibilityNodeInfo.UNDEFINED) {
+ break;
+ }
+ final int realViewId = AccessibilityNodeInfo.getAccessibilityViewId(sourceId);
+ View focusHost = mView.findViewByAccessibilityId(realViewId);
+ setAccessibilityFocusedHost(focusHost);
+ } break;
+ case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED: {
+ final long sourceId = event.getSourceNodeId();
+ // If the event is not from a virtual node we are not interested.
+ final int virtualViewId = AccessibilityNodeInfo.getVirtualDescendantId(sourceId);
+ if (virtualViewId == AccessibilityNodeInfo.UNDEFINED) {
+ break;
+ }
+ setAccessibilityFocusedHost(null);
+ } break;
+ }
mAccessibilityManager.sendAccessibilityEvent(event);
return true;
}
diff --git a/core/java/android/view/VolumePanel.java b/core/java/android/view/VolumePanel.java
index 110c239..78984e0 100644
--- a/core/java/android/view/VolumePanel.java
+++ b/core/java/android/view/VolumePanel.java
@@ -296,41 +296,33 @@
private boolean isMuted(int streamType) {
if (streamType == STREAM_MASTER) {
- return mAudioService.isMasterMute();
+ return mAudioManager.isMasterMute();
} else {
- return mAudioService.isStreamMute(streamType);
+ return mAudioManager.isStreamMute(streamType);
}
}
private int getStreamMaxVolume(int streamType) {
if (streamType == STREAM_MASTER) {
- return mAudioService.getMasterMaxVolume();
+ return mAudioManager.getMasterMaxVolume();
} else {
- return mAudioService.getStreamMaxVolume(streamType);
+ return mAudioManager.getStreamMaxVolume(streamType);
}
}
private int getStreamVolume(int streamType) {
if (streamType == STREAM_MASTER) {
- return mAudioService.getMasterVolume();
+ return mAudioManager.getMasterVolume();
} else {
- return mAudioService.getStreamVolume(streamType);
+ return mAudioManager.getStreamVolume(streamType);
}
}
private void setStreamVolume(int streamType, int index, int flags) {
if (streamType == STREAM_MASTER) {
- mAudioService.setMasterVolume(index, flags);
+ mAudioManager.setMasterVolume(index, flags);
} else {
- mAudioService.setStreamVolume(streamType, index, flags);
- }
- }
-
- private int getLastAudibleStreamVolume(int streamType) {
- if (streamType == STREAM_MASTER) {
- return mAudioService.getLastAudibleMasterVolume();
- } else {
- return mAudioService.getLastAudibleStreamVolume(streamType);
+ mAudioManager.setStreamVolume(streamType, index, flags);
}
}
@@ -399,13 +391,18 @@
/** Update the mute and progress state of a slider */
private void updateSlider(StreamControl sc) {
- sc.seekbarView.setProgress(getLastAudibleStreamVolume(sc.streamType));
+ sc.seekbarView.setProgress(getStreamVolume(sc.streamType));
final boolean muted = isMuted(sc.streamType);
sc.icon.setImageResource(muted ? sc.iconMuteRes : sc.iconRes);
- if (sc.streamType == AudioManager.STREAM_RING && muted
- && mAudioManager.shouldVibrate(AudioManager.VIBRATE_TYPE_RINGER)) {
+ if (sc.streamType == AudioManager.STREAM_RING &&
+ mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE) {
sc.icon.setImageResource(R.drawable.ic_audio_ring_notif_vibrate);
}
+ if (sc.streamType != mAudioManager.getMasterStreamType() && muted) {
+ sc.seekbarView.setEnabled(false);
+ } else {
+ sc.seekbarView.setEnabled(true);
+ }
}
private boolean isExpanded() {
@@ -510,9 +507,7 @@
}
protected void onShowVolumeChanged(int streamType, int flags) {
- int index = isMuted(streamType) ?
- getLastAudibleStreamVolume(streamType)
- : getStreamVolume(streamType);
+ int index = getStreamVolume(streamType);
mRingIsSilent = false;
@@ -592,6 +587,11 @@
sc.seekbarView.setMax(max);
}
sc.seekbarView.setProgress(index);
+ if (streamType != mAudioManager.getMasterStreamType() && isMuted(streamType)) {
+ sc.seekbarView.setEnabled(false);
+ } else {
+ sc.seekbarView.setEnabled(true);
+ }
}
if (!mDialog.isShowing()) {
@@ -607,8 +607,7 @@
// Do a little vibrate if applicable (only when going into vibrate mode)
if ((flags & AudioManager.FLAG_VIBRATE) != 0 &&
mAudioService.isStreamAffectedByRingerMode(streamType) &&
- mAudioService.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE &&
- mAudioService.shouldVibrate(AudioManager.VIBRATE_TYPE_RINGER)) {
+ mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE) {
sendMessageDelayed(obtainMessage(MSG_VIBRATE), VIBRATE_DELAY);
}
}
@@ -646,7 +645,7 @@
protected void onVibrate() {
// Make sure we ended up in vibrate ringer mode
- if (mAudioService.getRingerMode() != AudioManager.RINGER_MODE_VIBRATE) {
+ if (mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_VIBRATE) {
return;
}
diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
index 24e90fd..bd341d0 100644
--- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java
+++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
@@ -441,10 +441,6 @@
sAccessibilityNodeInfoCache.clear();
}
- public void removeCachedNode(long accessibilityNodeId) {
- sAccessibilityNodeInfoCache.remove(accessibilityNodeId);
- }
-
public void onAccessibilityEvent(AccessibilityEvent event) {
sAccessibilityNodeInfoCache.onAccessibilityEvent(event);
}
@@ -630,7 +626,7 @@
applyCompatibilityScaleIfNeeded(info, windowScale);
info.setConnectionId(connectionId);
info.setSealed(true);
- sAccessibilityNodeInfoCache.put(info.getSourceNodeId(), info);
+ sAccessibilityNodeInfoCache.add(info);
}
}
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfoCache.java b/core/java/android/view/accessibility/AccessibilityNodeInfoCache.java
index d2609bb..52b7772 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfoCache.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfoCache.java
@@ -16,10 +16,15 @@
package android.view.accessibility;
+import android.os.Build;
import android.util.Log;
import android.util.LongSparseArray;
import android.util.SparseLongArray;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.Queue;
+
/**
* Simple cache for AccessibilityNodeInfos. The cache is mapping an
* accessibility id to an info. The cache allows storing of
@@ -36,10 +41,14 @@
private static final boolean DEBUG = false;
+ private static final boolean CHECK_INTEGRITY = true;
+
private final Object mLock = new Object();
private final LongSparseArray<AccessibilityNodeInfo> mCacheImpl;
+ private int mWindowId;
+
public AccessibilityNodeInfoCache() {
if (ENABLED) {
mCacheImpl = new LongSparseArray<AccessibilityNodeInfo>();
@@ -59,21 +68,49 @@
final int eventType = event.getEventType();
switch (eventType) {
case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED: {
+ // New window so we clear the cache.
+ mWindowId = event.getWindowId();
clear();
} break;
+ case AccessibilityEvent.TYPE_VIEW_HOVER_ENTER:
+ case AccessibilityEvent.TYPE_VIEW_HOVER_EXIT: {
+ final int windowId = event.getWindowId();
+ if (mWindowId != windowId) {
+ // New window so we clear the cache.
+ mWindowId = windowId;
+ clear();
+ }
+ } break;
case AccessibilityEvent.TYPE_VIEW_FOCUSED:
+ case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED:
case AccessibilityEvent.TYPE_VIEW_SELECTED:
case AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED:
case AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED: {
- final long accessibilityNodeId = event.getSourceNodeId();
- remove(accessibilityNodeId);
+ // Since we prefetch the descendants of a node we
+ // just remove the entire subtree since when the node
+ // is fetched we will gets its descendant anyway.
+ synchronized (mLock) {
+ final long sourceId = event.getSourceNodeId();
+ clearSubTreeLocked(sourceId);
+ if (eventType == AccessibilityEvent.TYPE_VIEW_FOCUSED) {
+ clearSubtreeWithOldInputFocusLocked(sourceId);
+ }
+ if (eventType == AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED) {
+ clearSubtreeWithOldAccessibilityFocusLocked(sourceId);
+ }
+ }
} break;
case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED:
case AccessibilityEvent.TYPE_VIEW_SCROLLED: {
- final long accessibilityNodeId = event.getSourceNodeId();
- clearSubTree(accessibilityNodeId);
+ synchronized (mLock) {
+ final long accessibilityNodeId = event.getSourceNodeId();
+ clearSubTreeLocked(accessibilityNodeId);
+ }
} break;
}
+ if (Build.IS_DEBUGGABLE && CHECK_INTEGRITY) {
+ checkIntegrity();
+ }
}
}
@@ -105,51 +142,45 @@
/**
* Caches an {@link AccessibilityNodeInfo} given its accessibility node id.
*
- * @param accessibilityNodeId The info accessibility node id.
* @param info The {@link AccessibilityNodeInfo} to cache.
*/
- public void put(long accessibilityNodeId, AccessibilityNodeInfo info) {
+ public void add(AccessibilityNodeInfo info) {
if (ENABLED) {
synchronized(mLock) {
if (DEBUG) {
- Log.i(LOG_TAG, "put(" + accessibilityNodeId + ", " + info + ")");
+ Log.i(LOG_TAG, "add(" + info + ")");
}
+
+ final long sourceId = info.getSourceNodeId();
+ AccessibilityNodeInfo oldInfo = mCacheImpl.get(sourceId);
+ if (oldInfo != null) {
+ // If the added node is in the cache we have to be careful if
+ // the new one represents a source state where some of the
+ // children have been removed to avoid having disconnected
+ // subtrees in the cache.
+ SparseLongArray oldChildrenIds = oldInfo.getChildNodeIds();
+ SparseLongArray newChildrenIds = info.getChildNodeIds();
+ final int oldChildCount = oldChildrenIds.size();
+ for (int i = 0; i < oldChildCount; i++) {
+ final long oldChildId = oldChildrenIds.valueAt(i);
+ if (newChildrenIds.indexOfValue(oldChildId) < 0) {
+ clearSubTreeLocked(oldChildId);
+ }
+ }
+
+ // Also be careful if the parent has changed since the new
+ // parent may be a predecessor of the old parent which will
+ // make the cached tree cyclic.
+ final long oldParentId = oldInfo.getParentNodeId();
+ if (info.getParentNodeId() != oldParentId) {
+ clearSubTreeLocked(oldParentId);
+ }
+ }
+
// Cache a copy since the client calls to AccessibilityNodeInfo#recycle()
// will wipe the data of the cached info.
AccessibilityNodeInfo clone = AccessibilityNodeInfo.obtain(info);
- mCacheImpl.put(accessibilityNodeId, clone);
- }
- }
- }
-
- /**
- * Returns whether the cache contains an accessibility node id key.
- *
- * @param accessibilityNodeId The key for which to check.
- * @return True if the key is in the cache.
- */
- public boolean containsKey(long accessibilityNodeId) {
- if (ENABLED) {
- synchronized(mLock) {
- return (mCacheImpl.indexOfKey(accessibilityNodeId) >= 0);
- }
- } else {
- return false;
- }
- }
-
- /**
- * Removes a cached {@link AccessibilityNodeInfo}.
- *
- * @param accessibilityNodeId The info accessibility node id.
- */
- public void remove(long accessibilityNodeId) {
- if (ENABLED) {
- synchronized(mLock) {
- if (DEBUG) {
- Log.i(LOG_TAG, "remove(" + accessibilityNodeId + ")");
- }
- mCacheImpl.remove(accessibilityNodeId);
+ mCacheImpl.put(sourceId, clone);
}
}
}
@@ -179,7 +210,7 @@
*
* @param rootNodeId The root id.
*/
- private void clearSubTree(long rootNodeId) {
+ private void clearSubTreeLocked(long rootNodeId) {
AccessibilityNodeInfo current = mCacheImpl.get(rootNodeId);
if (current == null) {
return;
@@ -189,7 +220,124 @@
final int childCount = childNodeIds.size();
for (int i = 0; i < childCount; i++) {
final long childNodeId = childNodeIds.valueAt(i);
- clearSubTree(childNodeId);
+ clearSubTreeLocked(childNodeId);
+ }
+ }
+
+ /**
+ * We are enforcing the invariant for a single input focus.
+ *
+ * @param currentInputFocusId The current input focused node.
+ */
+ private void clearSubtreeWithOldInputFocusLocked(long currentInputFocusId) {
+ final int cacheSize = mCacheImpl.size();
+ for (int i = 0; i < cacheSize; i++) {
+ AccessibilityNodeInfo info = mCacheImpl.valueAt(i);
+ final long infoSourceId = info.getSourceNodeId();
+ if (infoSourceId != currentInputFocusId && info.isFocused()) {
+ clearSubTreeLocked(infoSourceId);
+ return;
+ }
+ }
+ }
+
+ /**
+ * We are enforcing the invariant for a single accessibility focus.
+ *
+ * @param currentInputFocusId The current input focused node.
+ */
+ private void clearSubtreeWithOldAccessibilityFocusLocked(long currentAccessibilityFocusId) {
+ final int cacheSize = mCacheImpl.size();
+ for (int i = 0; i < cacheSize; i++) {
+ AccessibilityNodeInfo info = mCacheImpl.valueAt(i);
+ final long infoSourceId = info.getSourceNodeId();
+ if (infoSourceId != currentAccessibilityFocusId && info.isAccessibilityFocused()) {
+ clearSubTreeLocked(infoSourceId);
+ return;
+ }
+ }
+ }
+
+ /**
+ * Check the integrity of the cache which is it does not have nodes
+ * from more than one window, there are no duplicates, all nodes are
+ * connected, there is a single input focused node, and there is a
+ * single accessibility focused node.
+ */
+ private void checkIntegrity() {
+ synchronized (mLock) {
+ // Get the root.
+ if (mCacheImpl.size() <= 0) {
+ return;
+ }
+
+ // If the cache is a tree it does not matter from
+ // which node we start to search for the root.
+ AccessibilityNodeInfo root = mCacheImpl.valueAt(0);
+ AccessibilityNodeInfo parent = root;
+ while (parent != null) {
+ root = parent;
+ parent = mCacheImpl.get(parent.getParentNodeId());
+ }
+
+ // Traverse the tree and do some checks.
+ final int windowId = root.getWindowId();
+ AccessibilityNodeInfo accessFocus = null;
+ AccessibilityNodeInfo inputFocus = null;
+ HashSet<AccessibilityNodeInfo> seen = new HashSet<AccessibilityNodeInfo>();
+ Queue<AccessibilityNodeInfo> fringe = new LinkedList<AccessibilityNodeInfo>();
+ fringe.add(root);
+
+ while (!fringe.isEmpty()) {
+ AccessibilityNodeInfo current = fringe.poll();
+ // Check for duplicates
+ if (!seen.add(current)) {
+ Log.e(LOG_TAG, "Duplicate node: " + current);
+ return;
+ }
+
+ // Check for one accessibility focus.
+ if (current.isAccessibilityFocused()) {
+ if (accessFocus != null) {
+ Log.e(LOG_TAG, "Duplicate accessibility focus:" + current);
+ } else {
+ accessFocus = current;
+ }
+ }
+
+ // Check for one input focus.
+ if (current.isFocused()) {
+ if (inputFocus != null) {
+ Log.e(LOG_TAG, "Duplicate input focus: " + current);
+ } else {
+ inputFocus = current;
+ }
+ }
+
+ SparseLongArray childIds = current.getChildNodeIds();
+ final int childCount = childIds.size();
+ for (int i = 0; i < childCount; i++) {
+ final long childId = childIds.valueAt(i);
+ AccessibilityNodeInfo child = mCacheImpl.get(childId);
+ if (child != null) {
+ fringe.add(child);
+ }
+ }
+ }
+
+ // Check for disconnected nodes or ones from another window.
+ final int cacheSize = mCacheImpl.size();
+ for (int i = 0; i < cacheSize; i++) {
+ AccessibilityNodeInfo info = mCacheImpl.valueAt(i);
+ if (!seen.contains(info)) {
+ if (info.getWindowId() == windowId) {
+ Log.e(LOG_TAG, "Disconneced node: ");
+ } else {
+ Log.e(LOG_TAG, "Node from: " + info.getWindowId() + " not from:"
+ + windowId + " " + info);
+ }
+ }
+ }
}
}
}
diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java
index eb6b7e3..f4796d5 100644
--- a/core/java/android/webkit/WebViewClassic.java
+++ b/core/java/android/webkit/WebViewClassic.java
@@ -88,7 +88,6 @@
import android.view.ViewGroup;
import android.view.ViewParent;
import android.view.ViewRootImpl;
-import android.view.ViewTreeObserver;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
@@ -888,20 +887,18 @@
private Point mSelectHandleLeftOffset;
private Point mSelectHandleRightOffset;
private Point mSelectHandleCenterOffset;
- private Point mSelectCursorBase = new Point();
- private int mSelectCursorBaseLayerId;
- private QuadF mSelectCursorBaseTextQuad = new QuadF();
- private Point mSelectCursorExtent = new Point();
- private int mSelectCursorExtentLayerId;
- private QuadF mSelectCursorExtentTextQuad = new QuadF();
+ private Point mSelectCursorLeft = new Point();
+ private int mSelectCursorLeftLayerId;
+ private QuadF mSelectCursorLeftTextQuad = new QuadF();
+ private Point mSelectCursorRight = new Point();
+ private int mSelectCursorRightLayerId;
+ private QuadF mSelectCursorRightTextQuad = new QuadF();
private Point mSelectDraggingCursor;
private Point mSelectDraggingOffset;
private QuadF mSelectDraggingTextQuad;
private boolean mIsCaretSelection;
- static final int HANDLE_ID_START = 0;
- static final int HANDLE_ID_END = 1;
- static final int HANDLE_ID_BASE = 2;
- static final int HANDLE_ID_EXTENT = 3;
+ static final int HANDLE_ID_LEFT = 0;
+ static final int HANDLE_ID_RIGHT = 1;
// the color used to highlight the touch rectangles
static final int HIGHLIGHT_COLOR = 0x6633b5e5;
@@ -3722,13 +3719,13 @@
return;
}
if (mSelectingText) {
- if (mSelectCursorBaseLayerId == mCurrentScrollingLayerId) {
- mSelectCursorBase.offset(dx, dy);
- mSelectCursorBaseTextQuad.offset(dx, dy);
+ if (mSelectCursorLeftLayerId == mCurrentScrollingLayerId) {
+ mSelectCursorLeft.offset(dx, dy);
+ mSelectCursorLeftTextQuad.offset(dx, dy);
}
- if (mSelectCursorExtentLayerId == mCurrentScrollingLayerId) {
- mSelectCursorExtent.offset(dx, dy);
- mSelectCursorExtentTextQuad.offset(dx, dy);
+ if (mSelectCursorRightLayerId == mCurrentScrollingLayerId) {
+ mSelectCursorRight.offset(dx, dy);
+ mSelectCursorRightTextQuad.offset(dx, dy);
}
} else if (mHandleAlpha.getAlpha() > 0) {
// stop fading as we're not going to move with the layer.
@@ -3829,6 +3826,9 @@
// reset the flag since we set to true in if need after
// loading is see onPageFinished(Url)
mAccessibilityScriptInjected = false;
+
+ // Don't start out editing.
+ mIsEditingText = false;
}
/**
@@ -4589,18 +4589,10 @@
* startX, startY, endX, endY
*/
private void getSelectionHandles(int[] handles) {
- handles[0] = mSelectCursorBase.x;
- handles[1] = mSelectCursorBase.y;
- handles[2] = mSelectCursorExtent.x;
- handles[3] = mSelectCursorExtent.y;
- if (!nativeIsBaseFirst(mNativeClass)) {
- int swap = handles[0];
- handles[0] = handles[2];
- handles[2] = swap;
- swap = handles[1];
- handles[1] = handles[3];
- handles[3] = swap;
- }
+ handles[0] = mSelectCursorLeft.x;
+ handles[1] = mSelectCursorLeft.y;
+ handles[2] = mSelectCursorRight.x;
+ handles[3] = mSelectCursorRight.y;
}
// draw history
@@ -5107,8 +5099,8 @@
ClipboardManager cm = (ClipboardManager)(mContext
.getSystemService(Context.CLIPBOARD_SERVICE));
if (cm.hasPrimaryClip()) {
- Point cursorPoint = new Point(contentToViewX(mSelectCursorBase.x),
- contentToViewY(mSelectCursorBase.y));
+ Point cursorPoint = new Point(contentToViewX(mSelectCursorLeft.x),
+ contentToViewY(mSelectCursorLeft.y));
Point cursorTop = calculateCaretTop();
cursorTop.set(contentToViewX(cursorTop.x),
contentToViewY(cursorTop.y));
@@ -5158,12 +5150,12 @@
* calculates the top of a caret.
*/
private Point calculateCaretTop() {
- float scale = scaleAlongSegment(mSelectCursorBase.x, mSelectCursorBase.y,
- mSelectCursorBaseTextQuad.p4, mSelectCursorBaseTextQuad.p3);
+ float scale = scaleAlongSegment(mSelectCursorLeft.x, mSelectCursorLeft.y,
+ mSelectCursorLeftTextQuad.p4, mSelectCursorLeftTextQuad.p3);
int x = Math.round(scaleCoordinate(scale,
- mSelectCursorBaseTextQuad.p1.x, mSelectCursorBaseTextQuad.p2.x));
+ mSelectCursorLeftTextQuad.p1.x, mSelectCursorLeftTextQuad.p2.x));
int y = Math.round(scaleCoordinate(scale,
- mSelectCursorBaseTextQuad.p1.y, mSelectCursorBaseTextQuad.p2.y));
+ mSelectCursorLeftTextQuad.p1.y, mSelectCursorLeftTextQuad.p2.y));
return new Point(x, y);
}
@@ -5174,46 +5166,40 @@
}
private void syncSelectionCursors() {
- mSelectCursorBaseLayerId =
- nativeGetHandleLayerId(mNativeClass, HANDLE_ID_BASE,
- mSelectCursorBase, mSelectCursorBaseTextQuad);
- mSelectCursorExtentLayerId =
- nativeGetHandleLayerId(mNativeClass, HANDLE_ID_EXTENT,
- mSelectCursorExtent, mSelectCursorExtentTextQuad);
+ mSelectCursorLeftLayerId =
+ nativeGetHandleLayerId(mNativeClass, HANDLE_ID_LEFT,
+ mSelectCursorLeft, mSelectCursorLeftTextQuad);
+ mSelectCursorRightLayerId =
+ nativeGetHandleLayerId(mNativeClass, HANDLE_ID_RIGHT,
+ mSelectCursorRight, mSelectCursorRightTextQuad);
}
private void adjustSelectionCursors() {
- boolean wasDraggingStart = (mSelectDraggingCursor == mSelectCursorBase);
+ if (mIsCaretSelection) {
+ return; // no need to swap left and right handles.
+ }
+
+ boolean wasDraggingLeft = (mSelectDraggingCursor == mSelectCursorLeft);
int oldX = mSelectDraggingCursor.x;
int oldY = mSelectDraggingCursor.y;
- int oldStartX = mSelectCursorBase.x;
- int oldStartY = mSelectCursorBase.y;
- int oldEndX = mSelectCursorExtent.x;
- int oldEndY = mSelectCursorExtent.y;
-
+ int oldLeftX = mSelectCursorLeft.x;
+ int oldLeftY = mSelectCursorLeft.y;
+ int oldRightX = mSelectCursorRight.x;
+ int oldRightY = mSelectCursorRight.y;
syncSelectionCursors();
- boolean dragChanged = oldX != mSelectDraggingCursor.x ||
- oldY != mSelectDraggingCursor.y;
- if (dragChanged && !mIsCaretSelection) {
- boolean draggingStart;
- if (wasDraggingStart) {
- float endStart = distanceSquared(oldEndX, oldEndY,
- mSelectCursorBase);
- float endEnd = distanceSquared(oldEndX, oldEndY,
- mSelectCursorExtent);
- draggingStart = endStart > endEnd;
- } else {
- float startStart = distanceSquared(oldStartX, oldStartY,
- mSelectCursorBase);
- float startEnd = distanceSquared(oldStartX, oldStartY,
- mSelectCursorExtent);
- draggingStart = startStart > startEnd;
- }
- mSelectDraggingCursor = (draggingStart
- ? mSelectCursorBase : mSelectCursorExtent);
- mSelectDraggingTextQuad = (draggingStart
- ? mSelectCursorBaseTextQuad : mSelectCursorExtentTextQuad);
- mSelectDraggingOffset = (draggingStart
+
+ boolean rightChanged = (oldRightX != mSelectCursorRight.x
+ || oldRightY != mSelectCursorRight.y);
+ boolean leftChanged = (oldLeftX != mSelectCursorLeft.x
+ || oldLeftY != mSelectCursorLeft.y);
+ if (leftChanged && rightChanged) {
+ // Left and right switched places, so swap dragging cursor
+ boolean draggingLeft = !wasDraggingLeft;
+ mSelectDraggingCursor = (draggingLeft
+ ? mSelectCursorLeft : mSelectCursorRight);
+ mSelectDraggingTextQuad = (draggingLeft
+ ? mSelectCursorLeftTextQuad : mSelectCursorRightTextQuad);
+ mSelectDraggingOffset = (draggingLeft
? mSelectHandleLeftOffset : mSelectHandleRightOffset);
}
mSelectDraggingCursor.set(oldX, oldY);
@@ -5239,14 +5225,11 @@
private void updateWebkitSelection() {
int[] handles = null;
if (mIsCaretSelection) {
- mSelectCursorExtent.set(mSelectCursorBase.x, mSelectCursorBase.y);
+ mSelectCursorRight.set(mSelectCursorLeft.x, mSelectCursorLeft.y);
}
if (mSelectingText) {
handles = new int[4];
- handles[0] = mSelectCursorBase.x;
- handles[1] = mSelectCursorBase.y;
- handles[2] = mSelectCursorExtent.x;
- handles[3] = mSelectCursorExtent.y;
+ getSelectionHandles(handles);
} else {
nativeSetTextSelection(mNativeClass, 0);
}
@@ -5610,21 +5593,21 @@
Point caretTop = calculateCaretTop();
if (visibleRect.width() < mEditTextContentBounds.width()) {
// The whole edit won't fit in the width, so use the caret rect
- if (mSelectCursorBase.x < caretTop.x) {
- showRect.left = Math.max(0, mSelectCursorBase.x - buffer);
+ if (mSelectCursorLeft.x < caretTop.x) {
+ showRect.left = Math.max(0, mSelectCursorLeft.x - buffer);
showRect.right = caretTop.x + buffer;
} else {
showRect.left = Math.max(0, caretTop.x - buffer);
- showRect.right = mSelectCursorBase.x + buffer;
+ showRect.right = mSelectCursorLeft.x + buffer;
}
}
if (visibleRect.height() < mEditTextContentBounds.height()) {
// The whole edit won't fit in the height, so use the caret rect
- if (mSelectCursorBase.y > caretTop.y) {
+ if (mSelectCursorLeft.y > caretTop.y) {
showRect.top = Math.max(0, caretTop.y - buffer);
- showRect.bottom = mSelectCursorBase.y + buffer;
+ showRect.bottom = mSelectCursorLeft.y + buffer;
} else {
- showRect.top = Math.max(0, mSelectCursorBase.y - buffer);
+ showRect.top = Math.max(0, mSelectCursorLeft.y - buffer);
showRect.bottom = caretTop.y + buffer;
}
}
@@ -5885,25 +5868,25 @@
if (mSelectHandleCenter != null && mSelectHandleCenter.getBounds()
.contains(shiftedX, shiftedY)) {
mSelectionStarted = true;
- mSelectDraggingCursor = mSelectCursorBase;
+ mSelectDraggingCursor = mSelectCursorLeft;
mSelectDraggingOffset = mSelectHandleCenterOffset;
- mSelectDraggingTextQuad = mSelectCursorBaseTextQuad;
+ mSelectDraggingTextQuad = mSelectCursorLeftTextQuad;
mPrivateHandler.removeMessages(CLEAR_CARET_HANDLE);
hidePasteButton();
} else if (mSelectHandleLeft != null
&& mSelectHandleLeft.getBounds()
.contains(shiftedX, shiftedY)) {
- mSelectionStarted = true;
- mSelectDraggingCursor = mSelectCursorBase;
- mSelectDraggingOffset = mSelectHandleLeftOffset;
- mSelectDraggingTextQuad = mSelectCursorBaseTextQuad;
+ mSelectionStarted = true;
+ mSelectDraggingOffset = mSelectHandleLeftOffset;
+ mSelectDraggingCursor = mSelectCursorLeft;
+ mSelectDraggingTextQuad = mSelectCursorLeftTextQuad;
} else if (mSelectHandleRight != null
&& mSelectHandleRight.getBounds()
.contains(shiftedX, shiftedY)) {
mSelectionStarted = true;
- mSelectDraggingCursor = mSelectCursorExtent;
mSelectDraggingOffset = mSelectHandleRightOffset;
- mSelectDraggingTextQuad = mSelectCursorExtentTextQuad;
+ mSelectDraggingCursor = mSelectCursorRight;
+ mSelectDraggingTextQuad = mSelectCursorRightTextQuad;
} else if (mIsCaretSelection) {
selectionDone();
}
@@ -8648,7 +8631,6 @@
private native void nativeUpdateDrawGLFunction(int nativeInstance, Rect invScreenRect,
Rect screenRect, RectF visibleContentRect, float scale);
private native String nativeGetSelection();
- private native Rect nativeLayerBounds(int layer);
private native void nativeSetHeightCanMeasure(boolean measure);
private native boolean nativeSetBaseLayer(int nativeInstance,
int layer, boolean showVisualIndicator, boolean isPictureAfterFirstLayout);
@@ -8691,7 +8673,6 @@
private static native void nativeSetTextSelection(int instance, int selection);
private static native int nativeGetHandleLayerId(int instance, int handle,
Point cursorLocation, QuadF textQuad);
- private static native boolean nativeIsBaseFirst(int instance);
private static native void nativeMapLayerRect(int instance, int layerId,
Rect rect);
// Returns 1 if a layer sync is needed, else 0
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 3b4ec7d..04c8cdc 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -42,6 +42,7 @@
import android.util.StateSet;
import android.view.ActionMode;
import android.view.ContextMenu.ContextMenuInfo;
+import android.view.FocusFinder;
import android.view.Gravity;
import android.view.HapticFeedbackConstants;
import android.view.InputDevice;
@@ -56,6 +57,7 @@
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;
@@ -1327,6 +1329,119 @@
}
@Override
+ public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
+ if ((focusableMode & FOCUSABLES_ACCESSIBILITY) == FOCUSABLES_ACCESSIBILITY
+ && (direction == ACCESSIBILITY_FOCUS_FORWARD
+ || direction == ACCESSIBILITY_FOCUS_BACKWARD)) {
+ if (canTakeAccessibilityFocusFromHover()) {
+ views.add(this);
+ }
+ } else {
+ super.addFocusables(views, direction, focusableMode);
+ }
+ }
+
+ @Override
+ public View focusSearch(int direction) {
+ return focusSearch(null, direction);
+ }
+
+ @Override
+ public View focusSearch(View focused, int direction) {
+ switch (direction) {
+ case ACCESSIBILITY_FOCUS_FORWARD: {
+ ViewRootImpl viewRootImpl = getViewRootImpl();
+ if (viewRootImpl == null) {
+ break;
+ }
+ View currentFocus = viewRootImpl.getAccessibilityFocusedHost();
+ if (currentFocus == null) {
+ break;
+ }
+ // If we have the focus try giving it to the first child.
+ if (currentFocus == this) {
+ final int firstVisiblePosition = getFirstVisiblePosition();
+ if (firstVisiblePosition >= 0) {
+ return getChildAt(0);
+ }
+ return null;
+ }
+ // Find the item that has accessibility focus.
+ final int currentPosition = getPositionForView(currentFocus);
+ if (currentPosition < 0 || currentPosition >= getCount()) {
+ break;
+ }
+ // Try to advance focus in the current item.
+ View currentItem = getChildAt(currentPosition - getFirstVisiblePosition());
+ if (currentItem instanceof ViewGroup) {
+ ViewGroup currentItemGroup = (ViewGroup) currentItem;
+ View nextFocus = FocusFinder.getInstance().findNextFocus(currentItemGroup,
+ currentFocus, direction);
+ if (nextFocus != null && nextFocus != currentItemGroup
+ && nextFocus != currentFocus) {
+ return nextFocus;
+ }
+ }
+ // Try to move focus to the next item.
+ final int nextPosition = currentPosition - getFirstVisiblePosition() + 1;
+ if (nextPosition < getChildCount()) {
+ return getChildAt(nextPosition);
+ }
+ } break;
+ case ACCESSIBILITY_FOCUS_BACKWARD: {
+ ViewRootImpl viewRootImpl = getViewRootImpl();
+ if (viewRootImpl == null) {
+ break;
+ }
+ View currentFocus = viewRootImpl.getAccessibilityFocusedHost();
+ if (currentFocus == null) {
+ break;
+ }
+ // If we have the focus do a generic search.
+ if (currentFocus == this) {
+ return super.focusSearch(this, direction);
+ }
+ // Find the item that has accessibility focus.
+ final int currentPosition = getPositionForView(currentFocus);
+ if (currentPosition < 0 || currentPosition >= getCount()) {
+ break;
+ }
+ // Try to advance focus in the current item.
+ View currentItem = getChildAt(currentPosition - getFirstVisiblePosition());
+ if (currentItem instanceof ViewGroup) {
+ ViewGroup currentItemGroup = (ViewGroup) currentItem;
+ View nextFocus = FocusFinder.getInstance().findNextFocus(currentItemGroup,
+ currentFocus, direction);
+ if (nextFocus != null && nextFocus != currentItemGroup
+ && nextFocus != currentFocus) {
+ return nextFocus;
+ }
+ }
+ // Try to move focus to the previous item.
+ final int nextPosition = currentPosition - getFirstVisiblePosition() - 1;
+ if (nextPosition >= 0) {
+ return getChildAt(nextPosition);
+ } else {
+ return this;
+ }
+ }
+ }
+ return super.focusSearch(focused, direction);
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public View findViewToTakeAccessibilityFocusFromHover(View child, View descendant) {
+ final int position = getPositionForView(child);
+ if (position != INVALID_POSITION) {
+ return getChildAt(position - mFirstPosition);
+ }
+ return super.findViewToTakeAccessibilityFocusFromHover(child, descendant);
+ }
+
+ @Override
public void sendAccessibilityEvent(int eventType) {
// Since this class calls onScrollChanged even if the mFirstPosition and the
// child count have not changed we will avoid sending duplicate accessibility
@@ -1365,6 +1480,9 @@
@Override
public boolean performAccessibilityAction(int action, Bundle arguments) {
+ if (super.performAccessibilityAction(action, arguments)) {
+ return true;
+ }
switch (action) {
case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: {
if (getLastVisiblePosition() < getCount() - 1) {
@@ -1381,7 +1499,7 @@
}
} return false;
}
- return super.performAccessibilityAction(action, arguments);
+ return false;
}
/**
diff --git a/core/java/android/widget/ActivityChooserModel.java b/core/java/android/widget/ActivityChooserModel.java
index c6104bc..fe6c4f5 100644
--- a/core/java/android/widget/ActivityChooserModel.java
+++ b/core/java/android/widget/ActivityChooserModel.java
@@ -765,16 +765,6 @@
}
/**
- * Gets whether the given observer is already registered.
- *
- * @param observer The observer.
- * @return True if already registered.
- */
- public boolean isRegisteredObserver(DataSetObserver observer) {
- return mObservers.contains(observer);
- }
-
- /**
* Represents a record in the history.
*/
public final static class HistoricalRecord {
diff --git a/core/java/android/widget/ActivityChooserView.java b/core/java/android/widget/ActivityChooserView.java
index 0c0bb1e..be6b4e2 100644
--- a/core/java/android/widget/ActivityChooserView.java
+++ b/core/java/android/widget/ActivityChooserView.java
@@ -20,10 +20,8 @@
import android.content.Context;
import android.content.Intent;
-import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
-import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.database.DataSetObserver;
@@ -176,11 +174,6 @@
private int mDefaultActionButtonContentDescription;
/**
- * Whether this view has a default activity affordance.
- */
- private boolean mHasDefaultActivity;
-
- /**
* Create a new instance.
*
* @param context The application environment.
@@ -252,8 +245,6 @@
Resources resources = context.getResources();
mListPopupMaxWidth = Math.max(resources.getDisplayMetrics().widthPixels / 2,
resources.getDimensionPixelSize(com.android.internal.R.dimen.config_prefDialogWidth));
-
- updateHasDefaultActivity();
}
/**
@@ -267,21 +258,6 @@
}
}
- @Override
- protected void onConfigurationChanged(Configuration newConfig) {
- Configuration oldConfig = mContext.getResources().getConfiguration();
- final int changed = oldConfig.diff(newConfig);
- if ((changed & ActivityInfo.CONFIG_SCREEN_SIZE) != 0
- || (changed & ActivityInfo.CONFIG_ORIENTATION) != 0) {
- updateHasDefaultActivity();
- }
- }
-
- private void updateHasDefaultActivity() {
- mHasDefaultActivity = mContext.getResources().getBoolean(
- R.bool.activity_chooser_view_has_default_activity);
- }
-
/**
* Sets the background for the button that expands the activity
* overflow list.
@@ -407,8 +383,7 @@
protected void onAttachedToWindow() {
super.onAttachedToWindow();
ActivityChooserModel dataModel = mAdapter.getDataModel();
- if (dataModel != null
- && !dataModel.isRegisteredObserver(mModelDataSetOberver)) {
+ if (dataModel != null) {
dataModel.registerObserver(mModelDataSetOberver);
}
mIsAttachedToWindow = true;
@@ -418,8 +393,7 @@
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
ActivityChooserModel dataModel = mAdapter.getDataModel();
- if (dataModel != null
- && dataModel.isRegisteredObserver(mModelDataSetOberver)) {
+ if (dataModel != null) {
dataModel.unregisterObserver(mModelDataSetOberver);
}
ViewTreeObserver viewTreeObserver = getViewTreeObserver();
@@ -522,7 +496,7 @@
// Default activity button.
final int activityCount = mAdapter.getActivityCount();
final int historySize = mAdapter.getHistorySize();
- if (mHasDefaultActivity && activityCount > 0 && historySize > 0) {
+ if (activityCount > 0 && historySize > 0) {
mDefaultActivityButton.setVisibility(VISIBLE);
ResolveInfo activity = mAdapter.getDefaultActivity();
PackageManager packageManager = mContext.getPackageManager();
@@ -538,9 +512,9 @@
}
// Activity chooser content.
if (mDefaultActivityButton.getVisibility() == VISIBLE) {
- mActivityChooserContent.setBackground(mActivityChooserContentBackground);
+ mActivityChooserContent.setBackgroundDrawable(mActivityChooserContentBackground);
} else {
- mActivityChooserContent.setBackground(null);
+ mActivityChooserContent.setBackgroundDrawable(null);
}
}
@@ -603,7 +577,7 @@
// OnLongClickListener#onLongClick
@Override
public boolean onLongClick(View view) {
- if (mHasDefaultActivity && view == mDefaultActivityButton) {
+ if (view == mDefaultActivityButton) {
if (mAdapter.getCount() > 0) {
mIsSelectingDefaultActivity = true;
showPopupUnchecked(mInitialActivityCount);
@@ -656,16 +630,14 @@
public void setDataModel(ActivityChooserModel dataModel) {
ActivityChooserModel oldDataModel = mAdapter.getDataModel();
- if (oldDataModel != null) {
+ if (oldDataModel != null && isShown()) {
oldDataModel.unregisterObserver(mModelDataSetOberver);
}
mDataModel = dataModel;
- if (dataModel != null) {
+ if (dataModel != null && isShown()) {
dataModel.registerObserver(mModelDataSetOberver);
- notifyDataSetChanged();
- } else {
- notifyDataSetInvalidated();
}
+ notifyDataSetChanged();
}
@Override
diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java
index abfc577..502de31 100644
--- a/core/java/android/widget/AdapterView.java
+++ b/core/java/android/widget/AdapterView.java
@@ -24,7 +24,6 @@
import android.util.SparseArray;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
-import android.view.MotionEvent;
import android.view.SoundEffectConstants;
import android.view.View;
import android.view.ViewDebug;
@@ -32,6 +31,7 @@
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeProvider;
/**
* An AdapterView is a view whose children are determined by an {@link Adapter}.
@@ -957,24 +957,6 @@
event.setItemCount(getCount());
}
- /**
- * @hide
- */
- @Override
- public boolean onRequestAccessibilityFocusFromHover(float x, float y) {
- // We prefer to five focus to the child instead of this view.
- // Usually the children are not actionable for accessibility,
- // and they will not take accessibility focus, so we give it.
- final int childCount = getChildCount();
- for (int i = 0; i < childCount; i++) {
- View child = getChildAt(i);
- if (isTransformedTouchPointInView(x, y, child, null)) {
- return child.requestAccessibilityFocus();
- }
- }
- return super.onRequestAccessibilityFocusFromHover(x, y);
- }
-
private boolean isScrollableForAccessibility() {
T adapter = getAdapter();
if (adapter != null) {
diff --git a/core/java/android/widget/CheckedTextView.java b/core/java/android/widget/CheckedTextView.java
index 278192c..61935c2 100644
--- a/core/java/android/widget/CheckedTextView.java
+++ b/core/java/android/widget/CheckedTextView.java
@@ -93,6 +93,7 @@
if (mChecked != checked) {
mChecked = checked;
refreshDrawableState();
+ notifyAccessibilityStateChanged();
}
}
diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java
index 02c4c4f..0a71c5a 100644
--- a/core/java/android/widget/CompoundButton.java
+++ b/core/java/android/widget/CompoundButton.java
@@ -114,6 +114,7 @@
if (mChecked != checked) {
mChecked = checked;
refreshDrawableState();
+ notifyAccessibilityStateChanged();
// Avoid infinite recursions if setChecked() is called from a listener
if (mBroadcasting) {
diff --git a/core/java/android/widget/Gallery.java b/core/java/android/widget/Gallery.java
index 03fdc39..b2c8164 100644
--- a/core/java/android/widget/Gallery.java
+++ b/core/java/android/widget/Gallery.java
@@ -20,6 +20,7 @@
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Rect;
+import android.os.Bundle;
import android.util.AttributeSet;
import android.util.Log;
import android.view.ContextMenu.ContextMenuInfo;
@@ -1367,6 +1368,35 @@
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
info.setClassName(Gallery.class.getName());
+ info.setScrollable(mItemCount > 1);
+ if (mItemCount > 0 && mSelectedPosition < mItemCount - 1) {
+ info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
+ }
+ if (mItemCount > 0 && mSelectedPosition > 0) {
+ info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
+ }
+ }
+
+ @Override
+ public boolean performAccessibilityAction(int action, Bundle arguments) {
+ if (super.performAccessibilityAction(action, arguments)) {
+ return true;
+ }
+ switch (action) {
+ case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: {
+ if (mItemCount > 0 && mSelectedPosition < mItemCount - 1) {
+ final int currentChildIndex = mSelectedPosition - mFirstPosition;
+ return scrollToChild(currentChildIndex + 1);
+ }
+ } return false;
+ case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: {
+ if (mItemCount > 0 && mSelectedPosition > 0) {
+ final int currentChildIndex = mSelectedPosition - mFirstPosition;
+ return scrollToChild(currentChildIndex - 1);
+ }
+ } return false;
+ }
+ return false;
}
/**
diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java
index cb10d0a..60a1d15 100644
--- a/core/java/android/widget/GridLayout.java
+++ b/core/java/android/widget/GridLayout.java
@@ -581,7 +581,7 @@
}
private int getDefaultMargin(View c, boolean isAtEdge, boolean horizontal, boolean leading) {
- return /*isAtEdge ? DEFAULT_CONTAINER_MARGIN :*/ getDefaultMargin(c, horizontal, leading);
+ return isAtEdge ? DEFAULT_CONTAINER_MARGIN : getDefaultMargin(c, horizontal, leading);
}
private int getDefaultMargin(View c, LayoutParams p, boolean horizontal, boolean leading) {
@@ -733,6 +733,11 @@
@Override
protected void onSetLayoutParams(View child, ViewGroup.LayoutParams layoutParams) {
super.onSetLayoutParams(child, layoutParams);
+
+ if (!checkLayoutParams(layoutParams)) {
+ handleInvalidParams("supplied LayoutParams are of the wrong type");
+ }
+
invalidateStructure();
}
@@ -740,6 +745,43 @@
return (LayoutParams) c.getLayoutParams();
}
+ private static void handleInvalidParams(String msg) {
+ throw new IllegalArgumentException(msg + ". ");
+ }
+
+ private void checkLayoutParams(LayoutParams lp, boolean horizontal) {
+ String groupName = horizontal ? "column" : "row";
+ Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
+ Interval span = spec.span;
+ if (span.min != UNDEFINED && span.min < 0) {
+ handleInvalidParams(groupName + " indices must be positive");
+ }
+ Axis axis = horizontal ? horizontalAxis : verticalAxis;
+ int count = axis.definedCount;
+ if (count != UNDEFINED) {
+ if (span.max > count) {
+ handleInvalidParams(groupName +
+ " indices (start + span) mustn't exceed the " + groupName + " count");
+ }
+ if (span.size() > count) {
+ handleInvalidParams(groupName + " span mustn't exceed the " + groupName + " count");
+ }
+ }
+ }
+
+ @Override
+ protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
+ if (!(p instanceof LayoutParams)) {
+ return false;
+ }
+ LayoutParams lp = (LayoutParams) p;
+
+ checkLayoutParams(lp, true);
+ checkLayoutParams(lp, false);
+
+ return true;
+ }
+
@Override
protected LayoutParams generateDefaultLayoutParams() {
return new LayoutParams();
@@ -1143,6 +1185,7 @@
Interval span = spec.span;
result = max(result, span.min);
result = max(result, span.max);
+ result = max(result, span.size());
}
return result == -1 ? UNDEFINED : result;
}
@@ -1159,6 +1202,11 @@
}
public void setCount(int count) {
+ if (count != UNDEFINED && count < getMaxIndex()) {
+ handleInvalidParams((horizontal ? "column" : "row") +
+ "Count must be greater than or equal to the maximum of all grid indices " +
+ "(and spans) defined in the LayoutParams of each child");
+ }
this.definedCount = count;
}
@@ -1478,20 +1526,6 @@
This is a special case of the Linear Programming problem that is, in turn,
equivalent to the single-source shortest paths problem on a digraph, for
which the O(n^2) Bellman-Ford algorithm the most commonly used general solution.
-
- Other algorithms are faster in the case where no arcs have negative weights
- but allowing negative weights turns out to be the same as accommodating maximum
- size requirements as well as minimum ones.
-
- Bellman-Ford works by iteratively 'relaxing' constraints over all nodes (an O(N)
- process) and performing this step N times. Proof of correctness hinges on the
- fact that there can be no negative weight chains of length > N - unless a
- 'negative weight loop' exists. The algorithm catches this case in a final
- checking phase that reports failure.
-
- By topologically sorting the nodes and checking this condition at each step
- typical layout problems complete after the first iteration and the algorithm
- completes in O(N) steps with very low constants.
*/
private void solve(Arc[] arcs, int[] locations) {
String axisName = horizontal ? "horizontal" : "vertical";
diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java
index ffabd1d9..f889cb7 100644
--- a/core/java/android/widget/HorizontalScrollView.java
+++ b/core/java/android/widget/HorizontalScrollView.java
@@ -739,6 +739,9 @@
@Override
public boolean performAccessibilityAction(int action, Bundle arguments) {
+ if (super.performAccessibilityAction(action, arguments)) {
+ return true;
+ }
switch (action) {
case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: {
final int viewportWidth = getWidth() - mPaddingLeft - mPaddingRight;
@@ -757,7 +760,7 @@
}
} return false;
}
- return super.performAccessibilityAction(action, arguments);
+ return false;
}
@Override
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index 7c809b3..b825e1b 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -950,6 +950,8 @@
provider.sendAccessibilityEventForVirtualView(hoveredVirtualViewId,
AccessibilityEvent.TYPE_VIEW_HOVER_ENTER);
mLastHoveredChildVirtualViewId = hoveredVirtualViewId;
+ provider.performAction(hoveredVirtualViewId,
+ AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null);
} break;
case MotionEvent.ACTION_HOVER_MOVE: {
if (mLastHoveredChildVirtualViewId != hoveredVirtualViewId
@@ -960,6 +962,8 @@
provider.sendAccessibilityEventForVirtualView(hoveredVirtualViewId,
AccessibilityEvent.TYPE_VIEW_HOVER_ENTER);
mLastHoveredChildVirtualViewId = hoveredVirtualViewId;
+ provider.performAction(hoveredVirtualViewId,
+ AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null);
}
} break;
case MotionEvent.ACTION_HOVER_EXIT: {
@@ -1413,9 +1417,16 @@
}
@Override
- public void sendAccessibilityEvent(int eventType) {
- // Do not send accessibility events - we want the user to
- // perceive this widget as several controls rather as a whole.
+ public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
+ // We do not want the real descendant to be considered focus search
+ // since it is managed by the accessibility node provider.
+ if ((focusableMode & FOCUSABLES_ACCESSIBILITY) == FOCUSABLES_ACCESSIBILITY) {
+ if (canTakeAccessibilityFocusFromHover() || getAccessibilityNodeProvider() != null) {
+ views.add(this);
+ return;
+ }
+ }
+ super.addFocusables(views, direction, focusableMode);
}
@Override
@@ -2072,7 +2083,12 @@
}
}
+ /**
+ * Class for managing virtual view tree rooted at this picker.
+ */
class AccessibilityNodeProviderImpl extends AccessibilityNodeProvider {
+ private static final int UNDEFINED = Integer.MIN_VALUE;
+
private static final int VIRTUAL_VIEW_ID_INCREMENT = 1;
private static final int VIRTUAL_VIEW_ID_INPUT = 2;
@@ -2083,6 +2099,8 @@
private final int[] mTempArray = new int[2];
+ private int mAccessibilityFocusedView = UNDEFINED;
+
@Override
public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) {
switch (virtualViewId) {
@@ -2137,6 +2155,37 @@
@Override
public boolean performAction(int virtualViewId, int action, Bundle arguments) {
switch (virtualViewId) {
+ case View.NO_ID: {
+ switch (action) {
+ case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: {
+ if (mAccessibilityFocusedView != virtualViewId) {
+ mAccessibilityFocusedView = virtualViewId;
+ requestAccessibilityFocus();
+ return true;
+ }
+ } return false;
+ case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: {
+ if (mAccessibilityFocusedView == virtualViewId) {
+ mAccessibilityFocusedView = UNDEFINED;
+ clearAccessibilityFocus();
+ return true;
+ }
+ return false;
+ }
+ case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: {
+ if (getWrapSelectorWheel() || getValue() < getMaxValue()) {
+ changeValueByOne(true);
+ return true;
+ }
+ } return false;
+ case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: {
+ if (getWrapSelectorWheel() || getValue() > getMinValue()) {
+ changeValueByOne(false);
+ return true;
+ }
+ } return false;
+ }
+ } break;
case VIRTUAL_VIEW_ID_INPUT: {
switch (action) {
case AccessibilityNodeInfo.ACTION_FOCUS: {
@@ -2149,25 +2198,182 @@
mInputText.clearFocus();
return true;
}
- } break;
+ return false;
+ }
+ case AccessibilityNodeInfo.ACTION_CLICK: {
+ showSoftInput();
+ return true;
+ }
+ case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: {
+ if (mAccessibilityFocusedView != virtualViewId) {
+ mAccessibilityFocusedView = virtualViewId;
+ sendAccessibilityEventForVirtualView(virtualViewId,
+ AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
+ mInputText.invalidate();
+ return true;
+ }
+ } return false;
+ case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: {
+ if (mAccessibilityFocusedView == virtualViewId) {
+ mAccessibilityFocusedView = UNDEFINED;
+ sendAccessibilityEventForVirtualView(virtualViewId,
+ AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED);
+ mInputText.invalidate();
+ return true;
+ }
+ } return false;
+ default: {
+ return mInputText.performAccessibilityAction(action, arguments);
+ }
+ }
+ } return false;
+ case VIRTUAL_VIEW_ID_INCREMENT: {
+ switch (action) {
+ case AccessibilityNodeInfo.ACTION_CLICK: {
+ NumberPicker.this.changeValueByOne(true);
+ sendAccessibilityEventForVirtualView(virtualViewId,
+ AccessibilityEvent.TYPE_VIEW_CLICKED);
+ } return true;
+ case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: {
+ if (mAccessibilityFocusedView != virtualViewId) {
+ mAccessibilityFocusedView = virtualViewId;
+ sendAccessibilityEventForVirtualView(virtualViewId,
+ AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
+ invalidate(0, mBottomSelectionDividerBottom, mRight, mBottom);
+ return true;
+ }
+ } return false;
+ case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: {
+ if (mAccessibilityFocusedView == virtualViewId) {
+ mAccessibilityFocusedView = UNDEFINED;
+ sendAccessibilityEventForVirtualView(virtualViewId,
+ AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED);
+ invalidate(0, mBottomSelectionDividerBottom, mRight, mBottom);
+ return true;
+ }
+ } return false;
+ }
+ } return false;
+ case VIRTUAL_VIEW_ID_DECREMENT: {
+ switch (action) {
+ case AccessibilityNodeInfo.ACTION_CLICK: {
+ final boolean increment = (virtualViewId == VIRTUAL_VIEW_ID_INCREMENT);
+ NumberPicker.this.changeValueByOne(increment);
+ sendAccessibilityEventForVirtualView(virtualViewId,
+ AccessibilityEvent.TYPE_VIEW_CLICKED);
+ } return true;
+ case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: {
+ if (mAccessibilityFocusedView != virtualViewId) {
+ mAccessibilityFocusedView = virtualViewId;
+ sendAccessibilityEventForVirtualView(virtualViewId,
+ AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
+ invalidate(0, 0, mRight, mTopSelectionDividerTop);
+ return true;
+ }
+ } return false;
+ case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: {
+ if (mAccessibilityFocusedView == virtualViewId) {
+ mAccessibilityFocusedView = UNDEFINED;
+ sendAccessibilityEventForVirtualView(virtualViewId,
+ AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED);
+ invalidate(0, 0, mRight, mTopSelectionDividerTop);
+ return true;
+ }
+ } return false;
+ }
+ } return false;
+ }
+ return super.performAction(virtualViewId, action, arguments);
+ }
+
+ @Override
+ public AccessibilityNodeInfo findAccessibilityFocus(int virtualViewId) {
+ return createAccessibilityNodeInfo(mAccessibilityFocusedView);
+ }
+
+ @Override
+ public AccessibilityNodeInfo accessibilityFocusSearch(int direction, int virtualViewId) {
+ switch (direction) {
+ case View.ACCESSIBILITY_FOCUS_DOWN:
+ case View.ACCESSIBILITY_FOCUS_FORWARD: {
+ switch (mAccessibilityFocusedView) {
+ case UNDEFINED: {
+ return createAccessibilityNodeInfo(View.NO_ID);
+ }
+ case View.NO_ID: {
+ if (hasVirtualDecrementButton()) {
+ return createAccessibilityNodeInfo(VIRTUAL_VIEW_ID_DECREMENT);
+ }
+ }
+ //$FALL-THROUGH$
+ case VIRTUAL_VIEW_ID_DECREMENT: {
+ return createAccessibilityNodeInfo(VIRTUAL_VIEW_ID_INPUT);
+ }
+ case VIRTUAL_VIEW_ID_INPUT: {
+ if (hasVirtualIncrementButton()) {
+ return createAccessibilityNodeInfo(VIRTUAL_VIEW_ID_INCREMENT);
+ }
+ }
+ //$FALL-THROUGH$
+ case VIRTUAL_VIEW_ID_INCREMENT: {
+ View nextFocus = NumberPicker.this.focusSearch(direction);
+ if (nextFocus != null) {
+ return nextFocus.createAccessibilityNodeInfo();
+ }
+ return null;
+ }
+ }
+ } break;
+ case View.ACCESSIBILITY_FOCUS_UP:
+ case View.ACCESSIBILITY_FOCUS_BACKWARD: {
+ switch (mAccessibilityFocusedView) {
+ case UNDEFINED: {
+ return createAccessibilityNodeInfo(View.NO_ID);
+ }
+ case View.NO_ID: {
+ if (hasVirtualIncrementButton()) {
+ return createAccessibilityNodeInfo(VIRTUAL_VIEW_ID_INCREMENT);
+ }
+ }
+ //$FALL-THROUGH$
+ case VIRTUAL_VIEW_ID_INCREMENT: {
+ return createAccessibilityNodeInfo(VIRTUAL_VIEW_ID_INPUT);
+ }
+ case VIRTUAL_VIEW_ID_INPUT: {
+ if (hasVirtualDecrementButton()) {
+ return createAccessibilityNodeInfo(VIRTUAL_VIEW_ID_DECREMENT);
+ }
+ }
+ //$FALL-THROUGH$
+ case VIRTUAL_VIEW_ID_DECREMENT: {
+ View nextFocus = NumberPicker.this.focusSearch(direction);
+ if (nextFocus != null) {
+ return nextFocus.createAccessibilityNodeInfo();
+ }
+ return null;
+ }
}
} break;
}
- return super.performAction(virtualViewId, action, arguments);
+ return null;
}
public void sendAccessibilityEventForVirtualView(int virtualViewId, int eventType) {
switch (virtualViewId) {
case VIRTUAL_VIEW_ID_DECREMENT: {
- sendAccessibilityEventForVirtualButton(virtualViewId, eventType,
- getVirtualDecrementButtonText());
+ if (hasVirtualDecrementButton()) {
+ sendAccessibilityEventForVirtualButton(virtualViewId, eventType,
+ getVirtualDecrementButtonText());
+ }
} break;
case VIRTUAL_VIEW_ID_INPUT: {
sendAccessibilityEventForVirtualText(eventType);
} break;
case VIRTUAL_VIEW_ID_INCREMENT: {
- sendAccessibilityEventForVirtualButton(virtualViewId, eventType,
- getVirtualIncrementButtonText());
+ if (hasVirtualIncrementButton()) {
+ sendAccessibilityEventForVirtualButton(virtualViewId, eventType,
+ getVirtualIncrementButtonText());
+ }
} break;
}
}
@@ -2227,8 +2433,13 @@
private AccessibilityNodeInfo createAccessibiltyNodeInfoForInputText() {
AccessibilityNodeInfo info = mInputText.createAccessibilityNodeInfo();
- info.setLongClickable(true);
info.setSource(NumberPicker.this, VIRTUAL_VIEW_ID_INPUT);
+ if (mAccessibilityFocusedView != VIRTUAL_VIEW_ID_INPUT) {
+ info.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS);
+ }
+ if (mAccessibilityFocusedView == VIRTUAL_VIEW_ID_INPUT) {
+ info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
+ }
return info;
}
@@ -2252,6 +2463,15 @@
getLocationOnScreen(locationOnScreen);
boundsInScreen.offset(locationOnScreen[0], locationOnScreen[1]);
info.setBoundsInScreen(boundsInScreen);
+
+ if (mAccessibilityFocusedView != virtualViewId) {
+ info.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS);
+ }
+ if (mAccessibilityFocusedView == virtualViewId) {
+ info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
+ }
+ info.addAction(AccessibilityNodeInfo.ACTION_CLICK);
+
return info;
}
@@ -2261,9 +2481,15 @@
info.setClassName(NumberPicker.class.getName());
info.setPackageName(mContext.getPackageName());
info.setSource(NumberPicker.this);
- info.addChild(NumberPicker.this, VIRTUAL_VIEW_ID_DECREMENT);
+
+ if (hasVirtualDecrementButton()) {
+ info.addChild(NumberPicker.this, VIRTUAL_VIEW_ID_DECREMENT);
+ }
info.addChild(NumberPicker.this, VIRTUAL_VIEW_ID_INPUT);
- info.addChild(NumberPicker.this, VIRTUAL_VIEW_ID_INCREMENT);
+ if (hasVirtualIncrementButton()) {
+ info.addChild(NumberPicker.this, VIRTUAL_VIEW_ID_INCREMENT);
+ }
+
info.setParent((View) getParent());
info.setEnabled(NumberPicker.this.isEnabled());
info.setScrollable(true);
@@ -2276,9 +2502,31 @@
getLocationOnScreen(locationOnScreen);
boundsInScreen.offset(locationOnScreen[0], locationOnScreen[1]);
info.setBoundsInScreen(boundsInScreen);
+
+ if (mAccessibilityFocusedView != View.NO_ID) {
+ info.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS);
+ }
+ if (mAccessibilityFocusedView == View.NO_ID) {
+ info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
+ }
+ if (getWrapSelectorWheel() || getValue() < getMaxValue()) {
+ info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
+ }
+ if (getWrapSelectorWheel() || getValue() > getMinValue()) {
+ info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
+ }
+
return info;
}
+ private boolean hasVirtualDecrementButton() {
+ return getWrapSelectorWheel() || getValue() > getMinValue();
+ }
+
+ private boolean hasVirtualIncrementButton() {
+ return getWrapSelectorWheel() || getValue() < getMaxValue();
+ }
+
private String getVirtualDecrementButtonText() {
int value = mValue - 1;
if (mWrapSelectorWheel) {
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index b398ce4..a499743 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -742,6 +742,9 @@
@Override
public boolean performAccessibilityAction(int action, Bundle arguments) {
+ if (super.performAccessibilityAction(action, arguments)) {
+ return true;
+ }
switch (action) {
case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: {
final int viewportHeight = getHeight() - mPaddingBottom - mPaddingTop;
@@ -760,7 +763,7 @@
}
} return false;
}
- return super.performAccessibilityAction(action, arguments);
+ return false;
}
@Override
diff --git a/core/java/android/widget/ShareActionProvider.java b/core/java/android/widget/ShareActionProvider.java
index 21840ca..4045497 100644
--- a/core/java/android/widget/ShareActionProvider.java
+++ b/core/java/android/widget/ShareActionProvider.java
@@ -44,7 +44,6 @@
* <code>
* // In Activity#onCreateOptionsMenu
* public boolean onCreateOptionsMenu(Menu menu) {
- * getManuInflater().inflate(R.menu.my_menu, menu);
* // Get the menu item.
* MenuItem menuItem = menu.findItem(R.id.my_menu_item);
* // Get the provider and hold onto it to set/change the share intent.
@@ -246,7 +245,7 @@
* call {@link android.app.Activity#invalidateOptionsMenu()} to recreate the
* action view. You should <strong>not</strong> call
* {@link android.app.Activity#invalidateOptionsMenu()} from
- * {@link android.app.Activity#onCreateOptionsMenu(Menu)}.
+ * {@link android.app.Activity#onCreateOptionsMenu(Menu)}."
* <p>
* <code>
* private void doShare(Intent intent) {
diff --git a/core/java/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java
index 7ca02e1..74ea038 100644
--- a/core/java/android/widget/SpellChecker.java
+++ b/core/java/android/widget/SpellChecker.java
@@ -132,8 +132,6 @@
// Restore SpellCheckSpans in pool
for (int i = 0; i < mLength; i++) {
- // Resets id and progress to invalidate spell check span
- mSpellCheckSpans[i].setSpellCheckInProgress(false);
mIds[i] = -1;
}
mLength = 0;
@@ -200,15 +198,16 @@
private void addSpellCheckSpan(Editable editable, int start, int end) {
final int index = nextSpellCheckSpanIndex();
- editable.setSpan(mSpellCheckSpans[index], start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ SpellCheckSpan spellCheckSpan = mSpellCheckSpans[index];
+ editable.setSpan(spellCheckSpan, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ spellCheckSpan.setSpellCheckInProgress(false);
mIds[index] = mSpanSequenceCounter++;
}
- public void removeSpellCheckSpan(SpellCheckSpan spellCheckSpan) {
+ public void onSpellCheckSpanRemoved(SpellCheckSpan spellCheckSpan) {
+ // Recycle any removed SpellCheckSpan (from this code or during text edition)
for (int i = 0; i < mLength; i++) {
if (mSpellCheckSpans[i] == spellCheckSpan) {
- // Resets id and progress to invalidate spell check span
- mSpellCheckSpans[i].setSpellCheckInProgress(false);
mIds[i] = -1;
return;
}
@@ -387,6 +386,7 @@
final SpellCheckSpan spellCheckSpan =
onGetSuggestionsInternal(results[i], USE_SPAN_RANGE, USE_SPAN_RANGE);
if (spellCheckSpan != null) {
+ // onSpellCheckSpanRemoved will recycle this span in the pool
editable.removeSpan(spellCheckSpan);
}
}
@@ -414,11 +414,12 @@
suggestionsInfo, offset, length);
if (spellCheckSpan == null && scs != null) {
// the spellCheckSpan is shared by all the "SuggestionsInfo"s in the same
- // SentenceSuggestionsInfo
+ // SentenceSuggestionsInfo. Removal is deferred after this loop.
spellCheckSpan = scs;
}
}
if (spellCheckSpan != null) {
+ // onSpellCheckSpanRemoved will recycle this span in the pool
editable.removeSpan(spellCheckSpan);
}
}
@@ -633,7 +634,8 @@
}
break;
}
- removeSpellCheckSpan(spellCheckSpan);
+ // This spellCheckSpan is replaced by the one we are creating
+ editable.removeSpan(spellCheckSpan);
spellCheckStart = Math.min(spanStart, spellCheckStart);
spellCheckEnd = Math.max(spanEnd, spellCheckEnd);
}
diff --git a/core/java/android/widget/StackView.java b/core/java/android/widget/StackView.java
index 22df3bc..dd0915b 100644
--- a/core/java/android/widget/StackView.java
+++ b/core/java/android/widget/StackView.java
@@ -32,6 +32,7 @@
import android.graphics.RectF;
import android.graphics.Region;
import android.graphics.TableMaskFilter;
+import android.os.Bundle;
import android.util.AttributeSet;
import android.util.Log;
import android.view.InputDevice;
@@ -1228,6 +1229,35 @@
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
info.setClassName(StackView.class.getName());
+ info.setScrollable(getChildCount() > 1);
+ if (getDisplayedChild() < getChildCount() - 1) {
+ info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
+ }
+ if (getDisplayedChild() > 0) {
+ info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
+ }
+ }
+
+ @Override
+ public boolean performAccessibilityAction(int action, Bundle arguments) {
+ if (super.performAccessibilityAction(action, arguments)) {
+ return true;
+ }
+ switch (action) {
+ case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: {
+ if (getDisplayedChild() < getChildCount() - 1) {
+ showNext();
+ return true;
+ }
+ } return false;
+ case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: {
+ if (getDisplayedChild() > 0) {
+ showPrevious();
+ return true;
+ }
+ } return false;
+ }
+ return false;
}
class LayoutParams extends ViewGroup.LayoutParams {
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 56eca01..fc56e11 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -1472,6 +1472,10 @@
}
setText(mText);
+
+ if (hasPasswordTransformationMethod()) {
+ notifyAccessibilityStateChanged();
+ }
}
/**
@@ -7236,7 +7240,7 @@
if (mEditor != null && mEditor.mSpellChecker != null && newStart < 0 &&
what instanceof SpellCheckSpan) {
- mEditor.mSpellChecker.removeSpellCheckSpan((SpellCheckSpan) what);
+ mEditor.mSpellChecker.onSpellCheckSpanRemoved((SpellCheckSpan) what);
}
}
diff --git a/core/java/com/android/internal/view/menu/MenuBuilder.java b/core/java/com/android/internal/view/menu/MenuBuilder.java
index 9fbca82..458ea2f 100644
--- a/core/java/com/android/internal/view/menu/MenuBuilder.java
+++ b/core/java/com/android/internal/view/menu/MenuBuilder.java
@@ -873,15 +873,20 @@
boolean invoked = itemImpl.invoke();
+ final ActionProvider provider = item.getActionProvider();
+ final boolean providerHasSubMenu = provider != null && provider.hasSubMenu();
if (itemImpl.hasCollapsibleActionView()) {
invoked |= itemImpl.expandActionView();
if (invoked) close(true);
- } else if (item.hasSubMenu()) {
+ } else if (itemImpl.hasSubMenu() || providerHasSubMenu) {
close(false);
- final SubMenuBuilder subMenu = (SubMenuBuilder) item.getSubMenu();
- final ActionProvider provider = item.getActionProvider();
- if (provider != null && provider.hasSubMenu()) {
+ if (!itemImpl.hasSubMenu()) {
+ itemImpl.setSubMenu(new SubMenuBuilder(getContext(), this, itemImpl));
+ }
+
+ final SubMenuBuilder subMenu = (SubMenuBuilder) itemImpl.getSubMenu();
+ if (providerHasSubMenu) {
provider.onPrepareSubMenu(subMenu);
}
invoked |= dispatchSubMenuSelected(subMenu);
diff --git a/core/java/com/android/internal/widget/PointerLocationView.java b/core/java/com/android/internal/widget/PointerLocationView.java
index 1d6af90..85e6c16 100644
--- a/core/java/com/android/internal/widget/PointerLocationView.java
+++ b/core/java/com/android/internal/widget/PointerLocationView.java
@@ -527,7 +527,7 @@
ps.addTrace(coords.x, coords.y);
ps.mXVelocity = mVelocity.getXVelocity(id);
ps.mYVelocity = mVelocity.getYVelocity(id);
- mVelocity.getEstimator(id, -1, -1, ps.mEstimator);
+ mVelocity.getEstimator(id, ps.mEstimator);
ps.mToolType = event.getToolType(i);
}
}
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 60929ac..e3d11f2 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -326,8 +326,8 @@
// ----------------------------------------------------------------------------
static void android_view_GLES20Canvas_drawBitmap(JNIEnv* env, jobject clazz,
- OpenGLRenderer* renderer, SkBitmap* bitmap, jbyteArray buffer, float left,
- float top, SkPaint* paint) {
+ OpenGLRenderer* renderer, SkBitmap* bitmap, jbyteArray buffer,
+ jfloat left, jfloat top, SkPaint* paint) {
// This object allows the renderer to allocate a global JNI ref to the buffer object.
JavaHeapBitmapRef bitmapRef(env, bitmap, buffer);
@@ -354,6 +354,31 @@
renderer->drawBitmap(bitmap, matrix, paint);
}
+static void android_view_GLES20Canvas_drawBitmapData(JNIEnv* env, jobject clazz,
+ OpenGLRenderer* renderer, jintArray colors, jint offset, jint stride,
+ jfloat left, jfloat top, jint width, jint height, jboolean hasAlpha, SkPaint* paint) {
+ SkBitmap* bitmap = new SkBitmap;
+ bitmap->setConfig(hasAlpha ? SkBitmap::kARGB_8888_Config : SkBitmap::kRGB_565_Config,
+ width, height);
+
+ if (!bitmap->allocPixels()) {
+ delete bitmap;
+ return;
+ }
+
+ if (!GraphicsJNI::SetPixels(env, colors, offset, stride, 0, 0, width, height, *bitmap)) {
+ delete bitmap;
+ return;
+ }
+
+ renderer->drawBitmapData(bitmap, left, top, paint);
+
+ // If the renderer is a deferred renderer it will own the bitmap
+ if (!renderer->isDeferred()) {
+ delete bitmap;
+ }
+}
+
static void android_view_GLES20Canvas_drawBitmapMesh(JNIEnv* env, jobject clazz,
OpenGLRenderer* renderer, SkBitmap* bitmap, jbyteArray buffer,
jint meshWidth, jint meshHeight, jfloatArray vertices, jint offset,
@@ -880,6 +905,7 @@
{ "nDrawBitmap", "(II[BFFI)V", (void*) android_view_GLES20Canvas_drawBitmap },
{ "nDrawBitmap", "(II[BFFFFFFFFI)V",(void*) android_view_GLES20Canvas_drawBitmapRect },
{ "nDrawBitmap", "(II[BII)V", (void*) android_view_GLES20Canvas_drawBitmapMatrix },
+ { "nDrawBitmap", "(I[IIIFFIIZI)V", (void*) android_view_GLES20Canvas_drawBitmapData },
{ "nDrawBitmapMesh", "(II[BII[FI[III)V",(void*) android_view_GLES20Canvas_drawBitmapMesh },
diff --git a/core/jni/android_view_VelocityTracker.cpp b/core/jni/android_view_VelocityTracker.cpp
index 04d1056..0180e0a 100644
--- a/core/jni/android_view_VelocityTracker.cpp
+++ b/core/jni/android_view_VelocityTracker.cpp
@@ -48,8 +48,7 @@
void addMovement(const MotionEvent* event);
void computeCurrentVelocity(int32_t units, float maxVelocity);
void getVelocity(int32_t id, float* outVx, float* outVy);
- bool getEstimator(int32_t id, uint32_t degree, nsecs_t horizon,
- VelocityTracker::Estimator* outEstimator);
+ bool getEstimator(int32_t id, VelocityTracker::Estimator* outEstimator);
private:
struct Velocity {
@@ -129,9 +128,8 @@
}
}
-bool VelocityTrackerState::getEstimator(int32_t id, uint32_t degree, nsecs_t horizon,
- VelocityTracker::Estimator* outEstimator) {
- return mVelocityTracker.getEstimator(id, degree, horizon, outEstimator);
+bool VelocityTrackerState::getEstimator(int32_t id, VelocityTracker::Estimator* outEstimator) {
+ return mVelocityTracker.getEstimator(id, outEstimator);
}
@@ -186,14 +184,10 @@
}
static jboolean android_view_VelocityTracker_nativeGetEstimator(JNIEnv* env, jclass clazz,
- jint ptr, jint id, jint degree, jint horizonMillis, jobject outEstimatorObj) {
+ jint ptr, jint id, jobject outEstimatorObj) {
VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr);
VelocityTracker::Estimator estimator;
- bool result = state->getEstimator(id,
- degree < 0 ? VelocityTracker::DEFAULT_DEGREE : uint32_t(degree),
- horizonMillis < 0 ? VelocityTracker::DEFAULT_HORIZON :
- nsecs_t(horizonMillis) * 1000000L,
- &estimator);
+ bool result = state->getEstimator(id, &estimator);
jfloatArray xCoeffObj = jfloatArray(env->GetObjectField(outEstimatorObj,
gEstimatorClassInfo.xCoeff));
@@ -236,7 +230,7 @@
"(II)F",
(void*)android_view_VelocityTracker_nativeGetYVelocity },
{ "nativeGetEstimator",
- "(IIIILandroid/view/VelocityTracker$Estimator;)Z",
+ "(IILandroid/view/VelocityTracker$Estimator;)Z",
(void*)android_view_VelocityTracker_nativeGetEstimator },
};
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_answer_active.png b/core/res/res/drawable-hdpi/ic_lockscreen_answer_active.png
deleted file mode 100644
index d201bfb7..0000000
--- a/core/res/res/drawable-hdpi/ic_lockscreen_answer_active.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_answer_focused.png b/core/res/res/drawable-hdpi/ic_lockscreen_answer_focused.png
deleted file mode 100644
index efb29f1..0000000
--- a/core/res/res/drawable-hdpi/ic_lockscreen_answer_focused.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_answer_normal.png b/core/res/res/drawable-hdpi/ic_lockscreen_answer_normal.png
deleted file mode 100644
index 176d448..0000000
--- a/core/res/res/drawable-hdpi/ic_lockscreen_answer_normal.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_decline_activated.png b/core/res/res/drawable-hdpi/ic_lockscreen_decline_activated.png
deleted file mode 100644
index 9866769..0000000
--- a/core/res/res/drawable-hdpi/ic_lockscreen_decline_activated.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_decline_focused.png b/core/res/res/drawable-hdpi/ic_lockscreen_decline_focused.png
deleted file mode 100644
index f37b16a..0000000
--- a/core/res/res/drawable-hdpi/ic_lockscreen_decline_focused.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_decline_normal.png b/core/res/res/drawable-hdpi/ic_lockscreen_decline_normal.png
deleted file mode 100644
index d88087b..0000000
--- a/core/res/res/drawable-hdpi/ic_lockscreen_decline_normal.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_text_activated.png b/core/res/res/drawable-hdpi/ic_lockscreen_text_activated.png
deleted file mode 100644
index 0ebff0b..0000000
--- a/core/res/res/drawable-hdpi/ic_lockscreen_text_activated.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_text_focusde.png b/core/res/res/drawable-hdpi/ic_lockscreen_text_focusde.png
deleted file mode 100644
index 5f1b881..0000000
--- a/core/res/res/drawable-hdpi/ic_lockscreen_text_focusde.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_text_normal.png b/core/res/res/drawable-hdpi/ic_lockscreen_text_normal.png
deleted file mode 100644
index bf73a26..0000000
--- a/core/res/res/drawable-hdpi/ic_lockscreen_text_normal.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_answer_active.png b/core/res/res/drawable-mdpi/ic_lockscreen_answer_active.png
deleted file mode 100644
index 0ad03c0..0000000
--- a/core/res/res/drawable-mdpi/ic_lockscreen_answer_active.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_answer_focused.png b/core/res/res/drawable-mdpi/ic_lockscreen_answer_focused.png
deleted file mode 100644
index f46e8bd..0000000
--- a/core/res/res/drawable-mdpi/ic_lockscreen_answer_focused.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_answer_normal.png b/core/res/res/drawable-mdpi/ic_lockscreen_answer_normal.png
deleted file mode 100644
index ddeeb18..0000000
--- a/core/res/res/drawable-mdpi/ic_lockscreen_answer_normal.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_decline_activated.png b/core/res/res/drawable-mdpi/ic_lockscreen_decline_activated.png
deleted file mode 100644
index d1aae18..0000000
--- a/core/res/res/drawable-mdpi/ic_lockscreen_decline_activated.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_decline_focused.png b/core/res/res/drawable-mdpi/ic_lockscreen_decline_focused.png
deleted file mode 100644
index b52c844..0000000
--- a/core/res/res/drawable-mdpi/ic_lockscreen_decline_focused.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_decline_normal.png b/core/res/res/drawable-mdpi/ic_lockscreen_decline_normal.png
deleted file mode 100644
index 722027e..0000000
--- a/core/res/res/drawable-mdpi/ic_lockscreen_decline_normal.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_text_activated.png b/core/res/res/drawable-mdpi/ic_lockscreen_text_activated.png
deleted file mode 100644
index 878ff1f..0000000
--- a/core/res/res/drawable-mdpi/ic_lockscreen_text_activated.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_text_focusde.png b/core/res/res/drawable-mdpi/ic_lockscreen_text_focusde.png
deleted file mode 100644
index 1de7586..0000000
--- a/core/res/res/drawable-mdpi/ic_lockscreen_text_focusde.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_text_normal.png b/core/res/res/drawable-mdpi/ic_lockscreen_text_normal.png
deleted file mode 100644
index e007322..0000000
--- a/core/res/res/drawable-mdpi/ic_lockscreen_text_normal.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_answer_active.png b/core/res/res/drawable-xhdpi/ic_lockscreen_answer_active.png
deleted file mode 100644
index 8edf62d..0000000
--- a/core/res/res/drawable-xhdpi/ic_lockscreen_answer_active.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_answer_focused.png b/core/res/res/drawable-xhdpi/ic_lockscreen_answer_focused.png
deleted file mode 100644
index 2a47e9b..0000000
--- a/core/res/res/drawable-xhdpi/ic_lockscreen_answer_focused.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_answer_normal.png b/core/res/res/drawable-xhdpi/ic_lockscreen_answer_normal.png
deleted file mode 100644
index f049dc9..0000000
--- a/core/res/res/drawable-xhdpi/ic_lockscreen_answer_normal.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_decline_activated.png b/core/res/res/drawable-xhdpi/ic_lockscreen_decline_activated.png
deleted file mode 100644
index 4244ca0..0000000
--- a/core/res/res/drawable-xhdpi/ic_lockscreen_decline_activated.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_decline_focused.png b/core/res/res/drawable-xhdpi/ic_lockscreen_decline_focused.png
deleted file mode 100644
index a98a379..0000000
--- a/core/res/res/drawable-xhdpi/ic_lockscreen_decline_focused.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_decline_normal.png b/core/res/res/drawable-xhdpi/ic_lockscreen_decline_normal.png
deleted file mode 100644
index fa2a0f4..0000000
--- a/core/res/res/drawable-xhdpi/ic_lockscreen_decline_normal.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_text_activated.png b/core/res/res/drawable-xhdpi/ic_lockscreen_text_activated.png
deleted file mode 100644
index ddebe3e..0000000
--- a/core/res/res/drawable-xhdpi/ic_lockscreen_text_activated.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_text_focusde.png b/core/res/res/drawable-xhdpi/ic_lockscreen_text_focusde.png
deleted file mode 100644
index 42c8ad2..0000000
--- a/core/res/res/drawable-xhdpi/ic_lockscreen_text_focusde.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_text_normal.png b/core/res/res/drawable-xhdpi/ic_lockscreen_text_normal.png
deleted file mode 100644
index ff65f20..0000000
--- a/core/res/res/drawable-xhdpi/ic_lockscreen_text_normal.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/ic_lockscreen_answer.xml b/core/res/res/drawable/ic_lockscreen_answer.xml
deleted file mode 100644
index dd50930..0000000
--- a/core/res/res/drawable/ic_lockscreen_answer.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-
- <item
- android:state_enabled="true"
- android:state_active="false"
- android:state_focused="false"
- android:drawable="@drawable/ic_lockscreen_answer_normal" />
-
- <item
- android:state_enabled="true"
- android:state_active="true"
- android:state_focused="false"
- android:drawable="@drawable/ic_lockscreen_answer_active" />
-
- <item
- android:state_enabled="true"
- android:state_active="false"
- android:state_focused="true"
- android:drawable="@drawable/ic_lockscreen_answer_active" />
-
-</selector>
diff --git a/core/res/res/drawable/ic_lockscreen_decline.xml b/core/res/res/drawable/ic_lockscreen_decline.xml
deleted file mode 100644
index 58e9d38..0000000
--- a/core/res/res/drawable/ic_lockscreen_decline.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-
- <item
- android:state_enabled="true"
- android:state_active="false"
- android:state_focused="false"
- android:drawable="@drawable/ic_lockscreen_decline_normal" />
-
- <item
- android:state_enabled="true"
- android:state_active="true"
- android:state_focused="false"
- android:drawable="@drawable/ic_lockscreen_decline_activated" />
-
- <item
- android:state_enabled="true"
- android:state_active="false"
- android:state_focused="true"
- android:drawable="@drawable/ic_lockscreen_decline_activated" />
-
-</selector>
diff --git a/core/res/res/drawable/ic_lockscreen_send_sms.xml b/core/res/res/drawable/ic_lockscreen_send_sms.xml
deleted file mode 100644
index 0d09297..0000000
--- a/core/res/res/drawable/ic_lockscreen_send_sms.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-
- <item
- android:state_enabled="true"
- android:state_active="false"
- android:state_focused="false"
- android:drawable="@drawable/ic_lockscreen_text_normal" />
-
- <item
- android:state_enabled="true"
- android:state_active="true"
- android:state_focused="false"
- android:drawable="@drawable/ic_lockscreen_text_activated" />
-
- <item
- android:state_enabled="true"
- android:state_active="false"
- android:state_focused="true"
- android:drawable="@drawable/ic_lockscreen_text_activated" />
-
-</selector>
diff --git a/core/res/res/layout-large/action_mode_close_item.xml b/core/res/res/layout-large/action_mode_close_item.xml
index 96aa451..f8b397a 100644
--- a/core/res/res/layout-large/action_mode_close_item.xml
+++ b/core/res/res/layout-large/action_mode_close_item.xml
@@ -34,6 +34,7 @@
android:layout_marginLeft="4dip"
android:layout_marginRight="16dip"
android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="?android:attr/actionMenuTextColor"
android:textSize="12sp"
android:textAllCaps="true"
android:text="@string/action_mode_done" />
diff --git a/core/res/res/layout/time_picker_holo.xml b/core/res/res/layout/time_picker_holo.xml
index 91e66bc..7b91022 100644
--- a/core/res/res/layout/time_picker_holo.xml
+++ b/core/res/res/layout/time_picker_holo.xml
@@ -44,6 +44,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
+ android:importantForAccessibility="no"
/>
<!-- minute -->
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index d31afa1..25cfb7f 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -796,7 +796,7 @@
<string name="js_dialog_title_default" msgid="6961903213729667573">"Javascript"</string>
<string name="js_dialog_before_unload" msgid="730366588032430474">"Vil du gå væk fra denne side?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Tryk på OK for at fortsætte eller Annuller for at blive på den aktuelle side."</string>
<string name="save_password_label" msgid="6860261758665825069">"Bekræft"</string>
- <string name="double_tap_toast" msgid="4595046515400268881">"Tip: Dobbeltklik for at zoome ind eller ud."</string>
+ <string name="double_tap_toast" msgid="4595046515400268881">"Tip! Dobbeltklik for at zoome ind eller ud."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"Autofyld"</string>
<string name="setup_autofill" msgid="7103495070180590814">"Konfigurer Autofyld"</string>
<string name="autofill_address_name_separator" msgid="6350145154779706772">" "</string>
@@ -997,7 +997,7 @@
<string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> blev oprindeligt åbnet."</string>
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Skaler"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Vis altid"</string>
- <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Aktiver dette igen i Systemindstillinger > Apps > Downloadet."</string>
+ <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Aktivér dette igen i Systemindstillinger > Apps > Downloadet."</string>
<string name="smv_application" msgid="3307209192155442829">"Appen <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) har overtrådt sin egen StrictMode-politik."</string>
<string name="smv_process" msgid="5120397012047462446">"Processen <xliff:g id="PROCESS">%1$s</xliff:g> har overtrådt sin egen StrictMode-politik."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android opgraderes..."</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 225f8e6..3d51570 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -1107,7 +1107,7 @@
<string name="usb_ptp_notification_title" msgid="1960817192216064833">"Als Kamera angeschlossen"</string>
<string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Als Installationsprogramm angeschlossen"</string>
<string name="usb_accessory_notification_title" msgid="7848236974087653666">"Mit USB-Zubehör verbunden"</string>
- <string name="usb_notification_message" msgid="2290859399983720271">"Zum Anzeigen weiterer USB-Optionen berühren"</string>
+ <string name="usb_notification_message" msgid="2290859399983720271">"Für mehr USB-Optionen berühren"</string>
<string name="extmedia_format_title" product="nosdcard" msgid="9020092196061007262">"USB-Speicher formatieren?"</string>
<string name="extmedia_format_title" product="default" msgid="3648415921526526069">"SD-Karte formatieren?"</string>
<string name="extmedia_format_message" product="nosdcard" msgid="3934016853425761078">"Alle in Ihrem USB-Speicher abgelegten Dateien werden gelöscht. Diese Aktion kann nicht rückgängig gemacht werden!"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 800f503..7e3e95b 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -175,28 +175,20 @@
<string name="permgroupdesc_location" msgid="5704679763124170100">"現在地を追跡します。"</string>
<string name="permgrouplab_network" msgid="5808983377727109831">"ネットワーク通信"</string>
<string name="permgroupdesc_network" msgid="4478299413241861987">"さまざまなネットワーク機能にアクセスします。"</string>
- <!-- no translation found for permgrouplab_bluetoothNetwork (1585403544162128109) -->
- <skip />
- <!-- no translation found for permgroupdesc_bluetoothNetwork (5625288577164282391) -->
- <skip />
- <!-- no translation found for permgrouplab_shortrangeNetwork (130808676377486118) -->
- <skip />
- <!-- no translation found for permgroupdesc_shortrangeNetwork (1884069062653436007) -->
- <skip />
+ <string name="permgrouplab_bluetoothNetwork" msgid="1585403544162128109">"Bluetooth"</string>
+ <string name="permgroupdesc_bluetoothNetwork" msgid="5625288577164282391">"Bluetooth経由でデバイスやネットワークにアクセスします。"</string>
+ <string name="permgrouplab_shortrangeNetwork" msgid="130808676377486118">"短距離ネットワーク"</string>
+ <string name="permgroupdesc_shortrangeNetwork" msgid="1884069062653436007">"NFCなどの近距離ネットワーク経由でデバイスにアクセスします。"</string>
<string name="permgrouplab_audioSettings" msgid="8329261670151871235">"音声設定"</string>
<string name="permgroupdesc_audioSettings" msgid="2641515403347568130">"音声設定を変更します。"</string>
<string name="permgrouplab_affectsBattery" msgid="6209246653424798033">"電池への影響"</string>
<string name="permgroupdesc_affectsBattery" msgid="6441275320638916947">"短時間で電池を消費する機能を使用します。"</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"カレンダー"</string>
<string name="permgroupdesc_calendar" msgid="5777534316982184416">"カレンダーと予定に直接アクセスします。"</string>
- <!-- no translation found for permgrouplab_dictionary (4148597128843641379) -->
- <skip />
- <!-- no translation found for permgroupdesc_dictionary (7921166355964764490) -->
- <skip />
- <!-- no translation found for permgrouplab_writeDictionary (8090237702432576788) -->
- <skip />
- <!-- no translation found for permgroupdesc_writeDictionary (2711561994497361646) -->
- <skip />
+ <string name="permgrouplab_dictionary" msgid="4148597128843641379">"単語リストの読み取り"</string>
+ <string name="permgroupdesc_dictionary" msgid="7921166355964764490">"単語リストから語句を読み取ります。"</string>
+ <string name="permgrouplab_writeDictionary" msgid="8090237702432576788">"単語リストへの書き込み"</string>
+ <string name="permgroupdesc_writeDictionary" msgid="2711561994497361646">"単語リストに語句を追加します。"</string>
<string name="permgrouplab_bookmarks" msgid="1949519673103968229">"ブックマークと履歴"</string>
<string name="permgroupdesc_bookmarks" msgid="4169771606257963028">"ブックマークとブラウザの履歴に直接アクセスします。"</string>
<string name="permgrouplab_deviceAlarms" msgid="6117704629728824101">"アラーム"</string>
@@ -569,8 +561,7 @@
<string name="permdesc_sdcardRead" product="nosdcard" msgid="3530894470637667917">"USBストレージ(写真やメディアなど)の読み取りをアプリに許可します。"</string>
<string name="permdesc_sdcardRead" product="default" msgid="2555811422562526606">"SDカードのコンテンツ(写真やメディアなど)の読み取りをアプリに許可します。"</string>
<string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"USBストレージのコンテンツの変更または削除"</string>
- <!-- no translation found for permlab_sdcardWrite (8805693630050458763) -->
- <skip />
+ <string name="permlab_sdcardWrite" product="default" msgid="8805693630050458763">"SDカードのコンテンツの変更または削除"</string>
<string name="permdesc_sdcardWrite" product="nosdcard" msgid="6175406299445710888">"USBストレージへの書き込みをアプリに許可します。"</string>
<string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"SDカードへの書き込みをアプリに許可します。"</string>
<string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"内部メディアストレージの内容の変更/削除"</string>
@@ -1090,8 +1081,7 @@
<string name="date_time_set" msgid="5777075614321087758">"設定"</string>
<string name="date_time_done" msgid="2507683751759308828">"完了"</string>
<string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ff900000">"NEW: "</font></string>
- <!-- no translation found for perms_description_app (5139836143293299417) -->
- <skip />
+ <string name="perms_description_app" msgid="5139836143293299417">"<xliff:g id="APP_NAME">%1$s</xliff:g>で提供されます。"</string>
<string name="no_permissions" msgid="7283357728219338112">"権限の許可は必要ありません"</string>
<string name="usb_storage_activity_title" msgid="4465055157209648641">"USBマスストレージ"</string>
<string name="usb_storage_title" msgid="5901459041398751495">"USB接続"</string>
@@ -1322,6 +1312,5 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"ブラウザを起動しますか?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"通話を受けますか?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"常時"</string>
- <!-- no translation found for activity_resolver_use_once (405646673463328329) -->
- <skip />
+ <string name="activity_resolver_use_once" msgid="405646673463328329">"今回のみ"</string>
</resources>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index d39c75c..a0e00eb 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -175,28 +175,20 @@
<string name="permgroupdesc_location" msgid="5704679763124170100">"Overvåking av telefonens fysiske posisjon."</string>
<string name="permgrouplab_network" msgid="5808983377727109831">"Nettverkstilgang"</string>
<string name="permgroupdesc_network" msgid="4478299413241861987">"Tilgang til ulike nettverksfunksjoner."</string>
- <!-- no translation found for permgrouplab_bluetoothNetwork (1585403544162128109) -->
- <skip />
- <!-- no translation found for permgroupdesc_bluetoothNetwork (5625288577164282391) -->
- <skip />
- <!-- no translation found for permgrouplab_shortrangeNetwork (130808676377486118) -->
- <skip />
- <!-- no translation found for permgroupdesc_shortrangeNetwork (1884069062653436007) -->
- <skip />
+ <string name="permgrouplab_bluetoothNetwork" msgid="1585403544162128109">"Bluetooth"</string>
+ <string name="permgroupdesc_bluetoothNetwork" msgid="5625288577164282391">"Bruke enheter og nettverk gjennom Bluetooth"</string>
+ <string name="permgrouplab_shortrangeNetwork" msgid="130808676377486118">"Nettverk med kort rekkevidde"</string>
+ <string name="permgroupdesc_shortrangeNetwork" msgid="1884069062653436007">"Bruke enheter via nettverk med kort rekkevidde, som NFC."</string>
<string name="permgrouplab_audioSettings" msgid="8329261670151871235">"Lydinnstillingene"</string>
<string name="permgroupdesc_audioSettings" msgid="2641515403347568130">"Endre lydinnstillingene."</string>
<string name="permgrouplab_affectsBattery" msgid="6209246653424798033">"Påvirker batteriet"</string>
<string name="permgroupdesc_affectsBattery" msgid="6441275320638916947">"Bruke funksjoner som kan tappe batteriet fortere."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Kalenderen"</string>
<string name="permgroupdesc_calendar" msgid="5777534316982184416">"Direkte tilgang til kalenderen og aktiviteter."</string>
- <!-- no translation found for permgrouplab_dictionary (4148597128843641379) -->
- <skip />
- <!-- no translation found for permgroupdesc_dictionary (7921166355964764490) -->
- <skip />
- <!-- no translation found for permgrouplab_writeDictionary (8090237702432576788) -->
- <skip />
- <!-- no translation found for permgroupdesc_writeDictionary (2711561994497361646) -->
- <skip />
+ <string name="permgrouplab_dictionary" msgid="4148597128843641379">"Lese brukerordlisten"</string>
+ <string name="permgroupdesc_dictionary" msgid="7921166355964764490">"Lese ord i brukerordlisten."</string>
+ <string name="permgrouplab_writeDictionary" msgid="8090237702432576788">"Skrive i brukerordlisten"</string>
+ <string name="permgroupdesc_writeDictionary" msgid="2711561994497361646">"Legge til ord i brukerordlisten."</string>
<string name="permgrouplab_bookmarks" msgid="1949519673103968229">"Bokmerkene og loggen"</string>
<string name="permgroupdesc_bookmarks" msgid="4169771606257963028">"Direkte tilgang til bokmerker og nettleserloggen."</string>
<string name="permgrouplab_deviceAlarms" msgid="6117704629728824101">"Alarmen"</string>
@@ -569,8 +561,7 @@
<string name="permdesc_sdcardRead" product="nosdcard" msgid="3530894470637667917">"Tillater at appen leser innholdet i USB-lagring, som kan inneholde bilder og medier."</string>
<string name="permdesc_sdcardRead" product="default" msgid="2555811422562526606">"Tillater at appen leser innholdet i SD-kort, som kan inneholde bilder og medier."</string>
<string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"endrer eller sletter innholdet i USB-lagringen"</string>
- <!-- no translation found for permlab_sdcardWrite (8805693630050458763) -->
- <skip />
+ <string name="permlab_sdcardWrite" product="default" msgid="8805693630050458763">"endre eller slette innhold i SD-kortet"</string>
<string name="permdesc_sdcardWrite" product="nosdcard" msgid="6175406299445710888">"Gir appen tillatelse til å skrive til USB-lagringen."</string>
<string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Lar appen skrive til SD-kortet."</string>
<string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"endre eller slette innhold på interne medier"</string>
@@ -1090,8 +1081,7 @@
<string name="date_time_set" msgid="5777075614321087758">"Lagre"</string>
<string name="date_time_done" msgid="2507683751759308828">"Ferdig"</string>
<string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ff900000">"NYTT: "</font></string>
- <!-- no translation found for perms_description_app (5139836143293299417) -->
- <skip />
+ <string name="perms_description_app" msgid="5139836143293299417">"Levert av <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="no_permissions" msgid="7283357728219338112">"Trenger ingen rettigheter"</string>
<string name="usb_storage_activity_title" msgid="4465055157209648641">"USB-masselagring"</string>
<string name="usb_storage_title" msgid="5901459041398751495">"USB koblet til"</string>
@@ -1322,6 +1312,5 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Vil du starte nettleseren?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Vil du besvare anropet?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Alltid"</string>
- <!-- no translation found for activity_resolver_use_once (405646673463328329) -->
- <skip />
+ <string name="activity_resolver_use_once" msgid="405646673463328329">"Bare én gang"</string>
</resources>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 60ea8e8..10effa3 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -175,28 +175,20 @@
<string name="permgroupdesc_location" msgid="5704679763124170100">"Monitorowanie fizycznej lokalizacji"</string>
<string name="permgrouplab_network" msgid="5808983377727109831">"Połączenia sieciowe"</string>
<string name="permgroupdesc_network" msgid="4478299413241861987">"Uzyskiwanie dostępu do różnych funkcji sieciowych"</string>
- <!-- no translation found for permgrouplab_bluetoothNetwork (1585403544162128109) -->
- <skip />
- <!-- no translation found for permgroupdesc_bluetoothNetwork (5625288577164282391) -->
- <skip />
- <!-- no translation found for permgrouplab_shortrangeNetwork (130808676377486118) -->
- <skip />
- <!-- no translation found for permgroupdesc_shortrangeNetwork (1884069062653436007) -->
- <skip />
+ <string name="permgrouplab_bluetoothNetwork" msgid="1585403544162128109">"Bluetooth"</string>
+ <string name="permgroupdesc_bluetoothNetwork" msgid="5625288577164282391">"Urządzenia dostępowe i sieci przez Bluetooth."</string>
+ <string name="permgrouplab_shortrangeNetwork" msgid="130808676377486118">"Sieci krótkiego zasięgu"</string>
+ <string name="permgroupdesc_shortrangeNetwork" msgid="1884069062653436007">"Dostęp do urządzeń przez sieci krótkiego zasięgu, takie jak NFC."</string>
<string name="permgrouplab_audioSettings" msgid="8329261670151871235">"Ustawienia dźwięku"</string>
<string name="permgroupdesc_audioSettings" msgid="2641515403347568130">"Zmiana ustawień dźwięku."</string>
<string name="permgrouplab_affectsBattery" msgid="6209246653424798033">"Użycie baterii"</string>
<string name="permgroupdesc_affectsBattery" msgid="6441275320638916947">"Korzystanie z funkcji, które mogą szybko rozładować baterię."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Kalendarz"</string>
<string name="permgroupdesc_calendar" msgid="5777534316982184416">"Bezpośredni dostęp do kalendarza i wydarzeń."</string>
- <!-- no translation found for permgrouplab_dictionary (4148597128843641379) -->
- <skip />
- <!-- no translation found for permgroupdesc_dictionary (7921166355964764490) -->
- <skip />
- <!-- no translation found for permgrouplab_writeDictionary (8090237702432576788) -->
- <skip />
- <!-- no translation found for permgroupdesc_writeDictionary (2711561994497361646) -->
- <skip />
+ <string name="permgrouplab_dictionary" msgid="4148597128843641379">"Czytanie słownika użytkownika"</string>
+ <string name="permgroupdesc_dictionary" msgid="7921166355964764490">"Czytanie wyrazów ze słownika użytkownika."</string>
+ <string name="permgrouplab_writeDictionary" msgid="8090237702432576788">"Zapisywanie w słowniku użytkownika"</string>
+ <string name="permgroupdesc_writeDictionary" msgid="2711561994497361646">"Dodawanie wyrazów do słownika użytkownika."</string>
<string name="permgrouplab_bookmarks" msgid="1949519673103968229">"Zakładki i historia"</string>
<string name="permgroupdesc_bookmarks" msgid="4169771606257963028">"Bezpośredni dostęp do zakładek i historii przeglądarki."</string>
<string name="permgrouplab_deviceAlarms" msgid="6117704629728824101">"Alarm"</string>
@@ -569,8 +561,7 @@
<string name="permdesc_sdcardRead" product="nosdcard" msgid="3530894470637667917">"Zezwala aplikacji na odczytywanie zawartości pamięci USB, która może obejmować zdjęcia i multimedia."</string>
<string name="permdesc_sdcardRead" product="default" msgid="2555811422562526606">"Zezwala aplikacji na odczytywanie zawartości karty SD, która może obejmować zdjęcia i multimedia."</string>
<string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"modyfikowanie i usuwanie zawartości pamięci USB"</string>
- <!-- no translation found for permlab_sdcardWrite (8805693630050458763) -->
- <skip />
+ <string name="permlab_sdcardWrite" product="default" msgid="8805693630050458763">"modyfikowanie i usuwanie zawartości karty SD"</string>
<string name="permdesc_sdcardWrite" product="nosdcard" msgid="6175406299445710888">"Pozwala aplikacji na zapis w pamięci USB."</string>
<string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Pozwala aplikacji na zapis na karcie SD."</string>
<string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"modyfikowanie/usuwanie zawartości pamięci wew."</string>
@@ -1090,8 +1081,7 @@
<string name="date_time_set" msgid="5777075614321087758">"Ustaw"</string>
<string name="date_time_done" msgid="2507683751759308828">"Gotowe"</string>
<string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ff900000">"NOWE: "</font></string>
- <!-- no translation found for perms_description_app (5139836143293299417) -->
- <skip />
+ <string name="perms_description_app" msgid="5139836143293299417">"Dostarczane przez <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="no_permissions" msgid="7283357728219338112">"Nie są wymagane żadne uprawnienia"</string>
<string name="usb_storage_activity_title" msgid="4465055157209648641">"Pamięć masowa USB"</string>
<string name="usb_storage_title" msgid="5901459041398751495">"Połączenie przez USB"</string>
@@ -1322,6 +1312,5 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Uruchomić przeglądarkę?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Odebrać połączenie?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Zawsze"</string>
- <!-- no translation found for activity_resolver_use_once (405646673463328329) -->
- <skip />
+ <string name="activity_resolver_use_once" msgid="405646673463328329">"Tylko raz"</string>
</resources>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index ba10acd..4236d50 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -176,9 +176,9 @@
<string name="permgrouplab_network" msgid="5808983377727109831">"Comunicação da rede"</string>
<string name="permgroupdesc_network" msgid="4478299413241861987">"Acesse diversos recursos de rede."</string>
<string name="permgrouplab_bluetoothNetwork" msgid="1585403544162128109">"Bluetooth"</string>
- <string name="permgroupdesc_bluetoothNetwork" msgid="5625288577164282391">"Acessar dispositivos e redes através do Bluetooth."</string>
+ <string name="permgroupdesc_bluetoothNetwork" msgid="5625288577164282391">"Acessar dispositivos e redes por meio do Bluetooth."</string>
<string name="permgrouplab_shortrangeNetwork" msgid="130808676377486118">"Redes de curto alcance"</string>
- <string name="permgroupdesc_shortrangeNetwork" msgid="1884069062653436007">"Acessar dispositivos através de redes de curto alcance de redes como a NFC."</string>
+ <string name="permgroupdesc_shortrangeNetwork" msgid="1884069062653436007">"Acessar dispositivos por meio de redes de curto alcance de redes como a NFC."</string>
<string name="permgrouplab_audioSettings" msgid="8329261670151871235">"Configurações de áudio"</string>
<string name="permgroupdesc_audioSettings" msgid="2641515403347568130">"Alterar as configurações de áudio."</string>
<string name="permgrouplab_affectsBattery" msgid="6209246653424798033">"Afeta a bateria"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 45783d1..dd639858 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -175,28 +175,20 @@
<string name="permgroupdesc_location" msgid="5704679763124170100">"Monitorizează locaţia dvs. fizică."</string>
<string name="permgrouplab_network" msgid="5808983377727109831">"Comunicare în reţea"</string>
<string name="permgroupdesc_network" msgid="4478299413241861987">"Accesează diferite funcţii ale reţelei."</string>
- <!-- no translation found for permgrouplab_bluetoothNetwork (1585403544162128109) -->
- <skip />
- <!-- no translation found for permgroupdesc_bluetoothNetwork (5625288577164282391) -->
- <skip />
- <!-- no translation found for permgrouplab_shortrangeNetwork (130808676377486118) -->
- <skip />
- <!-- no translation found for permgroupdesc_shortrangeNetwork (1884069062653436007) -->
- <skip />
+ <string name="permgrouplab_bluetoothNetwork" msgid="1585403544162128109">"Bluetooth"</string>
+ <string name="permgroupdesc_bluetoothNetwork" msgid="5625288577164282391">"Accesează dispozitive şi reţele prin intermediul Bluetooth."</string>
+ <string name="permgrouplab_shortrangeNetwork" msgid="130808676377486118">"Reţele cu distanţă scurtă"</string>
+ <string name="permgroupdesc_shortrangeNetwork" msgid="1884069062653436007">"Accesează dispozitive prin intermediul reţelelor cu distanţă scurtă, cum ar fi NFC."</string>
<string name="permgrouplab_audioSettings" msgid="8329261670151871235">"Setările audio"</string>
<string name="permgroupdesc_audioSettings" msgid="2641515403347568130">"Modifică setările audio."</string>
<string name="permgrouplab_affectsBattery" msgid="6209246653424798033">"Capacitatea de a afecta bateria"</string>
<string name="permgroupdesc_affectsBattery" msgid="6441275320638916947">"Utilizează funcţii care pot consuma rapid bateria."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Calendarul"</string>
<string name="permgroupdesc_calendar" msgid="5777534316982184416">"Acces direct la calendar şi la evenimente."</string>
- <!-- no translation found for permgrouplab_dictionary (4148597128843641379) -->
- <skip />
- <!-- no translation found for permgroupdesc_dictionary (7921166355964764490) -->
- <skip />
- <!-- no translation found for permgrouplab_writeDictionary (8090237702432576788) -->
- <skip />
- <!-- no translation found for permgroupdesc_writeDictionary (2711561994497361646) -->
- <skip />
+ <string name="permgrouplab_dictionary" msgid="4148597128843641379">"Citeşte dicţionarul utilizatorului"</string>
+ <string name="permgroupdesc_dictionary" msgid="7921166355964764490">"Citeşte cuvinte din dicţionarul utilizatorului."</string>
+ <string name="permgrouplab_writeDictionary" msgid="8090237702432576788">"Scrie în dicţionarul utilizatorului"</string>
+ <string name="permgroupdesc_writeDictionary" msgid="2711561994497361646">"Adaugă cuvinte în dicţionarul utilizatorului."</string>
<string name="permgrouplab_bookmarks" msgid="1949519673103968229">"Marcajele şi Istoricul"</string>
<string name="permgroupdesc_bookmarks" msgid="4169771606257963028">"Acces direct la marcaje şi la istoricul navigării."</string>
<string name="permgrouplab_deviceAlarms" msgid="6117704629728824101">"Alarma"</string>
@@ -569,8 +561,7 @@
<string name="permdesc_sdcardRead" product="nosdcard" msgid="3530894470637667917">"Permite aplic. să citească conţin. stoc. USB, care poate include fotogr. şi media."</string>
<string name="permdesc_sdcardRead" product="default" msgid="2555811422562526606">"Permite aplicaţiei să citească conţinutul cardului SD, care poate include fotografii şi conţinut media."</string>
<string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"modifică sau şterge conţinutul stocării USB"</string>
- <!-- no translation found for permlab_sdcardWrite (8805693630050458763) -->
- <skip />
+ <string name="permlab_sdcardWrite" product="default" msgid="8805693630050458763">"modifică sau şterge conţinutul cardului SD"</string>
<string name="permdesc_sdcardWrite" product="nosdcard" msgid="6175406299445710888">"Permite scriere în stoc. USB."</string>
<string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Permite aplicaţiei să scrie pe cardul SD."</string>
<string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"modif./şterg. conţinutul media stocat intern"</string>
@@ -1090,8 +1081,7 @@
<string name="date_time_set" msgid="5777075614321087758">"Setaţi"</string>
<string name="date_time_done" msgid="2507683751759308828">"Terminat"</string>
<string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ff900000">"NOU: "</font></string>
- <!-- no translation found for perms_description_app (5139836143293299417) -->
- <skip />
+ <string name="perms_description_app" msgid="5139836143293299417">"Furnizată de <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="no_permissions" msgid="7283357728219338112">"Nu se solicită nicio permisiune"</string>
<string name="usb_storage_activity_title" msgid="4465055157209648641">"Stocare masivă USB"</string>
<string name="usb_storage_title" msgid="5901459041398751495">"USB conectat"</string>
@@ -1322,6 +1312,5 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Lansaţi browserul?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Acceptaţi apelul?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Întotdeauna"</string>
- <!-- no translation found for activity_resolver_use_once (405646673463328329) -->
- <skip />
+ <string name="activity_resolver_use_once" msgid="405646673463328329">"Doar o singură dată"</string>
</resources>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 251d487..f91db69 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -175,28 +175,20 @@
<string name="permgroupdesc_location" msgid="5704679763124170100">"Övervaka din fysiska plats."</string>
<string name="permgrouplab_network" msgid="5808983377727109831">"Nätverkskommunikation"</string>
<string name="permgroupdesc_network" msgid="4478299413241861987">"Åtkomst till olika nätverksfunktioner."</string>
- <!-- no translation found for permgrouplab_bluetoothNetwork (1585403544162128109) -->
- <skip />
- <!-- no translation found for permgroupdesc_bluetoothNetwork (5625288577164282391) -->
- <skip />
- <!-- no translation found for permgrouplab_shortrangeNetwork (130808676377486118) -->
- <skip />
- <!-- no translation found for permgroupdesc_shortrangeNetwork (1884069062653436007) -->
- <skip />
+ <string name="permgrouplab_bluetoothNetwork" msgid="1585403544162128109">"Bluetooth"</string>
+ <string name="permgroupdesc_bluetoothNetwork" msgid="5625288577164282391">"Få åtkomst till enheter och nätverk via Bluetooth."</string>
+ <string name="permgrouplab_shortrangeNetwork" msgid="130808676377486118">"Nätverk för kommunikation på nära håll"</string>
+ <string name="permgroupdesc_shortrangeNetwork" msgid="1884069062653436007">"Få åtkomst till enheter via nätverk för kommunikation på nära håll, som NFC."</string>
<string name="permgrouplab_audioSettings" msgid="8329261670151871235">"Ljudinställningar"</string>
<string name="permgroupdesc_audioSettings" msgid="2641515403347568130">"Ändra ljudinställningar."</string>
<string name="permgrouplab_affectsBattery" msgid="6209246653424798033">"Påverkar batteriet"</string>
<string name="permgroupdesc_affectsBattery" msgid="6441275320638916947">"Använda funktioner som gör att batteriet tar slut snabbt."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Kalender"</string>
<string name="permgroupdesc_calendar" msgid="5777534316982184416">"Direktåtkomst till kalender och händelser."</string>
- <!-- no translation found for permgrouplab_dictionary (4148597128843641379) -->
- <skip />
- <!-- no translation found for permgroupdesc_dictionary (7921166355964764490) -->
- <skip />
- <!-- no translation found for permgrouplab_writeDictionary (8090237702432576788) -->
- <skip />
- <!-- no translation found for permgroupdesc_writeDictionary (2711561994497361646) -->
- <skip />
+ <string name="permgrouplab_dictionary" msgid="4148597128843641379">"Läsa den egna ordlistan"</string>
+ <string name="permgroupdesc_dictionary" msgid="7921166355964764490">"Läsa ord i den egna ordlistan."</string>
+ <string name="permgrouplab_writeDictionary" msgid="8090237702432576788">"Skriva i den egna ordlistan"</string>
+ <string name="permgroupdesc_writeDictionary" msgid="2711561994497361646">"Lägga till ord i den egna ordlistan."</string>
<string name="permgrouplab_bookmarks" msgid="1949519673103968229">"Bokmärken och historik"</string>
<string name="permgroupdesc_bookmarks" msgid="4169771606257963028">"Direktåtkomst till bokmärken och webbläsarhistorik."</string>
<string name="permgrouplab_deviceAlarms" msgid="6117704629728824101">"Larm"</string>
@@ -569,8 +561,7 @@
<string name="permdesc_sdcardRead" product="nosdcard" msgid="3530894470637667917">"Tillåter att innehållet läses."</string>
<string name="permdesc_sdcardRead" product="default" msgid="2555811422562526606">"Tillåter att appen läser SD-kortets innehåll, inklusive eventuella bilder och media."</string>
<string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"ändra eller ta bort innehållet"</string>
- <!-- no translation found for permlab_sdcardWrite (8805693630050458763) -->
- <skip />
+ <string name="permlab_sdcardWrite" product="default" msgid="8805693630050458763">"ändra eller ta bort innehåll på SD-kortet"</string>
<string name="permdesc_sdcardWrite" product="nosdcard" msgid="6175406299445710888">"Gör att app skriver till USB."</string>
<string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Tillåter att appen skriver till SD-kortet."</string>
<string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"ändra/ta bort innehåll"</string>
@@ -1090,8 +1081,7 @@
<string name="date_time_set" msgid="5777075614321087758">"Ställ in"</string>
<string name="date_time_done" msgid="2507683751759308828">"Klar"</string>
<string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ff900000">"NY: "</font></string>
- <!-- no translation found for perms_description_app (5139836143293299417) -->
- <skip />
+ <string name="perms_description_app" msgid="5139836143293299417">"Tillhandahålls av <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="no_permissions" msgid="7283357728219338112">"Inga behörigheter krävs"</string>
<string name="usb_storage_activity_title" msgid="4465055157209648641">"USB-masslagring"</string>
<string name="usb_storage_title" msgid="5901459041398751495">"USB-ansluten"</string>
@@ -1322,6 +1312,5 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Vill du öppna webbläsaren?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Vill du ta emot samtal?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Alltid"</string>
- <!-- no translation found for activity_resolver_use_once (405646673463328329) -->
- <skip />
+ <string name="activity_resolver_use_once" msgid="405646673463328329">"Bara den här gången"</string>
</resources>
diff --git a/core/res/res/values-w500dp/bools.xml b/core/res/res/values-w500dp/bools.xml
deleted file mode 100644
index f53fd39..0000000
--- a/core/res/res/values-w500dp/bools.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<resources>
- <bool name="activity_chooser_view_has_default_activity">true</bool>
-</resources>
\ No newline at end of file
diff --git a/core/res/res/values/bools.xml b/core/res/res/values/bools.xml
index 6910ebe..f9762b1 100644
--- a/core/res/res/values/bools.xml
+++ b/core/res/res/values/bools.xml
@@ -22,5 +22,4 @@
<bool name="show_ongoing_ime_switcher">true</bool>
<bool name="action_bar_expanded_action_views_exclusive">true</bool>
<bool name="target_honeycomb_needs_options_menu">true</bool>
- <bool name="activity_chooser_view_has_default_activity">false</bool>
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 48038dd..a24e345c 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1380,7 +1380,6 @@
<java-symbol type="bool" name="config_wifi_dual_band_support" />
<java-symbol type="bool" name="config_wimaxEnabled" />
<java-symbol type="bool" name="show_ongoing_ime_switcher" />
- <java-symbol type="bool" name="activity_chooser_view_has_default_activity" />
<java-symbol type="color" name="config_defaultNotificationColor" />
<java-symbol type="drawable" name="ic_notification_ime_default" />
<java-symbol type="drawable" name="stat_notify_car_mode" />
diff --git a/core/tests/utillib/src/android/test/BandwidthTestCase.java b/core/tests/utillib/src/android/test/BandwidthTestCase.java
index 4f95f77..c03d9b3 100644
--- a/core/tests/utillib/src/android/test/BandwidthTestCase.java
+++ b/core/tests/utillib/src/android/test/BandwidthTestCase.java
@@ -18,6 +18,7 @@
import android.net.NetworkStats;
import android.net.TrafficStats;
import android.os.Bundle;
+import android.util.Log;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@@ -29,6 +30,7 @@
* as an {@link InstrumentationTestCase}
*/
public class BandwidthTestCase extends InstrumentationTestCase {
+ private static final String TAG = "BandwidthTestCase";
private static final String REPORT_KEY_PACKETS_SENT = "txPackets";
private static final String REPORT_KEY_PACKETS_RECEIVED = "rxPackets";
private static final String REPORT_KEY_BYTES_SENT = "txBytes";
@@ -86,11 +88,26 @@
}
} else if (method.isAnnotationPresent(BandwidthTest.class) ||
testClass.isAnnotationPresent(BandwidthTest.class)) {
- TrafficStats.startDataProfiling(null);
+ /**
+ * If bandwidth profiling fails for whatever reason the test
+ * should be allow to execute to its completion.
+ * Typically bandwidth profiling would fail when a lower level
+ * component is missing, such as the kernel module, for a newly
+ * introduced hardware.
+ */
+ try{
+ TrafficStats.startDataProfiling(null);
+ } catch(IllegalStateException isx){
+ Log.w(TAG, "Failed to start bandwidth profiling");
+ }
runMethod(method, 1, false);
- NetworkStats stats = TrafficStats.stopDataProfiling(null);
- NetworkStats.Entry entry = stats.getTotal(null);
- getInstrumentation().sendStatus(2, getBandwidthStats(entry));
+ try{
+ NetworkStats stats = TrafficStats.stopDataProfiling(null);
+ NetworkStats.Entry entry = stats.getTotal(null);
+ getInstrumentation().sendStatus(2, getBandwidthStats(entry));
+ } catch (IllegalStateException isx){
+ Log.w(TAG, "Failed to collect bandwidth stats");
+ }
} else {
runMethod(method, runCount, isRepetitive);
}
diff --git a/data/fonts/fallback_fonts.xml b/data/fonts/fallback_fonts.xml
index 8517152..5f7017e 100644
--- a/data/fonts/fallback_fonts.xml
+++ b/data/fonts/fallback_fonts.xml
@@ -72,6 +72,7 @@
<fileset>
<file>DroidSansTamil-Regular.ttf</file>
<file>DroidSansTamil-Bold.ttf</file>
+ </fileset>
</family>
<family>
<fileset>
diff --git a/include/androidfw/Input.h b/include/androidfw/Input.h
index aa8b824..2c91fab 100644
--- a/include/androidfw/Input.h
+++ b/include/androidfw/Input.h
@@ -176,7 +176,6 @@
status_t setAxisValue(int32_t axis, float value);
void scale(float scale);
- void lerp(const PointerCoords& a, const PointerCoords& b, float alpha);
inline float getX() const {
return getAxisValue(AMOTION_EVENT_AXIS_X);
diff --git a/include/androidfw/InputTransport.h b/include/androidfw/InputTransport.h
index 2924505..5706bce 100644
--- a/include/androidfw/InputTransport.h
+++ b/include/androidfw/InputTransport.h
@@ -92,6 +92,12 @@
PointerCoords coords;
} pointers[MAX_POINTERS];
+ int32_t getActionId() const {
+ uint32_t index = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK)
+ >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
+ return pointers[index].properties.id;
+ }
+
inline size_t size() const {
return sizeof(Motion) - sizeof(Pointer) * MAX_POINTERS
+ sizeof(Pointer) * pointerCount;
@@ -322,6 +328,10 @@
bool hasPendingBatch() const;
private:
+ // True if touch resampling is enabled.
+ const bool mResampleTouch;
+
+ // The input channel.
sp<InputChannel> mChannel;
// The current input message.
@@ -341,6 +351,7 @@
struct History {
nsecs_t eventTime;
BitSet32 idBits;
+ int32_t idToIndex[MAX_POINTER_ID + 1];
PointerCoords pointers[MAX_POINTERS];
void initializeFrom(const InputMessage* msg) {
@@ -349,10 +360,14 @@
for (size_t i = 0; i < msg->body.motion.pointerCount; i++) {
uint32_t id = msg->body.motion.pointers[i].properties.id;
idBits.markBit(id);
- size_t index = idBits.getIndexOfBit(id);
- pointers[index].copyFrom(msg->body.motion.pointers[i].coords);
+ idToIndex[id] = i;
+ pointers[i].copyFrom(msg->body.motion.pointers[i].coords);
}
}
+
+ const PointerCoords& getPointerById(uint32_t id) const {
+ return pointers[idToIndex[id]];
+ }
};
struct TouchState {
int32_t deviceId;
@@ -360,12 +375,15 @@
size_t historyCurrent;
size_t historySize;
History history[2];
+ History lastResample;
void initialize(int32_t deviceId, int32_t source) {
this->deviceId = deviceId;
this->source = source;
historyCurrent = 0;
historySize = 0;
+ lastResample.eventTime = 0;
+ lastResample.idBits.clear();
}
void addHistory(const InputMessage* msg) {
@@ -398,6 +416,7 @@
Batch& batch, size_t count, uint32_t* outSeq, InputEvent** outEvent);
void updateTouchState(InputMessage* msg);
+ void rewriteMessage(const TouchState& state, InputMessage* msg);
void resampleTouchState(nsecs_t frameTime, MotionEvent* event,
const InputMessage *next);
@@ -412,6 +431,8 @@
static bool canAddSample(const Batch& batch, const InputMessage* msg);
static ssize_t findSampleNoLaterThan(const Batch& batch, nsecs_t time);
static bool shouldResampleTool(int32_t toolType);
+
+ static bool isTouchResamplingEnabled();
};
} // namespace android
diff --git a/include/androidfw/VelocityTracker.h b/include/androidfw/VelocityTracker.h
index 6d17e1f..cbb07829 100644
--- a/include/androidfw/VelocityTracker.h
+++ b/include/androidfw/VelocityTracker.h
@@ -23,19 +23,13 @@
namespace android {
+class VelocityTrackerStrategy;
+
/*
* Calculates the velocity of pointer movements over time.
*/
class VelocityTracker {
public:
- // Default polynomial degree. (used by getVelocity)
- static const uint32_t DEFAULT_DEGREE = 2;
-
- // Default sample horizon. (used by getVelocity)
- // We don't use too much history by default since we want to react to quick
- // changes in direction.
- static const nsecs_t DEFAULT_HORIZON = 100 * 1000000; // 100 ms
-
struct Position {
float x, y;
};
@@ -43,6 +37,9 @@
struct Estimator {
static const size_t MAX_DEGREE = 2;
+ // Estimator time base.
+ nsecs_t time;
+
// Polynomial coefficients describing motion in X and Y.
float xCoeff[MAX_DEGREE + 1], yCoeff[MAX_DEGREE + 1];
@@ -54,6 +51,7 @@
float confidence;
inline void clear() {
+ time = 0;
degree = 0;
confidence = 0;
for (size_t i = 0; i <= MAX_DEGREE; i++) {
@@ -64,6 +62,7 @@
};
VelocityTracker();
+ ~VelocityTracker();
// Resets the velocity tracker state.
void clear();
@@ -88,35 +87,81 @@
// insufficient movement information for the pointer.
bool getVelocity(uint32_t id, float* outVx, float* outVy) const;
- // Gets a quadratic estimator for the movements of the specified pointer id.
+ // Gets an estimator for the recent movements of the specified pointer id.
// Returns false and clears the estimator if there is no information available
// about the pointer.
- bool getEstimator(uint32_t id, uint32_t degree, nsecs_t horizon,
- Estimator* outEstimator) const;
+ bool getEstimator(uint32_t id, Estimator* outEstimator) const;
// Gets the active pointer id, or -1 if none.
inline int32_t getActivePointerId() const { return mActivePointerId; }
// Gets a bitset containing all pointer ids from the most recent movement.
- inline BitSet32 getCurrentPointerIdBits() const { return mMovements[mIndex].idBits; }
+ inline BitSet32 getCurrentPointerIdBits() const { return mCurrentPointerIdBits; }
private:
+ nsecs_t mLastEventTime;
+ BitSet32 mCurrentPointerIdBits;
+ int32_t mActivePointerId;
+ VelocityTrackerStrategy* mStrategy;
+};
+
+
+/*
+ * Implements a particular velocity tracker algorithm.
+ */
+class VelocityTrackerStrategy {
+protected:
+ VelocityTrackerStrategy() { }
+
+public:
+ virtual ~VelocityTrackerStrategy() { }
+
+ virtual void clear() = 0;
+ virtual void clearPointers(BitSet32 idBits) = 0;
+ virtual void addMovement(nsecs_t eventTime, BitSet32 idBits,
+ const VelocityTracker::Position* positions) = 0;
+ virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const = 0;
+};
+
+
+/*
+ * Velocity tracker algorithm based on least-squares linear regression.
+ */
+class LeastSquaresVelocityTrackerStrategy : public VelocityTrackerStrategy {
+public:
+ LeastSquaresVelocityTrackerStrategy();
+ virtual ~LeastSquaresVelocityTrackerStrategy();
+
+ virtual void clear();
+ virtual void clearPointers(BitSet32 idBits);
+ virtual void addMovement(nsecs_t eventTime, BitSet32 idBits,
+ const VelocityTracker::Position* positions);
+ virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const;
+
+private:
+ // Polynomial degree. Must be less than or equal to Estimator::MAX_DEGREE.
+ static const uint32_t DEGREE = 2;
+
+ // Sample horizon.
+ // We don't use too much history by default since we want to react to quick
+ // changes in direction.
+ static const nsecs_t HORIZON = 100 * 1000000; // 100 ms
+
// Number of samples to keep.
static const uint32_t HISTORY_SIZE = 20;
struct Movement {
nsecs_t eventTime;
BitSet32 idBits;
- Position positions[MAX_POINTERS];
+ VelocityTracker::Position positions[MAX_POINTERS];
- inline const Position& getPosition(uint32_t id) const {
+ inline const VelocityTracker::Position& getPosition(uint32_t id) const {
return positions[idBits.getIndexOfBit(id)];
}
};
uint32_t mIndex;
Movement mMovements[HISTORY_SIZE];
- int32_t mActivePointerId;
};
} // namespace android
diff --git a/libs/androidfw/Input.cpp b/libs/androidfw/Input.cpp
index 40a6c47..97b0ec1 100644
--- a/libs/androidfw/Input.cpp
+++ b/libs/androidfw/Input.cpp
@@ -211,26 +211,6 @@
scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOOL_MINOR, scaleFactor);
}
-void PointerCoords::lerp(const PointerCoords& a, const PointerCoords& b, float alpha) {
- bits = 0;
- for (uint64_t bitsRemaining = a.bits | b.bits; bitsRemaining; ) {
- int32_t axis = __builtin_ctz(bitsRemaining);
- uint64_t axisBit = 1LL << axis;
- bitsRemaining &= ~axisBit;
- if (a.bits & axisBit) {
- if (b.bits & axisBit) {
- float aval = a.getAxisValue(axis);
- float bval = b.getAxisValue(axis);
- setAxisValue(axis, aval + alpha * (bval - aval));
- } else {
- setAxisValue(axis, a.getAxisValue(axis));
- }
- } else {
- setAxisValue(axis, b.getAxisValue(axis));
- }
- }
-}
-
#ifdef HAVE_ANDROID_OS
status_t PointerCoords::readFromParcel(Parcel* parcel) {
bits = parcel->readInt64();
diff --git a/libs/androidfw/InputTransport.cpp b/libs/androidfw/InputTransport.cpp
index 9a4182c..351c666 100644
--- a/libs/androidfw/InputTransport.cpp
+++ b/libs/androidfw/InputTransport.cpp
@@ -21,6 +21,7 @@
#include <cutils/log.h>
+#include <cutils/properties.h>
#include <errno.h>
#include <fcntl.h>
#include <androidfw/InputTransport.h>
@@ -43,15 +44,23 @@
// Latency added during resampling. A few milliseconds doesn't hurt much but
// reduces the impact of mispredicted touch positions.
-static const nsecs_t RESAMPLE_LATENCY = 4 * NANOS_PER_MS;
+static const nsecs_t RESAMPLE_LATENCY = 5 * NANOS_PER_MS;
// Minimum time difference between consecutive samples before attempting to resample.
-static const nsecs_t RESAMPLE_MIN_DELTA = 1 * NANOS_PER_MS;
+static const nsecs_t RESAMPLE_MIN_DELTA = 2 * NANOS_PER_MS;
-// Maximum linear interpolation scale value. The larger this is, the more error may
-// potentially be introduced.
-static const float RESAMPLE_MAX_ALPHA = 2.0f;
+// Maximum time to predict forward from the last known state, to avoid predicting too
+// far into the future. This time is further bounded by 50% of the last time delta.
+static const nsecs_t RESAMPLE_MAX_PREDICTION = 8 * NANOS_PER_MS;
+template<typename T>
+inline static T min(const T& a, const T& b) {
+ return a < b ? a : b;
+}
+
+inline static float lerp(float a, float b, float alpha) {
+ return a + alpha * (b - a);
+}
// --- InputMessage ---
@@ -352,12 +361,28 @@
// --- InputConsumer ---
InputConsumer::InputConsumer(const sp<InputChannel>& channel) :
+ mResampleTouch(isTouchResamplingEnabled()),
mChannel(channel), mMsgDeferred(false) {
}
InputConsumer::~InputConsumer() {
}
+bool InputConsumer::isTouchResamplingEnabled() {
+ char value[PROPERTY_VALUE_MAX];
+ int length = property_get("debug.inputconsumer.resample", value, NULL);
+ if (length > 0) {
+ if (!strcmp("0", value)) {
+ return false;
+ }
+ if (strcmp("1", value)) {
+ ALOGD("Unrecognized property value for 'debug.inputconsumer.resample'. "
+ "Use '1' or '0'.");
+ }
+ }
+ return true;
+}
+
status_t InputConsumer::consume(InputEventFactoryInterface* factory,
bool consumeBatches, nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) {
#if DEBUG_TRANSPORT_ACTIONS
@@ -538,18 +563,19 @@
}
void InputConsumer::updateTouchState(InputMessage* msg) {
- if (!(msg->body.motion.source & AINPUT_SOURCE_CLASS_POINTER)) {
+ if (!mResampleTouch ||
+ !(msg->body.motion.source & AINPUT_SOURCE_CLASS_POINTER)) {
return;
}
int32_t deviceId = msg->body.motion.deviceId;
int32_t source = msg->body.motion.source;
+ nsecs_t eventTime = msg->body.motion.eventTime;
- // TODO: Filter the incoming touch event so that it aligns better
- // with prior predictions. Turning RESAMPLE_LATENCY offsets the need
- // for filtering but it would be nice to reduce the latency further.
-
- switch (msg->body.motion.action) {
+ // Update the touch state history to incorporate the new input message.
+ // If the message is in the past relative to the most recently produced resampled
+ // touch, then use the resampled time and coordinates instead.
+ switch (msg->body.motion.action & AMOTION_EVENT_ACTION_MASK) {
case AMOTION_EVENT_ACTION_DOWN: {
ssize_t index = findTouchState(deviceId, source);
if (index < 0) {
@@ -567,6 +593,40 @@
if (index >= 0) {
TouchState& touchState = mTouchStates.editItemAt(index);
touchState.addHistory(msg);
+ if (eventTime < touchState.lastResample.eventTime) {
+ rewriteMessage(touchState, msg);
+ } else {
+ touchState.lastResample.idBits.clear();
+ }
+ }
+ break;
+ }
+
+ case AMOTION_EVENT_ACTION_POINTER_DOWN: {
+ ssize_t index = findTouchState(deviceId, source);
+ if (index >= 0) {
+ TouchState& touchState = mTouchStates.editItemAt(index);
+ touchState.lastResample.idBits.clearBit(msg->body.motion.getActionId());
+ rewriteMessage(touchState, msg);
+ }
+ break;
+ }
+
+ case AMOTION_EVENT_ACTION_POINTER_UP: {
+ ssize_t index = findTouchState(deviceId, source);
+ if (index >= 0) {
+ TouchState& touchState = mTouchStates.editItemAt(index);
+ rewriteMessage(touchState, msg);
+ touchState.lastResample.idBits.clearBit(msg->body.motion.getActionId());
+ }
+ break;
+ }
+
+ case AMOTION_EVENT_ACTION_SCROLL: {
+ ssize_t index = findTouchState(deviceId, source);
+ if (index >= 0) {
+ const TouchState& touchState = mTouchStates.itemAt(index);
+ rewriteMessage(touchState, msg);
}
break;
}
@@ -575,6 +635,8 @@
case AMOTION_EVENT_ACTION_CANCEL: {
ssize_t index = findTouchState(deviceId, source);
if (index >= 0) {
+ const TouchState& touchState = mTouchStates.itemAt(index);
+ rewriteMessage(touchState, msg);
mTouchStates.removeAt(index);
}
break;
@@ -582,13 +644,30 @@
}
}
+void InputConsumer::rewriteMessage(const TouchState& state, InputMessage* msg) {
+ for (size_t i = 0; i < msg->body.motion.pointerCount; i++) {
+ uint32_t id = msg->body.motion.pointers[i].properties.id;
+ if (state.lastResample.idBits.hasBit(id)) {
+ PointerCoords& msgCoords = msg->body.motion.pointers[i].coords;
+ const PointerCoords& resampleCoords = state.lastResample.getPointerById(id);
+#if DEBUG_RESAMPLING
+ ALOGD("[%d] - rewrite (%0.3f, %0.3f), old (%0.3f, %0.3f)", id,
+ resampleCoords.getAxisValue(AMOTION_EVENT_AXIS_X),
+ resampleCoords.getAxisValue(AMOTION_EVENT_AXIS_Y),
+ msgCoords.getAxisValue(AMOTION_EVENT_AXIS_X),
+ msgCoords.getAxisValue(AMOTION_EVENT_AXIS_Y));
+#endif
+ msgCoords.setAxisValue(AMOTION_EVENT_AXIS_X, resampleCoords.getX());
+ msgCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, resampleCoords.getY());
+ }
+ }
+}
+
void InputConsumer::resampleTouchState(nsecs_t sampleTime, MotionEvent* event,
const InputMessage* next) {
- if (event->getAction() != AMOTION_EVENT_ACTION_MOVE
- || !(event->getSource() & AINPUT_SOURCE_CLASS_POINTER)) {
-#if DEBUG_RESAMPLING
- ALOGD("Not resampled, not a move.");
-#endif
+ if (!mResampleTouch
+ || !(event->getSource() & AINPUT_SOURCE_CLASS_POINTER)
+ || event->getAction() != AMOTION_EVENT_ACTION_MOVE) {
return;
}
@@ -608,39 +687,9 @@
return;
}
+ // Ensure that the current sample has all of the pointers that need to be reported.
const History* current = touchState.getHistory(0);
- const History* other;
- History future;
- if (next) {
- future.initializeFrom(next);
- other = &future;
- } else if (touchState.historySize >= 2) {
- other = touchState.getHistory(1);
- } else {
-#if DEBUG_RESAMPLING
- ALOGD("Not resampled, insufficient data.");
-#endif
- return;
- }
-
- nsecs_t delta = current->eventTime - other->eventTime;
- if (delta > -RESAMPLE_MIN_DELTA && delta < RESAMPLE_MIN_DELTA) {
-#if DEBUG_RESAMPLING
- ALOGD("Not resampled, delta time is %lld", delta);
-#endif
- return;
- }
-
- float alpha = float(current->eventTime - sampleTime) / delta;
- if (fabs(alpha) > RESAMPLE_MAX_ALPHA) {
-#if DEBUG_RESAMPLING
- ALOGD("Not resampled, alpha is %f", alpha);
-#endif
- return;
- }
-
size_t pointerCount = event->getPointerCount();
- PointerCoords resampledCoords[MAX_POINTERS];
for (size_t i = 0; i < pointerCount; i++) {
uint32_t id = event->getPointerId(i);
if (!current->idBits.hasBit(id)) {
@@ -649,32 +698,89 @@
#endif
return;
}
- const PointerCoords& currentCoords =
- current->pointers[current->idBits.getIndexOfBit(id)];
+ }
+
+ // Find the data to use for resampling.
+ const History* other;
+ History future;
+ float alpha;
+ if (next) {
+ // Interpolate between current sample and future sample.
+ // So current->eventTime <= sampleTime <= future.eventTime.
+ future.initializeFrom(next);
+ other = &future;
+ nsecs_t delta = future.eventTime - current->eventTime;
+ if (delta < RESAMPLE_MIN_DELTA) {
+#if DEBUG_RESAMPLING
+ ALOGD("Not resampled, delta time is %lld ns.", delta);
+#endif
+ return;
+ }
+ alpha = float(sampleTime - current->eventTime) / delta;
+ } else if (touchState.historySize >= 2) {
+ // Extrapolate future sample using current sample and past sample.
+ // So other->eventTime <= current->eventTime <= sampleTime.
+ other = touchState.getHistory(1);
+ nsecs_t delta = current->eventTime - other->eventTime;
+ if (delta < RESAMPLE_MIN_DELTA) {
+#if DEBUG_RESAMPLING
+ ALOGD("Not resampled, delta time is %lld ns.", delta);
+#endif
+ return;
+ }
+ nsecs_t maxPredict = current->eventTime + min(delta / 2, RESAMPLE_MAX_PREDICTION);
+ if (sampleTime > maxPredict) {
+#if DEBUG_RESAMPLING
+ ALOGD("Sample time is too far in the future, adjusting prediction "
+ "from %lld to %lld ns.",
+ sampleTime - current->eventTime, maxPredict - current->eventTime);
+#endif
+ sampleTime = maxPredict;
+ }
+ alpha = float(current->eventTime - sampleTime) / delta;
+ } else {
+#if DEBUG_RESAMPLING
+ ALOGD("Not resampled, insufficient data.");
+#endif
+ return;
+ }
+
+ // Resample touch coordinates.
+ touchState.lastResample.eventTime = sampleTime;
+ touchState.lastResample.idBits.clear();
+ for (size_t i = 0; i < pointerCount; i++) {
+ uint32_t id = event->getPointerId(i);
+ touchState.lastResample.idToIndex[id] = i;
+ touchState.lastResample.idBits.markBit(id);
+ PointerCoords& resampledCoords = touchState.lastResample.pointers[i];
+ const PointerCoords& currentCoords = current->getPointerById(id);
if (other->idBits.hasBit(id)
&& shouldResampleTool(event->getToolType(i))) {
- const PointerCoords& otherCoords =
- other->pointers[other->idBits.getIndexOfBit(id)];
- resampledCoords[i].lerp(currentCoords, otherCoords, alpha);
+ const PointerCoords& otherCoords = other->getPointerById(id);
+ resampledCoords.copyFrom(currentCoords);
+ resampledCoords.setAxisValue(AMOTION_EVENT_AXIS_X,
+ lerp(currentCoords.getX(), otherCoords.getX(), alpha));
+ resampledCoords.setAxisValue(AMOTION_EVENT_AXIS_Y,
+ lerp(currentCoords.getY(), otherCoords.getY(), alpha));
#if DEBUG_RESAMPLING
ALOGD("[%d] - out (%0.3f, %0.3f), cur (%0.3f, %0.3f), "
"other (%0.3f, %0.3f), alpha %0.3f",
- i, resampledCoords[i].getX(), resampledCoords[i].getY(),
+ id, resampledCoords.getX(), resampledCoords.getY(),
currentCoords.getX(), currentCoords.getY(),
otherCoords.getX(), otherCoords.getY(),
alpha);
#endif
} else {
- resampledCoords[i].copyFrom(currentCoords);
+ resampledCoords.copyFrom(currentCoords);
#if DEBUG_RESAMPLING
ALOGD("[%d] - out (%0.3f, %0.3f), cur (%0.3f, %0.3f)",
- i, resampledCoords[i].getX(), resampledCoords[i].getY(),
+ id, resampledCoords.getX(), resampledCoords.getY(),
currentCoords.getX(), currentCoords.getY());
#endif
}
}
- event->addSample(sampleTime, resampledCoords);
+ event->addSample(sampleTime, touchState.lastResample.pointers);
}
bool InputConsumer::shouldResampleTool(int32_t toolType) {
diff --git a/libs/androidfw/VelocityTracker.cpp b/libs/androidfw/VelocityTracker.cpp
index 2fb094e..5dbafd8 100644
--- a/libs/androidfw/VelocityTracker.cpp
+++ b/libs/androidfw/VelocityTracker.cpp
@@ -33,13 +33,17 @@
namespace android {
-// --- VelocityTracker ---
+// Nanoseconds per milliseconds.
+static const nsecs_t NANOS_PER_MS = 1000000;
-const uint32_t VelocityTracker::DEFAULT_DEGREE;
-const nsecs_t VelocityTracker::DEFAULT_HORIZON;
-const uint32_t VelocityTracker::HISTORY_SIZE;
+// Threshold for determining that a pointer has stopped moving.
+// Some input devices do not send ACTION_MOVE events in the case where a pointer has
+// stopped. We need to detect this case so that we can accurately predict the
+// velocity after the pointer starts moving again.
+static const nsecs_t ASSUME_POINTER_STOPPED_TIME = 40 * NANOS_PER_MS;
-static inline float vectorDot(const float* a, const float* b, uint32_t m) {
+
+static float vectorDot(const float* a, const float* b, uint32_t m) {
float r = 0;
while (m--) {
r += *(a++) * *(b++);
@@ -47,7 +51,7 @@
return r;
}
-static inline float vectorNorm(const float* a, uint32_t m) {
+static float vectorNorm(const float* a, uint32_t m) {
float r = 0;
while (m--) {
float t = *(a++);
@@ -91,45 +95,59 @@
}
#endif
-VelocityTracker::VelocityTracker() {
- clear();
+
+// --- VelocityTracker ---
+
+VelocityTracker::VelocityTracker() :
+ mLastEventTime(0), mCurrentPointerIdBits(0), mActivePointerId(-1),
+ mStrategy(new LeastSquaresVelocityTrackerStrategy()) {
+}
+
+VelocityTracker::~VelocityTracker() {
+ delete mStrategy;
}
void VelocityTracker::clear() {
- mIndex = 0;
- mMovements[0].idBits.clear();
+ mCurrentPointerIdBits.clear();
mActivePointerId = -1;
+
+ mStrategy->clear();
}
void VelocityTracker::clearPointers(BitSet32 idBits) {
- BitSet32 remainingIdBits(mMovements[mIndex].idBits.value & ~idBits.value);
- mMovements[mIndex].idBits = remainingIdBits;
+ BitSet32 remainingIdBits(mCurrentPointerIdBits.value & ~idBits.value);
+ mCurrentPointerIdBits = remainingIdBits;
if (mActivePointerId >= 0 && idBits.hasBit(mActivePointerId)) {
mActivePointerId = !remainingIdBits.isEmpty() ? remainingIdBits.firstMarkedBit() : -1;
}
+
+ mStrategy->clearPointers(idBits);
}
void VelocityTracker::addMovement(nsecs_t eventTime, BitSet32 idBits, const Position* positions) {
- if (++mIndex == HISTORY_SIZE) {
- mIndex = 0;
- }
-
while (idBits.count() > MAX_POINTERS) {
idBits.clearLastMarkedBit();
}
- Movement& movement = mMovements[mIndex];
- movement.eventTime = eventTime;
- movement.idBits = idBits;
- uint32_t count = idBits.count();
- for (uint32_t i = 0; i < count; i++) {
- movement.positions[i] = positions[i];
+ if ((mCurrentPointerIdBits.value & idBits.value)
+ && eventTime >= mLastEventTime + ASSUME_POINTER_STOPPED_TIME) {
+#if DEBUG_VELOCITY
+ ALOGD("VelocityTracker: stopped for %0.3f ms, clearing state.",
+ (eventTime - mLastEventTime) * 0.000001f);
+#endif
+ // We have not received any movements for too long. Assume that all pointers
+ // have stopped.
+ mStrategy->clear();
+ }
+ mLastEventTime = eventTime;
+
+ mCurrentPointerIdBits = idBits;
+ if (mActivePointerId < 0 || !idBits.hasBit(mActivePointerId)) {
+ mActivePointerId = idBits.isEmpty() ? -1 : idBits.firstMarkedBit();
}
- if (mActivePointerId < 0 || !idBits.hasBit(mActivePointerId)) {
- mActivePointerId = count != 0 ? idBits.firstMarkedBit() : -1;
- }
+ mStrategy->addMovement(eventTime, idBits, positions);
#if DEBUG_VELOCITY
ALOGD("VelocityTracker: addMovement eventTime=%lld, idBits=0x%08x, activePointerId=%d",
@@ -139,13 +157,13 @@
uint32_t index = idBits.getIndexOfBit(id);
iterBits.clearBit(id);
Estimator estimator;
- getEstimator(id, DEFAULT_DEGREE, DEFAULT_HORIZON, &estimator);
+ getEstimator(id, &estimator);
ALOGD(" %d: position (%0.3f, %0.3f), "
"estimator (degree=%d, xCoeff=%s, yCoeff=%s, confidence=%f)",
id, positions[index].x, positions[index].y,
int(estimator.degree),
- vectorToString(estimator.xCoeff, estimator.degree).string(),
- vectorToString(estimator.yCoeff, estimator.degree).string(),
+ vectorToString(estimator.xCoeff, estimator.degree + 1).string(),
+ vectorToString(estimator.yCoeff, estimator.degree + 1).string(),
estimator.confidence);
}
#endif
@@ -194,6 +212,11 @@
idBits.markBit(event->getPointerId(i));
}
+ uint32_t pointerIndex[MAX_POINTERS];
+ for (size_t i = 0; i < pointerCount; i++) {
+ pointerIndex[i] = idBits.getIndexOfBit(event->getPointerId(i));
+ }
+
nsecs_t eventTime;
Position positions[pointerCount];
@@ -201,20 +224,77 @@
for (size_t h = 0; h < historySize; h++) {
eventTime = event->getHistoricalEventTime(h);
for (size_t i = 0; i < pointerCount; i++) {
- positions[i].x = event->getHistoricalX(i, h);
- positions[i].y = event->getHistoricalY(i, h);
+ uint32_t index = pointerIndex[i];
+ positions[index].x = event->getHistoricalX(i, h);
+ positions[index].y = event->getHistoricalY(i, h);
}
addMovement(eventTime, idBits, positions);
}
eventTime = event->getEventTime();
for (size_t i = 0; i < pointerCount; i++) {
- positions[i].x = event->getX(i);
- positions[i].y = event->getY(i);
+ uint32_t index = pointerIndex[i];
+ positions[index].x = event->getX(i);
+ positions[index].y = event->getY(i);
}
addMovement(eventTime, idBits, positions);
}
+bool VelocityTracker::getVelocity(uint32_t id, float* outVx, float* outVy) const {
+ Estimator estimator;
+ if (getEstimator(id, &estimator) && estimator.degree >= 1) {
+ *outVx = estimator.xCoeff[1];
+ *outVy = estimator.yCoeff[1];
+ return true;
+ }
+ *outVx = 0;
+ *outVy = 0;
+ return false;
+}
+
+bool VelocityTracker::getEstimator(uint32_t id, Estimator* outEstimator) const {
+ return mStrategy->getEstimator(id, outEstimator);
+}
+
+
+// --- LeastSquaresVelocityTrackerStrategy ---
+
+const uint32_t LeastSquaresVelocityTrackerStrategy::DEGREE;
+const nsecs_t LeastSquaresVelocityTrackerStrategy::HORIZON;
+const uint32_t LeastSquaresVelocityTrackerStrategy::HISTORY_SIZE;
+
+LeastSquaresVelocityTrackerStrategy::LeastSquaresVelocityTrackerStrategy() {
+ clear();
+}
+
+LeastSquaresVelocityTrackerStrategy::~LeastSquaresVelocityTrackerStrategy() {
+}
+
+void LeastSquaresVelocityTrackerStrategy::clear() {
+ mIndex = 0;
+ mMovements[0].idBits.clear();
+}
+
+void LeastSquaresVelocityTrackerStrategy::clearPointers(BitSet32 idBits) {
+ BitSet32 remainingIdBits(mMovements[mIndex].idBits.value & ~idBits.value);
+ mMovements[mIndex].idBits = remainingIdBits;
+}
+
+void LeastSquaresVelocityTrackerStrategy::addMovement(nsecs_t eventTime, BitSet32 idBits,
+ const VelocityTracker::Position* positions) {
+ if (++mIndex == HISTORY_SIZE) {
+ mIndex = 0;
+ }
+
+ Movement& movement = mMovements[mIndex];
+ movement.eventTime = eventTime;
+ movement.idBits = idBits;
+ uint32_t count = idBits.count();
+ for (uint32_t i = 0; i < count; i++) {
+ movement.positions[i] = positions[i];
+ }
+}
+
/**
* Solves a linear least squares problem to obtain a N degree polynomial that fits
* the specified input data as nearly as possible.
@@ -361,22 +441,8 @@
return true;
}
-bool VelocityTracker::getVelocity(uint32_t id, float* outVx, float* outVy) const {
- Estimator estimator;
- if (getEstimator(id, DEFAULT_DEGREE, DEFAULT_HORIZON, &estimator)) {
- if (estimator.degree >= 1) {
- *outVx = estimator.xCoeff[1];
- *outVy = estimator.yCoeff[1];
- return true;
- }
- }
- *outVx = 0;
- *outVy = 0;
- return false;
-}
-
-bool VelocityTracker::getEstimator(uint32_t id, uint32_t degree, nsecs_t horizon,
- Estimator* outEstimator) const {
+bool LeastSquaresVelocityTrackerStrategy::getEstimator(uint32_t id,
+ VelocityTracker::Estimator* outEstimator) const {
outEstimator->clear();
// Iterate over movement samples in reverse time order and collect samples.
@@ -393,11 +459,11 @@
}
nsecs_t age = newestMovement.eventTime - movement.eventTime;
- if (age > horizon) {
+ if (age > HORIZON) {
break;
}
- const Position& position = movement.getPosition(id);
+ const VelocityTracker::Position& position = movement.getPosition(id);
x[m] = position.x;
y[m] = position.y;
time[m] = -age * 0.000000001f;
@@ -409,9 +475,7 @@
}
// Calculate a least squares polynomial fit.
- if (degree > Estimator::MAX_DEGREE) {
- degree = Estimator::MAX_DEGREE;
- }
+ uint32_t degree = DEGREE;
if (degree > m - 1) {
degree = m - 1;
}
@@ -420,6 +484,7 @@
uint32_t n = degree + 1;
if (solveLeastSquares(time, x, m, n, outEstimator->xCoeff, &xdet)
&& solveLeastSquares(time, y, m, n, outEstimator->yCoeff, &ydet)) {
+ outEstimator->time = newestMovement.eventTime;
outEstimator->degree = degree;
outEstimator->confidence = xdet * ydet;
#if DEBUG_LEAST_SQUARES
@@ -436,6 +501,7 @@
// No velocity data available for this pointer, but we do have its current position.
outEstimator->xCoeff[0] = x[0];
outEstimator->yCoeff[0] = y[0];
+ outEstimator->time = newestMovement.eventTime;
outEstimator->degree = 0;
outEstimator->confidence = 1;
return true;
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index f6ca77c..a5f653a 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -49,6 +49,7 @@
"DrawBitmap",
"DrawBitmapMatrix",
"DrawBitmapRect",
+ "DrawBitmapData",
"DrawBitmapMesh",
"DrawPatch",
"DrawColor",
@@ -161,6 +162,13 @@
}
mBitmapResources.clear();
+ for (size_t i = 0; i < mOwnedBitmapResources.size(); i++) {
+ SkBitmap* bitmap = mOwnedBitmapResources.itemAt(i);
+ caches.resourceCache.decrementRefcount(bitmap);
+ caches.resourceCache.destructor(bitmap);
+ }
+ mOwnedBitmapResources.clear();
+
for (size_t i = 0; i < mFilterResources.size(); i++) {
caches.resourceCache.decrementRefcount(mFilterResources.itemAt(i));
}
@@ -216,44 +224,51 @@
Caches& caches = Caches::getInstance();
- const Vector<SkBitmap*> &bitmapResources = recorder.getBitmapResources();
+ const Vector<SkBitmap*>& bitmapResources = recorder.getBitmapResources();
for (size_t i = 0; i < bitmapResources.size(); i++) {
SkBitmap* resource = bitmapResources.itemAt(i);
mBitmapResources.add(resource);
caches.resourceCache.incrementRefcount(resource);
}
- const Vector<SkiaColorFilter*> &filterResources = recorder.getFilterResources();
+ const Vector<SkBitmap*> &ownedBitmapResources = recorder.getOwnedBitmapResources();
+ for (size_t i = 0; i < ownedBitmapResources.size(); i++) {
+ SkBitmap* resource = ownedBitmapResources.itemAt(i);
+ mOwnedBitmapResources.add(resource);
+ caches.resourceCache.incrementRefcount(resource);
+ }
+
+ const Vector<SkiaColorFilter*>& filterResources = recorder.getFilterResources();
for (size_t i = 0; i < filterResources.size(); i++) {
SkiaColorFilter* resource = filterResources.itemAt(i);
mFilterResources.add(resource);
caches.resourceCache.incrementRefcount(resource);
}
- const Vector<SkiaShader*> &shaders = recorder.getShaders();
+ const Vector<SkiaShader*>& shaders = recorder.getShaders();
for (size_t i = 0; i < shaders.size(); i++) {
SkiaShader* resource = shaders.itemAt(i);
mShaders.add(resource);
caches.resourceCache.incrementRefcount(resource);
}
- const Vector<SkPaint*> &paints = recorder.getPaints();
+ const Vector<SkPaint*>& paints = recorder.getPaints();
for (size_t i = 0; i < paints.size(); i++) {
mPaints.add(paints.itemAt(i));
}
- const Vector<SkPath*> &paths = recorder.getPaths();
+ const Vector<SkPath*>& paths = recorder.getPaths();
for (size_t i = 0; i < paths.size(); i++) {
mPaths.add(paths.itemAt(i));
}
- const SortedVector<SkPath*> &sourcePaths = recorder.getSourcePaths();
+ const SortedVector<SkPath*>& sourcePaths = recorder.getSourcePaths();
for (size_t i = 0; i < sourcePaths.size(); i++) {
mSourcePaths.add(sourcePaths.itemAt(i));
caches.resourceCache.incrementRefcount(sourcePaths.itemAt(i));
}
- const Vector<SkMatrix*> &matrices = recorder.getMatrices();
+ const Vector<SkMatrix*>& matrices = recorder.getMatrices();
for (size_t i = 0; i < matrices.size(); i++) {
mMatrices.add(matrices.itemAt(i));
}
@@ -434,6 +449,14 @@
(char*) indent, OP_NAMES[op], bitmap, f1, f2, f3, f4, f5, f6, f7, f8, paint);
}
break;
+ case DrawBitmapData: {
+ SkBitmap* bitmap = getBitmapData();
+ float x = getFloat();
+ float y = getFloat();
+ SkPaint* paint = getPaint(renderer);
+ ALOGD("%s%s %.2f, %.2f, %p", (char*) indent, OP_NAMES[op], x, y, paint);
+ }
+ break;
case DrawBitmapMesh: {
int verticesCount = 0;
uint32_t colorsCount = 0;
@@ -1020,6 +1043,16 @@
renderer.drawBitmap(bitmap, f1, f2, f3, f4, f5, f6, f7, f8, paint);
}
break;
+ case DrawBitmapData: {
+ SkBitmap* bitmap = getBitmapData();
+ float x = getFloat();
+ float y = getFloat();
+ SkPaint* paint = getPaint(renderer);
+ DISPLAY_LIST_LOGD("%s%s %p, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
+ bitmap, x, y, paint);
+ renderer.drawBitmap(bitmap, x, y, paint);
+ }
+ break;
case DrawBitmapMesh: {
int32_t verticesCount = 0;
uint32_t colorsCount = 0;
@@ -1273,6 +1306,12 @@
}
mBitmapResources.clear();
+ for (size_t i = 0; i < mOwnedBitmapResources.size(); i++) {
+ SkBitmap* bitmap = mOwnedBitmapResources.itemAt(i);
+ caches.resourceCache.decrementRefcount(bitmap);
+ }
+ mOwnedBitmapResources.clear();
+
for (size_t i = 0; i < mFilterResources.size(); i++) {
caches.resourceCache.decrementRefcount(mFilterResources.itemAt(i));
}
@@ -1314,6 +1353,10 @@
return displayList;
}
+bool DisplayListRenderer::isDeferred() {
+ return true;
+}
+
void DisplayListRenderer::setViewport(int width, int height) {
mOrthoMatrix.loadOrtho(0, width, height, 0, -1, 1);
@@ -1487,6 +1530,15 @@
addSkip(location);
}
+void DisplayListRenderer::drawBitmapData(SkBitmap* bitmap, float left, float top, SkPaint* paint) {
+ const bool reject = quickReject(left, top, left + bitmap->width(), bitmap->height());
+ uint32_t* location = addOp(DisplayList::DrawBitmapData, reject);
+ addBitmapData(bitmap);
+ addPoint(left, top);
+ addPaint(paint);
+ addSkip(location);
+}
+
void DisplayListRenderer::drawBitmapMesh(SkBitmap* bitmap, int meshWidth, int meshHeight,
float* vertices, int* colors, SkPaint* paint) {
addOp(DisplayList::DrawBitmapMesh);
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 5ce770d..93b065d 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -91,6 +91,7 @@
DrawBitmap,
DrawBitmapMatrix,
DrawBitmapRect,
+ DrawBitmapData,
DrawBitmapMesh,
DrawPatch,
DrawColor,
@@ -397,7 +398,6 @@
private:
void init();
-
void initProperties();
void clearResources();
@@ -422,6 +422,10 @@
return (SkBitmap*) getInt();
}
+ SkBitmap* getBitmapData() {
+ return (SkBitmap*) getInt();
+ }
+
SkiaShader* getShader() {
return (SkiaShader*) getInt();
}
@@ -483,6 +487,7 @@
}
Vector<SkBitmap*> mBitmapResources;
+ Vector<SkBitmap*> mOwnedBitmapResources;
Vector<SkiaColorFilter*> mFilterResources;
Vector<SkPaint*> mPaints;
@@ -538,6 +543,8 @@
ANDROID_API DisplayList* getDisplayList(DisplayList* displayList);
+ virtual bool isDeferred();
+
virtual void setViewport(int width, int height);
virtual void prepareDirty(float left, float top, float right, float bottom, bool opaque);
virtual void finish();
@@ -574,6 +581,7 @@
virtual void drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop,
float srcRight, float srcBottom, float dstLeft, float dstTop,
float dstRight, float dstBottom, SkPaint* paint);
+ virtual void drawBitmapData(SkBitmap* bitmap, float left, float top, SkPaint* paint);
virtual void drawBitmapMesh(SkBitmap* bitmap, int meshWidth, int meshHeight,
float* vertices, int* colors, SkPaint* paint);
virtual void drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs,
@@ -619,6 +627,10 @@
return mBitmapResources;
}
+ const Vector<SkBitmap*>& getOwnedBitmapResources() const {
+ return mOwnedBitmapResources;
+ }
+
const Vector<SkiaColorFilter*>& getFilterResources() const {
return mFilterResources;
}
@@ -701,16 +713,12 @@
void addInts(const int32_t* values, uint32_t count) {
mWriter.writeInt(count);
- for (uint32_t i = 0; i < count; i++) {
- mWriter.writeInt(values[i]);
- }
+ mWriter.write(values, count * sizeof(int32_t));
}
void addUInts(const uint32_t* values, int8_t count) {
mWriter.writeInt(count);
- for (int8_t i = 0; i < count; i++) {
- mWriter.writeInt(values[i]);
- }
+ mWriter.write(values, count * sizeof(uint32_t));
}
inline void addFloat(float value) {
@@ -719,9 +727,7 @@
void addFloats(const float* values, int32_t count) {
mWriter.writeInt(count);
- for (int32_t i = 0; i < count; i++) {
- mWriter.writeScalar(values[i]);
- }
+ mWriter.write(values, count * sizeof(float));
}
inline void addPoint(float x, float y) {
@@ -805,6 +811,12 @@
Caches::getInstance().resourceCache.incrementRefcount(bitmap);
}
+ void addBitmapData(SkBitmap* bitmap) {
+ addInt((int) bitmap);
+ mOwnedBitmapResources.add(bitmap);
+ Caches::getInstance().resourceCache.incrementRefcount(bitmap);
+ }
+
inline void addShader(SkiaShader* shader) {
if (!shader) {
addInt((int) NULL);
@@ -831,6 +843,7 @@
}
Vector<SkBitmap*> mBitmapResources;
+ Vector<SkBitmap*> mOwnedBitmapResources;
Vector<SkiaColorFilter*> mFilterResources;
Vector<SkPaint*> mPaints;
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index 9e7fbb5..a0bf8e3 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -540,9 +540,11 @@
issueDrawCommand();
mCurrentQuadIndex = 0;
}
+
for (uint32_t i = 0; i < mActiveFonts.size(); i++) {
mActiveFonts[i]->invalidateTextureCache();
}
+
for (uint32_t i = 0; i < mCacheLines.size(); i++) {
mCacheLines[i]->mCurrentCol = 0;
}
@@ -551,8 +553,9 @@
void FontRenderer::deallocateTextureMemory(CacheTexture *cacheTexture) {
if (cacheTexture && cacheTexture->mTexture) {
glDeleteTextures(1, &cacheTexture->mTextureId);
- delete cacheTexture->mTexture;
+ delete[] cacheTexture->mTexture;
cacheTexture->mTexture = NULL;
+ cacheTexture->mTextureId = 0;
}
}
@@ -582,11 +585,19 @@
deallocateTextureMemory(mCacheTexture512);
}
-void FontRenderer::allocateTextureMemory(CacheTexture *cacheTexture) {
+void FontRenderer::allocateTextureMemory(CacheTexture* cacheTexture) {
int width = cacheTexture->mWidth;
int height = cacheTexture->mHeight;
+
cacheTexture->mTexture = new uint8_t[width * height];
+#if DEBUG_FONT_RENDERER
memset(cacheTexture->mTexture, 0, width * height * sizeof(uint8_t));
+#endif
+
+ if (!cacheTexture->mTextureId) {
+ glGenTextures(1, &cacheTexture->mTextureId);
+ }
+
glBindTexture(GL_TEXTURE_2D, cacheTexture->mTextureId);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
// Initialize texture dimensions
@@ -654,11 +665,12 @@
uint32_t cacheWidth = cacheLine->mMaxWidth;
- CacheTexture *cacheTexture = cacheLine->mCacheTexture;
- if (cacheTexture->mTexture == NULL) {
+ CacheTexture* cacheTexture = cacheLine->mCacheTexture;
+ if (!cacheTexture->mTexture) {
// Large-glyph texture memory is allocated only as needed
allocateTextureMemory(cacheTexture);
}
+
uint8_t* cacheBuffer = cacheTexture->mTexture;
uint8_t* bitmapBuffer = (uint8_t*) glyph.fImage;
unsigned int stride = glyph.rowBytes();
@@ -675,34 +687,39 @@
}
CacheTexture* FontRenderer::createCacheTexture(int width, int height, bool allocate) {
- GLuint textureId;
- glGenTextures(1, &textureId);
uint8_t* textureMemory = NULL;
+ CacheTexture* cacheTexture = new CacheTexture(textureMemory, width, height);
- CacheTexture* cacheTexture = new CacheTexture(textureMemory, textureId, width, height);
if (allocate) {
allocateTextureMemory(cacheTexture);
}
+
return cacheTexture;
}
void FontRenderer::initTextTexture() {
+ for (uint32_t i = 0; i < mCacheLines.size(); i++) {
+ delete mCacheLines[i];
+ }
mCacheLines.clear();
+ if (mCacheTextureSmall) {
+ delete mCacheTextureSmall;
+ delete mCacheTexture128;
+ delete mCacheTexture256;
+ delete mCacheTexture512;
+ }
+
// Next, use other, separate caches for large glyphs.
uint16_t maxWidth = 0;
if (Caches::hasInstance()) {
maxWidth = Caches::getInstance().maxTextureSize;
}
+
if (maxWidth > MAX_TEXT_CACHE_WIDTH || maxWidth == 0) {
maxWidth = MAX_TEXT_CACHE_WIDTH;
}
- if (mCacheTextureSmall != NULL) {
- delete mCacheTextureSmall;
- delete mCacheTexture128;
- delete mCacheTexture256;
- delete mCacheTexture512;
- }
+
mCacheTextureSmall = createCacheTexture(mSmallCacheWidth, mSmallCacheHeight, true);
mCacheTexture128 = createCacheTexture(maxWidth, 256, false);
mCacheTexture256 = createCacheTexture(maxWidth, 256, false);
@@ -776,12 +793,6 @@
initTextTexture();
initVertexArrayBuffers();
- // We store a string with letters in a rough frequency of occurrence
- mLatinPrecache = String16("eisarntolcdugpmhbyfvkwzxjq ");
- mLatinPrecache += String16("EISARNTOLCDUGPMHBYFVKWZXJQ");
- mLatinPrecache += String16(",.?!()-+@;:'");
- mLatinPrecache += String16("0123456789");
-
mInitialized = true;
}
@@ -944,11 +955,19 @@
void FontRenderer::precacheLatin(SkPaint* paint) {
// Remaining capacity is measured in %
uint32_t remainingCapacity = getRemainingCacheCapacity();
- uint32_t precacheIdx = 0;
- while (remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) {
- mCurrentFont->getCachedGlyph(paint, (int32_t) mLatinPrecache[precacheIdx]);
+ uint32_t precacheIndex = 0;
+
+ // We store a string with letters in a rough frequency of occurrence
+ String16 l("eisarntolcdugpmhbyfvkwzxjq EISARNTOLCDUGPMHBYFVKWZXJQ,.?!()-+@;:'0123456789");
+
+ size_t size = l.size();
+ uint16_t latin[size];
+ paint->utfToGlyphs(l.string(), SkPaint::kUTF16_TextEncoding, size * sizeof(char16_t), latin);
+
+ while (remainingCapacity > 25 && precacheIndex < size) {
+ mCurrentFont->getCachedGlyph(paint, TO_GLYPH(latin[precacheIndex]));
remainingCapacity = getRemainingCacheCapacity();
- precacheIdx ++;
+ precacheIndex++;
}
}
diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h
index 4fc5862..2ab680e 100644
--- a/libs/hwui/FontRenderer.h
+++ b/libs/hwui/FontRenderer.h
@@ -41,11 +41,13 @@
#if RENDER_TEXT_AS_GLYPHS
typedef uint16_t glyph_t;
+ #define TO_GLYPH(g) g
#define GET_METRICS(paint, glyph) paint->getGlyphMetrics(glyph)
#define GET_GLYPH(text) nextGlyph((const uint16_t**) &text)
#define IS_END_OF_STRING(glyph) false
#else
typedef SkUnichar glyph_t;
+ #define TO_GLYPH(g) ((SkUnichar) g)
#define GET_METRICS(paint, glyph) paint->getUnicharMetrics(glyph)
#define GET_GLYPH(text) SkUTF16_NextUnichar((const uint16_t**) &text)
#define IS_END_OF_STRING(glyph) glyph < 0
@@ -59,15 +61,15 @@
class CacheTexture {
public:
- CacheTexture(){}
- CacheTexture(uint8_t* texture, GLuint textureId, uint16_t width, uint16_t height) :
- mTexture(texture), mTextureId(textureId), mWidth(width), mHeight(height),
- mLinearFiltering(false) {}
+ CacheTexture() { }
+ CacheTexture(uint8_t* texture, uint16_t width, uint16_t height) :
+ mTexture(texture), mTextureId(0), mWidth(width), mHeight(height),
+ mLinearFiltering(false) { }
~CacheTexture() {
- if (mTexture != NULL) {
+ if (mTexture) {
delete[] mTexture;
}
- if (mTextureId != 0) {
+ if (mTextureId) {
glDeleteTextures(1, &mTextureId);
}
}
@@ -88,7 +90,7 @@
mCurrentRow(currentRow),
mCurrentCol(currentCol),
mDirty(false),
- mCacheTexture(cacheTexture){
+ mCacheTexture(cacheTexture) {
}
bool fitBitmap(const SkGlyph& glyph, uint32_t *retOriginX, uint32_t *retOriginY);
@@ -98,7 +100,7 @@
uint32_t mCurrentRow;
uint32_t mCurrentCol;
bool mDirty;
- CacheTexture *mCacheTexture;
+ CacheTexture* mCacheTexture;
};
struct CachedGlyphInfo {
@@ -236,8 +238,6 @@
FontRenderer();
~FontRenderer();
- void init();
- void deinit();
void flushLargeCaches();
void setGammaTable(const uint8_t* gammaTable) {
@@ -278,6 +278,7 @@
GLuint getTexture(bool linearFiltering = false) {
checkInit();
+
if (linearFiltering != mCurrentCacheTexture->mLinearFiltering) {
mCurrentCacheTexture->mLinearFiltering = linearFiltering;
mLinearFiltering = linearFiltering;
@@ -287,6 +288,7 @@
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering);
}
+
return mCurrentCacheTexture->mTextureId;
}
@@ -326,7 +328,6 @@
void initRender(const Rect* clip, Rect* bounds);
void finishRender();
- String16 mLatinPrecache;
void precacheLatin(SkPaint* paint);
void issueDrawCommand();
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index da2192f..50f5d57 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -144,6 +144,10 @@
return STENCIL_BUFFER_SIZE;
}
+bool OpenGLRenderer::isDeferred() {
+ return false;
+}
+
void OpenGLRenderer::setViewport(int width, int height) {
mOrthoMatrix.loadOrtho(0, width, height, 0, -1, 1);
@@ -1502,6 +1506,21 @@
restore();
}
+void OpenGLRenderer::drawBitmapData(SkBitmap* bitmap, float left, float top, SkPaint* paint) {
+ const float right = left + bitmap->width();
+ const float bottom = top + bitmap->height();
+
+ if (quickReject(left, top, right, bottom)) {
+ return;
+ }
+
+ mCaches.activeTexture(0);
+ Texture* texture = mCaches.textureCache.getTransient(bitmap);
+ const AutoTexture autoCleanup(texture);
+
+ drawTextureRect(left, top, right, bottom, texture, paint);
+}
+
void OpenGLRenderer::drawBitmapMesh(SkBitmap* bitmap, int meshWidth, int meshHeight,
float* vertices, int* colors, SkPaint* paint) {
// TODO: Do a quickReject
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 18a6923..ab324ff 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -63,6 +63,8 @@
ANDROID_API OpenGLRenderer();
virtual ~OpenGLRenderer();
+ virtual bool isDeferred();
+
virtual void setViewport(int width, int height);
ANDROID_API void prepare(bool opaque);
@@ -115,6 +117,7 @@
virtual void drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop,
float srcRight, float srcBottom, float dstLeft, float dstTop,
float dstRight, float dstBottom, SkPaint* paint);
+ virtual void drawBitmapData(SkBitmap* bitmap, float left, float top, SkPaint* paint);
virtual void drawBitmapMesh(SkBitmap* bitmap, int meshWidth, int meshHeight,
float* vertices, int* colors, SkPaint* paint);
virtual void drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs,
diff --git a/libs/hwui/ResourceCache.cpp b/libs/hwui/ResourceCache.cpp
index 9ffad88..cf5f822 100644
--- a/libs/hwui/ResourceCache.cpp
+++ b/libs/hwui/ResourceCache.cpp
@@ -59,11 +59,11 @@
void ResourceCache::incrementRefcount(SkBitmap* bitmapResource) {
SkSafeRef(bitmapResource->pixelRef());
SkSafeRef(bitmapResource->getColorTable());
- incrementRefcount((void*)bitmapResource, kBitmap);
+ incrementRefcount((void*) bitmapResource, kBitmap);
}
void ResourceCache::incrementRefcount(SkPath* pathResource) {
- incrementRefcount((void*)pathResource, kPath);
+ incrementRefcount((void*) pathResource, kPath);
}
void ResourceCache::incrementRefcount(SkiaShader* shaderResource) {
diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp
index cc09aae..9fb61e4 100644
--- a/libs/hwui/TextureCache.cpp
+++ b/libs/hwui/TextureCache.cpp
@@ -160,6 +160,16 @@
return texture;
}
+Texture* TextureCache::getTransient(SkBitmap* bitmap) {
+ Texture* texture = new Texture;
+ texture->bitmapSize = bitmap->rowBytes() * bitmap->height();
+ texture->cleanup = true;
+
+ generateTexture(bitmap, texture, false);
+
+ return texture;
+}
+
void TextureCache::remove(SkBitmap* bitmap) {
mCache.remove(bitmap);
}
diff --git a/libs/hwui/TextureCache.h b/libs/hwui/TextureCache.h
index 10a05e0..31a2e3d 100644
--- a/libs/hwui/TextureCache.h
+++ b/libs/hwui/TextureCache.h
@@ -67,6 +67,11 @@
*/
Texture* get(SkBitmap* bitmap);
/**
+ * Returns the texture associated with the specified bitmap. The generated
+ * texture is not kept in the cache. The caller must destroy the texture.
+ */
+ Texture* getTransient(SkBitmap* bitmap);
+ /**
* Removes the texture associated with the specified bitmap.
* Upon remove the texture is freed.
*/
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 8015203..8da7d0f 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -701,6 +701,10 @@
// Check if the ringer mode changes with this volume adjustment. If
// it does, it will handle adjusting the volume, so we won't below
adjustVolume = checkForRingerModeChange(aliasIndex, direction, step);
+ if ((streamTypeAlias == getMasterStreamType()) &&
+ (mRingerMode == AudioManager.RINGER_MODE_SILENT)) {
+ streamState.setLastAudibleIndex(0, device);
+ }
}
// If stream is muted, adjust last audible index only
diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
index 3b87b96..f09c010 100644
--- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
+++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
@@ -223,6 +223,8 @@
@Override
public long calculateDirectorySize(String path) throws RemoteException {
+ Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
+
final File directory = new File(path);
if (directory.exists() && directory.isDirectory()) {
return MeasurementUtils.measureDirectory(path);
@@ -233,6 +235,8 @@
@Override
public long[] getFileSystemStats(String path) {
+ Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
+
try {
final StructStatFs stat = Libcore.os.statfs(path);
final long totalSize = stat.f_blocks * stat.f_bsize;
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index bc144bb..4cff67b 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -48,7 +48,7 @@
android:id="@+id/latestItems"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- systemui:rowHeight="@dimen/notification_height"
+ systemui:rowHeight="@dimen/notification_row_min_height"
/>
</ScrollView>
@@ -68,4 +68,4 @@
</com.android.systemui.statusbar.phone.CloseDragHandle>
-</FrameLayout><!-- end of sliding panel -->
\ No newline at end of file
+</FrameLayout><!-- end of sliding panel -->
diff --git a/packages/SystemUI/res/layout/system_bar_notification_panel.xml b/packages/SystemUI/res/layout/system_bar_notification_panel.xml
index 42af147..5579505 100644
--- a/packages/SystemUI/res/layout/system_bar_notification_panel.xml
+++ b/packages/SystemUI/res/layout/system_bar_notification_panel.xml
@@ -77,7 +77,7 @@
android:clickable="true"
android:focusable="true"
android:descendantFocusability="afterDescendants"
- systemui:rowHeight="@dimen/notification_height"
+ systemui:rowHeight="@dimen/notification_row_min_height"
/>
</ScrollView>
</LinearLayout>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 612ab6a..01068ec 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -138,7 +138,7 @@
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Søger efter GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Placeringen er angivet ved hjælp af GPS"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Ryd alle meddelelser."</string>
- <string name="dreams_dock_launcher" msgid="3541196417659166245">"Aktiver pauseskærm"</string>
+ <string name="dreams_dock_launcher" msgid="3541196417659166245">"Aktivér pauseskærm"</string>
<string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Oplysninger om appen"</string>
<string name="notifications_off_title" msgid="8936620513608443224">"Underretninger slået fra"</string>
<string name="notifications_off_text" msgid="2529001315769385273">"Tryk her for at slå underretninger til igen."</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index b7dcb14..c15a2fa 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -66,7 +66,7 @@
<string name="screenshot_saving_title" msgid="8242282144535555697">"Screenshot wird gespeichert..."</string>
<string name="screenshot_saving_text" msgid="2419718443411738818">"Screenshot wird gespeichert..."</string>
<string name="screenshot_saved_title" msgid="6461865960961414961">"Screenshot aufgenommen"</string>
- <string name="screenshot_saved_text" msgid="1152839647677558815">"Zum Anzeigen des Screenshots berühren"</string>
+ <string name="screenshot_saved_text" msgid="1152839647677558815">"Zum Ansehen berühren"</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"Screenshot konnte nicht aufgenommen werden."</string>
<string name="screenshot_failed_text" msgid="8134011269572415402">"Screenshot konnte nicht gespeichert werden. Eventuell wird der Speicher gerade verwendet."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB-Dateiübertragungsoptionen"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index eb493b2..70ba034 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -142,10 +142,8 @@
<string name="accessibility_clear_all" msgid="5235938559247164925">"通知をすべて消去。"</string>
<string name="dreams_dock_launcher" msgid="3541196417659166245">"スクリーンセーバーを有効にする"</string>
<string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"アプリ情報"</string>
- <!-- no translation found for notifications_off_title (8936620513608443224) -->
- <skip />
- <!-- no translation found for notifications_off_text (2529001315769385273) -->
- <skip />
+ <string name="notifications_off_title" msgid="8936620513608443224">"通知OFF"</string>
+ <string name="notifications_off_text" msgid="2529001315769385273">"通知を再度ONにするにはここをタップします。"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"画面は自動的に回転します。"</string>
<string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"画面は横向きにロックされています。"</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"画面は縦向きにロックされています。"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 2a9c1c8..a1ee469 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -140,10 +140,8 @@
<string name="accessibility_clear_all" msgid="5235938559247164925">"Fjern alle varslinger."</string>
<string name="dreams_dock_launcher" msgid="3541196417659166245">"Aktiver skjermbeskytter"</string>
<string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Info om app"</string>
- <!-- no translation found for notifications_off_title (8936620513608443224) -->
- <skip />
- <!-- no translation found for notifications_off_text (2529001315769385273) -->
- <skip />
+ <string name="notifications_off_title" msgid="8936620513608443224">"Varsler er deaktivert"</string>
+ <string name="notifications_off_text" msgid="2529001315769385273">"Trykk her for å aktivere varsler på nytt."</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Skjermen roterer automatisk."</string>
<string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Skjermen er låst i liggende retning."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Skjermen er låst i stående retning."</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index b01345e..b4a77a2 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -140,10 +140,8 @@
<string name="accessibility_clear_all" msgid="5235938559247164925">"Usuń wszystkie powiadomienia."</string>
<string name="dreams_dock_launcher" msgid="3541196417659166245">"Włącz wygaszacz ekranu."</string>
<string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"O aplikacji"</string>
- <!-- no translation found for notifications_off_title (8936620513608443224) -->
- <skip />
- <!-- no translation found for notifications_off_text (2529001315769385273) -->
- <skip />
+ <string name="notifications_off_title" msgid="8936620513608443224">"Powiadomienia wyłączone"</string>
+ <string name="notifications_off_text" msgid="2529001315769385273">"Kliknij tutaj, by przywrócić powiadomienia."</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ekran zostanie obrócony automatycznie."</string>
<string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Ekran jest zablokowany w orientacji poziomej."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Ekran jest zablokowany w orientacji pionowej."</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index f074d22..596ceec 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -62,8 +62,8 @@
<string name="compat_mode_off" msgid="4434467572461327898">"Ampliar p/ preencher tela"</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"Zoom em modo de compatibilidade"</string>
<string name="compat_mode_help_body" msgid="4946726776359270040">"Quando um aplicativo é desenvolvido para uma tela menor, um controle de zoom é exibido perto do relógio."</string>
- <string name="screenshot_saving_ticker" msgid="7403652894056693515">"Salvar captura de tela..."</string>
- <string name="screenshot_saving_title" msgid="8242282144535555697">"Salvar captura de tela..."</string>
+ <string name="screenshot_saving_ticker" msgid="7403652894056693515">"Salvando captura de tela..."</string>
+ <string name="screenshot_saving_title" msgid="8242282144535555697">"Salvando captura de tela..."</string>
<string name="screenshot_saving_text" msgid="2419718443411738818">"A captura de tela está sendo salva."</string>
<string name="screenshot_saved_title" msgid="6461865960961414961">"Captura de tela obtida."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"Toque para visualizar a captura de tela."</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 4750ac5..87eec9f 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -140,10 +140,8 @@
<string name="accessibility_clear_all" msgid="5235938559247164925">"Ştergeţi toate notificările."</string>
<string name="dreams_dock_launcher" msgid="3541196417659166245">"Activaţi screensaverul"</string>
<string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Informaţii despre aplicaţie"</string>
- <!-- no translation found for notifications_off_title (8936620513608443224) -->
- <skip />
- <!-- no translation found for notifications_off_text (2529001315769385273) -->
- <skip />
+ <string name="notifications_off_title" msgid="8936620513608443224">"Notificările sunt dezactivate"</string>
+ <string name="notifications_off_text" msgid="2529001315769385273">"Apăsaţi aici pentru a reactiva notificările."</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ecranul se va roti în mod automat."</string>
<string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Ecranul este blocat în orientarea de tip peisaj."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Ecranul este blocat în orientarea de tip portret."</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 7ca04e6..3277fb6 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -65,7 +65,7 @@
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"Сохранение..."</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"Сохранение..."</string>
<string name="screenshot_saving_text" msgid="2419718443411738818">"Сохранение..."</string>
- <string name="screenshot_saved_title" msgid="6461865960961414961">"Скриншот сохранен."</string>
+ <string name="screenshot_saved_title" msgid="6461865960961414961">"Скриншот сохранен"</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"Нажмите, чтобы просмотреть"</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"Не удалось сохранить скриншот."</string>
<string name="screenshot_failed_text" msgid="8134011269572415402">"Не удалось сохранить скриншот. Возможно, накопители заняты."</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 36950dc..afbe0fb 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -140,10 +140,8 @@
<string name="accessibility_clear_all" msgid="5235938559247164925">"Ta bort alla meddelanden."</string>
<string name="dreams_dock_launcher" msgid="3541196417659166245">"Aktivera skärmsläckare"</string>
<string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Info om appen"</string>
- <!-- no translation found for notifications_off_title (8936620513608443224) -->
- <skip />
- <!-- no translation found for notifications_off_text (2529001315769385273) -->
- <skip />
+ <string name="notifications_off_title" msgid="8936620513608443224">"Meddelanden inaktiverade"</string>
+ <string name="notifications_off_text" msgid="2529001315769385273">"Knacka lätt här om du vill aktivera meddelanden igen."</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Skärmen roteras automatiskt."</string>
<string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Bildskärmens riktning är nu låst i liggande format."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Bildskärmens riktning är nu låst i stående format."</string>
diff --git a/packages/SystemUI/res/values-xhdpi/dimens.xml b/packages/SystemUI/res/values-xhdpi/dimens.xml
deleted file mode 100644
index 303841a..0000000
--- a/packages/SystemUI/res/values-xhdpi/dimens.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (c) 2011, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
-*/
--->
-<resources>
- <!-- thickness (height) of each notification row, including any separators or padding -->
- <!-- note: this is the same value as in values/dimens.xml; the value is overridden in
- values-hdpi/dimens.xml and so we need to re-assert the general value here -->
- <dimen name="notification_height">68dp</dimen>
-
- <!-- thickness (height) of dividers between each notification row -->
- <!-- same as in values/dimens.xml; see note at notification_height -->
- <dimen name="notification_divider_height">2dp</dimen>
-</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index f548166..9042045 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -49,18 +49,21 @@
reducing false presses on navbar buttons; approx 2mm -->
<dimen name="navigation_bar_deadzone_size">12dp</dimen>
- <!-- thickness (height) of each 1U notification row plus glow, padding, etc -->
- <dimen name="notification_height">72dp</dimen>
-
<!-- Height of notification icons in the status bar -->
<dimen name="status_bar_icon_size">@*android:dimen/status_bar_icon_size</dimen>
- <!-- Height of a small notification in the status bar plus glow, padding, etc -->
- <dimen name="notification_min_height">72dp</dimen>
+ <!-- Height of a small notification in the status bar -->
+ <dimen name="notification_min_height">64dp</dimen>
<!-- Height of a large notification in the status bar -->
<dimen name="notification_max_height">256dp</dimen>
+ <!-- Height of a small notification in the status bar plus glow, padding, etc -->
+ <dimen name="notification_row_min_height">72dp</dimen>
+
+ <!-- Height of a large notification in the status bar plus glow, padding, etc -->
+ <dimen name="notification_row_max_height">260dp</dimen>
+
<!-- size at which Notification icons will be drawn in the status bar -->
<dimen name="status_bar_icon_drawing_size">18dip</dimen>
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index 6785c29..39d686f 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -19,6 +19,7 @@
import android.animation.Animator;
import android.animation.LayoutTransition;
import android.app.ActivityManager;
+import android.app.ActivityManagerNative;
import android.app.ActivityOptions;
import android.content.Context;
import android.content.Intent;
@@ -26,13 +27,13 @@
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
-import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.Shader.TileMode;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
+import android.os.RemoteException;
import android.provider.Settings;
import android.util.AttributeSet;
import android.util.Log;
@@ -283,8 +284,19 @@
}
}
+ static void sendCloseSystemWindows(Context context, String reason) {
+ if (ActivityManagerNative.isSystemReady()) {
+ try {
+ ActivityManagerNative.getDefault().closeSystemDialogs(reason);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+
public void show(boolean show, boolean animate,
ArrayList<TaskDescription> recentTaskDescriptions, boolean firstScreenful) {
+ sendCloseSystemWindows(mContext, BaseStatusBar.SYSTEM_DIALOG_REASON_RECENT_APPS);
+
// For now, disable animations. We may want to re-enable in the future
if (show) {
animate = false;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index a44279a..4b223dd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -85,6 +85,9 @@
protected static final boolean ENABLE_INTRUDERS = false;
+ // Should match the value in PhoneWindowManager
+ public static final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
+
public static final int EXPANDED_LEAVE_ALONE = -10000;
public static final int EXPANDED_FULL_OPEN = -10001;
@@ -400,6 +403,15 @@
return new H();
}
+ static void sendCloseSystemWindows(Context context, String reason) {
+ if (ActivityManagerNative.isSystemReady()) {
+ try {
+ ActivityManagerNative.getDefault().closeSystemDialogs(reason);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+
protected class H extends Handler {
public void handleMessage(Message m) {
switch (m.what) {
@@ -466,7 +478,7 @@
protected boolean inflateViews(NotificationData.Entry entry, ViewGroup parent) {
int rowHeight =
- mContext.getResources().getDimensionPixelSize(R.dimen.notification_height);
+ mContext.getResources().getDimensionPixelSize(R.dimen.notification_row_min_height);
int minHeight =
mContext.getResources().getDimensionPixelSize(R.dimen.notification_min_height);
int maxHeight =
@@ -486,7 +498,6 @@
// for blaming (see SwipeHelper.setLongPressListener)
row.setTag(sbn.pkg);
- ViewGroup.LayoutParams lp = row.getLayoutParams();
workAroundBadLayerDrawableOpacity(row);
View vetoButton = updateNotificationVetoButton(row, sbn);
vetoButton.setContentDescription(mContext.getString(
@@ -498,13 +509,6 @@
ViewGroup content = (ViewGroup)row.findViewById(R.id.content);
ViewGroup adaptive = (ViewGroup)row.findViewById(R.id.adaptive);
- // Ensure that R.id.content is properly set to 64dp high if 1U
- lp = content.getLayoutParams();
- if (large == null) {
- lp.height = minHeight;
- }
- content.setLayoutParams(lp);
-
content.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
PendingIntent contentIntent = sbn.notification.contentIntent;
@@ -516,6 +520,7 @@
content.setOnClickListener(null);
}
+ // TODO(cwren) normalize variable names with those in updateNotification
View expandedOneU = null;
View expandedLarge = null;
Exception exception = null;
@@ -544,7 +549,7 @@
SizeAdaptiveLayout.LayoutParams params =
new SizeAdaptiveLayout.LayoutParams(expandedLarge.getLayoutParams());
params.minHeight = minHeight+1;
- params.maxHeight = SizeAdaptiveLayout.LayoutParams.UNBOUNDED;
+ params.maxHeight = maxHeight;
adaptive.addView(expandedLarge, params);
}
row.setDrawingCacheEnabled(true);
@@ -711,20 +716,18 @@
}
protected boolean expandView(NotificationData.Entry entry, boolean expand) {
- if (entry.expandable()) {
- int rowHeight =
- mContext.getResources().getDimensionPixelSize(R.dimen.notification_height);
- ViewGroup.LayoutParams lp = entry.row.getLayoutParams();
- if (expand) {
- lp.height = ViewGroup.LayoutParams.WRAP_CONTENT;
- } else {
- lp.height = rowHeight;
- }
- entry.row.setLayoutParams(lp);
- return expand;
+ int rowHeight =
+ mContext.getResources().getDimensionPixelSize(R.dimen.notification_row_min_height);
+ ViewGroup.LayoutParams lp = entry.row.getLayoutParams();
+ if (entry.expandable() && expand) {
+ if (DEBUG) Slog.d(TAG, "setting expanded row height to WRAP_CONTENT");
+ lp.height = ViewGroup.LayoutParams.WRAP_CONTENT;
} else {
- return false;
+ if (DEBUG) Slog.d(TAG, "setting collapsed row height to " + rowHeight);
+ lp.height = rowHeight;
}
+ entry.row.setLayoutParams(lp);
+ return expand;
}
protected void updateExpansionStates() {
@@ -751,7 +754,7 @@
protected abstract void tick(IBinder key, StatusBarNotification n, boolean firstTime);
protected abstract void updateExpandedViewPos(int expandedPosition);
protected abstract int getExpandedViewMaxHeight();
- protected abstract boolean isStatusBarExpanded();
+ protected abstract boolean shouldDisableNavbarGestures();
protected boolean isTopNotification(ViewGroup parent, NotificationData.Entry entry) {
return parent.indexOfChild(entry.row) == 0;
@@ -769,32 +772,41 @@
final StatusBarNotification oldNotification = oldEntry.notification;
// XXX: modify when we do something more intelligent with the two content views
- final RemoteViews oldContentView = (oldNotification.notification.bigContentView != null)
- ? oldNotification.notification.bigContentView
- : oldNotification.notification.contentView;
- final RemoteViews contentView = (notification.notification.bigContentView != null)
- ? notification.notification.bigContentView
- : notification.notification.contentView;
+ final RemoteViews oldContentView = oldNotification.notification.contentView;
+ final RemoteViews contentView = notification.notification.contentView;
+ final RemoteViews oldBigContentView = oldNotification.notification.bigContentView;
+ final RemoteViews bigContentView = notification.notification.bigContentView;
if (DEBUG) {
Slog.d(TAG, "old notification: when=" + oldNotification.notification.when
+ " ongoing=" + oldNotification.isOngoing()
+ " expanded=" + oldEntry.expanded
+ " contentView=" + oldContentView
+ + " bigContentView=" + oldBigContentView
+ " rowParent=" + oldEntry.row.getParent());
Slog.d(TAG, "new notification: when=" + notification.notification.when
+ " ongoing=" + oldNotification.isOngoing()
- + " contentView=" + contentView);
+ + " contentView=" + contentView
+ + " bigContentView=" + bigContentView);
}
// Can we just reapply the RemoteViews in place? If when didn't change, the order
// didn't change.
+
+ // 1U is never null
boolean contentsUnchanged = oldEntry.expanded != null
- && contentView != null && oldContentView != null
&& contentView.getPackage() != null
&& oldContentView.getPackage() != null
&& oldContentView.getPackage().equals(contentView.getPackage())
&& oldContentView.getLayoutId() == contentView.getLayoutId();
+ // large view may be null
+ boolean bigContentsUnchanged =
+ (oldEntry.getLargeView() == null && bigContentView == null)
+ || ((oldEntry.getLargeView() != null && bigContentView != null)
+ && bigContentView.getPackage() != null
+ && oldBigContentView.getPackage() != null
+ && oldBigContentView.getPackage().equals(bigContentView.getPackage())
+ && oldBigContentView.getLayoutId() == bigContentView.getLayoutId());
ViewGroup rowParent = (ViewGroup) oldEntry.row.getParent();
boolean orderUnchanged = notification.notification.when==oldNotification.notification.when
&& notification.score == oldNotification.score;
@@ -804,12 +816,15 @@
&& !TextUtils.equals(notification.notification.tickerText,
oldEntry.notification.notification.tickerText);
boolean isTopAnyway = isTopNotification(rowParent, oldEntry);
- if (contentsUnchanged && (orderUnchanged || isTopAnyway)) {
+ if (contentsUnchanged && bigContentsUnchanged && (orderUnchanged || isTopAnyway)) {
if (DEBUG) Slog.d(TAG, "reusing notification for key: " + key);
oldEntry.notification = notification;
try {
// Reapply the RemoteViews
- contentView.reapply(mContext, oldEntry.content);
+ contentView.reapply(mContext, oldEntry.expanded);
+ if (bigContentView != null && oldEntry.getLargeView() != null) {
+ bigContentView.reapply(mContext, oldEntry.getLargeView());
+ }
// update the contentIntent
final PendingIntent contentIntent = notification.notification.contentIntent;
if (contentIntent != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DelegateViewHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/DelegateViewHelper.java
index 912a165..0e6dfd5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DelegateViewHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DelegateViewHelper.java
@@ -53,7 +53,7 @@
}
public boolean onInterceptTouchEvent(MotionEvent event) {
- if (mBar.isStatusBarExpanded()) {
+ if (mBar.shouldDisableNavbarGestures()) {
return false;
}
switch (event.getAction()) {
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 6122390..287c2922 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -1977,7 +1977,7 @@
if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
String reason = intent.getStringExtra("reason");
if (reason != null) {
- excludeRecents = reason.equals("recentapps");
+ excludeRecents = reason.equals(SYSTEM_DIALOG_REASON_RECENT_APPS);
}
}
animateCollapse(excludeRecents);
@@ -2111,8 +2111,8 @@
}
@Override
- protected boolean isStatusBarExpanded() {
- return mExpanded;
+ protected boolean shouldDisableNavbarGestures() {
+ return mExpanded || (mDisabled & StatusBarManager.DISABLE_HOME) != 0;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
index 0fe7a0a..f41d99c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
@@ -101,8 +101,8 @@
float densityScale = getResources().getDisplayMetrics().density;
float pagingTouchSlop = ViewConfiguration.get(mContext).getScaledPagingTouchSlop();
mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, densityScale, pagingTouchSlop);
- int minHeight = getResources().getDimensionPixelSize(R.dimen.notification_min_height);
- int maxHeight = getResources().getDimensionPixelSize(R.dimen.notification_max_height);
+ int minHeight = getResources().getDimensionPixelSize(R.dimen.notification_row_min_height);
+ int maxHeight = getResources().getDimensionPixelSize(R.dimen.notification_row_max_height);
mExpandHelper = new ExpandHelper(mContext, this, minHeight, maxHeight);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
index a2c7637..dba1606 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -1582,7 +1582,7 @@
if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
String reason = intent.getStringExtra("reason");
if (reason != null) {
- excludeRecents = reason.equals("recentapps");
+ excludeRecents = reason.equals(SYSTEM_DIALOG_REASON_RECENT_APPS);
}
}
if (Intent.ACTION_SCREEN_OFF.equals(action)) {
@@ -1620,8 +1620,9 @@
}
@Override
- protected boolean isStatusBarExpanded() {
- return mNotificationPanel.getVisibility() == View.VISIBLE;
+ protected boolean shouldDisableNavbarGestures() {
+ return mNotificationPanel.getVisibility() == View.VISIBLE
+ || (mDisabled & StatusBarManager.DISABLE_HOME) != 0;
}
}
diff --git a/policy/src/com/android/internal/policy/impl/BiometricSensorUnlock.java b/policy/src/com/android/internal/policy/impl/BiometricSensorUnlock.java
index a13ccc2..f476f82 100644
--- a/policy/src/com/android/internal/policy/impl/BiometricSensorUnlock.java
+++ b/policy/src/com/android/internal/policy/impl/BiometricSensorUnlock.java
@@ -21,8 +21,7 @@
interface BiometricSensorUnlock {
/**
* Initializes the view provided for the biometric unlock UI to work within. The provided area
- * completely covers the backup unlock mechanism. The view is then displayed in the same manner
- * as if {@link BiometricSensorUnlock#show(long)} was called with a timeout of 0.
+ * completely covers the backup unlock mechanism.
* @param biometricUnlockView View provided for the biometric unlock UI.
*/
public void initializeView(View biometricUnlockView);
diff --git a/policy/src/com/android/internal/policy/impl/FaceUnlock.java b/policy/src/com/android/internal/policy/impl/FaceUnlock.java
index ffdeeb1..c46b94a 100644
--- a/policy/src/com/android/internal/policy/impl/FaceUnlock.java
+++ b/policy/src/com/android/internal/policy/impl/FaceUnlock.java
@@ -101,7 +101,6 @@
public void initializeView(View biometricUnlockView) {
Log.d(TAG, "initializeView()");
mFaceUnlockView = biometricUnlockView;
- show(0);
}
/**
@@ -469,10 +468,8 @@
if (mLockPatternUtils == null) {
Log.d(TAG, "mLockPatternUtils is null");
}
- Log.d(TAG, "x,y,w,h,live: " + x + "," + y + "," + w + "," + h + "," +
- (mLockPatternUtils.isBiometricWeakLivelinessEnabled()?"yes":"no"));
- mService.startUi(windowToken, x, y, w, h,
- mLockPatternUtils.isBiometricWeakLivelinessEnabled());
+ Log.d(TAG, "x,y,w,h,live: " + x + "," + y + "," + w + "," + h + ", no");
+ mService.startUi(windowToken, x, y, w, h, false);
Log.d(TAG, "mService.startUi() called");
} catch (RemoteException e) {
Log.e(TAG, "Caught exception starting Face Unlock: " + e.toString());
diff --git a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
index 8320b1d..049e6ac 100644
--- a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
+++ b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
@@ -414,12 +414,6 @@
}
};
- // Indicates whether a biometric unlock method is in use
- private boolean isBiometricUnlockInstalledAndSelected() {
- return (mLockPatternUtils.usingBiometricWeak() &&
- mLockPatternUtils.isBiometricWeakInstalled());
- }
-
/**
* @param context Used to inflate, and create views.
* @param callback Keyguard callback object for pokewakelock(), etc.
@@ -443,14 +437,6 @@
sIsFirstAppearanceAfterBoot = false;
mPluggedIn = mUpdateMonitor.isDevicePluggedIn();
mScreenOn = ((PowerManager)context.getSystemService(Context.POWER_SERVICE)).isScreenOn();
-
- // If the biometric unlock is not being used, we don't bother constructing it. Then we can
- // simply check if it is null when deciding whether we should make calls to it.
- if (isBiometricUnlockInstalledAndSelected()) {
- mBiometricUnlock = new FaceUnlock(context, updateMonitor, lockPatternUtils,
- mKeyguardScreenCallback);
- }
-
mUpdateMonitor.registerInfoCallback(mInfoCallback);
/**
@@ -848,19 +834,11 @@
}
}
- // Re-create the unlock screen if necessary. This is primarily required to properly handle
- // SIM state changes. This typically happens when this method is called by reset()
+ // Re-create the unlock screen if necessary.
final UnlockMode unlockMode = getUnlockMode();
if (mode == Mode.UnlockScreen && unlockMode != UnlockMode.Unknown) {
if (force || mUnlockScreen == null || unlockMode != mUnlockScreenMode) {
- boolean restartBiometricUnlock = false;
- if (mBiometricUnlock != null) {
- restartBiometricUnlock = mBiometricUnlock.stop();
- }
recreateUnlockScreen(unlockMode);
- if (mBiometricUnlock != null && restartBiometricUnlock) {
- maybeStartBiometricUnlock();
- }
}
}
@@ -973,13 +951,7 @@
throw new IllegalArgumentException("unknown unlock mode " + unlockMode);
}
initializeTransportControlView(unlockView);
-
- if (mBiometricUnlock != null) {
- // TODO: make faceLockAreaView a more general biometricUnlockView
- // We will need to add our Face Unlock specific child views programmatically in
- // initializeView rather than having them in the XML files.
- mBiometricUnlock.initializeView(unlockView.findViewById(R.id.faceLockAreaView));
- }
+ initializeBiometricUnlockView(unlockView);
mUnlockScreenMode = unlockMode;
return unlockView;
@@ -997,6 +969,55 @@
}
/**
+ * This returns false if there is any condition that indicates that the biometric unlock should
+ * not be used before the next time the unlock screen is recreated. In other words, if this
+ * returns false there is no need to even construct the biometric unlock.
+ */
+ private boolean useBiometricUnlock() {
+ final UnlockMode unlockMode = getUnlockMode();
+ final boolean backupIsTimedOut = (mUpdateMonitor.getFailedAttempts() >=
+ LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT);
+ return (mLockPatternUtils.usingBiometricWeak() &&
+ mLockPatternUtils.isBiometricWeakInstalled() &&
+ !mUpdateMonitor.getMaxBiometricUnlockAttemptsReached() &&
+ !backupIsTimedOut &&
+ (unlockMode == UnlockMode.Pattern || unlockMode == UnlockMode.Password));
+ }
+
+ private void initializeBiometricUnlockView(View view) {
+ boolean restartBiometricUnlock = false;
+
+ if (mBiometricUnlock != null) {
+ restartBiometricUnlock = mBiometricUnlock.stop();
+ }
+
+ // If the biometric unlock is not being used, we don't bother constructing it. Then we can
+ // simply check if it is null when deciding whether we should make calls to it.
+ mBiometricUnlock = null;
+ if (useBiometricUnlock()) {
+ // TODO: make faceLockAreaView a more general biometricUnlockView
+ // We will need to add our Face Unlock specific child views programmatically in
+ // initializeView rather than having them in the XML files.
+ View biometricUnlockView = view.findViewById(R.id.faceLockAreaView);
+ if (biometricUnlockView != null) {
+ mBiometricUnlock = new FaceUnlock(mContext, mUpdateMonitor, mLockPatternUtils,
+ mKeyguardScreenCallback);
+ mBiometricUnlock.initializeView(biometricUnlockView);
+
+ // If this is being called because the screen turned off, we want to cover the
+ // backup lock so it is covered when the screen turns back on.
+ if (!mScreenOn) mBiometricUnlock.show(0);
+ } else {
+ Log.w(TAG, "Couldn't find biometric unlock view");
+ }
+ }
+
+ if (mBiometricUnlock != null && restartBiometricUnlock) {
+ maybeStartBiometricUnlock();
+ }
+ }
+
+ /**
* Given the current state of things, what should be the initial mode of
* the lock screen (lock or unlock).
*/
diff --git a/services/java/com/android/server/CertBlacklister.java b/services/java/com/android/server/CertBlacklister.java
new file mode 100644
index 0000000..8b167d7
--- /dev/null
+++ b/services/java/com/android/server/CertBlacklister.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.content.Context;
+import android.content.ContentResolver;
+import android.database.ContentObserver;
+import android.os.Binder;
+import android.os.FileUtils;
+import android.provider.Settings;
+import android.util.Slog;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import libcore.io.IoUtils;
+
+/**
+ * <p>CertBlacklister provides a simple mechanism for updating the platform blacklists for SSL
+ * certificate public keys and serial numbers.
+ */
+public class CertBlacklister extends Binder {
+
+ private static final String TAG = "CertBlacklister";
+
+ private static final String BLACKLIST_ROOT = System.getenv("ANDROID_DATA") + "/misc/keychain/";
+
+ public static final String PUBKEY_PATH = BLACKLIST_ROOT + "pubkey_blacklist.txt";
+ public static final String SERIAL_PATH = BLACKLIST_ROOT + "serial_blacklist.txt";
+
+ public static final String PUBKEY_BLACKLIST_KEY = "pubkey_blacklist";
+ public static final String SERIAL_BLACKLIST_KEY = "serial_blacklist";
+
+ private static class BlacklistObserver extends ContentObserver {
+
+ private final String mKey;
+ private final String mName;
+ private final String mPath;
+ private final File mTmpDir;
+ private final ContentResolver mContentResolver;
+
+ public BlacklistObserver(String key, String name, String path, ContentResolver cr) {
+ super(null);
+ mKey = key;
+ mName = name;
+ mPath = path;
+ mTmpDir = new File(mPath).getParentFile();
+ mContentResolver = cr;
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ super.onChange(selfChange);
+ writeBlacklist();
+ }
+
+ public String getValue() {
+ return Settings.Secure.getString(mContentResolver, mKey);
+ }
+
+ private void writeBlacklist() {
+ new Thread("BlacklistUpdater") {
+ public void run() {
+ synchronized(mTmpDir) {
+ String blacklist = getValue();
+ if (blacklist != null) {
+ Slog.i(TAG, "Certificate blacklist changed, updating...");
+ FileOutputStream out = null;
+ try {
+ // create a temporary file
+ File tmp = File.createTempFile("journal", "", mTmpDir);
+ // mark it -rw-r--r--
+ tmp.setReadable(true, false);
+ // write to it
+ out = new FileOutputStream(tmp);
+ out.write(blacklist.getBytes());
+ // sync to disk
+ FileUtils.sync(out);
+ // atomic rename
+ tmp.renameTo(new File(mPath));
+ Slog.i(TAG, "Certificate blacklist updated");
+ } catch (IOException e) {
+ Slog.e(TAG, "Failed to write blacklist", e);
+ } finally {
+ IoUtils.closeQuietly(out);
+ }
+ }
+ }
+ }
+ }.start();
+ }
+ }
+
+ public CertBlacklister(Context context) {
+ registerObservers(context.getContentResolver());
+ }
+
+ private BlacklistObserver buildPubkeyObserver(ContentResolver cr) {
+ return new BlacklistObserver(PUBKEY_BLACKLIST_KEY,
+ "pubkey",
+ PUBKEY_PATH,
+ cr);
+ }
+
+ private BlacklistObserver buildSerialObserver(ContentResolver cr) {
+ return new BlacklistObserver(SERIAL_BLACKLIST_KEY,
+ "serial",
+ SERIAL_PATH,
+ cr);
+ }
+
+ private void registerObservers(ContentResolver cr) {
+ // set up the public key blacklist observer
+ cr.registerContentObserver(
+ Settings.Secure.getUriFor(PUBKEY_BLACKLIST_KEY),
+ true,
+ buildPubkeyObserver(cr)
+ );
+
+ // set up the serial number blacklist observer
+ cr.registerContentObserver(
+ Settings.Secure.getUriFor(SERIAL_BLACKLIST_KEY),
+ true,
+ buildSerialObserver(cr)
+ );
+ }
+}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index d9833ab..bb103580 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -623,6 +623,13 @@
} catch (Throwable e) {
reportWtf("starting CommonTimeManagementService service", e);
}
+
+ try {
+ Slog.i(TAG, "CertBlacklister");
+ CertBlacklister blacklister = new CertBlacklister(context);
+ } catch (Throwable e) {
+ reportWtf("starting CertBlacklister", e);
+ }
if (context.getResources().getBoolean(
com.android.internal.R.bool.config_enableDreams)) {
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index c300411..78ddb51 100755
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -1036,6 +1036,11 @@
final void activityStoppedLocked(ActivityRecord r, Bundle icicle, Bitmap thumbnail,
CharSequence description) {
+ if (r.state != ActivityState.STOPPING) {
+ Slog.i(TAG, "Activity reported stop, but no longer stopping: " + r);
+ mHandler.removeMessages(STOP_TIMEOUT_MSG, r);
+ return;
+ }
if (DEBUG_SAVED_STATE) Slog.i(TAG, "Saving icicle of " + r + ": " + icicle);
if (icicle != null) {
// If icicle is null, this is happening due to a timeout, so we
@@ -3538,7 +3543,7 @@
}
ActivityRecord r = mHistory.get(index);
- while (index > 0) {
+ while (index >= 0) {
ActivityRecord cur = mHistory.get(index);
if (cur.task != r.task) {
break;
@@ -4394,14 +4399,14 @@
r.forceNewConfig = false;
if (r.app == null || r.app.thread == null) {
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
- "Switch is destroying non-running " + r);
+ "Config is destroying non-running " + r);
destroyActivityLocked(r, true, false, "config");
} else if (r.state == ActivityState.PAUSING) {
// A little annoying: we are waiting for this activity to
// finish pausing. Let's not do anything now, but just
// flag that it needs to be restarted when done pausing.
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
- "Switch is skipping already pausing " + r);
+ "Config is skipping already pausing " + r);
r.configDestroy = true;
return true;
} else if (r.state == ActivityState.RESUMED) {
@@ -4410,12 +4415,12 @@
// Instead of doing the normal handshaking, just say
// "restart!".
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
- "Switch is restarting resumed " + r);
+ "Config is relaunching resumed " + r);
relaunchActivityLocked(r, r.configChangeFlags, true);
r.configChangeFlags = 0;
} else {
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
- "Switch is restarting non-resumed " + r);
+ "Config is relaunching non-resumed " + r);
relaunchActivityLocked(r, r.configChangeFlags, false);
r.configChangeFlags = 0;
}
@@ -4461,7 +4466,9 @@
r.startFreezingScreenLocked(r.app, 0);
try {
- if (DEBUG_SWITCH) Slog.i(TAG, "Switch is restarting resumed " + r);
+ if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG,
+ (andResume ? "Relaunching to RESUMED " : "Relaunching to PAUSED ")
+ + r);
r.forceNewConfig = false;
r.app.thread.scheduleRelaunchActivity(r.appToken, results, newIntents,
changes, !andResume, new Configuration(mService.mConfiguration));
@@ -4469,7 +4476,7 @@
// the caller will only pass in 'andResume' if this activity is
// currently resumed, which implies we aren't sleeping.
} catch (RemoteException e) {
- return false;
+ if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG, "Relaunch failed", e);
}
if (andResume) {
@@ -4478,6 +4485,10 @@
if (mMainStack) {
mService.reportResumedActivityLocked(r);
}
+ r.state = ActivityState.RESUMED;
+ } else {
+ mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
+ r.state = ActivityState.PAUSED;
}
return true;
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index d7c5eea..497ee4b 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -5600,16 +5600,18 @@
private final IPackageStatsObserver mObserver;
- public MeasureParams(PackageStats stats, boolean success, IPackageStatsObserver observer) {
+ public MeasureParams(PackageStats stats, IPackageStatsObserver observer) {
mObserver = observer;
mStats = stats;
- mSuccess = success;
}
@Override
void handleStartCopy() throws RemoteException {
- final boolean mounted;
+ synchronized (mInstallLock) {
+ mSuccess = getPackageSizeInfoLI(mStats.packageName, mStats);
+ }
+ final boolean mounted;
if (Environment.isExternalStorageEmulated()) {
mounted = true;
} else {
@@ -7781,22 +7783,16 @@
final IPackageStatsObserver observer) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.GET_PACKAGE_SIZE, null);
- // Queue up an async operation since the package deletion may take a little while.
- mHandler.post(new Runnable() {
- public void run() {
- mHandler.removeCallbacks(this);
- PackageStats stats = new PackageStats(packageName);
- final boolean success;
- synchronized (mInstallLock) {
- success = getPackageSizeInfoLI(packageName, stats);
- }
+ PackageStats stats = new PackageStats(packageName);
- Message msg = mHandler.obtainMessage(INIT_COPY);
- msg.obj = new MeasureParams(stats, success, observer);
- mHandler.sendMessage(msg);
- } //end run
- });
+ /*
+ * Queue up an async operation since the package measurement may take a
+ * little while.
+ */
+ Message msg = mHandler.obtainMessage(INIT_COPY);
+ msg.obj = new MeasureParams(stats, observer);
+ mHandler.sendMessage(msg);
}
private boolean getPackageSizeInfoLI(String packageName, PackageStats pStats) {
diff --git a/services/java/com/android/server/wm/WindowStateAnimator.java b/services/java/com/android/server/wm/WindowStateAnimator.java
index 0aa1b45..cba92f3 100644
--- a/services/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/java/com/android/server/wm/WindowStateAnimator.java
@@ -1186,6 +1186,7 @@
mSurfaceX = left;
mSurfaceY = top;
mSurface.setPosition(left, top);
+ mSurface.setWindowCrop(null);
} catch (RuntimeException e) {
Slog.w(TAG, "Error positioning surface of " + mWin
+ " pos=(" + left + "," + top + ")", e);
diff --git a/services/tests/servicestests/src/com/android/server/CertBlacklisterTest.java b/services/tests/servicestests/src/com/android/server/CertBlacklisterTest.java
new file mode 100644
index 0000000..10b9e7c
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/CertBlacklisterTest.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.content.Context;
+import android.content.Intent;
+import android.test.AndroidTestCase;
+import android.provider.Settings;
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.HashSet;
+
+import libcore.io.IoUtils;
+
+/**
+ * Tests for {@link com.android.server.CertBlacklister}
+ */
+public class CertBlacklisterTest extends AndroidTestCase {
+
+ private static final String BLACKLIST_ROOT = System.getenv("ANDROID_DATA") + "/misc/keychain/";
+
+ public static final String PUBKEY_PATH = BLACKLIST_ROOT + "pubkey_blacklist.txt";
+ public static final String SERIAL_PATH = BLACKLIST_ROOT + "serial_blacklist.txt";
+
+ public static final String PUBKEY_KEY = "pubkey_blacklist";
+ public static final String SERIAL_KEY = "serial_blacklist";
+
+ private void overrideSettings(String key, String value) throws Exception {
+ Settings.Secure.putString(mContext.getContentResolver(), key, value);
+ Thread.sleep(1000);
+ }
+
+ public void testClearBlacklistPubkey() throws Exception {
+ // clear the gservices setting for a clean slate
+ overrideSettings(PUBKEY_KEY, "");
+ // read the contents of the pubkey blacklist
+ String blacklist = IoUtils.readFileAsString(PUBKEY_PATH);
+ // Verify that it's empty
+ assertEquals("", blacklist);
+ }
+
+ public void testSetBlacklistPubkey() throws Exception {
+ // build a new thing to blacklist
+ String badPubkey = "7ccabd7db47e94a5759901b6a7dfd45d1c091ccc";
+ // add the gservices override
+ overrideSettings(PUBKEY_KEY, badPubkey);
+ // check the contents again
+ String blacklist = IoUtils.readFileAsString(PUBKEY_PATH);
+ // make sure that we're equal to the string we sent out
+ assertEquals(badPubkey, blacklist);
+ }
+
+ public void testChangeBlacklistPubkey() throws Exception {
+ String badPubkey = "6ccabd7db47e94a5759901b6a7dfd45d1c091ccc";
+ overrideSettings(PUBKEY_KEY, badPubkey);
+ badPubkey = "6ccabd7db47e94a5759901b6a7dfd45d1c091cce";
+ overrideSettings(PUBKEY_KEY, badPubkey);
+ String blacklist = IoUtils.readFileAsString(PUBKEY_PATH);
+ assertEquals(badPubkey, blacklist);
+ }
+
+ public void testMultiBlacklistPubkey() throws Exception {
+ String badPubkey = "6ccabd7db47e94a5759901b6a7dfd45d1c091ccc,6ccabd7db47e94a5759901b6a7dfd45d1c091ccd";
+ overrideSettings(PUBKEY_KEY, badPubkey);
+ String blacklist = IoUtils.readFileAsString(PUBKEY_PATH);
+ assertEquals(badPubkey, blacklist);
+ }
+
+ public void testInvalidMultiBlacklistPubkey() throws Exception {
+ String badPubkey = "6ccabd7db47e94a5759901b6a7dfd45d1c091ccc,ZZZZZ,6ccabd7db47e94a5759901b6a7dfd45d1c091ccd";
+ overrideSettings(PUBKEY_KEY, badPubkey);
+ String blacklist = IoUtils.readFileAsString(PUBKEY_PATH);
+ assertEquals(badPubkey, blacklist);
+ }
+
+ public void testInvalidCharsBlacklistPubkey() throws Exception {
+ String badPubkey = "\n6ccabd7db47e94a5759901b6a7dfd45d1c091ccc,-ZZZZZ,+6ccabd7db47e94a5759901b6a7dfd45d1c091ccd";
+ overrideSettings(PUBKEY_KEY, badPubkey);
+ String blacklist = IoUtils.readFileAsString(PUBKEY_PATH);
+ assertEquals(badPubkey, blacklist);
+ }
+
+ public void testLotsOfBlacklistedPubkeys() throws Exception {
+ StringBuilder bl = new StringBuilder();
+ for (int i=0; i < 1000; i++) {
+ bl.append("6ccabd7db47e94a5759901b6a7dfd45d1c091ccc,");
+ }
+ overrideSettings(PUBKEY_KEY, bl.toString());
+ String blacklist = IoUtils.readFileAsString(PUBKEY_PATH);
+ assertEquals(bl.toString(), blacklist);
+ }
+
+ public void testClearBlacklistSerial() throws Exception {
+ // clear the gservices setting for a clean slate
+ overrideSettings(SERIAL_KEY, "");
+ // read the contents of the pubkey blacklist
+ String blacklist = IoUtils.readFileAsString(SERIAL_PATH);
+ // Verify that it's empty
+ assertEquals("", blacklist);
+ }
+
+ public void testSetBlacklistSerial() throws Exception {
+ // build a new thing to blacklist
+ String badSerial = "22e514121e61c643b1e9b06bd4b9f7d0";
+ // add the gservices override
+ overrideSettings(SERIAL_KEY, badSerial);
+ // check the contents again
+ String blacklist = IoUtils.readFileAsString(SERIAL_PATH);
+ // make sure that we're equal to the string we sent out
+ assertEquals(badSerial, blacklist);
+ }
+
+ public void testChangeBlacklistSerial() throws Exception {
+ String badSerial = "22e514121e61c643b1e9b06bd4b9f7d0";
+ overrideSettings(SERIAL_KEY, badSerial);
+ badSerial = "22e514121e61c643b1e9b06bd4b9f7d1";
+ overrideSettings(SERIAL_KEY, badSerial);
+ String blacklist = IoUtils.readFileAsString(SERIAL_PATH);
+ assertEquals(badSerial, blacklist);
+ }
+
+ public void testMultiBlacklistSerial() throws Exception {
+ String badSerial = "22e514121e61c643b1e9b06bd4b9f7d0,22e514121e61c643b1e9b06bd4b9f7d1";
+ overrideSettings(SERIAL_KEY, badSerial);
+ String blacklist = IoUtils.readFileAsString(SERIAL_PATH);
+ assertEquals(badSerial, blacklist);
+ }
+
+ public void testInvalidMultiBlacklistSerial() throws Exception {
+ String badSerial = "22e514121e61c643b1e9b06bd4b9f7d0,ZZZZ,22e514121e61c643b1e9b06bd4b9f7d1";
+ overrideSettings(SERIAL_KEY, badSerial);
+ String blacklist = IoUtils.readFileAsString(SERIAL_PATH);
+ assertEquals(badSerial, blacklist);
+ }
+
+ public void testInvalidCharsBlacklistSerial() throws Exception {
+ String badSerial = "\n22e514121e61c643b1e9b06bd4b9f7d0,-ZZZZ,+22e514121e61c643b1e9b06bd4b9f7d1";
+ overrideSettings(SERIAL_KEY, badSerial);
+ String blacklist = IoUtils.readFileAsString(SERIAL_PATH);
+ assertEquals(badSerial, blacklist);
+ }
+
+ public void testLotsOfBlacklistedSerials() throws Exception {
+ StringBuilder bl = new StringBuilder();
+ for (int i=0; i < 1000; i++) {
+ bl.append("22e514121e61c643b1e9b06bd4b9f7d0,");
+ }
+ overrideSettings(SERIAL_KEY, bl.toString());
+ String blacklist = IoUtils.readFileAsString(SERIAL_PATH);
+ assertEquals(bl.toString(), blacklist);
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/IccSmsInterfaceManager.java b/telephony/java/com/android/internal/telephony/IccSmsInterfaceManager.java
index 9763265..5fef6de 100644
--- a/telephony/java/com/android/internal/telephony/IccSmsInterfaceManager.java
+++ b/telephony/java/com/android/internal/telephony/IccSmsInterfaceManager.java
@@ -112,7 +112,7 @@
*/
public void sendText(String destAddr, String scAddr,
String text, PendingIntent sentIntent, PendingIntent deliveryIntent) {
- mPhone.getContext().enforceCallingOrSelfPermission(
+ mPhone.getContext().enforceCallingPermission(
"android.permission.SEND_SMS",
"Sending SMS message");
if (Log.isLoggable("SMS", Log.VERBOSE)) {
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/BitmapMutateActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/BitmapMutateActivity.java
index db9017c..0d825d7 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/BitmapMutateActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/BitmapMutateActivity.java
@@ -87,7 +87,7 @@
int width = mBitmap1.getWidth();
int height = mBitmap1.getHeight();
- canvas.translate((getWidth() - width) / 2, (getHeight() - height) / 2);
+ canvas.translate((getWidth() - width) / 2, 0);
for (int x = 0; x < width; x++) {
int color = 0xff000000;
@@ -101,6 +101,11 @@
mBitmap1.setPixels(mPixels, 0, width, 0, 0, width, height);
canvas.drawBitmap(mBitmap1, 0.0f, 0.0f, mBitmapPaint);
+
+ canvas.save();
+ canvas.translate(0.0f, height + 32);
+ canvas.drawBitmap(mPixels, 0, width, 0.0f, 0.0f, width, height, false, mBitmapPaint);
+ canvas.restore();
}
}
}
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index b099202..2903faa 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -182,6 +182,14 @@
/* Tracks sequence number on a tether notification time out */
private int mTetherToken = 0;
+ /**
+ * Driver start time out.
+ */
+ private static final int DRIVER_START_TIME_OUT_MSECS = 10000;
+
+ /* Tracks sequence number on a driver time out */
+ private int mDriverStartToken = 0;
+
private LinkProperties mLinkProperties;
/* Tracks sequence number on a periodic scan message */
@@ -250,7 +258,8 @@
static final int CMD_STOP_SUPPLICANT_FAILED = BASE + 17;
/* Delayed stop to avoid shutting down driver too quick*/
static final int CMD_DELAYED_STOP_DRIVER = BASE + 18;
-
+ /* A delayed message sent to start driver when it fail to come up */
+ static final int CMD_DRIVER_START_TIMED_OUT = BASE + 19;
/* Start the soft access point */
static final int CMD_START_AP = BASE + 21;
@@ -1837,6 +1846,7 @@
case CMD_START_DRIVER:
case CMD_STOP_DRIVER:
case CMD_DELAYED_STOP_DRIVER:
+ case CMD_DRIVER_START_TIMED_OUT:
case CMD_START_AP:
case CMD_START_AP_SUCCESS:
case CMD_START_AP_FAILURE:
@@ -2476,10 +2486,16 @@
}
class DriverStartingState extends State {
+ private int mTries;
@Override
public void enter() {
if (DBG) log(getName() + "\n");
EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
+
+ mTries = 1;
+ /* Send ourselves a delayed message to start driver a second time */
+ sendMessageDelayed(obtainMessage(CMD_DRIVER_START_TIMED_OUT,
+ ++mDriverStartToken, 0), DRIVER_START_TIME_OUT_MSECS);
}
@Override
public boolean processMessage(Message message) {
@@ -2495,6 +2511,24 @@
transitionTo(mDriverStartedState);
}
break;
+ case CMD_DRIVER_START_TIMED_OUT:
+ if (message.arg1 == mDriverStartToken) {
+ if (mTries >= 2) {
+ loge("Failed to start driver after " + mTries);
+ transitionTo(mDriverStoppedState);
+ } else {
+ loge("Driver start failed, retrying");
+ mWakeLock.acquire();
+ mWifiNative.startDriver();
+ mWakeLock.release();
+
+ ++mTries;
+ /* Send ourselves a delayed message to start driver again */
+ sendMessageDelayed(obtainMessage(CMD_DRIVER_START_TIMED_OUT,
+ ++mDriverStartToken, 0), DRIVER_START_TIME_OUT_MSECS);
+ }
+ }
+ break;
/* Queue driver commands & connection events */
case CMD_START_DRIVER:
case CMD_STOP_DRIVER: