• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 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.car.settings.qc;
18 
19 import static com.android.car.qc.QCItem.QC_ACTION_TOGGLE_STATE;
20 import static com.android.car.qc.QCItem.QC_TYPE_ACTION_SWITCH;
21 
22 import android.content.ContentResolver;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.net.Uri;
26 import android.provider.Settings;
27 
28 import com.android.car.qc.QCActionItem;
29 import com.android.car.qc.QCItem;
30 import com.android.car.qc.QCList;
31 import com.android.car.qc.QCRow;
32 import com.android.car.settings.R;
33 import com.android.car.settings.common.BuildInfoUtil;
34 import com.android.settingslib.development.DevelopmentSettingsEnabler;
35 
36 /**
37  * Quick control for showing a toggle for enabling the Customization tool overlay.
38  */
39 public class DebugCustomizationOverlayRow extends SettingsQCItem {
40 
41     private static final String SERVICE_ENABLED_STATE = "1";
42     private static final String SERVICE_DISABLED_STATE = "0";
43     private static final String PACKAGE = "com.android.car.customization.tool";
44     private static final String SERVICE = PACKAGE + '/' + PACKAGE + ".CustomizationToolService";
45     private final ContentResolver mContentResolver;
46 
DebugCustomizationOverlayRow(Context context)47     public DebugCustomizationOverlayRow(Context context) {
48         super(context);
49         mContentResolver = context.getContentResolver();
50     }
51 
52     @Override
getQCItem()53     protected QCItem getQCItem() {
54         if (!BuildInfoUtil.isDevTesting(getContext())
55                 || !DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(getContext())) {
56             return null;
57         }
58 
59         QCActionItem actionItem = new QCActionItem.Builder(QC_TYPE_ACTION_SWITCH)
60                 .setChecked(isCustomizationToolActive())
61                 .setAction(getBroadcastIntent())
62                 .build();
63 
64         QCList.Builder listBuilder = new QCList.Builder()
65                 .addRow(new QCRow.Builder()
66                         .setTitle(getContext().getString(R.string.show_customization_overlay_title))
67                         .addEndItem(actionItem)
68                         .build()
69                 );
70         return listBuilder.build();
71     }
72 
73     @Override
onNotifyChange(Intent intent)74     void onNotifyChange(Intent intent) {
75         boolean newState =
76                 intent.getBooleanExtra(QC_ACTION_TOGGLE_STATE, /* defaultValue= */ false);
77         toggleCustomizationTool(newState);
78     }
79 
isCustomizationToolActive()80     private boolean isCustomizationToolActive() {
81         String accessibilityServices = Settings.Secure.getString(
82                 mContentResolver, Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
83         if (accessibilityServices == null || accessibilityServices.isEmpty()) {
84             return false;
85         }
86         String serviceStatus = Settings.Secure.getString(
87                 mContentResolver, Settings.Secure.ACCESSIBILITY_ENABLED);
88         return accessibilityServices.contains(SERVICE)
89                 && SERVICE_ENABLED_STATE.equals(serviceStatus);
90     }
91 
toggleCustomizationTool(boolean newState)92     private void toggleCustomizationTool(boolean newState) {
93         String newAccessibilityServices;
94         String newServiceState;
95         String currentServices = Settings.Secure.getString(
96                 mContentResolver, Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
97 
98         if (newState) {
99             newAccessibilityServices = getCurrentListPlusService(currentServices);
100             newServiceState = SERVICE_ENABLED_STATE;
101         } else {
102             newAccessibilityServices = getCurrentListMinusService(currentServices);
103             newServiceState = SERVICE_DISABLED_STATE;
104         }
105 
106         Settings.Secure.putString(
107                 mContentResolver, Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
108                 newAccessibilityServices);
109         Settings.Secure.putString(mContentResolver, Settings.Secure.ACCESSIBILITY_ENABLED,
110                 newServiceState);
111     }
112 
getCurrentListPlusService(String currentServices)113     private String getCurrentListPlusService(String currentServices) {
114         if (currentServices == null || currentServices.isEmpty()) {
115             return SERVICE;
116         }
117         return currentServices + ":" + SERVICE;
118     }
119 
getCurrentListMinusService(String currentServices)120     private String getCurrentListMinusService(String currentServices) {
121         if (currentServices == null || currentServices.isEmpty()) {
122             return "";
123         }
124         String newServiceList = currentServices.replace(
125                 SERVICE, /* replacement= */"").replace(/* target= */"::", /* replacement= */":");
126         if (newServiceList.indexOf(':') == 0) {
127             newServiceList = newServiceList.substring(/* beginIndex= */ 1);
128         }
129         if (newServiceList.lastIndexOf(':') == newServiceList.length() - 1) {
130             newServiceList = newServiceList.substring(/* beginIndex= */ 0,
131                     /* endIndex= */ newServiceList.length() - 1);
132         }
133 
134         return newServiceList;
135     }
136 
137     @Override
getUri()138     protected Uri getUri() {
139         return SettingsQCRegistry.DEBUG_CUSTOMIZATION_OVERLAY_URI;
140     }
141 
142     @Override
getBackgroundWorkerClass()143     Class getBackgroundWorkerClass() {
144         return DefaultQCBackgroundWorker.class;
145     }
146 }
147