1193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver/* 2193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver * Copyright (C) 2016 The Android Open Source Project 3193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver * 4193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver * Licensed under the Apache License, Version 2.0 (the "License"); 5193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver * you may not use this file except in compliance with the License. 6193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver * You may obtain a copy of the License at 7193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver * 8193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver * http://www.apache.org/licenses/LICENSE-2.0 9193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver * 10193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver * Unless required by applicable law or agreed to in writing, software 11193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver * distributed under the License is distributed on an "AS IS" BASIS, 12193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver * See the License for the specific language governing permissions and 14193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver * limitations under the License. 15193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver */ 16193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaverpackage android.text.style; 17193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver 18193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaverimport static android.view.accessibility.AccessibilityNodeInfo.ACTION_ARGUMENT_ACCESSIBLE_CLICKABLE_SPAN; 1923161e7170ec2493ec830d04205f5696be159026Phil Weaverimport static android.view.accessibility.AccessibilityNodeInfo.UNDEFINED_CONNECTION_ID; 2023161e7170ec2493ec830d04205f5696be159026Phil Weaverimport static android.view.accessibility.AccessibilityNodeInfo.UNDEFINED_NODE_ID; 2123161e7170ec2493ec830d04205f5696be159026Phil Weaverimport static android.view.accessibility.AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 22193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver 23193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaverimport android.os.Bundle; 24193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaverimport android.os.Parcel; 25193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaverimport android.os.Parcelable; 26193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaverimport android.text.ParcelableSpan; 27193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaverimport android.text.Spanned; 28193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaverimport android.text.TextUtils; 29193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaverimport android.view.View; 3023161e7170ec2493ec830d04205f5696be159026Phil Weaverimport android.view.accessibility.AccessibilityInteractionClient; 31193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaverimport android.view.accessibility.AccessibilityNodeInfo; 32193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver 33193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaverimport com.android.internal.R; 34193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver 35193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver/** 36193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver * {@link ClickableSpan} cannot be parceled, but accessibility services need to be able to cause 37193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver * their callback handlers to be called. This class serves as a parcelable placeholder for the 38193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver * real spans. 39193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver * 40193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver * This span is also passed back to an app's process when an accessibility service tries to click 41193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver * it. It contains enough information to track down the original clickable span so it can be 42193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver * called. 43193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver * 44193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver * @hide 45193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver */ 46193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaverpublic class AccessibilityClickableSpan extends ClickableSpan 47193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver implements ParcelableSpan { 48193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver // The id of the span this one replaces 49193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver private final int mOriginalClickableSpanId; 50193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver 5123161e7170ec2493ec830d04205f5696be159026Phil Weaver private int mWindowId = UNDEFINED_WINDOW_ID; 5223161e7170ec2493ec830d04205f5696be159026Phil Weaver private long mSourceNodeId = UNDEFINED_NODE_ID; 5323161e7170ec2493ec830d04205f5696be159026Phil Weaver private int mConnectionId = UNDEFINED_CONNECTION_ID; 54193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver 55193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver /** 56193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver * @param originalClickableSpanId The id of the span this one replaces 57193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver */ 58193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver public AccessibilityClickableSpan(int originalClickableSpanId) { 59193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver mOriginalClickableSpanId = originalClickableSpanId; 60193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver } 61193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver 62193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver public AccessibilityClickableSpan(Parcel p) { 63193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver mOriginalClickableSpanId = p.readInt(); 64193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver } 65193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver 66193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver @Override 67193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver public int getSpanTypeId() { 68193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver return getSpanTypeIdInternal(); 69193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver } 70193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver 71193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver @Override 72193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver public int getSpanTypeIdInternal() { 73193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver return TextUtils.ACCESSIBILITY_CLICKABLE_SPAN; 74193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver } 75193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver 76193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver @Override 77193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver public int describeContents() { 78193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver return 0; 79193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver } 80193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver 81193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver @Override 82193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver public void writeToParcel(Parcel dest, int flags) { 83193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver writeToParcelInternal(dest, flags); 84193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver } 85193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver 86193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver @Override 87193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver public void writeToParcelInternal(Parcel dest, int flags) { 88193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver dest.writeInt(mOriginalClickableSpanId); 89193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver } 90193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver 91193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver /** 92193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver * Find the ClickableSpan that matches the one used to create this object. 93193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver * 94193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver * @param text The text that contains the original ClickableSpan. 95193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver * @return The ClickableSpan that matches this object, or {@code null} if no such object 96193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver * can be found. 97193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver */ 98193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver public ClickableSpan findClickableSpan(CharSequence text) { 99193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver if (!(text instanceof Spanned)) { 100193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver return null; 101193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver } 102193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver Spanned sp = (Spanned) text; 103193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver ClickableSpan[] os = sp.getSpans(0, text.length(), ClickableSpan.class); 104193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver for (int i = 0; i < os.length; i++) { 105193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver if (os[i].getId() == mOriginalClickableSpanId) { 106193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver return os[i]; 107193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver } 108193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver } 109193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver return null; 110193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver } 111193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver 112193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver /** 11323161e7170ec2493ec830d04205f5696be159026Phil Weaver * Configure this object to perform clicks on the view that contains the original span. 114193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver * 11523161e7170ec2493ec830d04205f5696be159026Phil Weaver * @param accessibilityNodeInfo The info corresponding to the view containing the original 11623161e7170ec2493ec830d04205f5696be159026Phil Weaver * span. 117193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver */ 11823161e7170ec2493ec830d04205f5696be159026Phil Weaver public void copyConnectionDataFrom(AccessibilityNodeInfo accessibilityNodeInfo) { 11923161e7170ec2493ec830d04205f5696be159026Phil Weaver mConnectionId = accessibilityNodeInfo.getConnectionId(); 12023161e7170ec2493ec830d04205f5696be159026Phil Weaver mWindowId = accessibilityNodeInfo.getWindowId(); 12123161e7170ec2493ec830d04205f5696be159026Phil Weaver mSourceNodeId = accessibilityNodeInfo.getSourceNodeId(); 122193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver } 123193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver 124193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver /** 125193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver * Perform the click from an accessibility service. Will not work unless 126193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver * setAccessibilityNodeInfo is called with a properly initialized node. 127193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver * 128193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver * @param unused This argument is required by the superclass but is unused. The real view will 129193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver * be determined by the AccessibilityNodeInfo. 130193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver */ 131193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver @Override 132193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver public void onClick(View unused) { 133193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver Bundle arguments = new Bundle(); 134193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver arguments.putParcelable(ACTION_ARGUMENT_ACCESSIBLE_CLICKABLE_SPAN, this); 135193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver 13623161e7170ec2493ec830d04205f5696be159026Phil Weaver if ((mWindowId == UNDEFINED_WINDOW_ID) || (mSourceNodeId == UNDEFINED_NODE_ID) 13723161e7170ec2493ec830d04205f5696be159026Phil Weaver || (mConnectionId == UNDEFINED_CONNECTION_ID)) { 13823161e7170ec2493ec830d04205f5696be159026Phil Weaver throw new RuntimeException( 13923161e7170ec2493ec830d04205f5696be159026Phil Weaver "ClickableSpan for accessibility service not properly initialized"); 14023161e7170ec2493ec830d04205f5696be159026Phil Weaver } 14123161e7170ec2493ec830d04205f5696be159026Phil Weaver 14223161e7170ec2493ec830d04205f5696be159026Phil Weaver AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance(); 14323161e7170ec2493ec830d04205f5696be159026Phil Weaver client.performAccessibilityAction(mConnectionId, mWindowId, mSourceNodeId, 14423161e7170ec2493ec830d04205f5696be159026Phil Weaver R.id.accessibilityActionClickOnClickableSpan, arguments); 145193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver } 146193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver 147193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver public static final Parcelable.Creator<AccessibilityClickableSpan> CREATOR = 148193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver new Parcelable.Creator<AccessibilityClickableSpan>() { 149193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver @Override 150193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver public AccessibilityClickableSpan createFromParcel(Parcel parcel) { 151193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver return new AccessibilityClickableSpan(parcel); 152193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver } 153193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver 154193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver @Override 155193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver public AccessibilityClickableSpan[] newArray(int size) { 156193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver return new AccessibilityClickableSpan[size]; 157193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver } 158193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver }; 159193520e3dff5248ddcf8435203bf99d2ba667219Phil Weaver} 160