1 /*
2  * Copyright (C) 2017 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 
17 package com.android.tv.settings.accessibility;
18 
19 import android.content.ComponentName;
20 import android.content.Context;
21 import android.os.Bundle;
22 
23 import androidx.annotation.NonNull;
24 import androidx.fragment.app.Fragment;
25 import androidx.leanback.app.GuidedStepSupportFragment;
26 import androidx.leanback.widget.GuidanceStylist;
27 import androidx.leanback.widget.GuidedAction;
28 
29 import com.android.tv.settings.R;
30 
31 import java.util.List;
32 
33 /**
34  * Fragment for confirming [de]activation of accessibility service
35  */
36 public class AccessibilityServiceConfirmationFragment extends GuidedStepSupportFragment {
37     private static final String ARG_LABEL = "label";
38     private static final String ARG_COMPONENT = "component";
39     private static final String ARG_ENABLING = "enabling";
40 
41     /**
42      * Callback for dialog completion
43      */
44     public interface OnAccessibilityServiceConfirmedListener {
45         /**
46          * Called when enabling/disabling was confirmed by the user, not called otherwise.
47          * @param componentName Service in question
48          * @param enabling True for enabling
49          */
onAccessibilityServiceConfirmed(ComponentName componentName, boolean enabling)50         void onAccessibilityServiceConfirmed(ComponentName componentName, boolean enabling);
51     }
52 
53     /**
54      * Create a new instance of the fragment
55      * @param cn Component of service
56      * @param label Human readable label
57      * @param enabling True for enabling
58      * @return new fragment instance
59      */
newInstance(ComponentName cn, CharSequence label, boolean enabling)60     public static AccessibilityServiceConfirmationFragment newInstance(ComponentName cn,
61             CharSequence label, boolean enabling) {
62         Bundle args = new Bundle(3);
63         prepareArgs(args, cn, label, enabling);
64         AccessibilityServiceConfirmationFragment fragment =
65                 new AccessibilityServiceConfirmationFragment();
66         fragment.setArguments(args);
67         return fragment;
68     }
69 
70     /**
71      * Put args in bundle
72      * @param args Bundle to prepare
73      * @param cn Component of service
74      * @param label Human readable label
75      * @param enabling True for enabling
76      */
prepareArgs(@onNull Bundle args, ComponentName cn, CharSequence label, boolean enabling)77     public static void prepareArgs(@NonNull Bundle args, ComponentName cn, CharSequence label,
78             boolean enabling) {
79         args.putParcelable(ARG_COMPONENT, cn);
80         args.putCharSequence(ARG_LABEL, label);
81         args.putBoolean(ARG_ENABLING, enabling);
82     }
83 
84     @NonNull
85     @Override
onCreateGuidance(Bundle savedInstanceState)86     public GuidanceStylist.Guidance onCreateGuidance(Bundle savedInstanceState) {
87         final CharSequence label = getArguments().getCharSequence(ARG_LABEL);
88         String sanitizedLabel = label.toString()
89                 .replace("\t", "")
90                 .replace("\r", "")
91                 .replace("\n", "")
92                 .codePoints().limit(32)
93                 .collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append)
94                 .toString();
95 
96         if (getArguments().getBoolean(ARG_ENABLING)) {
97             return new GuidanceStylist.Guidance(
98                     getString(R.string.system_accessibility_service_on_confirm_title,
99                             sanitizedLabel),
100                     getString(R.string.system_accessibility_service_on_confirm_desc,
101                             sanitizedLabel),
102                     null,
103                     getActivity().getDrawable(R.drawable.ic_accessibility_new_132dp)
104             );
105         } else {
106             return new GuidanceStylist.Guidance(
107                     getString(R.string.system_accessibility_service_off_confirm_title,
108                             sanitizedLabel),
109                     getString(R.string.system_accessibility_service_off_confirm_desc,
110                             sanitizedLabel),
111                     null,
112                     getActivity().getDrawable(R.drawable.ic_accessibility_new_132dp)
113             );
114         }
115     }
116 
117     @Override
onCreateActions(@onNull List<GuidedAction> actions, Bundle savedInstanceState)118     public void onCreateActions(@NonNull List<GuidedAction> actions,
119             Bundle savedInstanceState) {
120         final Context context = getActivity();
121         actions.add(new GuidedAction.Builder(context)
122                 .clickAction(GuidedAction.ACTION_ID_OK).build());
123         actions.add(new GuidedAction.Builder(context)
124                 .clickAction(GuidedAction.ACTION_ID_CANCEL).build());
125     }
126 
127     @Override
onGuidedActionClicked(GuidedAction action)128     public void onGuidedActionClicked(GuidedAction action) {
129         if (action.getId() == GuidedAction.ACTION_ID_OK) {
130             final ComponentName component = getArguments().getParcelable(ARG_COMPONENT);
131             final Fragment fragment = getTargetFragment();
132             final boolean enabling = getArguments().getBoolean(ARG_ENABLING);
133             if (fragment instanceof OnAccessibilityServiceConfirmedListener) {
134                 ((OnAccessibilityServiceConfirmedListener) fragment)
135                         .onAccessibilityServiceConfirmed(component, enabling);
136             } else {
137                 throw new IllegalStateException("Target fragment is not an "
138                         + "OnAccessibilityServiceConfirmedListener");
139             }
140             getFragmentManager().popBackStack();
141         } else if (action.getId() == GuidedAction.ACTION_ID_CANCEL) {
142             getFragmentManager().popBackStack();
143         } else {
144             super.onGuidedActionClicked(action);
145         }
146     }
147 }
148