diff options
40 files changed, 538 insertions, 828 deletions
diff --git a/api/system-current.txt b/api/system-current.txt index 80863879a761..629cb3f30c97 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -27268,6 +27268,7 @@ package android.provider { field public static final java.lang.String SHOW_PROCESSES = "show_processes"; field public static final java.lang.String STAY_ON_WHILE_PLUGGED_IN = "stay_on_while_plugged_in"; field public static final java.lang.String SYS_PROP_SETTING_VERSION = "sys.settings_global_version"; + field public static final java.lang.String THEATER_MODE_ON = "theater_mode_on"; field public static final java.lang.String TRANSITION_ANIMATION_SCALE = "transition_animation_scale"; field public static final java.lang.String USB_MASS_STORAGE_ENABLED = "usb_mass_storage_enabled"; field public static final java.lang.String USE_GOOGLE_MAIL = "use_google_mail"; diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl index 27a03b69706a..5f7a17d33bd1 100644 --- a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl +++ b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl @@ -54,10 +54,6 @@ interface IAccessibilityServiceConnection { int action, in Bundle arguments, int interactionId, IAccessibilityInteractionConnectionCallback callback, long threadId); - boolean computeClickPointInScreen(int accessibilityWindowId, long accessibilityNodeId, - int interactionId, IAccessibilityInteractionConnectionCallback callback, - long threadId); - AccessibilityWindowInfo getWindow(int windowId); List<AccessibilityWindowInfo> getWindows(); diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index e05520379f57..dddbe7890546 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -18,6 +18,7 @@ package android.provider; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; +import android.annotation.SystemApi; import android.app.SearchManager; import android.app.WallpaperManager; import android.content.ComponentName; @@ -5104,6 +5105,7 @@ public final class Settings { * Whether Theater Mode is on. * {@hide} */ + @SystemApi public static final String THEATER_MODE_ON = "theater_mode_on"; /** diff --git a/core/java/android/transition/TransitionManager.java b/core/java/android/transition/TransitionManager.java index 7bd6287ae27b..80245efdfce0 100644 --- a/core/java/android/transition/TransitionManager.java +++ b/core/java/android/transition/TransitionManager.java @@ -268,7 +268,12 @@ public class TransitionManager { @Override public boolean onPreDraw() { removeListeners(); - sPendingTransitions.remove(mSceneRoot); + + // Don't start the transition if it's no longer pending. + if (!sPendingTransitions.remove(mSceneRoot)) { + return true; + } + // Add to running list, handle end to remove it final ArrayMap<ViewGroup, ArrayList<Transition>> runningTransitions = getRunningTransitions(); @@ -417,4 +422,24 @@ public class TransitionManager { sceneChangeRunTransition(sceneRoot, transitionClone); } } + + /** + * Ends all pending and ongoing transitions on the specified scene root. + * + * @param sceneRoot The root of the View hierarchy to end transitions on. + * @hide + */ + public static void endTransitions(final ViewGroup sceneRoot) { + sPendingTransitions.remove(sceneRoot); + + final ArrayList<Transition> runningTransitions = getRunningTransitions().get(sceneRoot); + if (runningTransitions != null) { + final int count = runningTransitions.size(); + for (int i = 0; i < count; i++) { + final Transition transition = runningTransitions.get(i); + transition.end(); + } + } + + } } diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java index 5e05683be3d0..68ad782ddbd9 100644 --- a/core/java/android/view/AccessibilityInteractionController.java +++ b/core/java/android/view/AccessibilityInteractionController.java @@ -636,95 +636,6 @@ final class AccessibilityInteractionController { } } - public void computeClickPointInScreenClientThread(long accessibilityNodeId, - Region interactiveRegion, int interactionId, - IAccessibilityInteractionConnectionCallback callback, int interrogatingPid, - long interrogatingTid, MagnificationSpec spec) { - Message message = mHandler.obtainMessage(); - message.what = PrivateHandler.MSG_COMPUTE_CLICK_POINT_IN_SCREEN; - - SomeArgs args = SomeArgs.obtain(); - args.argi1 = AccessibilityNodeInfo.getAccessibilityViewId(accessibilityNodeId); - args.argi2 = AccessibilityNodeInfo.getVirtualDescendantId(accessibilityNodeId); - args.argi3 = interactionId; - args.arg1 = callback; - args.arg2 = spec; - args.arg3 = interactiveRegion; - - message.obj = args; - - // If the interrogation is performed by the same thread as the main UI - // thread in this process, set the message as a static reference so - // after this call completes the same thread but in the interrogating - // client can handle the message to generate the result. - if (interrogatingPid == mMyProcessId && interrogatingTid == mMyLooperThreadId) { - AccessibilityInteractionClient.getInstanceForThread( - interrogatingTid).setSameThreadMessage(message); - } else { - mHandler.sendMessage(message); - } - } - - private void computeClickPointInScreenUiThread(Message message) { - SomeArgs args = (SomeArgs) message.obj; - final int accessibilityViewId = args.argi1; - final int virtualDescendantId = args.argi2; - final int interactionId = args.argi3; - final IAccessibilityInteractionConnectionCallback callback = - (IAccessibilityInteractionConnectionCallback) args.arg1; - final MagnificationSpec spec = (MagnificationSpec) args.arg2; - final Region interactiveRegion = (Region) args.arg3; - args.recycle(); - - boolean succeeded = false; - Point point = mTempPoint; - try { - if (mViewRootImpl.mView == null || mViewRootImpl.mAttachInfo == null) { - return; - } - View target = null; - if (accessibilityViewId != AccessibilityNodeInfo.UNDEFINED_ITEM_ID) { - target = findViewByAccessibilityId(accessibilityViewId); - } else { - target = mViewRootImpl.mView; - } - if (target != null && isShown(target)) { - AccessibilityNodeProvider provider = target.getAccessibilityNodeProvider(); - if (provider != null) { - // For virtual views just use the center of the bounds in screen. - AccessibilityNodeInfo node = null; - if (virtualDescendantId != AccessibilityNodeInfo.UNDEFINED_ITEM_ID) { - node = provider.createAccessibilityNodeInfo(virtualDescendantId); - } else { - node = provider.createAccessibilityNodeInfo( - AccessibilityNodeProvider.HOST_VIEW_ID); - } - if (node != null) { - succeeded = true; - Rect boundsInScreen = mTempRect; - node.getBoundsInScreen(boundsInScreen); - point.set(boundsInScreen.centerX(), boundsInScreen.centerY()); - } - } else if (virtualDescendantId == AccessibilityNodeInfo.UNDEFINED_ITEM_ID) { - // For a real view, ask the view to compute the click point. - succeeded = target.computeClickPointInScreenForAccessibility( - interactiveRegion, point); - } - } - } finally { - try { - Point result = null; - if (succeeded) { - applyAppScaleAndMagnificationSpecIfNeeded(point, spec); - result = point; - } - callback.setComputeClickPointInScreenActionResult(result, interactionId); - } catch (RemoteException re) { - /* ignore - the other side will time out */ - } - } - } - private View findViewByAccessibilityId(int accessibilityId) { View root = mViewRootImpl.mView; if (root == null) { @@ -1201,7 +1112,6 @@ final class AccessibilityInteractionController { private final static int MSG_FIND_ACCESSIBILITY_NODE_INFO_BY_TEXT = 4; private final static int MSG_FIND_FOCUS = 5; private final static int MSG_FOCUS_SEARCH = 6; - private final static int MSG_COMPUTE_CLICK_POINT_IN_SCREEN = 7; public PrivateHandler(Looper looper) { super(looper); @@ -1223,8 +1133,6 @@ final class AccessibilityInteractionController { return "MSG_FIND_FOCUS"; case MSG_FOCUS_SEARCH: return "MSG_FOCUS_SEARCH"; - case MSG_COMPUTE_CLICK_POINT_IN_SCREEN: - return "MSG_COMPUTE_CLICK_POINT_IN_SCREEN"; default: throw new IllegalArgumentException("Unknown message type: " + type); } @@ -1252,9 +1160,6 @@ final class AccessibilityInteractionController { case MSG_FOCUS_SEARCH: { focusSearchUiThread(message); } break; - case MSG_COMPUTE_CLICK_POINT_IN_SCREEN: { - computeClickPointInScreenUiThread(message); - } break; default: throw new IllegalArgumentException("Unknown message type: " + type); } diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java index 1c5c41c74905..5e45c8fe10dd 100644 --- a/core/java/android/view/MotionEvent.java +++ b/core/java/android/view/MotionEvent.java @@ -402,6 +402,23 @@ public final class MotionEvent extends InputEvent implements Parcelable { public static final int FLAG_TAINTED = 0x80000000; /** + * Private flag indicating that this event was synthesized by the system and + * should be delivered to the accessibility focused view first. When being + * dispatched such an event is not handled by predecessors of the accessibility + * focused view and after the event reaches that view the flag is cleared and + * normal event dispatch is performed. This ensures that the platform can click + * on any view that has accessibility focus which is semantically equivalent to + * asking the view to perform a click accessibility action but more generic as + * views not implementing click action correctly can still be activated. + * + * @hide + * @see #isTargetAccessibilityFocus() + * @see #setTargetAccessibilityFocus(boolean) + */ + public static final int FLAG_TARGET_ACCESSIBILITY_FOCUS = 0x40000000; + + + /** * Flag indicating the motion event intersected the top edge of the screen. */ public static final int EDGE_TOP = 0x00000001; @@ -1766,6 +1783,20 @@ public final class MotionEvent extends InputEvent implements Parcelable { nativeSetFlags(mNativePtr, tainted ? flags | FLAG_TAINTED : flags & ~FLAG_TAINTED); } + /** @hide */ + public final boolean isTargetAccessibilityFocus() { + final int flags = getFlags(); + return (flags & FLAG_TARGET_ACCESSIBILITY_FOCUS) != 0; + } + + /** @hide */ + public final void setTargetAccessibilityFocus(boolean targetsFocus) { + final int flags = getFlags(); + nativeSetFlags(mNativePtr, targetsFocus + ? flags | FLAG_TARGET_ACCESSIBILITY_FOCUS + : flags & ~FLAG_TARGET_ACCESSIBILITY_FOCUS); + } + /** * Returns the time (in ms) when the user originally pressed down to start * a stream of position events. diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 5b26ebba6b35..97e1bc0c304e 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -5522,12 +5522,23 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** - * Gets the location of this view in screen coordintates. + * Gets the location of this view in screen coordinates. * * @param outRect The output location * @hide */ public void getBoundsOnScreen(Rect outRect) { + getBoundsOnScreen(outRect, false); + } + + /** + * Gets the location of this view in screen coordinates. + * + * @param outRect The output location + * @param clipToParent Whether to clip child bounds to the parent ones. + * @hide + */ + public void getBoundsOnScreen(Rect outRect, boolean clipToParent) { if (mAttachInfo == null) { return; } @@ -5547,6 +5558,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback, position.offset(-parentView.mScrollX, -parentView.mScrollY); + if (clipToParent) { + position.left = Math.max(position.left, 0); + position.top = Math.max(position.top, 0); + position.right = Math.min(position.right, parentView.getWidth()); + position.bottom = Math.min(position.bottom, parentView.getHeight()); + } + if (!parentView.hasIdentityMatrix()) { parentView.getMatrix().mapRect(position); } @@ -5580,7 +5598,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, getDrawingRect(bounds); info.setBoundsInParent(bounds); - getBoundsOnScreen(bounds); + getBoundsOnScreen(bounds, true); info.setBoundsInScreen(bounds); ViewParent parent = getParentForAccessibility(); @@ -5776,142 +5794,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** - * Computes a point on which a sequence of a down/up event can be sent to - * trigger clicking this view. This method is for the exclusive use by the - * accessibility layer to determine where to send a click event in explore - * by touch mode. - * - * @param interactiveRegion The interactive portion of this window. - * @param outPoint The point to populate. - * @return True of such a point exists. - */ - boolean computeClickPointInScreenForAccessibility(Region interactiveRegion, - Point outPoint) { - // Since the interactive portion of the view is a region but as a view - // may have a transformation matrix which cannot be applied to a - // region we compute the view bounds rectangle and all interactive - // predecessor's and sibling's (siblings of predecessors included) - // rectangles that intersect the view bounds. At the - // end if the view was partially covered by another interactive - // view we compute the view's interactive region and pick a point - // on its boundary path as regions do not offer APIs to get inner - // points. Note that the the code is optimized to fail early and - // avoid unnecessary allocations plus computations. - - // The current approach has edge cases that may produce false - // positives or false negatives. For example, a portion of the - // view may be covered by an interactive descendant of a - // predecessor, which we do not compute. Also a view may be handling - // raw touch events instead registering click listeners, which - // we cannot compute. Despite these limitations this approach will - // work most of the time and it is a huge improvement over just - // blindly sending the down and up events in the center of the - // view. - - // Cannot click on an unattached view. - if (mAttachInfo == null) { - return false; - } - - // Attached to an invisible window means this view is not visible. - if (mAttachInfo.mWindowVisibility != View.VISIBLE) { - return false; - } - - RectF bounds = mAttachInfo.mTmpTransformRect; - bounds.set(0, 0, getWidth(), getHeight()); - List<RectF> intersections = mAttachInfo.mTmpRectList; - intersections.clear(); - - if (mParent instanceof ViewGroup) { - ViewGroup parentGroup = (ViewGroup) mParent; - if (!parentGroup.translateBoundsAndIntersectionsInWindowCoordinates( - this, bounds, intersections)) { - intersections.clear(); - return false; - } - } - - // Take into account the window location. - final int dx = mAttachInfo.mWindowLeft; - final int dy = mAttachInfo.mWindowTop; - bounds.offset(dx, dy); - offsetRects(intersections, dx, dy); - - if (intersections.isEmpty() && interactiveRegion == null) { - outPoint.set((int) bounds.centerX(), (int) bounds.centerY()); - } else { - // This view is partially covered by other views, then compute - // the not covered region and pick a point on its boundary. - Region region = new Region(); - region.set((int) bounds.left, (int) bounds.top, - (int) bounds.right, (int) bounds.bottom); - - final int intersectionCount = intersections.size(); - for (int i = intersectionCount - 1; i >= 0; i--) { - RectF intersection = intersections.remove(i); - region.op((int) intersection.left, (int) intersection.top, - (int) intersection.right, (int) intersection.bottom, - Region.Op.DIFFERENCE); - } - - // If the view is completely covered, done. - if (region.isEmpty()) { - return false; - } - - // Take into account the interactive portion of the window - // as the rest is covered by other windows. If no such a region - // then the whole window is interactive. - if (interactiveRegion != null) { - region.op(interactiveRegion, Region.Op.INTERSECT); - } - - // Take into account the window bounds. - final View root = getRootView(); - if (root != null) { - region.op(dx, dy, root.getWidth() + dx, root.getHeight() + dy, Region.Op.INTERSECT); - } - - // If the view is completely covered, done. - if (region.isEmpty()) { - return false; - } - - // Try a shortcut here. - if (region.isRect()) { - Rect regionBounds = mAttachInfo.mTmpInvalRect; - region.getBounds(regionBounds); - outPoint.set(regionBounds.centerX(), regionBounds.centerY()); - return true; - } - - // Get the a point on the region boundary path. - Path path = region.getBoundaryPath(); - PathMeasure pathMeasure = new PathMeasure(path, false); - final float[] coordinates = mAttachInfo.mTmpTransformLocation; - - // Without loss of generality pick a point. - final float point = pathMeasure.getLength() * 0.01f; - if (!pathMeasure.getPosTan(point, coordinates, null)) { - return false; - } - - outPoint.set(Math.round(coordinates[0]), Math.round(coordinates[1])); - } - - return true; - } - - static void offsetRects(List<RectF> rects, float offsetX, float offsetY) { - final int rectCount = rects.size(); - for (int i = 0; i < rectCount; i++) { - RectF intersection = rects.get(i); - intersection.offset(offsetX, offsetY); - } - } - - /** * Returns the delegate for implementing accessibility support via * composition. For more details see {@link AccessibilityDelegate}. * @@ -8525,6 +8407,17 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @return True if the event was handled by the view, false otherwise. */ public boolean dispatchTouchEvent(MotionEvent event) { + // If the event should be handled by accessibility focus first. + if (event.isTargetAccessibilityFocus()) { + // We don't have focus or no virtual descendant has it, do not handle the event. + if (!isAccessibilityFocused() && !(getViewRootImpl() != null && getViewRootImpl() + .getAccessibilityFocusedHost() == this)) { + return false; + } + // We have focus and got the event, then use normal event dispatch. + event.setTargetAccessibilityFocus(false); + } + boolean result = false; if (mInputEventConsistencyVerifier != null) { diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 49e4efa4f301..879fe19659a1 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -474,9 +474,6 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager @ViewDebug.ExportedProperty(category = "layout") private int mChildCountWithTransientState = 0; - // Iterator over the children in decreasing Z order (top children first). - private OrderedChildIterator mOrderedChildIterator; - /** * Currently registered axes for nested scrolling. Flag set consisting of * {@link #SCROLL_AXIS_HORIZONTAL} {@link #SCROLL_AXIS_VERTICAL} or {@link #SCROLL_AXIS_NONE} @@ -782,144 +779,6 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } /** - * Translates the given bounds and intersections from child coordinates to - * local coordinates. In case any interactive sibling of the calling child - * covers the latter, a new intersections is added to the intersection list. - * This method is for the exclusive use by the accessibility layer to compute - * a point where a sequence of down and up events would click on a view. - * - * @param child The child making the call. - * @param bounds The bounds to translate in child coordinates. - * @param intersections The intersections of interactive views covering the child. - * @return True if the bounds and intersections were computed, false otherwise. - */ - boolean translateBoundsAndIntersectionsInWindowCoordinates(View child, - RectF bounds, List<RectF> intersections) { - // Not attached, done. - if (mAttachInfo == null) { - return false; - } - - if (getAlpha() <= 0 || getTransitionAlpha() <= 0 || - getVisibility() != VISIBLE) { - // Cannot click on a view with an invisible predecessor. - return false; - } - - // Compensate for the child transformation. - if (!child.hasIdentityMatrix()) { - Matrix matrix = child.getMatrix(); - matrix.mapRect(bounds); - final int intersectionCount = intersections.size(); - for (int i = 0; i < intersectionCount; i++) { - RectF intersection = intersections.get(i); - matrix.mapRect(intersection); - } - } - - // Translate the bounds from child to parent coordinates. - final int dx = child.mLeft - mScrollX; - final int dy = child.mTop - mScrollY; - bounds.offset(dx, dy); - offsetRects(intersections, dx, dy); - - // If the bounds do not intersect our bounds, done. - if (!bounds.intersects(0, 0, getWidth(), getHeight())) { - return false; - } - - // Clip the bounds by our bounds. - bounds.left = Math.max(bounds.left, 0); - bounds.top = Math.max(bounds.top, 0); - bounds.right = Math.min(bounds.right, getWidth()); - bounds.bottom = Math.min(bounds.bottom, getHeight()); - - Iterator<View> iterator = obtainOrderedChildIterator(); - while (iterator.hasNext()) { - View sibling = iterator.next(); - - // We care only about siblings over the child. - if (sibling == child) { - break; - } - - // Ignore invisible views as they are not interactive. - if (!isVisible(sibling)) { - continue; - } - - // Compute the sibling bounds in its coordinates. - RectF siblingBounds = mAttachInfo.mTmpTransformRect1; - siblingBounds.set(0, 0, sibling.getWidth(), sibling.getHeight()); - - // Translate the sibling bounds to our coordinates. - offsetChildRectToMyCoords(siblingBounds, sibling); - - // Compute the intersection between the child and the sibling. - if (siblingBounds.intersect(bounds)) { - // Conservatively we consider an overlapping sibling to be - // interactive and ignore it. This is not ideal as if the - // sibling completely covers the view despite handling no - // touch events we will not be able to click on the view. - intersections.add(siblingBounds); - } - } - - releaseOrderedChildIterator(); - - if (mParent instanceof ViewGroup) { - ViewGroup parentGroup = (ViewGroup) mParent; - return parentGroup.translateBoundsAndIntersectionsInWindowCoordinates( - this, bounds, intersections); - } - - return true; - } - - private void offsetChildRectToMyCoords(RectF rect, View child) { - if (!child.hasIdentityMatrix()) { - child.getMatrix().mapRect(rect); - } - final int childDx = child.mLeft - mScrollX; - final int childDy = child.mTop - mScrollY; - rect.offset(childDx, childDy); - } - - private static boolean isVisible(View view) { - return (view.getAlpha() > 0 && view.getTransitionAlpha() > 0 && - view.getVisibility() == VISIBLE); - } - - /** - * Obtains the iterator to traverse the children in a descending Z order. - * Only one party can use the iterator at any given time and you cannot - * modify the children while using this iterator. Acquisition if already - * obtained is an error. - * - * @return The child iterator. - */ - OrderedChildIterator obtainOrderedChildIterator() { - if (mOrderedChildIterator == null) { - mOrderedChildIterator = new OrderedChildIterator(); - } else if (mOrderedChildIterator.isInitialized()) { - throw new IllegalStateException("Already obtained"); - } - mOrderedChildIterator.initialize(); - return mOrderedChildIterator; - } - - /** - * Releases the iterator to traverse the children in a descending Z order. - * Release if not obtained is an error. - */ - void releaseOrderedChildIterator() { - if (mOrderedChildIterator == null || !mOrderedChildIterator.isInitialized()) { - throw new IllegalStateException("Not obtained"); - } - mOrderedChildIterator.release(); - } - - /** * Called when a child view has changed whether or not it is tracking transient state. */ public void childHasTransientStateChanged(View child, boolean childHasTransientState) { @@ -2074,6 +1933,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager mInputEventConsistencyVerifier.onTouchEvent(ev, 1); } + // Whether this event should be handled by the accessibility focus first. + final boolean targetAccessibilityFocus = ev.isTargetAccessibilityFocus(); + boolean handled = false; if (onFilterTouchEventForSecurity(ev)) { final int action = ev.getAction(); @@ -2090,19 +1952,24 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager // Check for interception. final boolean intercepted; - if (actionMasked == MotionEvent.ACTION_DOWN - || mFirstTouchTarget != null) { - final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0; - if (!disallowIntercept) { - intercepted = onInterceptTouchEvent(ev); - ev.setAction(action); // restore action in case it was changed + if (!targetAccessibilityFocus) { + if (actionMasked == MotionEvent.ACTION_DOWN + || mFirstTouchTarget != null) { + final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0; + if (!disallowIntercept) { + intercepted = onInterceptTouchEvent(ev); + ev.setAction(action); // restore action in case it was changed + } else { + intercepted = false; + } } else { - intercepted = false; + // There are no touch targets and this action is not an initial down + // so this view group continues to intercept touches. + intercepted = true; } } else { - // There are no touch targets and this action is not an initial down - // so this view group continues to intercept touches. - intercepted = true; + // If event should reach the accessibility focus first, do not intercept it. + intercepted = false; } // Check for cancelation. @@ -2116,7 +1983,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager if (!canceled && !intercepted) { if (actionMasked == MotionEvent.ACTION_DOWN || (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN) - || actionMasked == MotionEvent.ACTION_HOVER_MOVE) { + || actionMasked == MotionEvent.ACTION_HOVER_MOVE + || targetAccessibilityFocus) { final int actionIndex = ev.getActionIndex(); // always 0 for down final int idBitsToAssign = split ? 1 << ev.getPointerId(actionIndex) : TouchTarget.ALL_POINTER_IDS; @@ -7408,57 +7276,4 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager canvas.drawLines(sDebugLines, paint); } - - private final class OrderedChildIterator implements Iterator<View> { - private List<View> mOrderedChildList; - private boolean mUseCustomOrder; - private int mCurrentIndex; - private boolean mInitialized; - - public void initialize() { - mOrderedChildList = buildOrderedChildList(); - mUseCustomOrder = (mOrderedChildList == null) - && isChildrenDrawingOrderEnabled(); - mCurrentIndex = mChildrenCount - 1; - mInitialized = true; - } - - public void release() { - if (mOrderedChildList != null) { - mOrderedChildList.clear(); - } - mUseCustomOrder = false; - mCurrentIndex = 0; - mInitialized = false; - } - - public boolean isInitialized() { - return mInitialized; - } - - @Override - public boolean hasNext() { - return (mCurrentIndex >= 0); - } - - @Override - public View next() { - if (!hasNext()) { - throw new NoSuchElementException("No such element"); - } - return getChild(mCurrentIndex--); - } - - private View getChild(int index) { - final int childIndex = mUseCustomOrder - ? getChildDrawingOrder(mChildrenCount, index) : index; - return (mOrderedChildList == null) - ? mChildren[childIndex] : mOrderedChildList.get(childIndex); - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - } } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 15e70605e2af..f78c0181a1fe 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -2712,7 +2712,7 @@ public final class ViewRootImpl implements ViewParent, final AccessibilityNodeProvider provider = host.getAccessibilityNodeProvider(); if (provider == null) { - host.getBoundsOnScreen(bounds); + host.getBoundsOnScreen(bounds, true); } else if (mAccessibilityFocusedVirtualView != null) { mAccessibilityFocusedVirtualView.getBoundsInScreen(bounds); } else { @@ -6844,26 +6844,6 @@ public final class ViewRootImpl implements ViewParent, } @Override - public void computeClickPointInScreen(long accessibilityNodeId, Region interactiveRegion, - int interactionId, IAccessibilityInteractionConnectionCallback callback, - int interrogatingPid, long interrogatingTid, MagnificationSpec spec) { - ViewRootImpl viewRootImpl = mViewRootImpl.get(); - if (viewRootImpl != null && viewRootImpl.mView != null) { - viewRootImpl.getAccessibilityInteractionController() - .computeClickPointInScreenClientThread(accessibilityNodeId, - interactiveRegion, interactionId, callback, interrogatingPid, - interrogatingTid, spec); - } else { - // We cannot make the call and notify the caller so it does not wait. - try { - callback.setComputeClickPointInScreenActionResult(null, interactionId); - } catch (RemoteException re) { - /* best effort - ignore */ - } - } - } - - @Override public void findAccessibilityNodeInfosByViewId(long accessibilityNodeId, String viewId, Region interactiveRegion, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java index 374f7e064409..cefd34d7fefd 100644 --- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java +++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java @@ -99,8 +99,6 @@ public final class AccessibilityInteractionClient private boolean mPerformAccessibilityActionResult; - private Point mComputeClickPointResult; - private Message mSameThreadMessage; private static final SparseArray<IAccessibilityServiceConnection> sConnectionCache = @@ -522,43 +520,6 @@ public final class AccessibilityInteractionClient return false; } - /** - * Computes a point in screen coordinates where sending a down/up events would - * perform a click on an {@link AccessibilityNodeInfo}. - * - * @param connectionId The id of a connection for interacting with the system. - * @param accessibilityWindowId A unique window id. Use - * {@link android.view.accessibility.AccessibilityNodeInfo#ACTIVE_WINDOW_ID} - * to query the currently active window. - * @param accessibilityNodeId A unique view id or virtual descendant id from - * where to start the search. Use - * {@link android.view.accessibility.AccessibilityNodeInfo#ROOT_NODE_ID} - * to start from the root. - * @return Point the click point of null if no such point. - */ - public Point computeClickPointInScreen(int connectionId, int accessibilityWindowId, - long accessibilityNodeId) { - try { - IAccessibilityServiceConnection connection = getConnection(connectionId); - if (connection != null) { - final int interactionId = mInteractionIdCounter.getAndIncrement(); - final boolean success = connection.computeClickPointInScreen( - accessibilityWindowId, accessibilityNodeId, - interactionId, this, Thread.currentThread().getId()); - if (success) { - return getComputeClickPointInScreenResultAndClear(interactionId); - } - } else { - if (DEBUG) { - Log.w(LOG_TAG, "No connection for connection id: " + connectionId); - } - } - } catch (RemoteException re) { - Log.w(LOG_TAG, "Error while calling remote computeClickPointInScreen", re); - } - return null; - } - public void clearCache() { sAccessibilityCache.clear(); } @@ -674,34 +635,6 @@ public final class AccessibilityInteractionClient } /** - * Gets the result of a request to compute a point in screen for clicking on a node. - * - * @param interactionId The interaction id to match the result with the request. - * @return The point or null if no such point. - */ - private Point getComputeClickPointInScreenResultAndClear(int interactionId) { - synchronized (mInstanceLock) { - final boolean success = waitForResultTimedLocked(interactionId); - Point result = success ? mComputeClickPointResult : null; - clearResultLocked(); - return result; - } - } - - /** - * {@inheritDoc} - */ - public void setComputeClickPointInScreenActionResult(Point point, int interactionId) { - synchronized (mInstanceLock) { - if (interactionId > mInteractionId) { - mComputeClickPointResult = point; - mInteractionId = interactionId; - } - mInstanceLock.notifyAll(); - } - } - - /** * Clears the result state. */ private void clearResultLocked() { @@ -709,7 +642,6 @@ public final class AccessibilityInteractionClient mFindAccessibilityNodeInfoResult = null; mFindAccessibilityNodeInfosResult = null; mPerformAccessibilityActionResult = false; - mComputeClickPointResult = null; } /** diff --git a/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl b/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl index 66a3f46f2498..cecc4af49e2e 100644 --- a/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl +++ b/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl @@ -54,8 +54,4 @@ oneway interface IAccessibilityInteractionConnection { void performAccessibilityAction(long accessibilityNodeId, int action, in Bundle arguments, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid); - - void computeClickPointInScreen(long accessibilityNodeId, in Region bounds, int interactionId, - IAccessibilityInteractionConnectionCallback callback, int interrogatingPid, - long interrogatingTid, in MagnificationSpec spec); } diff --git a/core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl b/core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl index f4802168d194..42ae1b32382b 100644 --- a/core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl +++ b/core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl @@ -52,12 +52,4 @@ oneway interface IAccessibilityInteractionConnectionCallback { * @param interactionId The interaction id to match the result with the request. */ void setPerformAccessibilityActionResult(boolean succeeded, int interactionId); - - /** - * Sets the result of a request to compute a point for clicking in a view. - * - * @param point The point of null if no such point. - * @param interactionId The interaction id to match the result with the request. - */ - void setComputeClickPointInScreenActionResult(in Point point, int interactionId); } diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java index 7cf3eed8bf4e..24380716127a 100644 --- a/core/java/android/widget/PopupWindow.java +++ b/core/java/android/widget/PopupWindow.java @@ -1020,23 +1020,24 @@ public class PopupWindow { return; } + TransitionManager.endTransitions(mDecorView); + unregisterForScrollChanged(); mIsShowing = true; mIsDropdown = false; - WindowManager.LayoutParams p = createPopupLayout(token); - p.windowAnimations = computeAnimationResource(); - + final WindowManager.LayoutParams p = createPopupLayoutParams(token); preparePopup(p); - if (gravity == Gravity.NO_GRAVITY) { - gravity = Gravity.TOP | Gravity.START; + + // Only override the default if some gravity was specified. + if (gravity != Gravity.NO_GRAVITY) { + p.gravity = gravity; } - p.gravity = gravity; + p.x = x; p.y = y; - if (mHeightMode < 0) p.height = mLastHeight = mHeightMode; - if (mWidthMode < 0) p.width = mLastWidth = mWidthMode; + invokePopup(p); } @@ -1102,20 +1103,18 @@ public class PopupWindow { return; } + TransitionManager.endTransitions(mDecorView); + registerForScrollChanged(anchor, xoff, yoff, gravity); mIsShowing = true; mIsDropdown = true; - WindowManager.LayoutParams p = createPopupLayout(anchor.getWindowToken()); + final WindowManager.LayoutParams p = createPopupLayoutParams(anchor.getWindowToken()); preparePopup(p); - updateAboveAnchor(findDropDownPosition(anchor, p, xoff, yoff, gravity)); - - if (mHeightMode < 0) p.height = mLastHeight = mHeightMode; - if (mWidthMode < 0) p.width = mLastWidth = mWidthMode; - - p.windowAnimations = computeAnimationResource(); + final boolean aboveAnchor = findDropDownPosition(anchor, p, xoff, yoff, gravity); + updateAboveAnchor(aboveAnchor); invokePopup(p); } @@ -1157,10 +1156,9 @@ public class PopupWindow { } /** - * <p>Prepare the popup by embedding in into a new ViewGroup if the - * background drawable is not null. If embedding is required, the layout - * parameters' height is modified to take into account the background's - * padding.</p> + * Prepare the popup by embedding it into a new ViewGroup if the background + * drawable is not null. If embedding is required, the layout parameters' + * height is modified to take into account the background's padding. * * @param p the layout parameters of the popup's content view */ @@ -1293,26 +1291,39 @@ public class PopupWindow { * * @return the layout parameters to pass to the window manager */ - private WindowManager.LayoutParams createPopupLayout(IBinder token) { - // generates the layout parameters for the drop down - // we want a fixed size view located at the bottom left of the anchor - WindowManager.LayoutParams p = new WindowManager.LayoutParams(); - // these gravity settings put the view at the top left corner of the - // screen. The view is then positioned to the appropriate location - // by setting the x and y offsets to match the anchor's bottom - // left corner + private WindowManager.LayoutParams createPopupLayoutParams(IBinder token) { + final WindowManager.LayoutParams p = new WindowManager.LayoutParams(); + + // These gravity settings put the view at the top left corner of the + // screen. The view is then positioned to the appropriate location by + // setting the x and y offsets to match the anchor's bottom-left + // corner. p.gravity = Gravity.START | Gravity.TOP; - p.width = mLastWidth = mWidth; - p.height = mLastHeight = mHeight; + p.flags = computeFlags(p.flags); + p.type = mWindowLayoutType; + p.token = token; + p.softInputMode = mSoftInputMode; + p.windowAnimations = computeAnimationResource(); + if (mBackground != null) { p.format = mBackground.getOpacity(); } else { p.format = PixelFormat.TRANSLUCENT; } - p.flags = computeFlags(p.flags); - p.type = mWindowLayoutType; - p.token = token; - p.softInputMode = mSoftInputMode; + + if (mHeightMode < 0) { + p.height = mLastHeight = mHeightMode; + } else { + p.height = mLastHeight = mHeight; + } + + if (mWidthMode < 0) { + p.width = mLastWidth = mWidthMode; + } else { + p.width = mLastWidth = mWidth; + } + + // Used for debugging. p.setTitle("PopupWindow:" + Integer.toHexString(hashCode())); return p; @@ -1569,30 +1580,32 @@ public class PopupWindow { * @see #showAsDropDown(android.view.View) */ public void dismiss() { - if (isShowing() && mDecorView != null) { - mIsShowing = false; + if (!isShowing()) { + return; + } - unregisterForScrollChanged(); + unregisterForScrollChanged(); - if (mExitTransition != null) { - mExitTransition.addTarget(mBackgroundView); - mExitTransition.addListener(new Transition.TransitionListenerAdapter() { - @Override - public void onTransitionEnd(Transition transition) { - transition.removeListener(this); - transition.removeTarget(mBackgroundView); + mIsShowing = false; - dismissImmediate(); - } - }); + if (mExitTransition != null) { + mExitTransition.addTarget(mBackgroundView); + mExitTransition.addListener(new Transition.TransitionListenerAdapter() { + @Override + public void onTransitionEnd(Transition transition) { + transition.removeListener(this); + transition.removeTarget(mBackgroundView); - TransitionManager.beginDelayedTransition(mDecorView, mExitTransition); + dismissImmediate(); + } + }); - // Transition to invisible. - mBackgroundView.setVisibility(View.INVISIBLE); - } else { - dismissImmediate(); - } + TransitionManager.beginDelayedTransition(mDecorView, mExitTransition); + + // Transition to invisible. + mBackgroundView.setVisibility(View.INVISIBLE); + } else { + dismissImmediate(); } } @@ -1851,15 +1864,13 @@ public class PopupWindow { } private void unregisterForScrollChanged() { - WeakReference<View> anchorRef = mAnchor; - View anchor = null; - if (anchorRef != null) { - anchor = anchorRef.get(); - } + final WeakReference<View> anchorRef = mAnchor; + final View anchor = anchorRef == null ? null : anchorRef.get(); if (anchor != null) { - ViewTreeObserver vto = anchor.getViewTreeObserver(); + final ViewTreeObserver vto = anchor.getViewTreeObserver(); vto.removeOnScrollChangedListener(mOnScrollChangedListener); } + mAnchor = null; } @@ -1867,7 +1878,8 @@ public class PopupWindow { unregisterForScrollChanged(); mAnchor = new WeakReference<>(anchor); - ViewTreeObserver vto = anchor.getViewTreeObserver(); + + final ViewTreeObserver vto = anchor.getViewTreeObserver(); if (vto != null) { vto.addOnScrollChangedListener(mOnScrollChangedListener); } diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index a32aa3ed103e..ab6dbff4e204 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -3857,7 +3857,7 @@ <!-- title for this message --> <string name="wifi_connect_alert_title">Allow connection?</string> <!-- message explaining who is connecting to what --> - <string name="wifi_connect_alert_message">%1$s would like to connect to %2$s</string> + <string name="wifi_connect_alert_message">Application %1$s would like to connect to Wifi Network %2$s</string> <!-- default application in case name can not be found --> <string name="wifi_connect_default_application">An application</string> diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml index 7804dd2422c7..18c83b4e499e 100644 --- a/core/res/res/xml/sms_short_codes.xml +++ b/core/res/res/xml/sms_short_codes.xml @@ -75,7 +75,7 @@ <shortcode country="cz" premium="9\\d{6,7}" free="116\\d{3}" /> <!-- Germany: 4-5 digits plus 1232xxx (premium codes from http://www.vodafone.de/infofaxe/537.pdf and http://premiumdienste.eplus.de/pdf/kodex.pdf), plus EU. To keep the premium regex from being too large, it only includes payment processors that have been used by SMS malware, with the regular pattern matching the other premium short codes. --> - <shortcode country="de" pattern="\\d{4,5}|1232\\d{3}" premium="11(?:111|833)|1232(?:013|021|060|075|286|358)|118(?:44|80|86)|20[25]00|220(?:21|22|88|99)|221(?:14|21)|223(?:44|53|77)|224[13]0|225(?:20|59|90)|226(?:06|10|20|26|30|40|56|70)|227(?:07|33|39|66|76|78|79|88|99)|228(?:08|11|66|77)|23300|30030|3[12347]000|330(?:33|55|66)|33(?:233|331|366|533)|34(?:34|567)|37000|40(?:040|123|444|[3568]00)|41(?:010|414)|44(?:000|044|344|44[24]|544)|50005|50100|50123|50555|51000|52(?:255|783)|54(?:100|2542)|55(?:077|[24]00|222|333|55|[12369]55)|56(?:789|886)|60800|6[13]000|66(?:[12348]66|566|766|777|88|999)|68888|70(?:07|123|777)|76766|77(?:007|070|222|444|[567]77)|80(?:008|123|888)|82(?:002|[378]00|323|444|472|474|488|727)|83(?:005|[169]00|333|830)|84(?:141|300|32[34]|343|488|499|777|888)|85888|86(?:188|566|640|644|650|677|868|888)|870[24]9|871(?:23|[49]9)|872(?:1[0-8]|49|99)|87499|875(?:49|55|99)|876(?:0[1367]|1[1245678]|54|99)|877(?:00|99)|878(?:15|25|3[567]|8[12])|87999|880(?:08|44|55|77|99)|88688|888(?:03|10|8|89)|8899|90(?:009|999)|99999" free="116\\d{3}" /> + <shortcode country="de" pattern="\\d{4,5}|1232\\d{3}" premium="11(?:111|833)|1232(?:013|021|060|075|286|358)|118(?:44|80|86)|20[25]00|220(?:21|22|88|99)|221(?:14|21)|223(?:44|53|77)|224[13]0|225(?:20|59|90)|226(?:06|10|20|26|30|40|56|70)|227(?:07|33|39|66|76|78|79|88|99)|228(?:08|11|66|77)|23300|30030|3[12347]000|330(?:33|55|66)|33(?:233|331|366|533)|34(?:34|567)|37000|40(?:040|123|444|[3568]00)|41(?:010|414)|44(?:000|044|344|44[24]|544)|50005|50100|50123|50555|51000|52(?:255|783)|54(?:100|2542)|55(?:077|[24]00|222|333|55|[12369]55)|56(?:789|886)|60800|6[13]000|66(?:[12348]66|566|766|777|88|999)|68888|70(?:07|123|777)|76766|77(?:007|070|222|444|[567]77)|80(?:008|123|888)|82(?:002|[378]00|323|444|472|474|488|727)|83(?:005|[169]00|333|830)|84(?:141|300|32[34]|343|488|499|777|888)|85888|86(?:188|566|640|644|650|677|868|888)|870[24]9|871(?:23|[49]9)|872(?:1[0-8]|49|99)|87499|875(?:49|55|99)|876(?:0[1367]|1[1245678]|54|99)|877(?:00|99)|878(?:15|25|3[567]|8[12])|87999|880(?:08|44|55|77|99)|88688|888(?:03|10|8|89)|8899|90(?:009|999)|99999" free="116\\d{3}|81214|81215" /> <!-- Denmark: see http://iprs.webspacecommerce.com/Denmark-Premium-Rate-Numbers --> <shortcode country="dk" pattern="\\d{4,5}" premium="1\\d{3}" free="116\\d{3}" /> diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp index cef2c84524e5..03b8283b80e1 100644 --- a/libs/hwui/Caches.cpp +++ b/libs/hwui/Caches.cpp @@ -72,9 +72,8 @@ bool Caches::init() { ATRACE_NAME("Caches::init"); - mRegionMesh = nullptr; - currentProgram = nullptr; + mProgram = nullptr; mFunctorsCount = 0; @@ -200,7 +199,7 @@ void Caches::terminate() { fboCache.clear(); programCache.clear(); - currentProgram = nullptr; + setProgram(nullptr); patchCache.clear(); @@ -213,6 +212,22 @@ void Caches::terminate() { mInitialized = false; } +void Caches::setProgram(const ProgramDescription& description) { + setProgram(programCache.get(description)); +} + +void Caches::setProgram(Program* program) { + if (!program || !program->isInUse()) { + if (mProgram) { + mProgram->remove(); + } + if (program) { + program->use(); + } + mProgram = program; + } +} + /////////////////////////////////////////////////////////////////////////////// // Debug /////////////////////////////////////////////////////////////////////////////// diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h index f6d347689029..16e20580cd10 100644 --- a/libs/hwui/Caches.h +++ b/libs/hwui/Caches.h @@ -162,8 +162,6 @@ public: void registerFunctors(uint32_t functorCount); void unregisterFunctors(uint32_t functorCount); - Program* currentProgram; - bool drawDeferDisabled; bool drawReorderDisabled; @@ -219,6 +217,10 @@ public: int propertyAmbientShadowStrength; int propertySpotShadowStrength; + void setProgram(const ProgramDescription& description); + void setProgram(Program* program); + + Program& program() { return *mProgram; } PixelBufferState& pixelBufferState() { return *mPixelBufferState; } TextureState& textureState() { return *mTextureState; } @@ -246,10 +248,6 @@ private: } RenderState* mRenderState; - - PixelBufferState* mPixelBufferState = nullptr; // TODO: move to RenderState - TextureState* mTextureState = nullptr; // TODO: move to RenderState - Extensions& mExtensions; // Used to render layers @@ -264,6 +262,12 @@ private: uint32_t mFunctorsCount; OverdrawColorSet mOverdrawDebugColorSet; + + // TODO: move below to RenderState + PixelBufferState* mPixelBufferState = nullptr; + TextureState* mTextureState = nullptr; + Program* mProgram = nullptr; // note: object owned by ProgramCache + }; // class Caches }; // namespace uirenderer diff --git a/libs/hwui/Dither.cpp b/libs/hwui/Dither.cpp index d637ec14d390..359c19327ad7 100644 --- a/libs/hwui/Dither.cpp +++ b/libs/hwui/Dither.cpp @@ -89,13 +89,13 @@ void Dither::clear() { // Program management /////////////////////////////////////////////////////////////////////////////// -void Dither::setupProgram(Program* program, GLuint* textureUnit) { +void Dither::setupProgram(Program& program, GLuint* textureUnit) { GLuint textureSlot = (*textureUnit)++; mCaches.textureState().activateTexture(textureSlot); bindDitherTexture(); - glUniform1i(program->getUniform("ditherSampler"), textureSlot); + glUniform1i(program.getUniform("ditherSampler"), textureSlot); } }; // namespace uirenderer diff --git a/libs/hwui/Dither.h b/libs/hwui/Dither.h index 38633af1c194..facd1ea13121 100644 --- a/libs/hwui/Dither.h +++ b/libs/hwui/Dither.h @@ -39,7 +39,7 @@ public: Dither(Caches& caches); void clear(); - void setupProgram(Program* program, GLuint* textureUnit); + void setupProgram(Program& program, GLuint* textureUnit); private: void bindDitherTexture(); diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp index 6dcd3e1433ce..55b2d196b604 100644 --- a/libs/hwui/FontRenderer.cpp +++ b/libs/hwui/FontRenderer.cpp @@ -516,9 +516,8 @@ void FontRenderer::issueDrawCommand(Vector<CacheTexture*>& cacheTextures) { TextureVertex* mesh = texture->mesh(); MeshState& meshState = renderState.meshState(); - Program* program = caches.currentProgram; - meshState.bindPositionVertexPointer(program, forceRebind, &mesh[0].x); - meshState.bindTexCoordsVertexPointer(program, forceRebind, &mesh[0].u); + meshState.bindPositionVertexPointer(forceRebind, &mesh[0].x); + meshState.bindTexCoordsVertexPointer(forceRebind, &mesh[0].u); glDrawElements(GL_TRIANGLES, texture->meshElementCount(), GL_UNSIGNED_SHORT, texture->indices()); diff --git a/libs/hwui/GammaFontRenderer.cpp b/libs/hwui/GammaFontRenderer.cpp index e97a4771ae3f..0bcd83a1a050 100644 --- a/libs/hwui/GammaFontRenderer.cpp +++ b/libs/hwui/GammaFontRenderer.cpp @@ -14,8 +14,6 @@ * limitations under the License. */ -#define LOG_TAG "OpenGLRenderer" - #include "Debug.h" #include "GammaFontRenderer.h" #include "Properties.h" @@ -96,7 +94,8 @@ GammaFontRenderer::~GammaFontRenderer() { // Shader-based renderer /////////////////////////////////////////////////////////////////////////////// -ShaderGammaFontRenderer::ShaderGammaFontRenderer(bool multiGamma): GammaFontRenderer() { +ShaderGammaFontRenderer::ShaderGammaFontRenderer(bool multiGamma) + : GammaFontRenderer() { INIT_LOGD("Creating shader gamma font renderer"); mRenderer = nullptr; mMultiGamma = multiGamma; @@ -123,9 +122,9 @@ void ShaderGammaFontRenderer::describe(ProgramDescription& description, } void ShaderGammaFontRenderer::setupProgram(ProgramDescription& description, - Program* program) const { + Program& program) const { if (description.hasGammaCorrection) { - glUniform1f(program->getUniform("gamma"), description.gamma); + glUniform1f(program.getUniform("gamma"), description.gamma); } } @@ -139,7 +138,8 @@ void ShaderGammaFontRenderer::endPrecaching() { // Lookup-based renderer /////////////////////////////////////////////////////////////////////////////// -LookupGammaFontRenderer::LookupGammaFontRenderer(): GammaFontRenderer() { +LookupGammaFontRenderer::LookupGammaFontRenderer() + : GammaFontRenderer() { INIT_LOGD("Creating lookup gamma font renderer"); // Compute the gamma tables @@ -162,7 +162,8 @@ void LookupGammaFontRenderer::endPrecaching() { // Lookup-based renderer, using 3 different correction tables /////////////////////////////////////////////////////////////////////////////// -Lookup3GammaFontRenderer::Lookup3GammaFontRenderer(): GammaFontRenderer() { +Lookup3GammaFontRenderer::Lookup3GammaFontRenderer() + : GammaFontRenderer() { INIT_LOGD("Creating lookup3 gamma font renderer"); // Compute the gamma tables diff --git a/libs/hwui/GammaFontRenderer.h b/libs/hwui/GammaFontRenderer.h index 19352d721a22..ca55bf1e74e0 100644 --- a/libs/hwui/GammaFontRenderer.h +++ b/libs/hwui/GammaFontRenderer.h @@ -38,7 +38,7 @@ public: virtual uint32_t getFontRendererSize(uint32_t fontRenderer, GLenum format) const = 0; virtual void describe(ProgramDescription& description, const SkPaint* paint) const = 0; - virtual void setupProgram(ProgramDescription& description, Program* program) const = 0; + virtual void setupProgram(ProgramDescription& description, Program& program) const = 0; virtual void endPrecaching() = 0; @@ -86,7 +86,7 @@ public: } void describe(ProgramDescription& description, const SkPaint* paint) const override; - void setupProgram(ProgramDescription& description, Program* program) const override; + void setupProgram(ProgramDescription& description, Program& program) const override; void endPrecaching() override; @@ -135,7 +135,7 @@ public: void describe(ProgramDescription& description, const SkPaint* paint) const override { } - void setupProgram(ProgramDescription& description, Program* program) const override { + void setupProgram(ProgramDescription& description, Program& program) const override { } void endPrecaching() override; @@ -171,7 +171,7 @@ public: void describe(ProgramDescription& description, const SkPaint* paint) const override { } - void setupProgram(ProgramDescription& description, Program* program) const override { + void setupProgram(ProgramDescription& description, Program& program) const override { } void endPrecaching() override; diff --git a/libs/hwui/Glop.h b/libs/hwui/Glop.h new file mode 100644 index 000000000000..730d9dfe57dd --- /dev/null +++ b/libs/hwui/Glop.h @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef ANDROID_HWUI_GLOP_H +#define ANDROID_HWUI_GLOP_H + +#include "Matrix.h" +#include "Rect.h" +#include "utils/Macros.h" + +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> + +namespace android { +namespace uirenderer { + +/* + * Enumerates optional vertex attributes + * + * Position is always enabled by MeshState, these other attributes + * are enabled/disabled dynamically based on mesh content. + */ +enum VertexAttribFlags { + // NOTE: position attribute always enabled + kTextureCoord_Attrib = 1 << 0, + kColor_Attrib = 1 << 1, + kAlpha_Attrib = 1 << 2, +}; + +/** + * Structure containing all data required to issue a single OpenGL draw + * + * Includes all of the mesh, fill, and GL state required to perform + * the operation. Pieces of data are either directly copied into the + * structure, or stored as a pointer or GL object reference to data + * managed + */ +// TODO: PREVENT_COPY_AND_ASSIGN(...) or similar +struct Glop { + Rect bounds; + + struct Mesh { + VertexAttribFlags vertexFlags = static_cast<VertexAttribFlags>(0); + GLuint primitiveMode; // GL_TRIANGLES and GL_TRIANGLE_STRIP supported + GLuint vertexBufferObject = 0; + GLuint indexBufferObject = 0; + int vertexCount; + GLsizei stride; + } mesh; + + struct Fill { + Program* program; + GLuint shaderId; + GLuint textureId; + + struct Color { + float a, r, g, b; + } color; + + /* TODO + union shader { + //... + }; TODO + union filter { + //color + //matrix + vector + }; + */ + } fill; + + struct Transform { + Matrix4 ortho; // TODO: out of op, since this is static per FBO + Matrix4 modelView; + Matrix4 canvas; + bool offset; + } transform; + + struct Blend { + static const SkXfermode::Mode kDisable = + static_cast<SkXfermode::Mode>(SkXfermode::kLastMode + 1); + SkXfermode::Mode mode; + bool swapSrcDst; + } blend; + + /** + * Additional render state to enumerate: + * - scissor + (bits for whether each of LTRB needed?) + * - stencil mode (draw into, mask, count, etc) + */ +}; + +} /* namespace uirenderer */ +} /* namespace android */ + +#endif // ANDROID_HWUI_GLOP_H diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 3ee9808bf5f1..b56ce4fda0b0 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -14,8 +14,6 @@ * limitations under the License. */ -#define LOG_TAG "OpenGLRenderer" - #include "OpenGLRenderer.h" #include "DeferredDisplayList.h" @@ -136,8 +134,6 @@ void OpenGLRenderer::initLight(const Vector3& lightCenter, float lightRadius, void OpenGLRenderer::onViewportInitialized() { glDisable(GL_DITHER); glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - - glEnableVertexAttribArray(Program::kBindingPosition); mFirstFrameAfterResize = true; } @@ -1714,20 +1710,20 @@ void OpenGLRenderer::setupDrawBlending(const SkPaint* paint, bool blend, bool sw } void OpenGLRenderer::setupDrawProgram() { - useProgram(mCaches.programCache.get(mDescription)); + mCaches.setProgram(mDescription); if (mDescription.hasRoundRectClip) { // TODO: avoid doing this repeatedly, stashing state pointer in program const RoundRectClipState* state = writableSnapshot()->roundRectClipState; const Rect& innerRect = state->innerRect; - glUniform4f(mCaches.currentProgram->getUniform("roundRectInnerRectLTRB"), + glUniform4f(mCaches.program().getUniform("roundRectInnerRectLTRB"), innerRect.left, innerRect.top, innerRect.right, innerRect.bottom); - glUniformMatrix4fv(mCaches.currentProgram->getUniform("roundRectInvTransform"), + glUniformMatrix4fv(mCaches.program().getUniform("roundRectInvTransform"), 1, GL_FALSE, &state->matrix.data[0]); // add half pixel to round out integer rect space to cover pixel centers float roundedOutRadius = state->radius + 0.5f; - glUniform1f(mCaches.currentProgram->getUniform("roundRectRadius"), + glUniform1f(mCaches.program().getUniform("roundRectRadius"), roundedOutRadius); } } @@ -1745,7 +1741,8 @@ void OpenGLRenderer::setupDrawModelView(ModelViewMode mode, bool offset, bool dirty = right - left > 0.0f && bottom - top > 0.0f; const Matrix4& transformMatrix = ignoreTransform ? Matrix4::identity() : *currentTransform(); - mCaches.currentProgram->set(writableSnapshot()->getOrthoMatrix(), + + mCaches.program().set(currentSnapshot()->getOrthoMatrix(), mModelViewMatrix, transformMatrix, offset); if (dirty && mTrackDirtyRegions) { if (!ignoreTransform) { @@ -1758,13 +1755,13 @@ void OpenGLRenderer::setupDrawModelView(ModelViewMode mode, bool offset, void OpenGLRenderer::setupDrawColorUniforms(bool hasShader) { if ((mColorSet && !hasShader) || (hasShader && mSetShaderColor)) { - mCaches.currentProgram->setColor(mColorR, mColorG, mColorB, mColorA); + mCaches.program().setColor(mColorR, mColorG, mColorB, mColorA); } } void OpenGLRenderer::setupDrawPureColorUniforms() { if (mSetShaderColor) { - mCaches.currentProgram->setColor(mColorR, mColorG, mColorB, mColorA); + mCaches.program().setColor(mColorR, mColorG, mColorB, mColorA); } } @@ -1799,7 +1796,7 @@ void OpenGLRenderer::setupDrawColorFilterUniforms(const SkColorFilter* filter) { const GLfloat r = a * SkColorGetR(color) / 255.0f; const GLfloat g = a * SkColorGetG(color) / 255.0f; const GLfloat b = a * SkColorGetB(color) / 255.0f; - glUniform4f(mCaches.currentProgram->getUniform("colorBlend"), r, g, b, a); + glUniform4f(mCaches.program().getUniform("colorBlend"), r, g, b, a); return; } @@ -1820,9 +1817,9 @@ void OpenGLRenderer::setupDrawColorFilterUniforms(const SkColorFilter* filter) { colorVector[2] = srcColorMatrix[14] / 255.0f; colorVector[3] = srcColorMatrix[19] / 255.0f; - glUniformMatrix4fv(mCaches.currentProgram->getUniform("colorMatrix"), 1, + glUniformMatrix4fv(mCaches.program().getUniform("colorMatrix"), 1, GL_FALSE, colorMatrix); - glUniform4fv(mCaches.currentProgram->getUniform("colorMatrixVector"), 1, colorVector); + glUniform4fv(mCaches.program().getUniform("colorMatrixVector"), 1, colorVector); return; } @@ -1830,12 +1827,12 @@ void OpenGLRenderer::setupDrawColorFilterUniforms(const SkColorFilter* filter) { } void OpenGLRenderer::setupDrawTextGammaUniforms() { - mCaches.fontRenderer->setupProgram(mDescription, mCaches.currentProgram); + mCaches.fontRenderer->setupProgram(mDescription, mCaches.program()); } void OpenGLRenderer::setupDrawSimpleMesh() { bool force = mRenderState.meshState().bindMeshBuffer(); - mRenderState.meshState().bindPositionVertexPointer(mCaches.currentProgram, force, nullptr); + mRenderState.meshState().bindPositionVertexPointer(force, nullptr); mRenderState.meshState().unbindIndicesBuffer(); } @@ -1856,7 +1853,7 @@ void OpenGLRenderer::setupDrawTextureTransform() { } void OpenGLRenderer::setupDrawTextureTransformUniforms(mat4& transform) { - glUniformMatrix4fv(mCaches.currentProgram->getUniform("mainTextureTransform"), 1, + glUniformMatrix4fv(mCaches.program().getUniform("mainTextureTransform"), 1, GL_FALSE, &transform.data[0]); } @@ -1869,9 +1866,9 @@ void OpenGLRenderer::setupDrawMesh(const GLvoid* vertices, force = mRenderState.meshState().unbindMeshBuffer(); } - mRenderState.meshState().bindPositionVertexPointer(mCaches.currentProgram, force, vertices); - if (mCaches.currentProgram->texCoords >= 0) { - mRenderState.meshState().bindTexCoordsVertexPointer(mCaches.currentProgram, force, texCoords); + mRenderState.meshState().bindPositionVertexPointer(force, vertices); + if (mCaches.program().texCoords >= 0) { + mRenderState.meshState().bindTexCoordsVertexPointer(force, texCoords); } mRenderState.meshState().unbindIndicesBuffer(); @@ -1882,13 +1879,11 @@ void OpenGLRenderer::setupDrawMesh(const GLvoid* vertices, bool force = mRenderState.meshState().unbindMeshBuffer(); GLsizei stride = sizeof(ColorTextureVertex); - mRenderState.meshState().bindPositionVertexPointer(mCaches.currentProgram, force, - vertices, stride); - if (mCaches.currentProgram->texCoords >= 0) { - mRenderState.meshState().bindTexCoordsVertexPointer(mCaches.currentProgram, force, - texCoords, stride); + mRenderState.meshState().bindPositionVertexPointer(force, vertices, stride); + if (mCaches.program().texCoords >= 0) { + mRenderState.meshState().bindTexCoordsVertexPointer(force, texCoords, stride); } - int slot = mCaches.currentProgram->getAttrib("colors"); + int slot = mCaches.program().getAttrib("colors"); if (slot >= 0) { glEnableVertexAttribArray(slot); glVertexAttribPointer(slot, 4, GL_FLOAT, GL_FALSE, stride, colors); @@ -1910,18 +1905,16 @@ void OpenGLRenderer::setupDrawMeshIndices(const GLvoid* vertices, } mRenderState.meshState().bindQuadIndicesBuffer(); - mRenderState.meshState().bindPositionVertexPointer(mCaches.currentProgram, force, vertices); - if (mCaches.currentProgram->texCoords >= 0) { - mRenderState.meshState().bindTexCoordsVertexPointer(mCaches.currentProgram, - force, texCoords); + mRenderState.meshState().bindPositionVertexPointer(force, vertices); + if (mCaches.program().texCoords >= 0) { + mRenderState.meshState().bindTexCoordsVertexPointer(force, texCoords); } } void OpenGLRenderer::setupDrawIndexedVertices(GLvoid* vertices) { bool force = mRenderState.meshState().unbindMeshBuffer(); mRenderState.meshState().bindQuadIndicesBuffer(); - mRenderState.meshState().bindPositionVertexPointer(mCaches.currentProgram, force, - vertices, kVertexStride); + mRenderState.meshState().bindPositionVertexPointer(force, vertices, kVertexStride); } /////////////////////////////////////////////////////////////////////////////// @@ -2143,7 +2136,7 @@ void OpenGLRenderer::drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, int m glDrawArrays(GL_TRIANGLES, 0, count); - int slot = mCaches.currentProgram->getAttrib("colors"); + int slot = mCaches.program().getAttrib("colors"); if (slot >= 0) { glDisableVertexAttribArray(slot); } @@ -2359,14 +2352,14 @@ void OpenGLRenderer::drawVertexBuffer(float translateX, float translateY, const void* vertices = vertexBuffer.getBuffer(); mRenderState.meshState().unbindMeshBuffer(); - mRenderState.meshState().bindPositionVertexPointer(mCaches.currentProgram, - true, vertices, isAA ? kAlphaVertexStride : kVertexStride); + mRenderState.meshState().bindPositionVertexPointer(true, vertices, + isAA ? kAlphaVertexStride : kVertexStride); mRenderState.meshState().resetTexCoordsVertexPointer(); int alphaSlot = -1; if (isAA) { void* alphaCoords = ((GLbyte*) vertices) + kVertexAlphaOffset; - alphaSlot = mCaches.currentProgram->getAttrib("vtxAlpha"); + alphaSlot = mCaches.program().getAttrib("vtxAlpha"); // TODO: avoid enable/disable in back to back uses of the alpha attribute glEnableVertexAttribArray(alphaSlot); glVertexAttribPointer(alphaSlot, 1, GL_FLOAT, GL_FALSE, kAlphaVertexStride, alphaCoords); @@ -3439,16 +3432,6 @@ void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode, } } -bool OpenGLRenderer::useProgram(Program* program) { - if (!program->isInUse()) { - if (mCaches.currentProgram != nullptr) mCaches.currentProgram->remove(); - program->use(); - mCaches.currentProgram = program; - return false; - } - return true; -} - void OpenGLRenderer::resetDrawTextureTexCoords(float u1, float v1, float u2, float v2) { TextureVertex* v = &mMeshVertices[0]; TextureVertex::setUV(v++, u1, v1); diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index cf6f0c845548..f0de089d0aee 100755 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -853,18 +853,6 @@ private: bool swapSrcDst = false); /** - * Use the specified program with the current GL context. If the program is already - * in use, it will not be bound again. If it is not in use, the current program is - * marked unused and the specified program becomes used and becomes the new - * current program. - * - * @param program The program to use - * - * @return true If the specified program was already in use, false otherwise. - */ - inline bool useProgram(Program* program); - - /** * Invoked before any drawing operation. This sets required state. */ void setupDraw(bool clear = true); diff --git a/libs/hwui/Program.cpp b/libs/hwui/Program.cpp index fb07dfab974a..5f34b3495681 100644 --- a/libs/hwui/Program.cpp +++ b/libs/hwui/Program.cpp @@ -46,7 +46,7 @@ Program::Program(const ProgramDescription& description, const char* vertex, cons glAttachShader(mProgramId, mVertexShader); glAttachShader(mProgramId, mFragmentShader); - position = bindAttrib("position", kBindingPosition); + bindAttrib("position", kBindingPosition); if (description.hasTexture || description.hasExternalTexture) { texCoords = bindAttrib("texCoords", kBindingTexCoords); } else { diff --git a/libs/hwui/Program.h b/libs/hwui/Program.h index d05b331909e2..b63745002158 100644 --- a/libs/hwui/Program.h +++ b/libs/hwui/Program.h @@ -366,12 +366,7 @@ public: void setColor(const float r, const float g, const float b, const float a); /** - * Name of the position attribute. - */ - int position; - - /** - * Name of the texCoords attribute if it exists, -1 otherwise. + * Name of the texCoords attribute if it exists (kBindingTexCoords), -1 otherwise. */ int texCoords; diff --git a/libs/hwui/SkiaShader.cpp b/libs/hwui/SkiaShader.cpp index e13c861aab4b..9c929daf6400 100644 --- a/libs/hwui/SkiaShader.cpp +++ b/libs/hwui/SkiaShader.cpp @@ -191,11 +191,11 @@ void SkiaLayerShader::setupProgram(Caches* caches, const mat4& modelViewMatrix, layer->setWrap(GL_CLAMP_TO_EDGE); layer->setFilter(GL_LINEAR); - Program* program = caches->currentProgram; - glUniform1i(program->getUniform("bitmapSampler"), textureSlot); - glUniformMatrix4fv(program->getUniform("textureTransform"), 1, + Program& program = caches->program(); + glUniform1i(program.getUniform("bitmapSampler"), textureSlot); + glUniformMatrix4fv(program.getUniform("textureTransform"), 1, GL_FALSE, &textureTransform.data[0]); - glUniform2f(program->getUniform("textureDimension"), 1.0f / width, 1.0f / height); + glUniform2f(program.getUniform("textureDimension"), 1.0f / width, 1.0f / height); } /////////////////////////////////////////////////////////////////////////////// @@ -277,7 +277,7 @@ void SkiaBitmapShader::setupProgram(Caches* caches, const mat4& modelViewMatrix, return; } - Program* program = caches->currentProgram; + Program& program = caches->program(); Texture* texture = shaderInfo.texture; const AutoTexture autoCleanup(texture); @@ -290,10 +290,10 @@ void SkiaBitmapShader::setupProgram(Caches* caches, const mat4& modelViewMatrix, bindTexture(caches, texture, shaderInfo.wrapS, shaderInfo.wrapT); texture->setFilter(GL_LINEAR); - glUniform1i(program->getUniform("bitmapSampler"), textureSlot); - glUniformMatrix4fv(program->getUniform("textureTransform"), 1, + glUniform1i(program.getUniform("bitmapSampler"), textureSlot); + glUniformMatrix4fv(program.getUniform("textureTransform"), 1, GL_FALSE, &textureTransform.data[0]); - glUniform2f(program->getUniform("textureDimension"), 1.0f / shaderInfo.width, + glUniform2f(program.getUniform("textureDimension"), 1.0f / shaderInfo.width, 1.0f / shaderInfo.height); } @@ -381,7 +381,7 @@ void SkiaGradientShader::setupProgram(Caches* caches, const mat4& modelViewMatri SkShader::GradientType gradType = shader.asAGradient(&gradInfo); - Program* program = caches->currentProgram; + Program& program = caches->program(); if (CC_UNLIKELY(!isSimpleGradient(gradInfo))) { if (gradInfo.fColorCount > COLOR_COUNT) { // There was not enough room in our arrays for all the colors and offsets. Try again, @@ -402,10 +402,10 @@ void SkiaGradientShader::setupProgram(Caches* caches, const mat4& modelViewMatri // Uniforms bindTexture(caches, texture, gTileModes[gradInfo.fTileMode], gTileModes[gradInfo.fTileMode]); - glUniform1i(program->getUniform("gradientSampler"), textureSlot); + glUniform1i(program.getUniform("gradientSampler"), textureSlot); } else { - bindUniformColor(program->getUniform("startColor"), gradInfo.fColors[0]); - bindUniformColor(program->getUniform("endColor"), gradInfo.fColors[1]); + bindUniformColor(program.getUniform("startColor"), gradInfo.fColors[0]); + bindUniformColor(program.getUniform("endColor"), gradInfo.fColors[1]); } caches->dither.setupProgram(program, textureUnit); @@ -428,7 +428,7 @@ void SkiaGradientShader::setupProgram(Caches* caches, const mat4& modelViewMatri mat4 screenSpace; computeScreenSpaceMatrix(screenSpace, unitMatrix, shader.getLocalMatrix(), modelViewMatrix); - glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]); + glUniformMatrix4fv(program.getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]); } /////////////////////////////////////////////////////////////////////////////// diff --git a/libs/hwui/renderstate/MeshState.cpp b/libs/hwui/renderstate/MeshState.cpp index 7820a66e0c67..022faf7dcafc 100644 --- a/libs/hwui/renderstate/MeshState.cpp +++ b/libs/hwui/renderstate/MeshState.cpp @@ -39,6 +39,9 @@ MeshState::MeshState() mQuadListIndices = 0; mShadowStripsIndices = 0; + + // position attribute always enabled + glEnableVertexAttribArray(Program::kBindingPosition); } MeshState::~MeshState() { @@ -83,21 +86,17 @@ bool MeshState::unbindMeshBuffer() { // Vertices /////////////////////////////////////////////////////////////////////////////// -void MeshState::bindPositionVertexPointer(const Program* currentProgram, bool force, - const GLvoid* vertices, GLsizei stride) { +void MeshState::bindPositionVertexPointer(bool force, const GLvoid* vertices, GLsizei stride) { if (force || vertices != mCurrentPositionPointer || stride != mCurrentPositionStride) { - GLuint slot = currentProgram->position; - glVertexAttribPointer(slot, 2, GL_FLOAT, GL_FALSE, stride, vertices); + glVertexAttribPointer(Program::kBindingPosition, 2, GL_FLOAT, GL_FALSE, stride, vertices); mCurrentPositionPointer = vertices; mCurrentPositionStride = stride; } } -void MeshState::bindTexCoordsVertexPointer(const Program* currentProgram, bool force, - const GLvoid* vertices, GLsizei stride) { +void MeshState::bindTexCoordsVertexPointer(bool force, const GLvoid* vertices, GLsizei stride) { if (force || vertices != mCurrentTexCoordsPointer || stride != mCurrentTexCoordsStride) { - GLuint slot = currentProgram->texCoords; - glVertexAttribPointer(slot, 2, GL_FLOAT, GL_FALSE, stride, vertices); + glVertexAttribPointer(Program::kBindingTexCoords, 2, GL_FLOAT, GL_FALSE, stride, vertices); mCurrentTexCoordsPointer = vertices; mCurrentTexCoordsStride = stride; } diff --git a/libs/hwui/renderstate/MeshState.h b/libs/hwui/renderstate/MeshState.h index 76f73d4f8278..9b1021dc8830 100644 --- a/libs/hwui/renderstate/MeshState.h +++ b/libs/hwui/renderstate/MeshState.h @@ -80,15 +80,15 @@ public: * Binds an attrib to the specified float vertex pointer. * Assumes a stride of gTextureVertexStride and a size of 2. */ - void bindPositionVertexPointer(const Program* currentProgram, bool force, - const GLvoid* vertices, GLsizei stride = kTextureVertexStride); + void bindPositionVertexPointer(bool force, const GLvoid* vertices, + GLsizei stride = kTextureVertexStride); /** * Binds an attrib to the specified float vertex pointer. * Assumes a stride of gTextureVertexStride and a size of 2. */ - void bindTexCoordsVertexPointer(const Program* currentProgram, bool force, - const GLvoid* vertices, GLsizei stride = kTextureVertexStride); + void bindTexCoordsVertexPointer(bool force, const GLvoid* vertices, + GLsizei stride = kTextureVertexStride); /** * Resets the vertex pointers. diff --git a/libs/hwui/renderstate/RenderState.cpp b/libs/hwui/renderstate/RenderState.cpp index 58ec321fd7f3..5e028447bf11 100644 --- a/libs/hwui/renderstate/RenderState.cpp +++ b/libs/hwui/renderstate/RenderState.cpp @@ -129,12 +129,7 @@ void RenderState::invokeFunctor(Functor* functor, DrawGlInfo::Mode mode, DrawGlI } void RenderState::interruptForFunctorInvoke() { - if (mCaches->currentProgram) { - if (mCaches->currentProgram->isInUse()) { - mCaches->currentProgram->remove(); - mCaches->currentProgram = nullptr; - } - } + mCaches->setProgram(nullptr); mCaches->textureState().resetActiveTexture(); meshState().unbindMeshBuffer(); meshState().unbindIndicesBuffer(); @@ -181,7 +176,6 @@ void RenderState::assertOnGLThread() { LOG_ALWAYS_FATAL_IF(!pthread_equal(mThreadId, curr), "Wrong thread!"); } - class DecStrongTask : public renderthread::RenderTask { public: DecStrongTask(VirtualLightRefBase* object) : mObject(object) {} @@ -200,5 +194,82 @@ void RenderState::postDecStrong(VirtualLightRefBase* object) { mRenderThread.queue(new DecStrongTask(object)); } +/////////////////////////////////////////////////////////////////////////////// +// Render +/////////////////////////////////////////////////////////////////////////////// + +/* + * Not yet supported: + * + * Textures + coordinates + * SkiaShader + * ColorFilter + * + // TODO: texture coord + // TODO: texture support + // TODO: skiashader support + // TODO: color filter support + */ + +void RenderState::render(const Glop& glop) { + const Glop::Mesh& mesh = glop.mesh; + const Glop::Fill& shader = glop.fill; + + // ---------- Shader + uniform setup ---------- + mCaches->setProgram(shader.program); + + Glop::Fill::Color color = shader.color; + shader.program->setColor(color.a, color.r, color.g, color.b); + + shader.program->set(glop.transform.ortho, + glop.transform.modelView, + glop.transform.canvas, + glop.transform.offset); + + // ---------- Mesh setup ---------- + if (glop.mesh.vertexFlags & kTextureCoord_Attrib) { + // TODO: support textures + LOG_ALWAYS_FATAL("textures not yet supported"); + } else { + meshState().disableTexCoordsVertexArray(); + } + if (glop.mesh.vertexFlags & kColor_Attrib) { + LOG_ALWAYS_FATAL("color attribute not yet supported"); + // TODO: enable color, disable when done + } + if (glop.mesh.vertexFlags & kAlpha_Attrib) { + LOG_ALWAYS_FATAL("alpha attribute not yet supported"); + // TODO: enable alpha attribute, disable when done + } + + /** + * Hard-coded vertex assumptions: + * - required + * - xy floats + * - 0 offset + * - in VBO + */ + bool force = meshState().bindMeshBuffer(mesh.vertexBufferObject); + meshState().bindPositionVertexPointer(force, nullptr, mesh.stride); + + /** + * Hard-coded index assumptions: + * - optional + * - 0 offset + * - in IBO + */ + meshState().bindIndicesBufferInternal(mesh.indexBufferObject); + + // ---------- GL state setup ---------- + + if (glop.blend.mode != Glop::Blend::kDisable) { + blend().enable(glop.blend.mode, glop.blend.swapSrcDst); + } else { + blend().disable(); + } + + glDrawElements(glop.mesh.primitiveMode, glop.mesh.vertexCount, GL_UNSIGNED_BYTE, nullptr); +} + } /* namespace uirenderer */ } /* namespace android */ diff --git a/libs/hwui/renderstate/RenderState.h b/libs/hwui/renderstate/RenderState.h index 4180f44ed477..2e28ff6cd4d9 100644 --- a/libs/hwui/renderstate/RenderState.h +++ b/libs/hwui/renderstate/RenderState.h @@ -22,11 +22,12 @@ #include <utils/Mutex.h> #include <utils/Functor.h> #include <utils/RefBase.h> - #include <private/hwui/DrawGlInfo.h> #include <renderstate/Blend.h> + #include "AssetAtlas.h" #include "Caches.h" +#include "Glop.h" #include "renderstate/MeshState.h" #include "renderstate/PixelBufferState.h" #include "renderstate/Scissor.h" @@ -83,6 +84,8 @@ public: // more thinking... void postDecStrong(VirtualLightRefBase* object); + void render(const Glop& glop); + AssetAtlas& assetAtlas() { return mAssetAtlas; } Blend& blend() { return *mBlend; } MeshState& meshState() { return *mMeshState; } @@ -96,6 +99,9 @@ private: void resumeFromFunctorInvoke(); void assertOnGLThread(); + void setupVertexAttributes(const Glop& glop); + void tearDownVertexAttributes(const Glop& glop); + RenderState(renderthread::RenderThread& thread); ~RenderState(); diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java index 6f322b639f01..b2e47287d9b6 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java @@ -87,7 +87,9 @@ public abstract class KeyguardAbsKeyInputView extends LinearLayout mEcaView = findViewById(R.id.keyguard_selector_fade_container); EmergencyButton button = (EmergencyButton) findViewById(R.id.emergency_call_button); - button.setCallback(this); + if (button != null) { + button.setCallback(this); + } } public void onEmergencyButtonClickedWhenInCall() { diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java index 053b3097e2cd..9aa572969978 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java @@ -143,7 +143,9 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit mHelpMessage = (KeyguardMessageArea) findViewById(R.id.keyguard_message_area); EmergencyButton button = (EmergencyButton) findViewById(R.id.emergency_call_button); - button.setCallback(this); + if (button != null) { + button.setCallback(this); + } } public void onEmergencyButtonClickedWhenInCall() { diff --git a/rs/java/android/renderscript/RenderScript.java b/rs/java/android/renderscript/RenderScript.java index 271fe05ed3aa..f37519ec7d51 100644 --- a/rs/java/android/renderscript/RenderScript.java +++ b/rs/java/android/renderscript/RenderScript.java @@ -330,10 +330,10 @@ public class RenderScript { rsnClosureSetGlobal(mContext, closureID, fieldID, value, size); } - native long rsnScriptGroup2Create(long con, long[] closures); - synchronized long nScriptGroup2Create(long[] closures) { + native long rsnScriptGroup2Create(long con, String cachePath, long[] closures); + synchronized long nScriptGroup2Create(String cachePath, long[] closures) { validate(); - return rsnScriptGroup2Create(mContext, closures); + return rsnScriptGroup2Create(mContext, cachePath, closures); } native void rsnScriptGroup2Execute(long con, long groupID); diff --git a/rs/java/android/renderscript/ScriptGroup2.java b/rs/java/android/renderscript/ScriptGroup2.java index dcad7873c2cd..366039e3342a 100644 --- a/rs/java/android/renderscript/ScriptGroup2.java +++ b/rs/java/android/renderscript/ScriptGroup2.java @@ -8,9 +8,6 @@ import java.util.List; import java.util.Map; /** - @hide Pending Android public API approval. - */ -/** ****************************** You have tried to change the API from what has been previously approved. @@ -240,12 +237,10 @@ public class ScriptGroup2 extends BaseObj { for (int i = 0; i < closureIDs.length; i++) { closureIDs[i] = closures.get(i).getID(rs); } - long id = rs.nScriptGroup2Create(closureIDs); + long id = rs.nScriptGroup2Create(ScriptC.mCachePath, closureIDs); setID(id); } - // TODO: If this was reflected method, we could enforce the number of - // arguments. public Object[] execute(Object... inputs) { if (inputs.length < mInputs.size()) { Log.e(TAG, this.toString() + " receives " + inputs.length + " inputs, " + @@ -309,8 +304,6 @@ public class ScriptGroup2 extends BaseObj { } public ScriptGroup2 create(Future... outputs) { - // TODO: Save all script groups that have been created and return one that was - // saved and matches the outputs. ScriptGroup2 ret = new ScriptGroup2(mRS, mClosures, mInputs, outputs); return ret; } diff --git a/rs/jni/android_renderscript_RenderScript.cpp b/rs/jni/android_renderscript_RenderScript.cpp index 06f4defd2ad9..cbcba398073c 100644 --- a/rs/jni/android_renderscript_RenderScript.cpp +++ b/rs/jni/android_renderscript_RenderScript.cpp @@ -258,7 +258,9 @@ nClosureSetGlobal(JNIEnv *_env, jobject _this, jlong con, jlong closureID, static long nScriptGroup2Create(JNIEnv *_env, jobject _this, jlong con, - jlongArray closureArray) { + jstring cacheDir, jlongArray closureArray) { + AutoJavaStringToUTF8 cacheDirUTF(_env, cacheDir); + jlong* jClosures = _env->GetLongArrayElements(closureArray, nullptr); jsize numClosures = _env->GetArrayLength(closureArray); RsClosure* closures = (RsClosure*)alloca(sizeof(RsClosure) * numClosures); @@ -266,8 +268,9 @@ nScriptGroup2Create(JNIEnv *_env, jobject _this, jlong con, closures[i] = (RsClosure)jClosures[i]; } - return (jlong)(uintptr_t)rsScriptGroup2Create((RsContext)con, closures, - numClosures); + return (jlong)(uintptr_t)rsScriptGroup2Create( + (RsContext)con, cacheDirUTF.c_str(), cacheDirUTF.length(), + closures, numClosures); } static void @@ -2008,7 +2011,7 @@ static JNINativeMethod methods[] = { {"rsnScriptKernelIDCreate", "(JJII)J", (void*)nScriptKernelIDCreate }, {"rsnScriptFieldIDCreate", "(JJI)J", (void*)nScriptFieldIDCreate }, {"rsnScriptGroupCreate", "(J[J[J[J[J[J)J", (void*)nScriptGroupCreate }, -{"rsnScriptGroup2Create", "(J[J)J", (void*)nScriptGroup2Create }, +{"rsnScriptGroup2Create", "(JLjava/lang/String;[J)J", (void*)nScriptGroup2Create }, {"rsnScriptGroupSetInput", "(JJJJ)V", (void*)nScriptGroupSetInput }, {"rsnScriptGroupSetOutput", "(JJJJ)V", (void*)nScriptGroupSetOutput }, {"rsnScriptGroupExecute", "(JJ)V", (void*)nScriptGroupExecute }, diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index 8c314cfc2a58..a712d789946c 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -170,6 +170,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { private final Rect mTempRect = new Rect(); + private final Rect mTempRect1 = new Rect(); + private final Point mTempPoint = new Point(); private final PackageManager mPackageManager; @@ -2535,57 +2537,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } @Override - public boolean computeClickPointInScreen(int accessibilityWindowId, - long accessibilityNodeId, int interactionId, - IAccessibilityInteractionConnectionCallback callback, long interrogatingTid) - throws RemoteException { - final int resolvedWindowId; - IAccessibilityInteractionConnection connection = null; - Region partialInteractiveRegion = mTempRegion; - synchronized (mLock) { - // We treat calls from a profile as if made by its parent as profiles - // share the accessibility state of the parent. The call below - // performs the current profile parent resolution. - final int resolvedUserId = mSecurityPolicy - .resolveCallingUserIdEnforcingPermissionsLocked( - UserHandle.USER_CURRENT); - if (resolvedUserId != mCurrentUserId) { - return false; - } - resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId); - final boolean permissionGranted = - mSecurityPolicy.canRetrieveWindowContentLocked(this); - if (!permissionGranted) { - return false; - } else { - connection = getConnectionLocked(resolvedWindowId); - if (connection == null) { - return false; - } - } - if (!mSecurityPolicy.computePartialInteractiveRegionForWindowLocked( - resolvedWindowId, partialInteractiveRegion)) { - partialInteractiveRegion = null; - } - } - final int interrogatingPid = Binder.getCallingPid(); - final long identityToken = Binder.clearCallingIdentity(); - MagnificationSpec spec = getCompatibleMagnificationSpecLocked(resolvedWindowId); - try { - connection.computeClickPointInScreen(accessibilityNodeId, partialInteractiveRegion, - interactionId, callback, interrogatingPid, interrogatingTid, spec); - return true; - } catch (RemoteException re) { - if (DEBUG) { - Slog.e(LOG_TAG, "Error computeClickPointInScreen()."); - } - } finally { - Binder.restoreCallingIdentity(identityToken); - } - return false; - } - - @Override public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) { mSecurityPolicy.enforceCallingPermission(Manifest.permission.DUMP, FUNCTION_DUMP); synchronized (mLock) { @@ -3238,38 +3189,36 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } synchronized (mLock) { - Point point = mClient.computeClickPointInScreen(mConnectionId, - focus.getWindowId(), focus.getSourceNodeId()); + Rect boundsInScreen = mTempRect; + focus.getBoundsInScreen(boundsInScreen); - if (point == null) { + // Clip to the window bounds. + Rect windowBounds = mTempRect1; + getWindowBounds(focus.getWindowId(), windowBounds); + boundsInScreen.intersect(windowBounds); + if (boundsInScreen.isEmpty()) { return false; } + // Apply magnification if needed. MagnificationSpec spec = getCompatibleMagnificationSpecLocked(focus.getWindowId()); if (spec != null && !spec.isNop()) { - point.offset((int) -spec.offsetX, (int) -spec.offsetY); - point.x = (int) (point.x * (1 / spec.scale)); - point.y = (int) (point.y * (1 / spec.scale)); + boundsInScreen.offset((int) -spec.offsetX, (int) -spec.offsetY); + boundsInScreen.scale(1 / spec.scale); } - // Make sure the point is within the window. - Rect windowBounds = mTempRect; - getWindowBounds(focus.getWindowId(), windowBounds); - if (!windowBounds.contains(point.x, point.y)) { - return false; - } - - // Make sure the point is within the screen. + // Clip to the screen bounds. Point screenSize = mTempPoint; mDefaultDisplay.getRealSize(screenSize); - if (point.x < 0 || point.x > screenSize.x - || point.y < 0 || point.y > screenSize.y) { + boundsInScreen.intersect(0, 0, screenSize.x, screenSize.y); + if (boundsInScreen.isEmpty()) { return false; } - outPoint.set(point.x, point.y); - return true; + outPoint.set(boundsInScreen.centerX(), boundsInScreen.centerY()); } + + return true; } private AccessibilityNodeInfo getAccessibilityFocusNotLocked() { diff --git a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java index b9ed89b27c10..f18b5ef338aa 100644 --- a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java +++ b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java @@ -77,6 +77,10 @@ class TouchExplorer implements EventStreamTransformation { private static final int STATE_DELEGATING = 0x00000004; private static final int STATE_GESTURE_DETECTING = 0x00000005; + private static final int CLICK_LOCATION_NONE = 0; + private static final int CLICK_LOCATION_ACCESSIBILITY_FOCUS = 1; + private static final int CLICK_LOCATION_LAST_TOUCH_EXPLORED = 2; + // The maximum of the cosine between the vectors of two moving // pointers so they can be considered moving in the same direction. private static final float MAX_DRAGGING_ANGLE_COS = 0.525321989f; // cos(pi/4) @@ -942,12 +946,16 @@ class TouchExplorer implements EventStreamTransformation { * * @param prototype The prototype from which to create the injected events. * @param policyFlags The policy flags associated with the event. + * @param targetAccessibilityFocus Whether the event targets the accessibility focus. */ - private void sendActionDownAndUp(MotionEvent prototype, int policyFlags) { + private void sendActionDownAndUp(MotionEvent prototype, int policyFlags, + boolean targetAccessibilityFocus) { // Tap with the pointer that last explored. final int pointerId = prototype.getPointerId(prototype.getActionIndex()); final int pointerIdBits = (1 << pointerId); + prototype.setTargetAccessibilityFocus(targetAccessibilityFocus); sendMotionEvent(prototype, MotionEvent.ACTION_DOWN, pointerIdBits, policyFlags); + prototype.setTargetAccessibilityFocus(targetAccessibilityFocus); sendMotionEvent(prototype, MotionEvent.ACTION_UP, pointerIdBits, policyFlags); } @@ -1155,7 +1163,8 @@ class TouchExplorer implements EventStreamTransformation { final int pointerIndex = secondTapUp.findPointerIndex(pointerId); Point clickLocation = mTempPoint; - if (!computeClickLocation(clickLocation)) { + final int result = computeClickLocation(clickLocation); + if (result == CLICK_LOCATION_NONE) { return; } @@ -1171,7 +1180,8 @@ class TouchExplorer implements EventStreamTransformation { secondTapUp.getEventTime(), MotionEvent.ACTION_DOWN, 1, properties, coords, 0, 0, 1.0f, 1.0f, secondTapUp.getDeviceId(), 0, secondTapUp.getSource(), secondTapUp.getFlags()); - sendActionDownAndUp(event, policyFlags); + final boolean targetAccessibilityFocus = (result == CLICK_LOCATION_ACCESSIBILITY_FOCUS); + sendActionDownAndUp(event, policyFlags, targetAccessibilityFocus); event.recycle(); } @@ -1216,7 +1226,7 @@ class TouchExplorer implements EventStreamTransformation { MAX_DRAGGING_ANGLE_COS); } - private boolean computeClickLocation(Point outLocation) { + private int computeClickLocation(Point outLocation) { MotionEvent lastExploreEvent = mInjectedPointerTracker.getLastInjectedHoverEventForClick(); if (lastExploreEvent != null) { final int lastExplorePointerIndex = lastExploreEvent.getActionIndex(); @@ -1224,14 +1234,17 @@ class TouchExplorer implements EventStreamTransformation { outLocation.y = (int) lastExploreEvent.getY(lastExplorePointerIndex); if (!mAms.accessibilityFocusOnlyInActiveWindow() || mLastTouchedWindowId == mAms.getActiveWindowId()) { - mAms.getAccessibilityFocusClickPointInScreen(outLocation); + if (mAms.getAccessibilityFocusClickPointInScreen(outLocation)) { + return CLICK_LOCATION_ACCESSIBILITY_FOCUS; + } else { + return CLICK_LOCATION_LAST_TOUCH_EXPLORED; + } } - return true; } if (mAms.getAccessibilityFocusClickPointInScreen(outLocation)) { - return true; + return CLICK_LOCATION_ACCESSIBILITY_FOCUS; } - return false; + return CLICK_LOCATION_NONE; } /** @@ -1310,14 +1323,13 @@ class TouchExplorer implements EventStreamTransformation { return; } - int clickLocationX; - int clickLocationY; - final int pointerId = mEvent.getPointerId(mEvent.getActionIndex()); final int pointerIndex = mEvent.findPointerIndex(pointerId); Point clickLocation = mTempPoint; - if (!computeClickLocation(clickLocation)) { + final int result = computeClickLocation(clickLocation); + + if (result == CLICK_LOCATION_NONE) { return; } diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java index 0500f94beabc..4f6b8f246e2b 100644 --- a/services/core/java/com/android/server/media/MediaSessionService.java +++ b/services/core/java/com/android/server/media/MediaSessionService.java @@ -823,7 +823,7 @@ public class MediaSessionService extends SystemService implements Monitor { pw.println("User Records:"); count = mUserRecords.size(); for (int i = 0; i < count; i++) { - UserRecord user = mUserRecords.get(i); + UserRecord user = mUserRecords.get(mUserRecords.keyAt(i)); user.dumpLocked(pw, ""); } } |