1 /*
2  * Copyright 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package androidx.core.view.accessibility;
17 
18 import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX;
19 
20 import android.os.Bundle;
21 import android.text.style.ClickableSpan;
22 import android.view.View;
23 
24 import androidx.annotation.RestrictTo;
25 
26 import org.jspecify.annotations.NonNull;
27 
28 /**
29  * {@link ClickableSpan} cannot be parceled, but accessibility services need to be able to cause
30  * their callback handlers to be called. This class serves as a placeholder for the
31  * real spans. Calling onClick on these from an accessibility service will result in onClick being
32  * called on the represented span in the app process.
33  */
34 public final class AccessibilityClickableSpanCompat extends ClickableSpan {
35 
36     // The id of the span this one replaces
37     private final int mOriginalClickableSpanId;
38 
39     private final AccessibilityNodeInfoCompat mNodeInfoCompat;
40 
41     private final int mClickableSpanActionId;
42 
43     /**
44      */
45     @RestrictTo(LIBRARY_GROUP_PREFIX)
46     public static final String SPAN_ID = "ACCESSIBILITY_CLICKABLE_SPAN_ID";
47 
48     /**
49      * @param originalClickableSpanId The id of the span this one replaces
50      * @param nodeInfoCompat The nodeInfoCompat to be associated with this span.
51      */
52     @RestrictTo(LIBRARY_GROUP_PREFIX)
AccessibilityClickableSpanCompat(int originalClickableSpanId, @NonNull AccessibilityNodeInfoCompat nodeInfoCompat, int clickableSpanActionId)53     public AccessibilityClickableSpanCompat(int originalClickableSpanId,
54             @NonNull AccessibilityNodeInfoCompat nodeInfoCompat, int clickableSpanActionId) {
55         mOriginalClickableSpanId = originalClickableSpanId;
56         mNodeInfoCompat = nodeInfoCompat;
57         mClickableSpanActionId = clickableSpanActionId;
58     }
59 
60     /**
61      * Perform the click from an accessibility service.
62      *
63      * @param unused This argument is required by the superclass but is unused. The real view will
64      * be determined by the AccessibilityNodeInfo.
65      */
66     @Override
onClick(@onNull View unused)67     public void onClick(@NonNull View unused) {
68         Bundle arguments = new Bundle();
69         arguments.putInt(SPAN_ID, mOriginalClickableSpanId);
70         mNodeInfoCompat.performAction(mClickableSpanActionId, arguments);
71     }
72 }
73